17db96d56Sopenharmony_ci#! /usr/bin/env python3 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci""" 47db96d56Sopenharmony_ciThe Python Debugger Pdb 57db96d56Sopenharmony_ci======================= 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciTo use the debugger in its simplest form: 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci >>> import pdb 107db96d56Sopenharmony_ci >>> pdb.run('<a statement>') 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ciThe debugger's prompt is '(Pdb) '. This will stop in the first 137db96d56Sopenharmony_cifunction call in <a statement>. 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ciAlternatively, if a statement terminated with an unhandled exception, 167db96d56Sopenharmony_ciyou can use pdb's post-mortem facility to inspect the contents of the 177db96d56Sopenharmony_citraceback: 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci >>> <a statement> 207db96d56Sopenharmony_ci <exception traceback> 217db96d56Sopenharmony_ci >>> import pdb 227db96d56Sopenharmony_ci >>> pdb.pm() 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ciThe commands recognized by the debugger are listed in the next 257db96d56Sopenharmony_cisection. Most can be abbreviated as indicated; e.g., h(elp) means 267db96d56Sopenharmony_cithat 'help' can be typed as 'h' or 'help' (but not as 'he' or 'hel', 277db96d56Sopenharmony_cinor as 'H' or 'Help' or 'HELP'). Optional arguments are enclosed in 287db96d56Sopenharmony_cisquare brackets. Alternatives in the command syntax are separated 297db96d56Sopenharmony_ciby a vertical bar (|). 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ciA blank line repeats the previous command literally, except for 327db96d56Sopenharmony_ci'list', where it lists the next 11 lines. 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ciCommands that the debugger doesn't recognize are assumed to be Python 357db96d56Sopenharmony_cistatements and are executed in the context of the program being 367db96d56Sopenharmony_cidebugged. Python statements can also be prefixed with an exclamation 377db96d56Sopenharmony_cipoint ('!'). This is a powerful way to inspect the program being 387db96d56Sopenharmony_cidebugged; it is even possible to change variables or call functions. 397db96d56Sopenharmony_ciWhen an exception occurs in such a statement, the exception name is 407db96d56Sopenharmony_ciprinted but the debugger's state is not changed. 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ciThe debugger supports aliases, which can save typing. And aliases can 437db96d56Sopenharmony_cihave parameters (see the alias help entry) which allows one a certain 447db96d56Sopenharmony_cilevel of adaptability to the context under examination. 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ciMultiple commands may be entered on a single line, separated by the 477db96d56Sopenharmony_cipair ';;'. No intelligence is applied to separating the commands; the 487db96d56Sopenharmony_ciinput is split at the first ';;', even if it is in the middle of a 497db96d56Sopenharmony_ciquoted string. 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ciIf a file ".pdbrc" exists in your home directory or in the current 527db96d56Sopenharmony_cidirectory, it is read in and executed as if it had been typed at the 537db96d56Sopenharmony_cidebugger prompt. This is particularly useful for aliases. If both 547db96d56Sopenharmony_cifiles exist, the one in the home directory is read first and aliases 557db96d56Sopenharmony_cidefined there can be overridden by the local file. This behavior can be 567db96d56Sopenharmony_cidisabled by passing the "readrc=False" argument to the Pdb constructor. 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ciAside from aliases, the debugger is not directly programmable; but it 597db96d56Sopenharmony_ciis implemented as a class from which you can derive your own debugger 607db96d56Sopenharmony_ciclass, which you can make as fancy as you like. 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ciDebugger commands 647db96d56Sopenharmony_ci================= 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci""" 677db96d56Sopenharmony_ci# NOTE: the actual command documentation is collected from docstrings of the 687db96d56Sopenharmony_ci# commands and is appended to __doc__ after the class has been defined. 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ciimport os 717db96d56Sopenharmony_ciimport io 727db96d56Sopenharmony_ciimport re 737db96d56Sopenharmony_ciimport sys 747db96d56Sopenharmony_ciimport cmd 757db96d56Sopenharmony_ciimport bdb 767db96d56Sopenharmony_ciimport dis 777db96d56Sopenharmony_ciimport code 787db96d56Sopenharmony_ciimport glob 797db96d56Sopenharmony_ciimport pprint 807db96d56Sopenharmony_ciimport signal 817db96d56Sopenharmony_ciimport inspect 827db96d56Sopenharmony_ciimport tokenize 837db96d56Sopenharmony_ciimport functools 847db96d56Sopenharmony_ciimport traceback 857db96d56Sopenharmony_ciimport linecache 867db96d56Sopenharmony_ci 877db96d56Sopenharmony_cifrom typing import Union 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ciclass Restart(Exception): 917db96d56Sopenharmony_ci """Causes a debugger to be restarted for the debugged python program.""" 927db96d56Sopenharmony_ci pass 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci__all__ = ["run", "pm", "Pdb", "runeval", "runctx", "runcall", "set_trace", 957db96d56Sopenharmony_ci "post_mortem", "help"] 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_cidef find_function(funcname, filename): 987db96d56Sopenharmony_ci cre = re.compile(r'def\s+%s\s*[(]' % re.escape(funcname)) 997db96d56Sopenharmony_ci try: 1007db96d56Sopenharmony_ci fp = tokenize.open(filename) 1017db96d56Sopenharmony_ci except OSError: 1027db96d56Sopenharmony_ci return None 1037db96d56Sopenharmony_ci # consumer of this info expects the first line to be 1 1047db96d56Sopenharmony_ci with fp: 1057db96d56Sopenharmony_ci for lineno, line in enumerate(fp, start=1): 1067db96d56Sopenharmony_ci if cre.match(line): 1077db96d56Sopenharmony_ci return funcname, filename, lineno 1087db96d56Sopenharmony_ci return None 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_cidef lasti2lineno(code, lasti): 1117db96d56Sopenharmony_ci linestarts = list(dis.findlinestarts(code)) 1127db96d56Sopenharmony_ci linestarts.reverse() 1137db96d56Sopenharmony_ci for i, lineno in linestarts: 1147db96d56Sopenharmony_ci if lasti >= i: 1157db96d56Sopenharmony_ci return lineno 1167db96d56Sopenharmony_ci return 0 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_ciclass _rstr(str): 1207db96d56Sopenharmony_ci """String that doesn't quote its repr.""" 1217db96d56Sopenharmony_ci def __repr__(self): 1227db96d56Sopenharmony_ci return self 1237db96d56Sopenharmony_ci 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ciclass _ScriptTarget(str): 1267db96d56Sopenharmony_ci def __new__(cls, val): 1277db96d56Sopenharmony_ci # Mutate self to be the "real path". 1287db96d56Sopenharmony_ci res = super().__new__(cls, os.path.realpath(val)) 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci # Store the original path for error reporting. 1317db96d56Sopenharmony_ci res.orig = val 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci return res 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci def check(self): 1367db96d56Sopenharmony_ci if not os.path.exists(self): 1377db96d56Sopenharmony_ci print('Error:', self.orig, 'does not exist') 1387db96d56Sopenharmony_ci sys.exit(1) 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci # Replace pdb's dir with script's dir in front of module search path. 1417db96d56Sopenharmony_ci sys.path[0] = os.path.dirname(self) 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci @property 1447db96d56Sopenharmony_ci def filename(self): 1457db96d56Sopenharmony_ci return self 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci @property 1487db96d56Sopenharmony_ci def namespace(self): 1497db96d56Sopenharmony_ci return dict( 1507db96d56Sopenharmony_ci __name__='__main__', 1517db96d56Sopenharmony_ci __file__=self, 1527db96d56Sopenharmony_ci __builtins__=__builtins__, 1537db96d56Sopenharmony_ci ) 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ci @property 1567db96d56Sopenharmony_ci def code(self): 1577db96d56Sopenharmony_ci with io.open_code(self) as fp: 1587db96d56Sopenharmony_ci return f"exec(compile({fp.read()!r}, {self!r}, 'exec'))" 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ciclass _ModuleTarget(str): 1627db96d56Sopenharmony_ci def check(self): 1637db96d56Sopenharmony_ci try: 1647db96d56Sopenharmony_ci self._details 1657db96d56Sopenharmony_ci except Exception: 1667db96d56Sopenharmony_ci traceback.print_exc() 1677db96d56Sopenharmony_ci sys.exit(1) 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci @functools.cached_property 1707db96d56Sopenharmony_ci def _details(self): 1717db96d56Sopenharmony_ci import runpy 1727db96d56Sopenharmony_ci return runpy._get_module_details(self) 1737db96d56Sopenharmony_ci 1747db96d56Sopenharmony_ci @property 1757db96d56Sopenharmony_ci def filename(self): 1767db96d56Sopenharmony_ci return self.code.co_filename 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci @property 1797db96d56Sopenharmony_ci def code(self): 1807db96d56Sopenharmony_ci name, spec, code = self._details 1817db96d56Sopenharmony_ci return code 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci @property 1847db96d56Sopenharmony_ci def _spec(self): 1857db96d56Sopenharmony_ci name, spec, code = self._details 1867db96d56Sopenharmony_ci return spec 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci @property 1897db96d56Sopenharmony_ci def namespace(self): 1907db96d56Sopenharmony_ci return dict( 1917db96d56Sopenharmony_ci __name__='__main__', 1927db96d56Sopenharmony_ci __file__=os.path.normcase(os.path.abspath(self.filename)), 1937db96d56Sopenharmony_ci __package__=self._spec.parent, 1947db96d56Sopenharmony_ci __loader__=self._spec.loader, 1957db96d56Sopenharmony_ci __spec__=self._spec, 1967db96d56Sopenharmony_ci __builtins__=__builtins__, 1977db96d56Sopenharmony_ci ) 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci# Interaction prompt line will separate file and call info from code 2017db96d56Sopenharmony_ci# text using value of line_prefix string. A newline and arrow may 2027db96d56Sopenharmony_ci# be to your liking. You can set it once pdb is imported using the 2037db96d56Sopenharmony_ci# command "pdb.line_prefix = '\n% '". 2047db96d56Sopenharmony_ci# line_prefix = ': ' # Use this to get the old situation back 2057db96d56Sopenharmony_ciline_prefix = '\n-> ' # Probably a better default 2067db96d56Sopenharmony_ci 2077db96d56Sopenharmony_ciclass Pdb(bdb.Bdb, cmd.Cmd): 2087db96d56Sopenharmony_ci 2097db96d56Sopenharmony_ci _previous_sigint_handler = None 2107db96d56Sopenharmony_ci 2117db96d56Sopenharmony_ci def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None, 2127db96d56Sopenharmony_ci nosigint=False, readrc=True): 2137db96d56Sopenharmony_ci bdb.Bdb.__init__(self, skip=skip) 2147db96d56Sopenharmony_ci cmd.Cmd.__init__(self, completekey, stdin, stdout) 2157db96d56Sopenharmony_ci sys.audit("pdb.Pdb") 2167db96d56Sopenharmony_ci if stdout: 2177db96d56Sopenharmony_ci self.use_rawinput = 0 2187db96d56Sopenharmony_ci self.prompt = '(Pdb) ' 2197db96d56Sopenharmony_ci self.aliases = {} 2207db96d56Sopenharmony_ci self.displaying = {} 2217db96d56Sopenharmony_ci self.mainpyfile = '' 2227db96d56Sopenharmony_ci self._wait_for_mainpyfile = False 2237db96d56Sopenharmony_ci self.tb_lineno = {} 2247db96d56Sopenharmony_ci # Try to load readline if it exists 2257db96d56Sopenharmony_ci try: 2267db96d56Sopenharmony_ci import readline 2277db96d56Sopenharmony_ci # remove some common file name delimiters 2287db96d56Sopenharmony_ci readline.set_completer_delims(' \t\n`@#$%^&*()=+[{]}\\|;:\'",<>?') 2297db96d56Sopenharmony_ci except ImportError: 2307db96d56Sopenharmony_ci pass 2317db96d56Sopenharmony_ci self.allow_kbdint = False 2327db96d56Sopenharmony_ci self.nosigint = nosigint 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci # Read ~/.pdbrc and ./.pdbrc 2357db96d56Sopenharmony_ci self.rcLines = [] 2367db96d56Sopenharmony_ci if readrc: 2377db96d56Sopenharmony_ci try: 2387db96d56Sopenharmony_ci with open(os.path.expanduser('~/.pdbrc'), encoding='utf-8') as rcFile: 2397db96d56Sopenharmony_ci self.rcLines.extend(rcFile) 2407db96d56Sopenharmony_ci except OSError: 2417db96d56Sopenharmony_ci pass 2427db96d56Sopenharmony_ci try: 2437db96d56Sopenharmony_ci with open(".pdbrc", encoding='utf-8') as rcFile: 2447db96d56Sopenharmony_ci self.rcLines.extend(rcFile) 2457db96d56Sopenharmony_ci except OSError: 2467db96d56Sopenharmony_ci pass 2477db96d56Sopenharmony_ci 2487db96d56Sopenharmony_ci self.commands = {} # associates a command list to breakpoint numbers 2497db96d56Sopenharmony_ci self.commands_doprompt = {} # for each bp num, tells if the prompt 2507db96d56Sopenharmony_ci # must be disp. after execing the cmd list 2517db96d56Sopenharmony_ci self.commands_silent = {} # for each bp num, tells if the stack trace 2527db96d56Sopenharmony_ci # must be disp. after execing the cmd list 2537db96d56Sopenharmony_ci self.commands_defining = False # True while in the process of defining 2547db96d56Sopenharmony_ci # a command list 2557db96d56Sopenharmony_ci self.commands_bnum = None # The breakpoint number for which we are 2567db96d56Sopenharmony_ci # defining a list 2577db96d56Sopenharmony_ci 2587db96d56Sopenharmony_ci def sigint_handler(self, signum, frame): 2597db96d56Sopenharmony_ci if self.allow_kbdint: 2607db96d56Sopenharmony_ci raise KeyboardInterrupt 2617db96d56Sopenharmony_ci self.message("\nProgram interrupted. (Use 'cont' to resume).") 2627db96d56Sopenharmony_ci self.set_step() 2637db96d56Sopenharmony_ci self.set_trace(frame) 2647db96d56Sopenharmony_ci 2657db96d56Sopenharmony_ci def reset(self): 2667db96d56Sopenharmony_ci bdb.Bdb.reset(self) 2677db96d56Sopenharmony_ci self.forget() 2687db96d56Sopenharmony_ci 2697db96d56Sopenharmony_ci def forget(self): 2707db96d56Sopenharmony_ci self.lineno = None 2717db96d56Sopenharmony_ci self.stack = [] 2727db96d56Sopenharmony_ci self.curindex = 0 2737db96d56Sopenharmony_ci self.curframe = None 2747db96d56Sopenharmony_ci self.tb_lineno.clear() 2757db96d56Sopenharmony_ci 2767db96d56Sopenharmony_ci def setup(self, f, tb): 2777db96d56Sopenharmony_ci self.forget() 2787db96d56Sopenharmony_ci self.stack, self.curindex = self.get_stack(f, tb) 2797db96d56Sopenharmony_ci while tb: 2807db96d56Sopenharmony_ci # when setting up post-mortem debugging with a traceback, save all 2817db96d56Sopenharmony_ci # the original line numbers to be displayed along the current line 2827db96d56Sopenharmony_ci # numbers (which can be different, e.g. due to finally clauses) 2837db96d56Sopenharmony_ci lineno = lasti2lineno(tb.tb_frame.f_code, tb.tb_lasti) 2847db96d56Sopenharmony_ci self.tb_lineno[tb.tb_frame] = lineno 2857db96d56Sopenharmony_ci tb = tb.tb_next 2867db96d56Sopenharmony_ci self.curframe = self.stack[self.curindex][0] 2877db96d56Sopenharmony_ci # The f_locals dictionary is updated from the actual frame 2887db96d56Sopenharmony_ci # locals whenever the .f_locals accessor is called, so we 2897db96d56Sopenharmony_ci # cache it here to ensure that modifications are not overwritten. 2907db96d56Sopenharmony_ci self.curframe_locals = self.curframe.f_locals 2917db96d56Sopenharmony_ci return self.execRcLines() 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ci # Can be executed earlier than 'setup' if desired 2947db96d56Sopenharmony_ci def execRcLines(self): 2957db96d56Sopenharmony_ci if not self.rcLines: 2967db96d56Sopenharmony_ci return 2977db96d56Sopenharmony_ci # local copy because of recursion 2987db96d56Sopenharmony_ci rcLines = self.rcLines 2997db96d56Sopenharmony_ci rcLines.reverse() 3007db96d56Sopenharmony_ci # execute every line only once 3017db96d56Sopenharmony_ci self.rcLines = [] 3027db96d56Sopenharmony_ci while rcLines: 3037db96d56Sopenharmony_ci line = rcLines.pop().strip() 3047db96d56Sopenharmony_ci if line and line[0] != '#': 3057db96d56Sopenharmony_ci if self.onecmd(line): 3067db96d56Sopenharmony_ci # if onecmd returns True, the command wants to exit 3077db96d56Sopenharmony_ci # from the interaction, save leftover rc lines 3087db96d56Sopenharmony_ci # to execute before next interaction 3097db96d56Sopenharmony_ci self.rcLines += reversed(rcLines) 3107db96d56Sopenharmony_ci return True 3117db96d56Sopenharmony_ci 3127db96d56Sopenharmony_ci # Override Bdb methods 3137db96d56Sopenharmony_ci 3147db96d56Sopenharmony_ci def user_call(self, frame, argument_list): 3157db96d56Sopenharmony_ci """This method is called when there is the remote possibility 3167db96d56Sopenharmony_ci that we ever need to stop in this function.""" 3177db96d56Sopenharmony_ci if self._wait_for_mainpyfile: 3187db96d56Sopenharmony_ci return 3197db96d56Sopenharmony_ci if self.stop_here(frame): 3207db96d56Sopenharmony_ci self.message('--Call--') 3217db96d56Sopenharmony_ci self.interaction(frame, None) 3227db96d56Sopenharmony_ci 3237db96d56Sopenharmony_ci def user_line(self, frame): 3247db96d56Sopenharmony_ci """This function is called when we stop or break at this line.""" 3257db96d56Sopenharmony_ci if self._wait_for_mainpyfile: 3267db96d56Sopenharmony_ci if (self.mainpyfile != self.canonic(frame.f_code.co_filename) 3277db96d56Sopenharmony_ci or frame.f_lineno <= 0): 3287db96d56Sopenharmony_ci return 3297db96d56Sopenharmony_ci self._wait_for_mainpyfile = False 3307db96d56Sopenharmony_ci if self.bp_commands(frame): 3317db96d56Sopenharmony_ci self.interaction(frame, None) 3327db96d56Sopenharmony_ci 3337db96d56Sopenharmony_ci def bp_commands(self, frame): 3347db96d56Sopenharmony_ci """Call every command that was set for the current active breakpoint 3357db96d56Sopenharmony_ci (if there is one). 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci Returns True if the normal interaction function must be called, 3387db96d56Sopenharmony_ci False otherwise.""" 3397db96d56Sopenharmony_ci # self.currentbp is set in bdb in Bdb.break_here if a breakpoint was hit 3407db96d56Sopenharmony_ci if getattr(self, "currentbp", False) and \ 3417db96d56Sopenharmony_ci self.currentbp in self.commands: 3427db96d56Sopenharmony_ci currentbp = self.currentbp 3437db96d56Sopenharmony_ci self.currentbp = 0 3447db96d56Sopenharmony_ci lastcmd_back = self.lastcmd 3457db96d56Sopenharmony_ci self.setup(frame, None) 3467db96d56Sopenharmony_ci for line in self.commands[currentbp]: 3477db96d56Sopenharmony_ci self.onecmd(line) 3487db96d56Sopenharmony_ci self.lastcmd = lastcmd_back 3497db96d56Sopenharmony_ci if not self.commands_silent[currentbp]: 3507db96d56Sopenharmony_ci self.print_stack_entry(self.stack[self.curindex]) 3517db96d56Sopenharmony_ci if self.commands_doprompt[currentbp]: 3527db96d56Sopenharmony_ci self._cmdloop() 3537db96d56Sopenharmony_ci self.forget() 3547db96d56Sopenharmony_ci return 3557db96d56Sopenharmony_ci return 1 3567db96d56Sopenharmony_ci 3577db96d56Sopenharmony_ci def user_return(self, frame, return_value): 3587db96d56Sopenharmony_ci """This function is called when a return trap is set here.""" 3597db96d56Sopenharmony_ci if self._wait_for_mainpyfile: 3607db96d56Sopenharmony_ci return 3617db96d56Sopenharmony_ci frame.f_locals['__return__'] = return_value 3627db96d56Sopenharmony_ci self.message('--Return--') 3637db96d56Sopenharmony_ci self.interaction(frame, None) 3647db96d56Sopenharmony_ci 3657db96d56Sopenharmony_ci def user_exception(self, frame, exc_info): 3667db96d56Sopenharmony_ci """This function is called if an exception occurs, 3677db96d56Sopenharmony_ci but only if we are to stop at or just below this level.""" 3687db96d56Sopenharmony_ci if self._wait_for_mainpyfile: 3697db96d56Sopenharmony_ci return 3707db96d56Sopenharmony_ci exc_type, exc_value, exc_traceback = exc_info 3717db96d56Sopenharmony_ci frame.f_locals['__exception__'] = exc_type, exc_value 3727db96d56Sopenharmony_ci 3737db96d56Sopenharmony_ci # An 'Internal StopIteration' exception is an exception debug event 3747db96d56Sopenharmony_ci # issued by the interpreter when handling a subgenerator run with 3757db96d56Sopenharmony_ci # 'yield from' or a generator controlled by a for loop. No exception has 3767db96d56Sopenharmony_ci # actually occurred in this case. The debugger uses this debug event to 3777db96d56Sopenharmony_ci # stop when the debuggee is returning from such generators. 3787db96d56Sopenharmony_ci prefix = 'Internal ' if (not exc_traceback 3797db96d56Sopenharmony_ci and exc_type is StopIteration) else '' 3807db96d56Sopenharmony_ci self.message('%s%s' % (prefix, 3817db96d56Sopenharmony_ci traceback.format_exception_only(exc_type, exc_value)[-1].strip())) 3827db96d56Sopenharmony_ci self.interaction(frame, exc_traceback) 3837db96d56Sopenharmony_ci 3847db96d56Sopenharmony_ci # General interaction function 3857db96d56Sopenharmony_ci def _cmdloop(self): 3867db96d56Sopenharmony_ci while True: 3877db96d56Sopenharmony_ci try: 3887db96d56Sopenharmony_ci # keyboard interrupts allow for an easy way to cancel 3897db96d56Sopenharmony_ci # the current command, so allow them during interactive input 3907db96d56Sopenharmony_ci self.allow_kbdint = True 3917db96d56Sopenharmony_ci self.cmdloop() 3927db96d56Sopenharmony_ci self.allow_kbdint = False 3937db96d56Sopenharmony_ci break 3947db96d56Sopenharmony_ci except KeyboardInterrupt: 3957db96d56Sopenharmony_ci self.message('--KeyboardInterrupt--') 3967db96d56Sopenharmony_ci 3977db96d56Sopenharmony_ci # Called before loop, handles display expressions 3987db96d56Sopenharmony_ci def preloop(self): 3997db96d56Sopenharmony_ci displaying = self.displaying.get(self.curframe) 4007db96d56Sopenharmony_ci if displaying: 4017db96d56Sopenharmony_ci for expr, oldvalue in displaying.items(): 4027db96d56Sopenharmony_ci newvalue = self._getval_except(expr) 4037db96d56Sopenharmony_ci # check for identity first; this prevents custom __eq__ to 4047db96d56Sopenharmony_ci # be called at every loop, and also prevents instances whose 4057db96d56Sopenharmony_ci # fields are changed to be displayed 4067db96d56Sopenharmony_ci if newvalue is not oldvalue and newvalue != oldvalue: 4077db96d56Sopenharmony_ci displaying[expr] = newvalue 4087db96d56Sopenharmony_ci self.message('display %s: %r [old: %r]' % 4097db96d56Sopenharmony_ci (expr, newvalue, oldvalue)) 4107db96d56Sopenharmony_ci 4117db96d56Sopenharmony_ci def interaction(self, frame, traceback): 4127db96d56Sopenharmony_ci # Restore the previous signal handler at the Pdb prompt. 4137db96d56Sopenharmony_ci if Pdb._previous_sigint_handler: 4147db96d56Sopenharmony_ci try: 4157db96d56Sopenharmony_ci signal.signal(signal.SIGINT, Pdb._previous_sigint_handler) 4167db96d56Sopenharmony_ci except ValueError: # ValueError: signal only works in main thread 4177db96d56Sopenharmony_ci pass 4187db96d56Sopenharmony_ci else: 4197db96d56Sopenharmony_ci Pdb._previous_sigint_handler = None 4207db96d56Sopenharmony_ci if self.setup(frame, traceback): 4217db96d56Sopenharmony_ci # no interaction desired at this time (happens if .pdbrc contains 4227db96d56Sopenharmony_ci # a command like "continue") 4237db96d56Sopenharmony_ci self.forget() 4247db96d56Sopenharmony_ci return 4257db96d56Sopenharmony_ci self.print_stack_entry(self.stack[self.curindex]) 4267db96d56Sopenharmony_ci self._cmdloop() 4277db96d56Sopenharmony_ci self.forget() 4287db96d56Sopenharmony_ci 4297db96d56Sopenharmony_ci def displayhook(self, obj): 4307db96d56Sopenharmony_ci """Custom displayhook for the exec in default(), which prevents 4317db96d56Sopenharmony_ci assignment of the _ variable in the builtins. 4327db96d56Sopenharmony_ci """ 4337db96d56Sopenharmony_ci # reproduce the behavior of the standard displayhook, not printing None 4347db96d56Sopenharmony_ci if obj is not None: 4357db96d56Sopenharmony_ci self.message(repr(obj)) 4367db96d56Sopenharmony_ci 4377db96d56Sopenharmony_ci def default(self, line): 4387db96d56Sopenharmony_ci if line[:1] == '!': line = line[1:] 4397db96d56Sopenharmony_ci locals = self.curframe_locals 4407db96d56Sopenharmony_ci globals = self.curframe.f_globals 4417db96d56Sopenharmony_ci try: 4427db96d56Sopenharmony_ci code = compile(line + '\n', '<stdin>', 'single') 4437db96d56Sopenharmony_ci save_stdout = sys.stdout 4447db96d56Sopenharmony_ci save_stdin = sys.stdin 4457db96d56Sopenharmony_ci save_displayhook = sys.displayhook 4467db96d56Sopenharmony_ci try: 4477db96d56Sopenharmony_ci sys.stdin = self.stdin 4487db96d56Sopenharmony_ci sys.stdout = self.stdout 4497db96d56Sopenharmony_ci sys.displayhook = self.displayhook 4507db96d56Sopenharmony_ci exec(code, globals, locals) 4517db96d56Sopenharmony_ci finally: 4527db96d56Sopenharmony_ci sys.stdout = save_stdout 4537db96d56Sopenharmony_ci sys.stdin = save_stdin 4547db96d56Sopenharmony_ci sys.displayhook = save_displayhook 4557db96d56Sopenharmony_ci except: 4567db96d56Sopenharmony_ci self._error_exc() 4577db96d56Sopenharmony_ci 4587db96d56Sopenharmony_ci def precmd(self, line): 4597db96d56Sopenharmony_ci """Handle alias expansion and ';;' separator.""" 4607db96d56Sopenharmony_ci if not line.strip(): 4617db96d56Sopenharmony_ci return line 4627db96d56Sopenharmony_ci args = line.split() 4637db96d56Sopenharmony_ci while args[0] in self.aliases: 4647db96d56Sopenharmony_ci line = self.aliases[args[0]] 4657db96d56Sopenharmony_ci ii = 1 4667db96d56Sopenharmony_ci for tmpArg in args[1:]: 4677db96d56Sopenharmony_ci line = line.replace("%" + str(ii), 4687db96d56Sopenharmony_ci tmpArg) 4697db96d56Sopenharmony_ci ii += 1 4707db96d56Sopenharmony_ci line = line.replace("%*", ' '.join(args[1:])) 4717db96d56Sopenharmony_ci args = line.split() 4727db96d56Sopenharmony_ci # split into ';;' separated commands 4737db96d56Sopenharmony_ci # unless it's an alias command 4747db96d56Sopenharmony_ci if args[0] != 'alias': 4757db96d56Sopenharmony_ci marker = line.find(';;') 4767db96d56Sopenharmony_ci if marker >= 0: 4777db96d56Sopenharmony_ci # queue up everything after marker 4787db96d56Sopenharmony_ci next = line[marker+2:].lstrip() 4797db96d56Sopenharmony_ci self.cmdqueue.append(next) 4807db96d56Sopenharmony_ci line = line[:marker].rstrip() 4817db96d56Sopenharmony_ci return line 4827db96d56Sopenharmony_ci 4837db96d56Sopenharmony_ci def onecmd(self, line): 4847db96d56Sopenharmony_ci """Interpret the argument as though it had been typed in response 4857db96d56Sopenharmony_ci to the prompt. 4867db96d56Sopenharmony_ci 4877db96d56Sopenharmony_ci Checks whether this line is typed at the normal prompt or in 4887db96d56Sopenharmony_ci a breakpoint command list definition. 4897db96d56Sopenharmony_ci """ 4907db96d56Sopenharmony_ci if not self.commands_defining: 4917db96d56Sopenharmony_ci return cmd.Cmd.onecmd(self, line) 4927db96d56Sopenharmony_ci else: 4937db96d56Sopenharmony_ci return self.handle_command_def(line) 4947db96d56Sopenharmony_ci 4957db96d56Sopenharmony_ci def handle_command_def(self, line): 4967db96d56Sopenharmony_ci """Handles one command line during command list definition.""" 4977db96d56Sopenharmony_ci cmd, arg, line = self.parseline(line) 4987db96d56Sopenharmony_ci if not cmd: 4997db96d56Sopenharmony_ci return 5007db96d56Sopenharmony_ci if cmd == 'silent': 5017db96d56Sopenharmony_ci self.commands_silent[self.commands_bnum] = True 5027db96d56Sopenharmony_ci return # continue to handle other cmd def in the cmd list 5037db96d56Sopenharmony_ci elif cmd == 'end': 5047db96d56Sopenharmony_ci self.cmdqueue = [] 5057db96d56Sopenharmony_ci return 1 # end of cmd list 5067db96d56Sopenharmony_ci cmdlist = self.commands[self.commands_bnum] 5077db96d56Sopenharmony_ci if arg: 5087db96d56Sopenharmony_ci cmdlist.append(cmd+' '+arg) 5097db96d56Sopenharmony_ci else: 5107db96d56Sopenharmony_ci cmdlist.append(cmd) 5117db96d56Sopenharmony_ci # Determine if we must stop 5127db96d56Sopenharmony_ci try: 5137db96d56Sopenharmony_ci func = getattr(self, 'do_' + cmd) 5147db96d56Sopenharmony_ci except AttributeError: 5157db96d56Sopenharmony_ci func = self.default 5167db96d56Sopenharmony_ci # one of the resuming commands 5177db96d56Sopenharmony_ci if func.__name__ in self.commands_resuming: 5187db96d56Sopenharmony_ci self.commands_doprompt[self.commands_bnum] = False 5197db96d56Sopenharmony_ci self.cmdqueue = [] 5207db96d56Sopenharmony_ci return 1 5217db96d56Sopenharmony_ci return 5227db96d56Sopenharmony_ci 5237db96d56Sopenharmony_ci # interface abstraction functions 5247db96d56Sopenharmony_ci 5257db96d56Sopenharmony_ci def message(self, msg): 5267db96d56Sopenharmony_ci print(msg, file=self.stdout) 5277db96d56Sopenharmony_ci 5287db96d56Sopenharmony_ci def error(self, msg): 5297db96d56Sopenharmony_ci print('***', msg, file=self.stdout) 5307db96d56Sopenharmony_ci 5317db96d56Sopenharmony_ci # Generic completion functions. Individual complete_foo methods can be 5327db96d56Sopenharmony_ci # assigned below to one of these functions. 5337db96d56Sopenharmony_ci 5347db96d56Sopenharmony_ci def _complete_location(self, text, line, begidx, endidx): 5357db96d56Sopenharmony_ci # Complete a file/module/function location for break/tbreak/clear. 5367db96d56Sopenharmony_ci if line.strip().endswith((':', ',')): 5377db96d56Sopenharmony_ci # Here comes a line number or a condition which we can't complete. 5387db96d56Sopenharmony_ci return [] 5397db96d56Sopenharmony_ci # First, try to find matching functions (i.e. expressions). 5407db96d56Sopenharmony_ci try: 5417db96d56Sopenharmony_ci ret = self._complete_expression(text, line, begidx, endidx) 5427db96d56Sopenharmony_ci except Exception: 5437db96d56Sopenharmony_ci ret = [] 5447db96d56Sopenharmony_ci # Then, try to complete file names as well. 5457db96d56Sopenharmony_ci globs = glob.glob(glob.escape(text) + '*') 5467db96d56Sopenharmony_ci for fn in globs: 5477db96d56Sopenharmony_ci if os.path.isdir(fn): 5487db96d56Sopenharmony_ci ret.append(fn + '/') 5497db96d56Sopenharmony_ci elif os.path.isfile(fn) and fn.lower().endswith(('.py', '.pyw')): 5507db96d56Sopenharmony_ci ret.append(fn + ':') 5517db96d56Sopenharmony_ci return ret 5527db96d56Sopenharmony_ci 5537db96d56Sopenharmony_ci def _complete_bpnumber(self, text, line, begidx, endidx): 5547db96d56Sopenharmony_ci # Complete a breakpoint number. (This would be more helpful if we could 5557db96d56Sopenharmony_ci # display additional info along with the completions, such as file/line 5567db96d56Sopenharmony_ci # of the breakpoint.) 5577db96d56Sopenharmony_ci return [str(i) for i, bp in enumerate(bdb.Breakpoint.bpbynumber) 5587db96d56Sopenharmony_ci if bp is not None and str(i).startswith(text)] 5597db96d56Sopenharmony_ci 5607db96d56Sopenharmony_ci def _complete_expression(self, text, line, begidx, endidx): 5617db96d56Sopenharmony_ci # Complete an arbitrary expression. 5627db96d56Sopenharmony_ci if not self.curframe: 5637db96d56Sopenharmony_ci return [] 5647db96d56Sopenharmony_ci # Collect globals and locals. It is usually not really sensible to also 5657db96d56Sopenharmony_ci # complete builtins, and they clutter the namespace quite heavily, so we 5667db96d56Sopenharmony_ci # leave them out. 5677db96d56Sopenharmony_ci ns = {**self.curframe.f_globals, **self.curframe_locals} 5687db96d56Sopenharmony_ci if '.' in text: 5697db96d56Sopenharmony_ci # Walk an attribute chain up to the last part, similar to what 5707db96d56Sopenharmony_ci # rlcompleter does. This will bail if any of the parts are not 5717db96d56Sopenharmony_ci # simple attribute access, which is what we want. 5727db96d56Sopenharmony_ci dotted = text.split('.') 5737db96d56Sopenharmony_ci try: 5747db96d56Sopenharmony_ci obj = ns[dotted[0]] 5757db96d56Sopenharmony_ci for part in dotted[1:-1]: 5767db96d56Sopenharmony_ci obj = getattr(obj, part) 5777db96d56Sopenharmony_ci except (KeyError, AttributeError): 5787db96d56Sopenharmony_ci return [] 5797db96d56Sopenharmony_ci prefix = '.'.join(dotted[:-1]) + '.' 5807db96d56Sopenharmony_ci return [prefix + n for n in dir(obj) if n.startswith(dotted[-1])] 5817db96d56Sopenharmony_ci else: 5827db96d56Sopenharmony_ci # Complete a simple name. 5837db96d56Sopenharmony_ci return [n for n in ns.keys() if n.startswith(text)] 5847db96d56Sopenharmony_ci 5857db96d56Sopenharmony_ci # Command definitions, called by cmdloop() 5867db96d56Sopenharmony_ci # The argument is the remaining string on the command line 5877db96d56Sopenharmony_ci # Return true to exit from the command loop 5887db96d56Sopenharmony_ci 5897db96d56Sopenharmony_ci def do_commands(self, arg): 5907db96d56Sopenharmony_ci """commands [bpnumber] 5917db96d56Sopenharmony_ci (com) ... 5927db96d56Sopenharmony_ci (com) end 5937db96d56Sopenharmony_ci (Pdb) 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci Specify a list of commands for breakpoint number bpnumber. 5967db96d56Sopenharmony_ci The commands themselves are entered on the following lines. 5977db96d56Sopenharmony_ci Type a line containing just 'end' to terminate the commands. 5987db96d56Sopenharmony_ci The commands are executed when the breakpoint is hit. 5997db96d56Sopenharmony_ci 6007db96d56Sopenharmony_ci To remove all commands from a breakpoint, type commands and 6017db96d56Sopenharmony_ci follow it immediately with end; that is, give no commands. 6027db96d56Sopenharmony_ci 6037db96d56Sopenharmony_ci With no bpnumber argument, commands refers to the last 6047db96d56Sopenharmony_ci breakpoint set. 6057db96d56Sopenharmony_ci 6067db96d56Sopenharmony_ci You can use breakpoint commands to start your program up 6077db96d56Sopenharmony_ci again. Simply use the continue command, or step, or any other 6087db96d56Sopenharmony_ci command that resumes execution. 6097db96d56Sopenharmony_ci 6107db96d56Sopenharmony_ci Specifying any command resuming execution (currently continue, 6117db96d56Sopenharmony_ci step, next, return, jump, quit and their abbreviations) 6127db96d56Sopenharmony_ci terminates the command list (as if that command was 6137db96d56Sopenharmony_ci immediately followed by end). This is because any time you 6147db96d56Sopenharmony_ci resume execution (even with a simple next or step), you may 6157db96d56Sopenharmony_ci encounter another breakpoint -- which could have its own 6167db96d56Sopenharmony_ci command list, leading to ambiguities about which list to 6177db96d56Sopenharmony_ci execute. 6187db96d56Sopenharmony_ci 6197db96d56Sopenharmony_ci If you use the 'silent' command in the command list, the usual 6207db96d56Sopenharmony_ci message about stopping at a breakpoint is not printed. This 6217db96d56Sopenharmony_ci may be desirable for breakpoints that are to print a specific 6227db96d56Sopenharmony_ci message and then continue. If none of the other commands 6237db96d56Sopenharmony_ci print anything, you will see no sign that the breakpoint was 6247db96d56Sopenharmony_ci reached. 6257db96d56Sopenharmony_ci """ 6267db96d56Sopenharmony_ci if not arg: 6277db96d56Sopenharmony_ci bnum = len(bdb.Breakpoint.bpbynumber) - 1 6287db96d56Sopenharmony_ci else: 6297db96d56Sopenharmony_ci try: 6307db96d56Sopenharmony_ci bnum = int(arg) 6317db96d56Sopenharmony_ci except: 6327db96d56Sopenharmony_ci self.error("Usage: commands [bnum]\n ...\n end") 6337db96d56Sopenharmony_ci return 6347db96d56Sopenharmony_ci try: 6357db96d56Sopenharmony_ci self.get_bpbynumber(bnum) 6367db96d56Sopenharmony_ci except ValueError as err: 6377db96d56Sopenharmony_ci self.error('cannot set commands: %s' % err) 6387db96d56Sopenharmony_ci return 6397db96d56Sopenharmony_ci 6407db96d56Sopenharmony_ci self.commands_bnum = bnum 6417db96d56Sopenharmony_ci # Save old definitions for the case of a keyboard interrupt. 6427db96d56Sopenharmony_ci if bnum in self.commands: 6437db96d56Sopenharmony_ci old_command_defs = (self.commands[bnum], 6447db96d56Sopenharmony_ci self.commands_doprompt[bnum], 6457db96d56Sopenharmony_ci self.commands_silent[bnum]) 6467db96d56Sopenharmony_ci else: 6477db96d56Sopenharmony_ci old_command_defs = None 6487db96d56Sopenharmony_ci self.commands[bnum] = [] 6497db96d56Sopenharmony_ci self.commands_doprompt[bnum] = True 6507db96d56Sopenharmony_ci self.commands_silent[bnum] = False 6517db96d56Sopenharmony_ci 6527db96d56Sopenharmony_ci prompt_back = self.prompt 6537db96d56Sopenharmony_ci self.prompt = '(com) ' 6547db96d56Sopenharmony_ci self.commands_defining = True 6557db96d56Sopenharmony_ci try: 6567db96d56Sopenharmony_ci self.cmdloop() 6577db96d56Sopenharmony_ci except KeyboardInterrupt: 6587db96d56Sopenharmony_ci # Restore old definitions. 6597db96d56Sopenharmony_ci if old_command_defs: 6607db96d56Sopenharmony_ci self.commands[bnum] = old_command_defs[0] 6617db96d56Sopenharmony_ci self.commands_doprompt[bnum] = old_command_defs[1] 6627db96d56Sopenharmony_ci self.commands_silent[bnum] = old_command_defs[2] 6637db96d56Sopenharmony_ci else: 6647db96d56Sopenharmony_ci del self.commands[bnum] 6657db96d56Sopenharmony_ci del self.commands_doprompt[bnum] 6667db96d56Sopenharmony_ci del self.commands_silent[bnum] 6677db96d56Sopenharmony_ci self.error('command definition aborted, old commands restored') 6687db96d56Sopenharmony_ci finally: 6697db96d56Sopenharmony_ci self.commands_defining = False 6707db96d56Sopenharmony_ci self.prompt = prompt_back 6717db96d56Sopenharmony_ci 6727db96d56Sopenharmony_ci complete_commands = _complete_bpnumber 6737db96d56Sopenharmony_ci 6747db96d56Sopenharmony_ci def do_break(self, arg, temporary = 0): 6757db96d56Sopenharmony_ci """b(reak) [ ([filename:]lineno | function) [, condition] ] 6767db96d56Sopenharmony_ci Without argument, list all breaks. 6777db96d56Sopenharmony_ci 6787db96d56Sopenharmony_ci With a line number argument, set a break at this line in the 6797db96d56Sopenharmony_ci current file. With a function name, set a break at the first 6807db96d56Sopenharmony_ci executable line of that function. If a second argument is 6817db96d56Sopenharmony_ci present, it is a string specifying an expression which must 6827db96d56Sopenharmony_ci evaluate to true before the breakpoint is honored. 6837db96d56Sopenharmony_ci 6847db96d56Sopenharmony_ci The line number may be prefixed with a filename and a colon, 6857db96d56Sopenharmony_ci to specify a breakpoint in another file (probably one that 6867db96d56Sopenharmony_ci hasn't been loaded yet). The file is searched for on 6877db96d56Sopenharmony_ci sys.path; the .py suffix may be omitted. 6887db96d56Sopenharmony_ci """ 6897db96d56Sopenharmony_ci if not arg: 6907db96d56Sopenharmony_ci if self.breaks: # There's at least one 6917db96d56Sopenharmony_ci self.message("Num Type Disp Enb Where") 6927db96d56Sopenharmony_ci for bp in bdb.Breakpoint.bpbynumber: 6937db96d56Sopenharmony_ci if bp: 6947db96d56Sopenharmony_ci self.message(bp.bpformat()) 6957db96d56Sopenharmony_ci return 6967db96d56Sopenharmony_ci # parse arguments; comma has lowest precedence 6977db96d56Sopenharmony_ci # and cannot occur in filename 6987db96d56Sopenharmony_ci filename = None 6997db96d56Sopenharmony_ci lineno = None 7007db96d56Sopenharmony_ci cond = None 7017db96d56Sopenharmony_ci comma = arg.find(',') 7027db96d56Sopenharmony_ci if comma > 0: 7037db96d56Sopenharmony_ci # parse stuff after comma: "condition" 7047db96d56Sopenharmony_ci cond = arg[comma+1:].lstrip() 7057db96d56Sopenharmony_ci arg = arg[:comma].rstrip() 7067db96d56Sopenharmony_ci # parse stuff before comma: [filename:]lineno | function 7077db96d56Sopenharmony_ci colon = arg.rfind(':') 7087db96d56Sopenharmony_ci funcname = None 7097db96d56Sopenharmony_ci if colon >= 0: 7107db96d56Sopenharmony_ci filename = arg[:colon].rstrip() 7117db96d56Sopenharmony_ci f = self.lookupmodule(filename) 7127db96d56Sopenharmony_ci if not f: 7137db96d56Sopenharmony_ci self.error('%r not found from sys.path' % filename) 7147db96d56Sopenharmony_ci return 7157db96d56Sopenharmony_ci else: 7167db96d56Sopenharmony_ci filename = f 7177db96d56Sopenharmony_ci arg = arg[colon+1:].lstrip() 7187db96d56Sopenharmony_ci try: 7197db96d56Sopenharmony_ci lineno = int(arg) 7207db96d56Sopenharmony_ci except ValueError: 7217db96d56Sopenharmony_ci self.error('Bad lineno: %s' % arg) 7227db96d56Sopenharmony_ci return 7237db96d56Sopenharmony_ci else: 7247db96d56Sopenharmony_ci # no colon; can be lineno or function 7257db96d56Sopenharmony_ci try: 7267db96d56Sopenharmony_ci lineno = int(arg) 7277db96d56Sopenharmony_ci except ValueError: 7287db96d56Sopenharmony_ci try: 7297db96d56Sopenharmony_ci func = eval(arg, 7307db96d56Sopenharmony_ci self.curframe.f_globals, 7317db96d56Sopenharmony_ci self.curframe_locals) 7327db96d56Sopenharmony_ci except: 7337db96d56Sopenharmony_ci func = arg 7347db96d56Sopenharmony_ci try: 7357db96d56Sopenharmony_ci if hasattr(func, '__func__'): 7367db96d56Sopenharmony_ci func = func.__func__ 7377db96d56Sopenharmony_ci code = func.__code__ 7387db96d56Sopenharmony_ci #use co_name to identify the bkpt (function names 7397db96d56Sopenharmony_ci #could be aliased, but co_name is invariant) 7407db96d56Sopenharmony_ci funcname = code.co_name 7417db96d56Sopenharmony_ci lineno = code.co_firstlineno 7427db96d56Sopenharmony_ci filename = code.co_filename 7437db96d56Sopenharmony_ci except: 7447db96d56Sopenharmony_ci # last thing to try 7457db96d56Sopenharmony_ci (ok, filename, ln) = self.lineinfo(arg) 7467db96d56Sopenharmony_ci if not ok: 7477db96d56Sopenharmony_ci self.error('The specified object %r is not a function ' 7487db96d56Sopenharmony_ci 'or was not found along sys.path.' % arg) 7497db96d56Sopenharmony_ci return 7507db96d56Sopenharmony_ci funcname = ok # ok contains a function name 7517db96d56Sopenharmony_ci lineno = int(ln) 7527db96d56Sopenharmony_ci if not filename: 7537db96d56Sopenharmony_ci filename = self.defaultFile() 7547db96d56Sopenharmony_ci # Check for reasonable breakpoint 7557db96d56Sopenharmony_ci line = self.checkline(filename, lineno) 7567db96d56Sopenharmony_ci if line: 7577db96d56Sopenharmony_ci # now set the break point 7587db96d56Sopenharmony_ci err = self.set_break(filename, line, temporary, cond, funcname) 7597db96d56Sopenharmony_ci if err: 7607db96d56Sopenharmony_ci self.error(err) 7617db96d56Sopenharmony_ci else: 7627db96d56Sopenharmony_ci bp = self.get_breaks(filename, line)[-1] 7637db96d56Sopenharmony_ci self.message("Breakpoint %d at %s:%d" % 7647db96d56Sopenharmony_ci (bp.number, bp.file, bp.line)) 7657db96d56Sopenharmony_ci 7667db96d56Sopenharmony_ci # To be overridden in derived debuggers 7677db96d56Sopenharmony_ci def defaultFile(self): 7687db96d56Sopenharmony_ci """Produce a reasonable default.""" 7697db96d56Sopenharmony_ci filename = self.curframe.f_code.co_filename 7707db96d56Sopenharmony_ci if filename == '<string>' and self.mainpyfile: 7717db96d56Sopenharmony_ci filename = self.mainpyfile 7727db96d56Sopenharmony_ci return filename 7737db96d56Sopenharmony_ci 7747db96d56Sopenharmony_ci do_b = do_break 7757db96d56Sopenharmony_ci 7767db96d56Sopenharmony_ci complete_break = _complete_location 7777db96d56Sopenharmony_ci complete_b = _complete_location 7787db96d56Sopenharmony_ci 7797db96d56Sopenharmony_ci def do_tbreak(self, arg): 7807db96d56Sopenharmony_ci """tbreak [ ([filename:]lineno | function) [, condition] ] 7817db96d56Sopenharmony_ci Same arguments as break, but sets a temporary breakpoint: it 7827db96d56Sopenharmony_ci is automatically deleted when first hit. 7837db96d56Sopenharmony_ci """ 7847db96d56Sopenharmony_ci self.do_break(arg, 1) 7857db96d56Sopenharmony_ci 7867db96d56Sopenharmony_ci complete_tbreak = _complete_location 7877db96d56Sopenharmony_ci 7887db96d56Sopenharmony_ci def lineinfo(self, identifier): 7897db96d56Sopenharmony_ci failed = (None, None, None) 7907db96d56Sopenharmony_ci # Input is identifier, may be in single quotes 7917db96d56Sopenharmony_ci idstring = identifier.split("'") 7927db96d56Sopenharmony_ci if len(idstring) == 1: 7937db96d56Sopenharmony_ci # not in single quotes 7947db96d56Sopenharmony_ci id = idstring[0].strip() 7957db96d56Sopenharmony_ci elif len(idstring) == 3: 7967db96d56Sopenharmony_ci # quoted 7977db96d56Sopenharmony_ci id = idstring[1].strip() 7987db96d56Sopenharmony_ci else: 7997db96d56Sopenharmony_ci return failed 8007db96d56Sopenharmony_ci if id == '': return failed 8017db96d56Sopenharmony_ci parts = id.split('.') 8027db96d56Sopenharmony_ci # Protection for derived debuggers 8037db96d56Sopenharmony_ci if parts[0] == 'self': 8047db96d56Sopenharmony_ci del parts[0] 8057db96d56Sopenharmony_ci if len(parts) == 0: 8067db96d56Sopenharmony_ci return failed 8077db96d56Sopenharmony_ci # Best first guess at file to look at 8087db96d56Sopenharmony_ci fname = self.defaultFile() 8097db96d56Sopenharmony_ci if len(parts) == 1: 8107db96d56Sopenharmony_ci item = parts[0] 8117db96d56Sopenharmony_ci else: 8127db96d56Sopenharmony_ci # More than one part. 8137db96d56Sopenharmony_ci # First is module, second is method/class 8147db96d56Sopenharmony_ci f = self.lookupmodule(parts[0]) 8157db96d56Sopenharmony_ci if f: 8167db96d56Sopenharmony_ci fname = f 8177db96d56Sopenharmony_ci item = parts[1] 8187db96d56Sopenharmony_ci answer = find_function(item, fname) 8197db96d56Sopenharmony_ci return answer or failed 8207db96d56Sopenharmony_ci 8217db96d56Sopenharmony_ci def checkline(self, filename, lineno): 8227db96d56Sopenharmony_ci """Check whether specified line seems to be executable. 8237db96d56Sopenharmony_ci 8247db96d56Sopenharmony_ci Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank 8257db96d56Sopenharmony_ci line or EOF). Warning: testing is not comprehensive. 8267db96d56Sopenharmony_ci """ 8277db96d56Sopenharmony_ci # this method should be callable before starting debugging, so default 8287db96d56Sopenharmony_ci # to "no globals" if there is no current frame 8297db96d56Sopenharmony_ci frame = getattr(self, 'curframe', None) 8307db96d56Sopenharmony_ci globs = frame.f_globals if frame else None 8317db96d56Sopenharmony_ci line = linecache.getline(filename, lineno, globs) 8327db96d56Sopenharmony_ci if not line: 8337db96d56Sopenharmony_ci self.message('End of file') 8347db96d56Sopenharmony_ci return 0 8357db96d56Sopenharmony_ci line = line.strip() 8367db96d56Sopenharmony_ci # Don't allow setting breakpoint at a blank line 8377db96d56Sopenharmony_ci if (not line or (line[0] == '#') or 8387db96d56Sopenharmony_ci (line[:3] == '"""') or line[:3] == "'''"): 8397db96d56Sopenharmony_ci self.error('Blank or comment') 8407db96d56Sopenharmony_ci return 0 8417db96d56Sopenharmony_ci return lineno 8427db96d56Sopenharmony_ci 8437db96d56Sopenharmony_ci def do_enable(self, arg): 8447db96d56Sopenharmony_ci """enable bpnumber [bpnumber ...] 8457db96d56Sopenharmony_ci Enables the breakpoints given as a space separated list of 8467db96d56Sopenharmony_ci breakpoint numbers. 8477db96d56Sopenharmony_ci """ 8487db96d56Sopenharmony_ci args = arg.split() 8497db96d56Sopenharmony_ci for i in args: 8507db96d56Sopenharmony_ci try: 8517db96d56Sopenharmony_ci bp = self.get_bpbynumber(i) 8527db96d56Sopenharmony_ci except ValueError as err: 8537db96d56Sopenharmony_ci self.error(err) 8547db96d56Sopenharmony_ci else: 8557db96d56Sopenharmony_ci bp.enable() 8567db96d56Sopenharmony_ci self.message('Enabled %s' % bp) 8577db96d56Sopenharmony_ci 8587db96d56Sopenharmony_ci complete_enable = _complete_bpnumber 8597db96d56Sopenharmony_ci 8607db96d56Sopenharmony_ci def do_disable(self, arg): 8617db96d56Sopenharmony_ci """disable bpnumber [bpnumber ...] 8627db96d56Sopenharmony_ci Disables the breakpoints given as a space separated list of 8637db96d56Sopenharmony_ci breakpoint numbers. Disabling a breakpoint means it cannot 8647db96d56Sopenharmony_ci cause the program to stop execution, but unlike clearing a 8657db96d56Sopenharmony_ci breakpoint, it remains in the list of breakpoints and can be 8667db96d56Sopenharmony_ci (re-)enabled. 8677db96d56Sopenharmony_ci """ 8687db96d56Sopenharmony_ci args = arg.split() 8697db96d56Sopenharmony_ci for i in args: 8707db96d56Sopenharmony_ci try: 8717db96d56Sopenharmony_ci bp = self.get_bpbynumber(i) 8727db96d56Sopenharmony_ci except ValueError as err: 8737db96d56Sopenharmony_ci self.error(err) 8747db96d56Sopenharmony_ci else: 8757db96d56Sopenharmony_ci bp.disable() 8767db96d56Sopenharmony_ci self.message('Disabled %s' % bp) 8777db96d56Sopenharmony_ci 8787db96d56Sopenharmony_ci complete_disable = _complete_bpnumber 8797db96d56Sopenharmony_ci 8807db96d56Sopenharmony_ci def do_condition(self, arg): 8817db96d56Sopenharmony_ci """condition bpnumber [condition] 8827db96d56Sopenharmony_ci Set a new condition for the breakpoint, an expression which 8837db96d56Sopenharmony_ci must evaluate to true before the breakpoint is honored. If 8847db96d56Sopenharmony_ci condition is absent, any existing condition is removed; i.e., 8857db96d56Sopenharmony_ci the breakpoint is made unconditional. 8867db96d56Sopenharmony_ci """ 8877db96d56Sopenharmony_ci args = arg.split(' ', 1) 8887db96d56Sopenharmony_ci try: 8897db96d56Sopenharmony_ci cond = args[1] 8907db96d56Sopenharmony_ci except IndexError: 8917db96d56Sopenharmony_ci cond = None 8927db96d56Sopenharmony_ci try: 8937db96d56Sopenharmony_ci bp = self.get_bpbynumber(args[0].strip()) 8947db96d56Sopenharmony_ci except IndexError: 8957db96d56Sopenharmony_ci self.error('Breakpoint number expected') 8967db96d56Sopenharmony_ci except ValueError as err: 8977db96d56Sopenharmony_ci self.error(err) 8987db96d56Sopenharmony_ci else: 8997db96d56Sopenharmony_ci bp.cond = cond 9007db96d56Sopenharmony_ci if not cond: 9017db96d56Sopenharmony_ci self.message('Breakpoint %d is now unconditional.' % bp.number) 9027db96d56Sopenharmony_ci else: 9037db96d56Sopenharmony_ci self.message('New condition set for breakpoint %d.' % bp.number) 9047db96d56Sopenharmony_ci 9057db96d56Sopenharmony_ci complete_condition = _complete_bpnumber 9067db96d56Sopenharmony_ci 9077db96d56Sopenharmony_ci def do_ignore(self, arg): 9087db96d56Sopenharmony_ci """ignore bpnumber [count] 9097db96d56Sopenharmony_ci Set the ignore count for the given breakpoint number. If 9107db96d56Sopenharmony_ci count is omitted, the ignore count is set to 0. A breakpoint 9117db96d56Sopenharmony_ci becomes active when the ignore count is zero. When non-zero, 9127db96d56Sopenharmony_ci the count is decremented each time the breakpoint is reached 9137db96d56Sopenharmony_ci and the breakpoint is not disabled and any associated 9147db96d56Sopenharmony_ci condition evaluates to true. 9157db96d56Sopenharmony_ci """ 9167db96d56Sopenharmony_ci args = arg.split() 9177db96d56Sopenharmony_ci try: 9187db96d56Sopenharmony_ci count = int(args[1].strip()) 9197db96d56Sopenharmony_ci except: 9207db96d56Sopenharmony_ci count = 0 9217db96d56Sopenharmony_ci try: 9227db96d56Sopenharmony_ci bp = self.get_bpbynumber(args[0].strip()) 9237db96d56Sopenharmony_ci except IndexError: 9247db96d56Sopenharmony_ci self.error('Breakpoint number expected') 9257db96d56Sopenharmony_ci except ValueError as err: 9267db96d56Sopenharmony_ci self.error(err) 9277db96d56Sopenharmony_ci else: 9287db96d56Sopenharmony_ci bp.ignore = count 9297db96d56Sopenharmony_ci if count > 0: 9307db96d56Sopenharmony_ci if count > 1: 9317db96d56Sopenharmony_ci countstr = '%d crossings' % count 9327db96d56Sopenharmony_ci else: 9337db96d56Sopenharmony_ci countstr = '1 crossing' 9347db96d56Sopenharmony_ci self.message('Will ignore next %s of breakpoint %d.' % 9357db96d56Sopenharmony_ci (countstr, bp.number)) 9367db96d56Sopenharmony_ci else: 9377db96d56Sopenharmony_ci self.message('Will stop next time breakpoint %d is reached.' 9387db96d56Sopenharmony_ci % bp.number) 9397db96d56Sopenharmony_ci 9407db96d56Sopenharmony_ci complete_ignore = _complete_bpnumber 9417db96d56Sopenharmony_ci 9427db96d56Sopenharmony_ci def do_clear(self, arg): 9437db96d56Sopenharmony_ci """cl(ear) filename:lineno\ncl(ear) [bpnumber [bpnumber...]] 9447db96d56Sopenharmony_ci With a space separated list of breakpoint numbers, clear 9457db96d56Sopenharmony_ci those breakpoints. Without argument, clear all breaks (but 9467db96d56Sopenharmony_ci first ask confirmation). With a filename:lineno argument, 9477db96d56Sopenharmony_ci clear all breaks at that line in that file. 9487db96d56Sopenharmony_ci """ 9497db96d56Sopenharmony_ci if not arg: 9507db96d56Sopenharmony_ci try: 9517db96d56Sopenharmony_ci reply = input('Clear all breaks? ') 9527db96d56Sopenharmony_ci except EOFError: 9537db96d56Sopenharmony_ci reply = 'no' 9547db96d56Sopenharmony_ci reply = reply.strip().lower() 9557db96d56Sopenharmony_ci if reply in ('y', 'yes'): 9567db96d56Sopenharmony_ci bplist = [bp for bp in bdb.Breakpoint.bpbynumber if bp] 9577db96d56Sopenharmony_ci self.clear_all_breaks() 9587db96d56Sopenharmony_ci for bp in bplist: 9597db96d56Sopenharmony_ci self.message('Deleted %s' % bp) 9607db96d56Sopenharmony_ci return 9617db96d56Sopenharmony_ci if ':' in arg: 9627db96d56Sopenharmony_ci # Make sure it works for "clear C:\foo\bar.py:12" 9637db96d56Sopenharmony_ci i = arg.rfind(':') 9647db96d56Sopenharmony_ci filename = arg[:i] 9657db96d56Sopenharmony_ci arg = arg[i+1:] 9667db96d56Sopenharmony_ci try: 9677db96d56Sopenharmony_ci lineno = int(arg) 9687db96d56Sopenharmony_ci except ValueError: 9697db96d56Sopenharmony_ci err = "Invalid line number (%s)" % arg 9707db96d56Sopenharmony_ci else: 9717db96d56Sopenharmony_ci bplist = self.get_breaks(filename, lineno)[:] 9727db96d56Sopenharmony_ci err = self.clear_break(filename, lineno) 9737db96d56Sopenharmony_ci if err: 9747db96d56Sopenharmony_ci self.error(err) 9757db96d56Sopenharmony_ci else: 9767db96d56Sopenharmony_ci for bp in bplist: 9777db96d56Sopenharmony_ci self.message('Deleted %s' % bp) 9787db96d56Sopenharmony_ci return 9797db96d56Sopenharmony_ci numberlist = arg.split() 9807db96d56Sopenharmony_ci for i in numberlist: 9817db96d56Sopenharmony_ci try: 9827db96d56Sopenharmony_ci bp = self.get_bpbynumber(i) 9837db96d56Sopenharmony_ci except ValueError as err: 9847db96d56Sopenharmony_ci self.error(err) 9857db96d56Sopenharmony_ci else: 9867db96d56Sopenharmony_ci self.clear_bpbynumber(i) 9877db96d56Sopenharmony_ci self.message('Deleted %s' % bp) 9887db96d56Sopenharmony_ci do_cl = do_clear # 'c' is already an abbreviation for 'continue' 9897db96d56Sopenharmony_ci 9907db96d56Sopenharmony_ci complete_clear = _complete_location 9917db96d56Sopenharmony_ci complete_cl = _complete_location 9927db96d56Sopenharmony_ci 9937db96d56Sopenharmony_ci def do_where(self, arg): 9947db96d56Sopenharmony_ci """w(here) 9957db96d56Sopenharmony_ci Print a stack trace, with the most recent frame at the bottom. 9967db96d56Sopenharmony_ci An arrow indicates the "current frame", which determines the 9977db96d56Sopenharmony_ci context of most commands. 'bt' is an alias for this command. 9987db96d56Sopenharmony_ci """ 9997db96d56Sopenharmony_ci self.print_stack_trace() 10007db96d56Sopenharmony_ci do_w = do_where 10017db96d56Sopenharmony_ci do_bt = do_where 10027db96d56Sopenharmony_ci 10037db96d56Sopenharmony_ci def _select_frame(self, number): 10047db96d56Sopenharmony_ci assert 0 <= number < len(self.stack) 10057db96d56Sopenharmony_ci self.curindex = number 10067db96d56Sopenharmony_ci self.curframe = self.stack[self.curindex][0] 10077db96d56Sopenharmony_ci self.curframe_locals = self.curframe.f_locals 10087db96d56Sopenharmony_ci self.print_stack_entry(self.stack[self.curindex]) 10097db96d56Sopenharmony_ci self.lineno = None 10107db96d56Sopenharmony_ci 10117db96d56Sopenharmony_ci def do_up(self, arg): 10127db96d56Sopenharmony_ci """u(p) [count] 10137db96d56Sopenharmony_ci Move the current frame count (default one) levels up in the 10147db96d56Sopenharmony_ci stack trace (to an older frame). 10157db96d56Sopenharmony_ci """ 10167db96d56Sopenharmony_ci if self.curindex == 0: 10177db96d56Sopenharmony_ci self.error('Oldest frame') 10187db96d56Sopenharmony_ci return 10197db96d56Sopenharmony_ci try: 10207db96d56Sopenharmony_ci count = int(arg or 1) 10217db96d56Sopenharmony_ci except ValueError: 10227db96d56Sopenharmony_ci self.error('Invalid frame count (%s)' % arg) 10237db96d56Sopenharmony_ci return 10247db96d56Sopenharmony_ci if count < 0: 10257db96d56Sopenharmony_ci newframe = 0 10267db96d56Sopenharmony_ci else: 10277db96d56Sopenharmony_ci newframe = max(0, self.curindex - count) 10287db96d56Sopenharmony_ci self._select_frame(newframe) 10297db96d56Sopenharmony_ci do_u = do_up 10307db96d56Sopenharmony_ci 10317db96d56Sopenharmony_ci def do_down(self, arg): 10327db96d56Sopenharmony_ci """d(own) [count] 10337db96d56Sopenharmony_ci Move the current frame count (default one) levels down in the 10347db96d56Sopenharmony_ci stack trace (to a newer frame). 10357db96d56Sopenharmony_ci """ 10367db96d56Sopenharmony_ci if self.curindex + 1 == len(self.stack): 10377db96d56Sopenharmony_ci self.error('Newest frame') 10387db96d56Sopenharmony_ci return 10397db96d56Sopenharmony_ci try: 10407db96d56Sopenharmony_ci count = int(arg or 1) 10417db96d56Sopenharmony_ci except ValueError: 10427db96d56Sopenharmony_ci self.error('Invalid frame count (%s)' % arg) 10437db96d56Sopenharmony_ci return 10447db96d56Sopenharmony_ci if count < 0: 10457db96d56Sopenharmony_ci newframe = len(self.stack) - 1 10467db96d56Sopenharmony_ci else: 10477db96d56Sopenharmony_ci newframe = min(len(self.stack) - 1, self.curindex + count) 10487db96d56Sopenharmony_ci self._select_frame(newframe) 10497db96d56Sopenharmony_ci do_d = do_down 10507db96d56Sopenharmony_ci 10517db96d56Sopenharmony_ci def do_until(self, arg): 10527db96d56Sopenharmony_ci """unt(il) [lineno] 10537db96d56Sopenharmony_ci Without argument, continue execution until the line with a 10547db96d56Sopenharmony_ci number greater than the current one is reached. With a line 10557db96d56Sopenharmony_ci number, continue execution until a line with a number greater 10567db96d56Sopenharmony_ci or equal to that is reached. In both cases, also stop when 10577db96d56Sopenharmony_ci the current frame returns. 10587db96d56Sopenharmony_ci """ 10597db96d56Sopenharmony_ci if arg: 10607db96d56Sopenharmony_ci try: 10617db96d56Sopenharmony_ci lineno = int(arg) 10627db96d56Sopenharmony_ci except ValueError: 10637db96d56Sopenharmony_ci self.error('Error in argument: %r' % arg) 10647db96d56Sopenharmony_ci return 10657db96d56Sopenharmony_ci if lineno <= self.curframe.f_lineno: 10667db96d56Sopenharmony_ci self.error('"until" line number is smaller than current ' 10677db96d56Sopenharmony_ci 'line number') 10687db96d56Sopenharmony_ci return 10697db96d56Sopenharmony_ci else: 10707db96d56Sopenharmony_ci lineno = None 10717db96d56Sopenharmony_ci self.set_until(self.curframe, lineno) 10727db96d56Sopenharmony_ci return 1 10737db96d56Sopenharmony_ci do_unt = do_until 10747db96d56Sopenharmony_ci 10757db96d56Sopenharmony_ci def do_step(self, arg): 10767db96d56Sopenharmony_ci """s(tep) 10777db96d56Sopenharmony_ci Execute the current line, stop at the first possible occasion 10787db96d56Sopenharmony_ci (either in a function that is called or in the current 10797db96d56Sopenharmony_ci function). 10807db96d56Sopenharmony_ci """ 10817db96d56Sopenharmony_ci self.set_step() 10827db96d56Sopenharmony_ci return 1 10837db96d56Sopenharmony_ci do_s = do_step 10847db96d56Sopenharmony_ci 10857db96d56Sopenharmony_ci def do_next(self, arg): 10867db96d56Sopenharmony_ci """n(ext) 10877db96d56Sopenharmony_ci Continue execution until the next line in the current function 10887db96d56Sopenharmony_ci is reached or it returns. 10897db96d56Sopenharmony_ci """ 10907db96d56Sopenharmony_ci self.set_next(self.curframe) 10917db96d56Sopenharmony_ci return 1 10927db96d56Sopenharmony_ci do_n = do_next 10937db96d56Sopenharmony_ci 10947db96d56Sopenharmony_ci def do_run(self, arg): 10957db96d56Sopenharmony_ci """run [args...] 10967db96d56Sopenharmony_ci Restart the debugged python program. If a string is supplied 10977db96d56Sopenharmony_ci it is split with "shlex", and the result is used as the new 10987db96d56Sopenharmony_ci sys.argv. History, breakpoints, actions and debugger options 10997db96d56Sopenharmony_ci are preserved. "restart" is an alias for "run". 11007db96d56Sopenharmony_ci """ 11017db96d56Sopenharmony_ci if arg: 11027db96d56Sopenharmony_ci import shlex 11037db96d56Sopenharmony_ci argv0 = sys.argv[0:1] 11047db96d56Sopenharmony_ci try: 11057db96d56Sopenharmony_ci sys.argv = shlex.split(arg) 11067db96d56Sopenharmony_ci except ValueError as e: 11077db96d56Sopenharmony_ci self.error('Cannot run %s: %s' % (arg, e)) 11087db96d56Sopenharmony_ci return 11097db96d56Sopenharmony_ci sys.argv[:0] = argv0 11107db96d56Sopenharmony_ci # this is caught in the main debugger loop 11117db96d56Sopenharmony_ci raise Restart 11127db96d56Sopenharmony_ci 11137db96d56Sopenharmony_ci do_restart = do_run 11147db96d56Sopenharmony_ci 11157db96d56Sopenharmony_ci def do_return(self, arg): 11167db96d56Sopenharmony_ci """r(eturn) 11177db96d56Sopenharmony_ci Continue execution until the current function returns. 11187db96d56Sopenharmony_ci """ 11197db96d56Sopenharmony_ci self.set_return(self.curframe) 11207db96d56Sopenharmony_ci return 1 11217db96d56Sopenharmony_ci do_r = do_return 11227db96d56Sopenharmony_ci 11237db96d56Sopenharmony_ci def do_continue(self, arg): 11247db96d56Sopenharmony_ci """c(ont(inue)) 11257db96d56Sopenharmony_ci Continue execution, only stop when a breakpoint is encountered. 11267db96d56Sopenharmony_ci """ 11277db96d56Sopenharmony_ci if not self.nosigint: 11287db96d56Sopenharmony_ci try: 11297db96d56Sopenharmony_ci Pdb._previous_sigint_handler = \ 11307db96d56Sopenharmony_ci signal.signal(signal.SIGINT, self.sigint_handler) 11317db96d56Sopenharmony_ci except ValueError: 11327db96d56Sopenharmony_ci # ValueError happens when do_continue() is invoked from 11337db96d56Sopenharmony_ci # a non-main thread in which case we just continue without 11347db96d56Sopenharmony_ci # SIGINT set. Would printing a message here (once) make 11357db96d56Sopenharmony_ci # sense? 11367db96d56Sopenharmony_ci pass 11377db96d56Sopenharmony_ci self.set_continue() 11387db96d56Sopenharmony_ci return 1 11397db96d56Sopenharmony_ci do_c = do_cont = do_continue 11407db96d56Sopenharmony_ci 11417db96d56Sopenharmony_ci def do_jump(self, arg): 11427db96d56Sopenharmony_ci """j(ump) lineno 11437db96d56Sopenharmony_ci Set the next line that will be executed. Only available in 11447db96d56Sopenharmony_ci the bottom-most frame. This lets you jump back and execute 11457db96d56Sopenharmony_ci code again, or jump forward to skip code that you don't want 11467db96d56Sopenharmony_ci to run. 11477db96d56Sopenharmony_ci 11487db96d56Sopenharmony_ci It should be noted that not all jumps are allowed -- for 11497db96d56Sopenharmony_ci instance it is not possible to jump into the middle of a 11507db96d56Sopenharmony_ci for loop or out of a finally clause. 11517db96d56Sopenharmony_ci """ 11527db96d56Sopenharmony_ci if self.curindex + 1 != len(self.stack): 11537db96d56Sopenharmony_ci self.error('You can only jump within the bottom frame') 11547db96d56Sopenharmony_ci return 11557db96d56Sopenharmony_ci try: 11567db96d56Sopenharmony_ci arg = int(arg) 11577db96d56Sopenharmony_ci except ValueError: 11587db96d56Sopenharmony_ci self.error("The 'jump' command requires a line number") 11597db96d56Sopenharmony_ci else: 11607db96d56Sopenharmony_ci try: 11617db96d56Sopenharmony_ci # Do the jump, fix up our copy of the stack, and display the 11627db96d56Sopenharmony_ci # new position 11637db96d56Sopenharmony_ci self.curframe.f_lineno = arg 11647db96d56Sopenharmony_ci self.stack[self.curindex] = self.stack[self.curindex][0], arg 11657db96d56Sopenharmony_ci self.print_stack_entry(self.stack[self.curindex]) 11667db96d56Sopenharmony_ci except ValueError as e: 11677db96d56Sopenharmony_ci self.error('Jump failed: %s' % e) 11687db96d56Sopenharmony_ci do_j = do_jump 11697db96d56Sopenharmony_ci 11707db96d56Sopenharmony_ci def do_debug(self, arg): 11717db96d56Sopenharmony_ci """debug code 11727db96d56Sopenharmony_ci Enter a recursive debugger that steps through the code 11737db96d56Sopenharmony_ci argument (which is an arbitrary expression or statement to be 11747db96d56Sopenharmony_ci executed in the current environment). 11757db96d56Sopenharmony_ci """ 11767db96d56Sopenharmony_ci sys.settrace(None) 11777db96d56Sopenharmony_ci globals = self.curframe.f_globals 11787db96d56Sopenharmony_ci locals = self.curframe_locals 11797db96d56Sopenharmony_ci p = Pdb(self.completekey, self.stdin, self.stdout) 11807db96d56Sopenharmony_ci p.prompt = "(%s) " % self.prompt.strip() 11817db96d56Sopenharmony_ci self.message("ENTERING RECURSIVE DEBUGGER") 11827db96d56Sopenharmony_ci try: 11837db96d56Sopenharmony_ci sys.call_tracing(p.run, (arg, globals, locals)) 11847db96d56Sopenharmony_ci except Exception: 11857db96d56Sopenharmony_ci self._error_exc() 11867db96d56Sopenharmony_ci self.message("LEAVING RECURSIVE DEBUGGER") 11877db96d56Sopenharmony_ci sys.settrace(self.trace_dispatch) 11887db96d56Sopenharmony_ci self.lastcmd = p.lastcmd 11897db96d56Sopenharmony_ci 11907db96d56Sopenharmony_ci complete_debug = _complete_expression 11917db96d56Sopenharmony_ci 11927db96d56Sopenharmony_ci def do_quit(self, arg): 11937db96d56Sopenharmony_ci """q(uit)\nexit 11947db96d56Sopenharmony_ci Quit from the debugger. The program being executed is aborted. 11957db96d56Sopenharmony_ci """ 11967db96d56Sopenharmony_ci self._user_requested_quit = True 11977db96d56Sopenharmony_ci self.set_quit() 11987db96d56Sopenharmony_ci return 1 11997db96d56Sopenharmony_ci 12007db96d56Sopenharmony_ci do_q = do_quit 12017db96d56Sopenharmony_ci do_exit = do_quit 12027db96d56Sopenharmony_ci 12037db96d56Sopenharmony_ci def do_EOF(self, arg): 12047db96d56Sopenharmony_ci """EOF 12057db96d56Sopenharmony_ci Handles the receipt of EOF as a command. 12067db96d56Sopenharmony_ci """ 12077db96d56Sopenharmony_ci self.message('') 12087db96d56Sopenharmony_ci self._user_requested_quit = True 12097db96d56Sopenharmony_ci self.set_quit() 12107db96d56Sopenharmony_ci return 1 12117db96d56Sopenharmony_ci 12127db96d56Sopenharmony_ci def do_args(self, arg): 12137db96d56Sopenharmony_ci """a(rgs) 12147db96d56Sopenharmony_ci Print the argument list of the current function. 12157db96d56Sopenharmony_ci """ 12167db96d56Sopenharmony_ci co = self.curframe.f_code 12177db96d56Sopenharmony_ci dict = self.curframe_locals 12187db96d56Sopenharmony_ci n = co.co_argcount + co.co_kwonlyargcount 12197db96d56Sopenharmony_ci if co.co_flags & inspect.CO_VARARGS: n = n+1 12207db96d56Sopenharmony_ci if co.co_flags & inspect.CO_VARKEYWORDS: n = n+1 12217db96d56Sopenharmony_ci for i in range(n): 12227db96d56Sopenharmony_ci name = co.co_varnames[i] 12237db96d56Sopenharmony_ci if name in dict: 12247db96d56Sopenharmony_ci self.message('%s = %r' % (name, dict[name])) 12257db96d56Sopenharmony_ci else: 12267db96d56Sopenharmony_ci self.message('%s = *** undefined ***' % (name,)) 12277db96d56Sopenharmony_ci do_a = do_args 12287db96d56Sopenharmony_ci 12297db96d56Sopenharmony_ci def do_retval(self, arg): 12307db96d56Sopenharmony_ci """retval 12317db96d56Sopenharmony_ci Print the return value for the last return of a function. 12327db96d56Sopenharmony_ci """ 12337db96d56Sopenharmony_ci if '__return__' in self.curframe_locals: 12347db96d56Sopenharmony_ci self.message(repr(self.curframe_locals['__return__'])) 12357db96d56Sopenharmony_ci else: 12367db96d56Sopenharmony_ci self.error('Not yet returned!') 12377db96d56Sopenharmony_ci do_rv = do_retval 12387db96d56Sopenharmony_ci 12397db96d56Sopenharmony_ci def _getval(self, arg): 12407db96d56Sopenharmony_ci try: 12417db96d56Sopenharmony_ci return eval(arg, self.curframe.f_globals, self.curframe_locals) 12427db96d56Sopenharmony_ci except: 12437db96d56Sopenharmony_ci self._error_exc() 12447db96d56Sopenharmony_ci raise 12457db96d56Sopenharmony_ci 12467db96d56Sopenharmony_ci def _getval_except(self, arg, frame=None): 12477db96d56Sopenharmony_ci try: 12487db96d56Sopenharmony_ci if frame is None: 12497db96d56Sopenharmony_ci return eval(arg, self.curframe.f_globals, self.curframe_locals) 12507db96d56Sopenharmony_ci else: 12517db96d56Sopenharmony_ci return eval(arg, frame.f_globals, frame.f_locals) 12527db96d56Sopenharmony_ci except: 12537db96d56Sopenharmony_ci exc_info = sys.exc_info()[:2] 12547db96d56Sopenharmony_ci err = traceback.format_exception_only(*exc_info)[-1].strip() 12557db96d56Sopenharmony_ci return _rstr('** raised %s **' % err) 12567db96d56Sopenharmony_ci 12577db96d56Sopenharmony_ci def _error_exc(self): 12587db96d56Sopenharmony_ci exc_info = sys.exc_info()[:2] 12597db96d56Sopenharmony_ci self.error(traceback.format_exception_only(*exc_info)[-1].strip()) 12607db96d56Sopenharmony_ci 12617db96d56Sopenharmony_ci def _msg_val_func(self, arg, func): 12627db96d56Sopenharmony_ci try: 12637db96d56Sopenharmony_ci val = self._getval(arg) 12647db96d56Sopenharmony_ci except: 12657db96d56Sopenharmony_ci return # _getval() has displayed the error 12667db96d56Sopenharmony_ci try: 12677db96d56Sopenharmony_ci self.message(func(val)) 12687db96d56Sopenharmony_ci except: 12697db96d56Sopenharmony_ci self._error_exc() 12707db96d56Sopenharmony_ci 12717db96d56Sopenharmony_ci def do_p(self, arg): 12727db96d56Sopenharmony_ci """p expression 12737db96d56Sopenharmony_ci Print the value of the expression. 12747db96d56Sopenharmony_ci """ 12757db96d56Sopenharmony_ci self._msg_val_func(arg, repr) 12767db96d56Sopenharmony_ci 12777db96d56Sopenharmony_ci def do_pp(self, arg): 12787db96d56Sopenharmony_ci """pp expression 12797db96d56Sopenharmony_ci Pretty-print the value of the expression. 12807db96d56Sopenharmony_ci """ 12817db96d56Sopenharmony_ci self._msg_val_func(arg, pprint.pformat) 12827db96d56Sopenharmony_ci 12837db96d56Sopenharmony_ci complete_print = _complete_expression 12847db96d56Sopenharmony_ci complete_p = _complete_expression 12857db96d56Sopenharmony_ci complete_pp = _complete_expression 12867db96d56Sopenharmony_ci 12877db96d56Sopenharmony_ci def do_list(self, arg): 12887db96d56Sopenharmony_ci """l(ist) [first [,last] | .] 12897db96d56Sopenharmony_ci 12907db96d56Sopenharmony_ci List source code for the current file. Without arguments, 12917db96d56Sopenharmony_ci list 11 lines around the current line or continue the previous 12927db96d56Sopenharmony_ci listing. With . as argument, list 11 lines around the current 12937db96d56Sopenharmony_ci line. With one argument, list 11 lines starting at that line. 12947db96d56Sopenharmony_ci With two arguments, list the given range; if the second 12957db96d56Sopenharmony_ci argument is less than the first, it is a count. 12967db96d56Sopenharmony_ci 12977db96d56Sopenharmony_ci The current line in the current frame is indicated by "->". 12987db96d56Sopenharmony_ci If an exception is being debugged, the line where the 12997db96d56Sopenharmony_ci exception was originally raised or propagated is indicated by 13007db96d56Sopenharmony_ci ">>", if it differs from the current line. 13017db96d56Sopenharmony_ci """ 13027db96d56Sopenharmony_ci self.lastcmd = 'list' 13037db96d56Sopenharmony_ci last = None 13047db96d56Sopenharmony_ci if arg and arg != '.': 13057db96d56Sopenharmony_ci try: 13067db96d56Sopenharmony_ci if ',' in arg: 13077db96d56Sopenharmony_ci first, last = arg.split(',') 13087db96d56Sopenharmony_ci first = int(first.strip()) 13097db96d56Sopenharmony_ci last = int(last.strip()) 13107db96d56Sopenharmony_ci if last < first: 13117db96d56Sopenharmony_ci # assume it's a count 13127db96d56Sopenharmony_ci last = first + last 13137db96d56Sopenharmony_ci else: 13147db96d56Sopenharmony_ci first = int(arg.strip()) 13157db96d56Sopenharmony_ci first = max(1, first - 5) 13167db96d56Sopenharmony_ci except ValueError: 13177db96d56Sopenharmony_ci self.error('Error in argument: %r' % arg) 13187db96d56Sopenharmony_ci return 13197db96d56Sopenharmony_ci elif self.lineno is None or arg == '.': 13207db96d56Sopenharmony_ci first = max(1, self.curframe.f_lineno - 5) 13217db96d56Sopenharmony_ci else: 13227db96d56Sopenharmony_ci first = self.lineno + 1 13237db96d56Sopenharmony_ci if last is None: 13247db96d56Sopenharmony_ci last = first + 10 13257db96d56Sopenharmony_ci filename = self.curframe.f_code.co_filename 13267db96d56Sopenharmony_ci # gh-93696: stdlib frozen modules provide a useful __file__ 13277db96d56Sopenharmony_ci # this workaround can be removed with the closure of gh-89815 13287db96d56Sopenharmony_ci if filename.startswith("<frozen"): 13297db96d56Sopenharmony_ci tmp = self.curframe.f_globals.get("__file__") 13307db96d56Sopenharmony_ci if isinstance(tmp, str): 13317db96d56Sopenharmony_ci filename = tmp 13327db96d56Sopenharmony_ci breaklist = self.get_file_breaks(filename) 13337db96d56Sopenharmony_ci try: 13347db96d56Sopenharmony_ci lines = linecache.getlines(filename, self.curframe.f_globals) 13357db96d56Sopenharmony_ci self._print_lines(lines[first-1:last], first, breaklist, 13367db96d56Sopenharmony_ci self.curframe) 13377db96d56Sopenharmony_ci self.lineno = min(last, len(lines)) 13387db96d56Sopenharmony_ci if len(lines) < last: 13397db96d56Sopenharmony_ci self.message('[EOF]') 13407db96d56Sopenharmony_ci except KeyboardInterrupt: 13417db96d56Sopenharmony_ci pass 13427db96d56Sopenharmony_ci do_l = do_list 13437db96d56Sopenharmony_ci 13447db96d56Sopenharmony_ci def do_longlist(self, arg): 13457db96d56Sopenharmony_ci """longlist | ll 13467db96d56Sopenharmony_ci List the whole source code for the current function or frame. 13477db96d56Sopenharmony_ci """ 13487db96d56Sopenharmony_ci filename = self.curframe.f_code.co_filename 13497db96d56Sopenharmony_ci breaklist = self.get_file_breaks(filename) 13507db96d56Sopenharmony_ci try: 13517db96d56Sopenharmony_ci lines, lineno = self._getsourcelines(self.curframe) 13527db96d56Sopenharmony_ci except OSError as err: 13537db96d56Sopenharmony_ci self.error(err) 13547db96d56Sopenharmony_ci return 13557db96d56Sopenharmony_ci self._print_lines(lines, lineno, breaklist, self.curframe) 13567db96d56Sopenharmony_ci do_ll = do_longlist 13577db96d56Sopenharmony_ci 13587db96d56Sopenharmony_ci def do_source(self, arg): 13597db96d56Sopenharmony_ci """source expression 13607db96d56Sopenharmony_ci Try to get source code for the given object and display it. 13617db96d56Sopenharmony_ci """ 13627db96d56Sopenharmony_ci try: 13637db96d56Sopenharmony_ci obj = self._getval(arg) 13647db96d56Sopenharmony_ci except: 13657db96d56Sopenharmony_ci return 13667db96d56Sopenharmony_ci try: 13677db96d56Sopenharmony_ci lines, lineno = self._getsourcelines(obj) 13687db96d56Sopenharmony_ci except (OSError, TypeError) as err: 13697db96d56Sopenharmony_ci self.error(err) 13707db96d56Sopenharmony_ci return 13717db96d56Sopenharmony_ci self._print_lines(lines, lineno) 13727db96d56Sopenharmony_ci 13737db96d56Sopenharmony_ci complete_source = _complete_expression 13747db96d56Sopenharmony_ci 13757db96d56Sopenharmony_ci def _print_lines(self, lines, start, breaks=(), frame=None): 13767db96d56Sopenharmony_ci """Print a range of lines.""" 13777db96d56Sopenharmony_ci if frame: 13787db96d56Sopenharmony_ci current_lineno = frame.f_lineno 13797db96d56Sopenharmony_ci exc_lineno = self.tb_lineno.get(frame, -1) 13807db96d56Sopenharmony_ci else: 13817db96d56Sopenharmony_ci current_lineno = exc_lineno = -1 13827db96d56Sopenharmony_ci for lineno, line in enumerate(lines, start): 13837db96d56Sopenharmony_ci s = str(lineno).rjust(3) 13847db96d56Sopenharmony_ci if len(s) < 4: 13857db96d56Sopenharmony_ci s += ' ' 13867db96d56Sopenharmony_ci if lineno in breaks: 13877db96d56Sopenharmony_ci s += 'B' 13887db96d56Sopenharmony_ci else: 13897db96d56Sopenharmony_ci s += ' ' 13907db96d56Sopenharmony_ci if lineno == current_lineno: 13917db96d56Sopenharmony_ci s += '->' 13927db96d56Sopenharmony_ci elif lineno == exc_lineno: 13937db96d56Sopenharmony_ci s += '>>' 13947db96d56Sopenharmony_ci self.message(s + '\t' + line.rstrip()) 13957db96d56Sopenharmony_ci 13967db96d56Sopenharmony_ci def do_whatis(self, arg): 13977db96d56Sopenharmony_ci """whatis arg 13987db96d56Sopenharmony_ci Print the type of the argument. 13997db96d56Sopenharmony_ci """ 14007db96d56Sopenharmony_ci try: 14017db96d56Sopenharmony_ci value = self._getval(arg) 14027db96d56Sopenharmony_ci except: 14037db96d56Sopenharmony_ci # _getval() already printed the error 14047db96d56Sopenharmony_ci return 14057db96d56Sopenharmony_ci code = None 14067db96d56Sopenharmony_ci # Is it an instance method? 14077db96d56Sopenharmony_ci try: 14087db96d56Sopenharmony_ci code = value.__func__.__code__ 14097db96d56Sopenharmony_ci except Exception: 14107db96d56Sopenharmony_ci pass 14117db96d56Sopenharmony_ci if code: 14127db96d56Sopenharmony_ci self.message('Method %s' % code.co_name) 14137db96d56Sopenharmony_ci return 14147db96d56Sopenharmony_ci # Is it a function? 14157db96d56Sopenharmony_ci try: 14167db96d56Sopenharmony_ci code = value.__code__ 14177db96d56Sopenharmony_ci except Exception: 14187db96d56Sopenharmony_ci pass 14197db96d56Sopenharmony_ci if code: 14207db96d56Sopenharmony_ci self.message('Function %s' % code.co_name) 14217db96d56Sopenharmony_ci return 14227db96d56Sopenharmony_ci # Is it a class? 14237db96d56Sopenharmony_ci if value.__class__ is type: 14247db96d56Sopenharmony_ci self.message('Class %s.%s' % (value.__module__, value.__qualname__)) 14257db96d56Sopenharmony_ci return 14267db96d56Sopenharmony_ci # None of the above... 14277db96d56Sopenharmony_ci self.message(type(value)) 14287db96d56Sopenharmony_ci 14297db96d56Sopenharmony_ci complete_whatis = _complete_expression 14307db96d56Sopenharmony_ci 14317db96d56Sopenharmony_ci def do_display(self, arg): 14327db96d56Sopenharmony_ci """display [expression] 14337db96d56Sopenharmony_ci 14347db96d56Sopenharmony_ci Display the value of the expression if it changed, each time execution 14357db96d56Sopenharmony_ci stops in the current frame. 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci Without expression, list all display expressions for the current frame. 14387db96d56Sopenharmony_ci """ 14397db96d56Sopenharmony_ci if not arg: 14407db96d56Sopenharmony_ci self.message('Currently displaying:') 14417db96d56Sopenharmony_ci for item in self.displaying.get(self.curframe, {}).items(): 14427db96d56Sopenharmony_ci self.message('%s: %r' % item) 14437db96d56Sopenharmony_ci else: 14447db96d56Sopenharmony_ci val = self._getval_except(arg) 14457db96d56Sopenharmony_ci self.displaying.setdefault(self.curframe, {})[arg] = val 14467db96d56Sopenharmony_ci self.message('display %s: %r' % (arg, val)) 14477db96d56Sopenharmony_ci 14487db96d56Sopenharmony_ci complete_display = _complete_expression 14497db96d56Sopenharmony_ci 14507db96d56Sopenharmony_ci def do_undisplay(self, arg): 14517db96d56Sopenharmony_ci """undisplay [expression] 14527db96d56Sopenharmony_ci 14537db96d56Sopenharmony_ci Do not display the expression any more in the current frame. 14547db96d56Sopenharmony_ci 14557db96d56Sopenharmony_ci Without expression, clear all display expressions for the current frame. 14567db96d56Sopenharmony_ci """ 14577db96d56Sopenharmony_ci if arg: 14587db96d56Sopenharmony_ci try: 14597db96d56Sopenharmony_ci del self.displaying.get(self.curframe, {})[arg] 14607db96d56Sopenharmony_ci except KeyError: 14617db96d56Sopenharmony_ci self.error('not displaying %s' % arg) 14627db96d56Sopenharmony_ci else: 14637db96d56Sopenharmony_ci self.displaying.pop(self.curframe, None) 14647db96d56Sopenharmony_ci 14657db96d56Sopenharmony_ci def complete_undisplay(self, text, line, begidx, endidx): 14667db96d56Sopenharmony_ci return [e for e in self.displaying.get(self.curframe, {}) 14677db96d56Sopenharmony_ci if e.startswith(text)] 14687db96d56Sopenharmony_ci 14697db96d56Sopenharmony_ci def do_interact(self, arg): 14707db96d56Sopenharmony_ci """interact 14717db96d56Sopenharmony_ci 14727db96d56Sopenharmony_ci Start an interactive interpreter whose global namespace 14737db96d56Sopenharmony_ci contains all the (global and local) names found in the current scope. 14747db96d56Sopenharmony_ci """ 14757db96d56Sopenharmony_ci ns = {**self.curframe.f_globals, **self.curframe_locals} 14767db96d56Sopenharmony_ci code.interact("*interactive*", local=ns) 14777db96d56Sopenharmony_ci 14787db96d56Sopenharmony_ci def do_alias(self, arg): 14797db96d56Sopenharmony_ci """alias [name [command [parameter parameter ...] ]] 14807db96d56Sopenharmony_ci Create an alias called 'name' that executes 'command'. The 14817db96d56Sopenharmony_ci command must *not* be enclosed in quotes. Replaceable 14827db96d56Sopenharmony_ci parameters can be indicated by %1, %2, and so on, while %* is 14837db96d56Sopenharmony_ci replaced by all the parameters. If no command is given, the 14847db96d56Sopenharmony_ci current alias for name is shown. If no name is given, all 14857db96d56Sopenharmony_ci aliases are listed. 14867db96d56Sopenharmony_ci 14877db96d56Sopenharmony_ci Aliases may be nested and can contain anything that can be 14887db96d56Sopenharmony_ci legally typed at the pdb prompt. Note! You *can* override 14897db96d56Sopenharmony_ci internal pdb commands with aliases! Those internal commands 14907db96d56Sopenharmony_ci are then hidden until the alias is removed. Aliasing is 14917db96d56Sopenharmony_ci recursively applied to the first word of the command line; all 14927db96d56Sopenharmony_ci other words in the line are left alone. 14937db96d56Sopenharmony_ci 14947db96d56Sopenharmony_ci As an example, here are two useful aliases (especially when 14957db96d56Sopenharmony_ci placed in the .pdbrc file): 14967db96d56Sopenharmony_ci 14977db96d56Sopenharmony_ci # Print instance variables (usage "pi classInst") 14987db96d56Sopenharmony_ci alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) 14997db96d56Sopenharmony_ci # Print instance variables in self 15007db96d56Sopenharmony_ci alias ps pi self 15017db96d56Sopenharmony_ci """ 15027db96d56Sopenharmony_ci args = arg.split() 15037db96d56Sopenharmony_ci if len(args) == 0: 15047db96d56Sopenharmony_ci keys = sorted(self.aliases.keys()) 15057db96d56Sopenharmony_ci for alias in keys: 15067db96d56Sopenharmony_ci self.message("%s = %s" % (alias, self.aliases[alias])) 15077db96d56Sopenharmony_ci return 15087db96d56Sopenharmony_ci if args[0] in self.aliases and len(args) == 1: 15097db96d56Sopenharmony_ci self.message("%s = %s" % (args[0], self.aliases[args[0]])) 15107db96d56Sopenharmony_ci else: 15117db96d56Sopenharmony_ci self.aliases[args[0]] = ' '.join(args[1:]) 15127db96d56Sopenharmony_ci 15137db96d56Sopenharmony_ci def do_unalias(self, arg): 15147db96d56Sopenharmony_ci """unalias name 15157db96d56Sopenharmony_ci Delete the specified alias. 15167db96d56Sopenharmony_ci """ 15177db96d56Sopenharmony_ci args = arg.split() 15187db96d56Sopenharmony_ci if len(args) == 0: return 15197db96d56Sopenharmony_ci if args[0] in self.aliases: 15207db96d56Sopenharmony_ci del self.aliases[args[0]] 15217db96d56Sopenharmony_ci 15227db96d56Sopenharmony_ci def complete_unalias(self, text, line, begidx, endidx): 15237db96d56Sopenharmony_ci return [a for a in self.aliases if a.startswith(text)] 15247db96d56Sopenharmony_ci 15257db96d56Sopenharmony_ci # List of all the commands making the program resume execution. 15267db96d56Sopenharmony_ci commands_resuming = ['do_continue', 'do_step', 'do_next', 'do_return', 15277db96d56Sopenharmony_ci 'do_quit', 'do_jump'] 15287db96d56Sopenharmony_ci 15297db96d56Sopenharmony_ci # Print a traceback starting at the top stack frame. 15307db96d56Sopenharmony_ci # The most recently entered frame is printed last; 15317db96d56Sopenharmony_ci # this is different from dbx and gdb, but consistent with 15327db96d56Sopenharmony_ci # the Python interpreter's stack trace. 15337db96d56Sopenharmony_ci # It is also consistent with the up/down commands (which are 15347db96d56Sopenharmony_ci # compatible with dbx and gdb: up moves towards 'main()' 15357db96d56Sopenharmony_ci # and down moves towards the most recent stack frame). 15367db96d56Sopenharmony_ci 15377db96d56Sopenharmony_ci def print_stack_trace(self): 15387db96d56Sopenharmony_ci try: 15397db96d56Sopenharmony_ci for frame_lineno in self.stack: 15407db96d56Sopenharmony_ci self.print_stack_entry(frame_lineno) 15417db96d56Sopenharmony_ci except KeyboardInterrupt: 15427db96d56Sopenharmony_ci pass 15437db96d56Sopenharmony_ci 15447db96d56Sopenharmony_ci def print_stack_entry(self, frame_lineno, prompt_prefix=line_prefix): 15457db96d56Sopenharmony_ci frame, lineno = frame_lineno 15467db96d56Sopenharmony_ci if frame is self.curframe: 15477db96d56Sopenharmony_ci prefix = '> ' 15487db96d56Sopenharmony_ci else: 15497db96d56Sopenharmony_ci prefix = ' ' 15507db96d56Sopenharmony_ci self.message(prefix + 15517db96d56Sopenharmony_ci self.format_stack_entry(frame_lineno, prompt_prefix)) 15527db96d56Sopenharmony_ci 15537db96d56Sopenharmony_ci # Provide help 15547db96d56Sopenharmony_ci 15557db96d56Sopenharmony_ci def do_help(self, arg): 15567db96d56Sopenharmony_ci """h(elp) 15577db96d56Sopenharmony_ci Without argument, print the list of available commands. 15587db96d56Sopenharmony_ci With a command name as argument, print help about that command. 15597db96d56Sopenharmony_ci "help pdb" shows the full pdb documentation. 15607db96d56Sopenharmony_ci "help exec" gives help on the ! command. 15617db96d56Sopenharmony_ci """ 15627db96d56Sopenharmony_ci if not arg: 15637db96d56Sopenharmony_ci return cmd.Cmd.do_help(self, arg) 15647db96d56Sopenharmony_ci try: 15657db96d56Sopenharmony_ci try: 15667db96d56Sopenharmony_ci topic = getattr(self, 'help_' + arg) 15677db96d56Sopenharmony_ci return topic() 15687db96d56Sopenharmony_ci except AttributeError: 15697db96d56Sopenharmony_ci command = getattr(self, 'do_' + arg) 15707db96d56Sopenharmony_ci except AttributeError: 15717db96d56Sopenharmony_ci self.error('No help for %r' % arg) 15727db96d56Sopenharmony_ci else: 15737db96d56Sopenharmony_ci if sys.flags.optimize >= 2: 15747db96d56Sopenharmony_ci self.error('No help for %r; please do not run Python with -OO ' 15757db96d56Sopenharmony_ci 'if you need command help' % arg) 15767db96d56Sopenharmony_ci return 15777db96d56Sopenharmony_ci if command.__doc__ is None: 15787db96d56Sopenharmony_ci self.error('No help for %r; __doc__ string missing' % arg) 15797db96d56Sopenharmony_ci return 15807db96d56Sopenharmony_ci self.message(command.__doc__.rstrip()) 15817db96d56Sopenharmony_ci 15827db96d56Sopenharmony_ci do_h = do_help 15837db96d56Sopenharmony_ci 15847db96d56Sopenharmony_ci def help_exec(self): 15857db96d56Sopenharmony_ci """(!) statement 15867db96d56Sopenharmony_ci Execute the (one-line) statement in the context of the current 15877db96d56Sopenharmony_ci stack frame. The exclamation point can be omitted unless the 15887db96d56Sopenharmony_ci first word of the statement resembles a debugger command. To 15897db96d56Sopenharmony_ci assign to a global variable you must always prefix the command 15907db96d56Sopenharmony_ci with a 'global' command, e.g.: 15917db96d56Sopenharmony_ci (Pdb) global list_options; list_options = ['-l'] 15927db96d56Sopenharmony_ci (Pdb) 15937db96d56Sopenharmony_ci """ 15947db96d56Sopenharmony_ci self.message((self.help_exec.__doc__ or '').strip()) 15957db96d56Sopenharmony_ci 15967db96d56Sopenharmony_ci def help_pdb(self): 15977db96d56Sopenharmony_ci help() 15987db96d56Sopenharmony_ci 15997db96d56Sopenharmony_ci # other helper functions 16007db96d56Sopenharmony_ci 16017db96d56Sopenharmony_ci def lookupmodule(self, filename): 16027db96d56Sopenharmony_ci """Helper function for break/clear parsing -- may be overridden. 16037db96d56Sopenharmony_ci 16047db96d56Sopenharmony_ci lookupmodule() translates (possibly incomplete) file or module name 16057db96d56Sopenharmony_ci into an absolute file name. 16067db96d56Sopenharmony_ci """ 16077db96d56Sopenharmony_ci if os.path.isabs(filename) and os.path.exists(filename): 16087db96d56Sopenharmony_ci return filename 16097db96d56Sopenharmony_ci f = os.path.join(sys.path[0], filename) 16107db96d56Sopenharmony_ci if os.path.exists(f) and self.canonic(f) == self.mainpyfile: 16117db96d56Sopenharmony_ci return f 16127db96d56Sopenharmony_ci root, ext = os.path.splitext(filename) 16137db96d56Sopenharmony_ci if ext == '': 16147db96d56Sopenharmony_ci filename = filename + '.py' 16157db96d56Sopenharmony_ci if os.path.isabs(filename): 16167db96d56Sopenharmony_ci return filename 16177db96d56Sopenharmony_ci for dirname in sys.path: 16187db96d56Sopenharmony_ci while os.path.islink(dirname): 16197db96d56Sopenharmony_ci dirname = os.readlink(dirname) 16207db96d56Sopenharmony_ci fullname = os.path.join(dirname, filename) 16217db96d56Sopenharmony_ci if os.path.exists(fullname): 16227db96d56Sopenharmony_ci return fullname 16237db96d56Sopenharmony_ci return None 16247db96d56Sopenharmony_ci 16257db96d56Sopenharmony_ci def _run(self, target: Union[_ModuleTarget, _ScriptTarget]): 16267db96d56Sopenharmony_ci # When bdb sets tracing, a number of call and line events happen 16277db96d56Sopenharmony_ci # BEFORE debugger even reaches user's code (and the exact sequence of 16287db96d56Sopenharmony_ci # events depends on python version). Take special measures to 16297db96d56Sopenharmony_ci # avoid stopping before reaching the main script (see user_line and 16307db96d56Sopenharmony_ci # user_call for details). 16317db96d56Sopenharmony_ci self._wait_for_mainpyfile = True 16327db96d56Sopenharmony_ci self._user_requested_quit = False 16337db96d56Sopenharmony_ci 16347db96d56Sopenharmony_ci self.mainpyfile = self.canonic(target.filename) 16357db96d56Sopenharmony_ci 16367db96d56Sopenharmony_ci # The target has to run in __main__ namespace (or imports from 16377db96d56Sopenharmony_ci # __main__ will break). Clear __main__ and replace with 16387db96d56Sopenharmony_ci # the target namespace. 16397db96d56Sopenharmony_ci import __main__ 16407db96d56Sopenharmony_ci __main__.__dict__.clear() 16417db96d56Sopenharmony_ci __main__.__dict__.update(target.namespace) 16427db96d56Sopenharmony_ci 16437db96d56Sopenharmony_ci self.run(target.code) 16447db96d56Sopenharmony_ci 16457db96d56Sopenharmony_ci 16467db96d56Sopenharmony_ci def _getsourcelines(self, obj): 16477db96d56Sopenharmony_ci # GH-103319 16487db96d56Sopenharmony_ci # inspect.getsourcelines() returns lineno = 0 for 16497db96d56Sopenharmony_ci # module-level frame which breaks our code print line number 16507db96d56Sopenharmony_ci # This method should be replaced by inspect.getsourcelines(obj) 16517db96d56Sopenharmony_ci # once this bug is fixed in inspect 16527db96d56Sopenharmony_ci lines, lineno = inspect.getsourcelines(obj) 16537db96d56Sopenharmony_ci lineno = max(1, lineno) 16547db96d56Sopenharmony_ci return lines, lineno 16557db96d56Sopenharmony_ci 16567db96d56Sopenharmony_ci# Collect all command help into docstring, if not run with -OO 16577db96d56Sopenharmony_ci 16587db96d56Sopenharmony_ciif __doc__ is not None: 16597db96d56Sopenharmony_ci # unfortunately we can't guess this order from the class definition 16607db96d56Sopenharmony_ci _help_order = [ 16617db96d56Sopenharmony_ci 'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable', 16627db96d56Sopenharmony_ci 'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until', 16637db96d56Sopenharmony_ci 'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist', 16647db96d56Sopenharmony_ci 'args', 'p', 'pp', 'whatis', 'source', 'display', 'undisplay', 16657db96d56Sopenharmony_ci 'interact', 'alias', 'unalias', 'debug', 'quit', 16667db96d56Sopenharmony_ci ] 16677db96d56Sopenharmony_ci 16687db96d56Sopenharmony_ci for _command in _help_order: 16697db96d56Sopenharmony_ci __doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n' 16707db96d56Sopenharmony_ci __doc__ += Pdb.help_exec.__doc__ 16717db96d56Sopenharmony_ci 16727db96d56Sopenharmony_ci del _help_order, _command 16737db96d56Sopenharmony_ci 16747db96d56Sopenharmony_ci 16757db96d56Sopenharmony_ci# Simplified interface 16767db96d56Sopenharmony_ci 16777db96d56Sopenharmony_cidef run(statement, globals=None, locals=None): 16787db96d56Sopenharmony_ci Pdb().run(statement, globals, locals) 16797db96d56Sopenharmony_ci 16807db96d56Sopenharmony_cidef runeval(expression, globals=None, locals=None): 16817db96d56Sopenharmony_ci return Pdb().runeval(expression, globals, locals) 16827db96d56Sopenharmony_ci 16837db96d56Sopenharmony_cidef runctx(statement, globals, locals): 16847db96d56Sopenharmony_ci # B/W compatibility 16857db96d56Sopenharmony_ci run(statement, globals, locals) 16867db96d56Sopenharmony_ci 16877db96d56Sopenharmony_cidef runcall(*args, **kwds): 16887db96d56Sopenharmony_ci return Pdb().runcall(*args, **kwds) 16897db96d56Sopenharmony_ci 16907db96d56Sopenharmony_cidef set_trace(*, header=None): 16917db96d56Sopenharmony_ci pdb = Pdb() 16927db96d56Sopenharmony_ci if header is not None: 16937db96d56Sopenharmony_ci pdb.message(header) 16947db96d56Sopenharmony_ci pdb.set_trace(sys._getframe().f_back) 16957db96d56Sopenharmony_ci 16967db96d56Sopenharmony_ci# Post-Mortem interface 16977db96d56Sopenharmony_ci 16987db96d56Sopenharmony_cidef post_mortem(t=None): 16997db96d56Sopenharmony_ci # handling the default 17007db96d56Sopenharmony_ci if t is None: 17017db96d56Sopenharmony_ci # sys.exc_info() returns (type, value, traceback) if an exception is 17027db96d56Sopenharmony_ci # being handled, otherwise it returns None 17037db96d56Sopenharmony_ci t = sys.exc_info()[2] 17047db96d56Sopenharmony_ci if t is None: 17057db96d56Sopenharmony_ci raise ValueError("A valid traceback must be passed if no " 17067db96d56Sopenharmony_ci "exception is being handled") 17077db96d56Sopenharmony_ci 17087db96d56Sopenharmony_ci p = Pdb() 17097db96d56Sopenharmony_ci p.reset() 17107db96d56Sopenharmony_ci p.interaction(None, t) 17117db96d56Sopenharmony_ci 17127db96d56Sopenharmony_cidef pm(): 17137db96d56Sopenharmony_ci post_mortem(sys.last_traceback) 17147db96d56Sopenharmony_ci 17157db96d56Sopenharmony_ci 17167db96d56Sopenharmony_ci# Main program for testing 17177db96d56Sopenharmony_ci 17187db96d56Sopenharmony_ciTESTCMD = 'import x; x.main()' 17197db96d56Sopenharmony_ci 17207db96d56Sopenharmony_cidef test(): 17217db96d56Sopenharmony_ci run(TESTCMD) 17227db96d56Sopenharmony_ci 17237db96d56Sopenharmony_ci# print help 17247db96d56Sopenharmony_cidef help(): 17257db96d56Sopenharmony_ci import pydoc 17267db96d56Sopenharmony_ci pydoc.pager(__doc__) 17277db96d56Sopenharmony_ci 17287db96d56Sopenharmony_ci_usage = """\ 17297db96d56Sopenharmony_ciusage: pdb.py [-c command] ... [-m module | pyfile] [arg] ... 17307db96d56Sopenharmony_ci 17317db96d56Sopenharmony_ciDebug the Python program given by pyfile. Alternatively, 17327db96d56Sopenharmony_cian executable module or package to debug can be specified using 17337db96d56Sopenharmony_cithe -m switch. 17347db96d56Sopenharmony_ci 17357db96d56Sopenharmony_ciInitial commands are read from .pdbrc files in your home directory 17367db96d56Sopenharmony_ciand in the current directory, if they exist. Commands supplied with 17377db96d56Sopenharmony_ci-c are executed after commands from .pdbrc files. 17387db96d56Sopenharmony_ci 17397db96d56Sopenharmony_ciTo let the script run until an exception occurs, use "-c continue". 17407db96d56Sopenharmony_ciTo let the script run up to a given line X in the debugged file, use 17417db96d56Sopenharmony_ci"-c 'until X'".""" 17427db96d56Sopenharmony_ci 17437db96d56Sopenharmony_ci 17447db96d56Sopenharmony_cidef main(): 17457db96d56Sopenharmony_ci import getopt 17467db96d56Sopenharmony_ci 17477db96d56Sopenharmony_ci opts, args = getopt.getopt(sys.argv[1:], 'mhc:', ['help', 'command=']) 17487db96d56Sopenharmony_ci 17497db96d56Sopenharmony_ci if not args: 17507db96d56Sopenharmony_ci print(_usage) 17517db96d56Sopenharmony_ci sys.exit(2) 17527db96d56Sopenharmony_ci 17537db96d56Sopenharmony_ci if any(opt in ['-h', '--help'] for opt, optarg in opts): 17547db96d56Sopenharmony_ci print(_usage) 17557db96d56Sopenharmony_ci sys.exit() 17567db96d56Sopenharmony_ci 17577db96d56Sopenharmony_ci commands = [optarg for opt, optarg in opts if opt in ['-c', '--command']] 17587db96d56Sopenharmony_ci 17597db96d56Sopenharmony_ci module_indicated = any(opt in ['-m'] for opt, optarg in opts) 17607db96d56Sopenharmony_ci cls = _ModuleTarget if module_indicated else _ScriptTarget 17617db96d56Sopenharmony_ci target = cls(args[0]) 17627db96d56Sopenharmony_ci 17637db96d56Sopenharmony_ci target.check() 17647db96d56Sopenharmony_ci 17657db96d56Sopenharmony_ci sys.argv[:] = args # Hide "pdb.py" and pdb options from argument list 17667db96d56Sopenharmony_ci 17677db96d56Sopenharmony_ci # Note on saving/restoring sys.argv: it's a good idea when sys.argv was 17687db96d56Sopenharmony_ci # modified by the script being debugged. It's a bad idea when it was 17697db96d56Sopenharmony_ci # changed by the user from the command line. There is a "restart" command 17707db96d56Sopenharmony_ci # which allows explicit specification of command line arguments. 17717db96d56Sopenharmony_ci pdb = Pdb() 17727db96d56Sopenharmony_ci pdb.rcLines.extend(commands) 17737db96d56Sopenharmony_ci while True: 17747db96d56Sopenharmony_ci try: 17757db96d56Sopenharmony_ci pdb._run(target) 17767db96d56Sopenharmony_ci if pdb._user_requested_quit: 17777db96d56Sopenharmony_ci break 17787db96d56Sopenharmony_ci print("The program finished and will be restarted") 17797db96d56Sopenharmony_ci except Restart: 17807db96d56Sopenharmony_ci print("Restarting", target, "with arguments:") 17817db96d56Sopenharmony_ci print("\t" + " ".join(sys.argv[1:])) 17827db96d56Sopenharmony_ci except SystemExit: 17837db96d56Sopenharmony_ci # In most cases SystemExit does not warrant a post-mortem session. 17847db96d56Sopenharmony_ci print("The program exited via sys.exit(). Exit status:", end=' ') 17857db96d56Sopenharmony_ci print(sys.exc_info()[1]) 17867db96d56Sopenharmony_ci except SyntaxError: 17877db96d56Sopenharmony_ci traceback.print_exc() 17887db96d56Sopenharmony_ci sys.exit(1) 17897db96d56Sopenharmony_ci except: 17907db96d56Sopenharmony_ci traceback.print_exc() 17917db96d56Sopenharmony_ci print("Uncaught exception. Entering post mortem debugging") 17927db96d56Sopenharmony_ci print("Running 'cont' or 'step' will restart the program") 17937db96d56Sopenharmony_ci t = sys.exc_info()[2] 17947db96d56Sopenharmony_ci pdb.interaction(None, t) 17957db96d56Sopenharmony_ci print("Post mortem debugger finished. The " + target + 17967db96d56Sopenharmony_ci " will be restarted") 17977db96d56Sopenharmony_ci 17987db96d56Sopenharmony_ci 17997db96d56Sopenharmony_ci# When invoked as main program, invoke the debugger on a script 18007db96d56Sopenharmony_ciif __name__ == '__main__': 18017db96d56Sopenharmony_ci import pdb 18027db96d56Sopenharmony_ci pdb.main() 1803