Download lib/python3.9/site-packages/IPython/core/debugger.py from camenduru/slahmr-test: direct link, hf CLI and curl.
- Browser
- Download file 33.4 kB
-
https://huggingface.co/camenduru/slahmr-test/resolve/main/lib/python3.9/site-packages/IPython/core/debugger.py
- Command line
-
hf download hf://camenduru/slahmr-test/lib/python3.9/site-packages/IPython/core/debugger.py
-
curl -L -o debugger.py https://huggingface.co/camenduru/slahmr-test/resolve/main/lib/python3.9/site-packages/IPython/core/debugger.py
33.4 kB
| # -*- coding: utf-8 -*- | |
| """ | |
| Pdb debugger class. | |
| This is an extension to PDB which adds a number of new features. | |
| Note that there is also the `IPython.terminal.debugger` class which provides UI | |
| improvements. | |
| We also strongly recommend to use this via the `ipdb` package, which provides | |
| extra configuration options. | |
| Among other things, this subclass of PDB: | |
| - supports many IPython magics like pdef/psource | |
| - hide frames in tracebacks based on `__tracebackhide__` | |
| - allows to skip frames based on `__debuggerskip__` | |
| The skipping and hiding frames are configurable via the `skip_predicates` | |
| command. | |
| By default, frames from readonly files will be hidden, frames containing | |
| ``__tracebackhide__=True`` will be hidden. | |
| Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent | |
| frames value of ``__debuggerskip__`` is ``True`` will be skipped. | |
| >>> def helpers_helper(): | |
| ... pass | |
| ... | |
| ... def helper_1(): | |
| ... print("don't step in me") | |
| ... helpers_helpers() # will be stepped over unless breakpoint set. | |
| ... | |
| ... | |
| ... def helper_2(): | |
| ... print("in me neither") | |
| ... | |
| One can define a decorator that wraps a function between the two helpers: | |
| >>> def pdb_skipped_decorator(function): | |
| ... | |
| ... | |
| ... def wrapped_fn(*args, **kwargs): | |
| ... __debuggerskip__ = True | |
| ... helper_1() | |
| ... __debuggerskip__ = False | |
| ... result = function(*args, **kwargs) | |
| ... __debuggerskip__ = True | |
| ... helper_2() | |
| ... # setting __debuggerskip__ to False again is not necessary | |
| ... return result | |
| ... | |
| ... return wrapped_fn | |
| When decorating a function, ipdb will directly step into ``bar()`` by | |
| default: | |
| >>> @foo_decorator | |
| ... def bar(x, y): | |
| ... return x * y | |
| You can toggle the behavior with | |
| ipdb> skip_predicates debuggerskip false | |
| or configure it in your ``.pdbrc`` | |
| License | |
| ------- | |
| Modified from the standard pdb.Pdb class to avoid including readline, so that | |
| the command line completion of other programs which include this isn't | |
| damaged. | |
| In the future, this class will be expanded with improvements over the standard | |
| pdb. | |
| The original code in this file is mainly lifted out of cmd.py in Python 2.2, | |
| with minor changes. Licensing should therefore be under the standard Python | |
| terms. For details on the PSF (Python Software Foundation) standard license, | |
| see: | |
| https://docs.python.org/2/license.html | |
| All the changes since then are under the same license as IPython. | |
| """ | |
| #***************************************************************************** | |
| # | |
| # This file is licensed under the PSF license. | |
| # | |
| # Copyright (C) 2001 Python Software Foundation, www.python.org | |
| # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu> | |
| # | |
| # | |
| #***************************************************************************** | |
| import inspect | |
| import linecache | |
| import sys | |
| import re | |
| import os | |
| from IPython import get_ipython | |
| from IPython.utils import PyColorize | |
| from IPython.utils import coloransi, py3compat | |
| from IPython.core.excolors import exception_colors | |
| # skip module docstests | |
| __skip_doctest__ = True | |
| prompt = 'ipdb> ' | |
| # We have to check this directly from sys.argv, config struct not yet available | |
| from pdb import Pdb as OldPdb | |
| # Allow the set_trace code to operate outside of an ipython instance, even if | |
| # it does so with some limitations. The rest of this support is implemented in | |
| # the Tracer constructor. | |
| DEBUGGERSKIP = "__debuggerskip__" | |
| def make_arrow(pad): | |
| """generate the leading arrow in front of traceback or debugger""" | |
| if pad >= 2: | |
| return '-'*(pad-2) + '> ' | |
| elif pad == 1: | |
| return '>' | |
| return '' | |
| def BdbQuit_excepthook(et, ev, tb, excepthook=None): | |
| """Exception hook which handles `BdbQuit` exceptions. | |
| All other exceptions are processed using the `excepthook` | |
| parameter. | |
| """ | |
| raise ValueError( | |
| "`BdbQuit_excepthook` is deprecated since version 5.1", | |
| ) | |
| def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None): | |
| raise ValueError( | |
| "`BdbQuit_IPython_excepthook` is deprecated since version 5.1", | |
| DeprecationWarning, stacklevel=2) | |
| RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+') | |
| def strip_indentation(multiline_string): | |
| return RGX_EXTRA_INDENT.sub('', multiline_string) | |
| def decorate_fn_with_doc(new_fn, old_fn, additional_text=""): | |
| """Make new_fn have old_fn's doc string. This is particularly useful | |
| for the ``do_...`` commands that hook into the help system. | |
| Adapted from from a comp.lang.python posting | |
| by Duncan Booth.""" | |
| def wrapper(*args, **kw): | |
| return new_fn(*args, **kw) | |
| if old_fn.__doc__: | |
| wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text | |
| return wrapper | |
| class Pdb(OldPdb): | |
| """Modified Pdb class, does not load readline. | |
| for a standalone version that uses prompt_toolkit, see | |
| `IPython.terminal.debugger.TerminalPdb` and | |
| `IPython.terminal.debugger.set_trace()` | |
| This debugger can hide and skip frames that are tagged according to some predicates. | |
| See the `skip_predicates` commands. | |
| """ | |
| default_predicates = { | |
| "tbhide": True, | |
| "readonly": False, | |
| "ipython_internal": True, | |
| "debuggerskip": True, | |
| } | |
| def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwargs): | |
| """Create a new IPython debugger. | |
| Parameters | |
| ---------- | |
| completekey : default None | |
| Passed to pdb.Pdb. | |
| stdin : default None | |
| Passed to pdb.Pdb. | |
| stdout : default None | |
| Passed to pdb.Pdb. | |
| context : int | |
| Number of lines of source code context to show when | |
| displaying stacktrace information. | |
| **kwargs | |
| Passed to pdb.Pdb. | |
| Notes | |
| ----- | |
| The possibilities are python version dependent, see the python | |
| docs for more info. | |
| """ | |
| # Parent constructor: | |
| try: | |
| self.context = int(context) | |
| if self.context <= 0: | |
| raise ValueError("Context must be a positive integer") | |
| except (TypeError, ValueError) as e: | |
| raise ValueError("Context must be a positive integer") from e | |
| # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`. | |
| OldPdb.__init__(self, completekey, stdin, stdout, **kwargs) | |
| # IPython changes... | |
| self.shell = get_ipython() | |
| if self.shell is None: | |
| save_main = sys.modules['__main__'] | |
| # No IPython instance running, we must create one | |
| from IPython.terminal.interactiveshell import \ | |
| TerminalInteractiveShell | |
| self.shell = TerminalInteractiveShell.instance() | |
| # needed by any code which calls __import__("__main__") after | |
| # the debugger was entered. See also #9941. | |
| sys.modules["__main__"] = save_main | |
| color_scheme = self.shell.colors | |
| self.aliases = {} | |
| # Create color table: we copy the default one from the traceback | |
| # module and add a few attributes needed for debugging | |
| self.color_scheme_table = exception_colors() | |
| # shorthands | |
| C = coloransi.TermColors | |
| cst = self.color_scheme_table | |
| cst['NoColor'].colors.prompt = C.NoColor | |
| cst['NoColor'].colors.breakpoint_enabled = C.NoColor | |
| cst['NoColor'].colors.breakpoint_disabled = C.NoColor | |
| cst['Linux'].colors.prompt = C.Green | |
| cst['Linux'].colors.breakpoint_enabled = C.LightRed | |
| cst['Linux'].colors.breakpoint_disabled = C.Red | |
| cst['LightBG'].colors.prompt = C.Blue | |
| cst['LightBG'].colors.breakpoint_enabled = C.LightRed | |
| cst['LightBG'].colors.breakpoint_disabled = C.Red | |
| cst['Neutral'].colors.prompt = C.Blue | |
| cst['Neutral'].colors.breakpoint_enabled = C.LightRed | |
| cst['Neutral'].colors.breakpoint_disabled = C.Red | |
| # Add a python parser so we can syntax highlight source while | |
| # debugging. | |
| self.parser = PyColorize.Parser(style=color_scheme) | |
| self.set_colors(color_scheme) | |
| # Set the prompt - the default prompt is '(Pdb)' | |
| self.prompt = prompt | |
| self.skip_hidden = True | |
| self.report_skipped = True | |
| # list of predicates we use to skip frames | |
| self._predicates = self.default_predicates | |
| # | |
| def set_colors(self, scheme): | |
| """Shorthand access to the color table scheme selector method.""" | |
| self.color_scheme_table.set_active_scheme(scheme) | |
| self.parser.style = scheme | |
| def set_trace(self, frame=None): | |
| if frame is None: | |
| frame = sys._getframe().f_back | |
| self.initial_frame = frame | |
| return super().set_trace(frame) | |
| def _hidden_predicate(self, frame): | |
| """ | |
| Given a frame return whether it it should be hidden or not by IPython. | |
| """ | |
| if self._predicates["readonly"]: | |
| fname = frame.f_code.co_filename | |
| # we need to check for file existence and interactively define | |
| # function would otherwise appear as RO. | |
| if os.path.isfile(fname) and not os.access(fname, os.W_OK): | |
| return True | |
| if self._predicates["tbhide"]: | |
| if frame in (self.curframe, getattr(self, "initial_frame", None)): | |
| return False | |
| frame_locals = self._get_frame_locals(frame) | |
| if "__tracebackhide__" not in frame_locals: | |
| return False | |
| return frame_locals["__tracebackhide__"] | |
| return False | |
| def hidden_frames(self, stack): | |
| """ | |
| Given an index in the stack return whether it should be skipped. | |
| This is used in up/down and where to skip frames. | |
| """ | |
| # The f_locals dictionary is updated from the actual frame | |
| # locals whenever the .f_locals accessor is called, so we | |
| # avoid calling it here to preserve self.curframe_locals. | |
| # Furthermore, there is no good reason to hide the current frame. | |
| ip_hide = [self._hidden_predicate(s[0]) for s in stack] | |
| ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"] | |
| if ip_start and self._predicates["ipython_internal"]: | |
| ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)] | |
| return ip_hide | |
| def interaction(self, frame, traceback): | |
| try: | |
| OldPdb.interaction(self, frame, traceback) | |
| except KeyboardInterrupt: | |
| self.stdout.write("\n" + self.shell.get_exception_only()) | |
| def precmd(self, line): | |
| """Perform useful escapes on the command before it is executed.""" | |
| if line.endswith("??"): | |
| line = "pinfo2 " + line[:-2] | |
| elif line.endswith("?"): | |
| line = "pinfo " + line[:-1] | |
| line = super().precmd(line) | |
| return line | |
| def new_do_frame(self, arg): | |
| OldPdb.do_frame(self, arg) | |
| def new_do_quit(self, arg): | |
| if hasattr(self, 'old_all_completions'): | |
| self.shell.Completer.all_completions = self.old_all_completions | |
| return OldPdb.do_quit(self, arg) | |
| do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit) | |
| def new_do_restart(self, arg): | |
| """Restart command. In the context of ipython this is exactly the same | |
| thing as 'quit'.""" | |
| self.msg("Restart doesn't make sense here. Using 'quit' instead.") | |
| return self.do_quit(arg) | |
| def print_stack_trace(self, context=None): | |
| Colors = self.color_scheme_table.active_colors | |
| ColorsNormal = Colors.Normal | |
| if context is None: | |
| context = self.context | |
| try: | |
| context = int(context) | |
| if context <= 0: | |
| raise ValueError("Context must be a positive integer") | |
| except (TypeError, ValueError) as e: | |
| raise ValueError("Context must be a positive integer") from e | |
| try: | |
| skipped = 0 | |
| for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack): | |
| if hidden and self.skip_hidden: | |
| skipped += 1 | |
| continue | |
| if skipped: | |
| print( | |
| f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n" | |
| ) | |
| skipped = 0 | |
| self.print_stack_entry(frame_lineno, context=context) | |
| if skipped: | |
| print( | |
| f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n" | |
| ) | |
| except KeyboardInterrupt: | |
| pass | |
| def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ', | |
| context=None): | |
| if context is None: | |
| context = self.context | |
| try: | |
| context = int(context) | |
| if context <= 0: | |
| raise ValueError("Context must be a positive integer") | |
| except (TypeError, ValueError) as e: | |
| raise ValueError("Context must be a positive integer") from e | |
| print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout) | |
| # vds: >> | |
| frame, lineno = frame_lineno | |
| filename = frame.f_code.co_filename | |
| self.shell.hooks.synchronize_with_editor(filename, lineno, 0) | |
| # vds: << | |
| def _get_frame_locals(self, frame): | |
| """ " | |
| Accessing f_local of current frame reset the namespace, so we want to avoid | |
| that or the following can happen | |
| ipdb> foo | |
| "old" | |
| ipdb> foo = "new" | |
| ipdb> foo | |
| "new" | |
| ipdb> where | |
| ipdb> foo | |
| "old" | |
| So if frame is self.current_frame we instead return self.curframe_locals | |
| """ | |
| if frame is self.curframe: | |
| return self.curframe_locals | |
| else: | |
| return frame.f_locals | |
| def format_stack_entry(self, frame_lineno, lprefix=': ', context=None): | |
| if context is None: | |
| context = self.context | |
| try: | |
| context = int(context) | |
| if context <= 0: | |
| print("Context must be a positive integer", file=self.stdout) | |
| except (TypeError, ValueError): | |
| print("Context must be a positive integer", file=self.stdout) | |
| import reprlib | |
| ret = [] | |
| Colors = self.color_scheme_table.active_colors | |
| ColorsNormal = Colors.Normal | |
| tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal) | |
| tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal) | |
| tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal) | |
| tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal) | |
| frame, lineno = frame_lineno | |
| return_value = '' | |
| loc_frame = self._get_frame_locals(frame) | |
| if "__return__" in loc_frame: | |
| rv = loc_frame["__return__"] | |
| # return_value += '->' | |
| return_value += reprlib.repr(rv) + "\n" | |
| ret.append(return_value) | |
| #s = filename + '(' + `lineno` + ')' | |
| filename = self.canonic(frame.f_code.co_filename) | |
| link = tpl_link % py3compat.cast_unicode(filename) | |
| if frame.f_code.co_name: | |
| func = frame.f_code.co_name | |
| else: | |
| func = "<lambda>" | |
| call = "" | |
| if func != "?": | |
| if "__args__" in loc_frame: | |
| args = reprlib.repr(loc_frame["__args__"]) | |
| else: | |
| args = '()' | |
| call = tpl_call % (func, args) | |
| # The level info should be generated in the same format pdb uses, to | |
| # avoid breaking the pdbtrack functionality of python-mode in *emacs. | |
| if frame is self.curframe: | |
| ret.append('> ') | |
| else: | |
| ret.append(" ") | |
| ret.append("%s(%s)%s\n" % (link, lineno, call)) | |
| start = lineno - 1 - context//2 | |
| lines = linecache.getlines(filename) | |
| start = min(start, len(lines) - context) | |
| start = max(start, 0) | |
| lines = lines[start : start + context] | |
| for i, line in enumerate(lines): | |
| show_arrow = start + 1 + i == lineno | |
| linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line | |
| ret.append( | |
| self.__format_line( | |
| linetpl, filename, start + 1 + i, line, arrow=show_arrow | |
| ) | |
| ) | |
| return "".join(ret) | |
| def __format_line(self, tpl_line, filename, lineno, line, arrow=False): | |
| bp_mark = "" | |
| bp_mark_color = "" | |
| new_line, err = self.parser.format2(line, 'str') | |
| if not err: | |
| line = new_line | |
| bp = None | |
| if lineno in self.get_file_breaks(filename): | |
| bps = self.get_breaks(filename, lineno) | |
| bp = bps[-1] | |
| if bp: | |
| Colors = self.color_scheme_table.active_colors | |
| bp_mark = str(bp.number) | |
| bp_mark_color = Colors.breakpoint_enabled | |
| if not bp.enabled: | |
| bp_mark_color = Colors.breakpoint_disabled | |
| numbers_width = 7 | |
| if arrow: | |
| # This is the line with the error | |
| pad = numbers_width - len(str(lineno)) - len(bp_mark) | |
| num = '%s%s' % (make_arrow(pad), str(lineno)) | |
| else: | |
| num = '%*s' % (numbers_width - len(bp_mark), str(lineno)) | |
| return tpl_line % (bp_mark_color + bp_mark, num, line) | |
| def print_list_lines(self, filename, first, last): | |
| """The printing (as opposed to the parsing part of a 'list' | |
| command.""" | |
| try: | |
| Colors = self.color_scheme_table.active_colors | |
| ColorsNormal = Colors.Normal | |
| tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal) | |
| tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal) | |
| src = [] | |
| if filename == "<string>" and hasattr(self, "_exec_filename"): | |
| filename = self._exec_filename | |
| for lineno in range(first, last+1): | |
| line = linecache.getline(filename, lineno) | |
| if not line: | |
| break | |
| if lineno == self.curframe.f_lineno: | |
| line = self.__format_line( | |
| tpl_line_em, filename, lineno, line, arrow=True | |
| ) | |
| else: | |
| line = self.__format_line( | |
| tpl_line, filename, lineno, line, arrow=False | |
| ) | |
| src.append(line) | |
| self.lineno = lineno | |
| print(''.join(src), file=self.stdout) | |
| except KeyboardInterrupt: | |
| pass | |
| def do_skip_predicates(self, args): | |
| """ | |
| Turn on/off individual predicates as to whether a frame should be hidden/skip. | |
| The global option to skip (or not) hidden frames is set with skip_hidden | |
| To change the value of a predicate | |
| skip_predicates key [true|false] | |
| Call without arguments to see the current values. | |
| To permanently change the value of an option add the corresponding | |
| command to your ``~/.pdbrc`` file. If you are programmatically using the | |
| Pdb instance you can also change the ``default_predicates`` class | |
| attribute. | |
| """ | |
| if not args.strip(): | |
| print("current predicates:") | |
| for p, v in self._predicates.items(): | |
| print(" ", p, ":", v) | |
| return | |
| type_value = args.strip().split(" ") | |
| if len(type_value) != 2: | |
| print( | |
| f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}" | |
| ) | |
| return | |
| type_, value = type_value | |
| if type_ not in self._predicates: | |
| print(f"{type_!r} not in {set(self._predicates.keys())}") | |
| return | |
| if value.lower() not in ("true", "yes", "1", "no", "false", "0"): | |
| print( | |
| f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')" | |
| ) | |
| return | |
| self._predicates[type_] = value.lower() in ("true", "yes", "1") | |
| if not any(self._predicates.values()): | |
| print( | |
| "Warning, all predicates set to False, skip_hidden may not have any effects." | |
| ) | |
| def do_skip_hidden(self, arg): | |
| """ | |
| Change whether or not we should skip frames with the | |
| __tracebackhide__ attribute. | |
| """ | |
| if not arg.strip(): | |
| print( | |
| f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change." | |
| ) | |
| elif arg.strip().lower() in ("true", "yes"): | |
| self.skip_hidden = True | |
| elif arg.strip().lower() in ("false", "no"): | |
| self.skip_hidden = False | |
| if not any(self._predicates.values()): | |
| print( | |
| "Warning, all predicates set to False, skip_hidden may not have any effects." | |
| ) | |
| def do_list(self, arg): | |
| """Print lines of code from the current stack frame | |
| """ | |
| self.lastcmd = 'list' | |
| last = None | |
| if arg: | |
| try: | |
| x = eval(arg, {}, {}) | |
| if type(x) == type(()): | |
| first, last = x | |
| first = int(first) | |
| last = int(last) | |
| if last < first: | |
| # Assume it's a count | |
| last = first + last | |
| else: | |
| first = max(1, int(x) - 5) | |
| except: | |
| print('*** Error in argument:', repr(arg), file=self.stdout) | |
| return | |
| elif self.lineno is None: | |
| first = max(1, self.curframe.f_lineno - 5) | |
| else: | |
| first = self.lineno + 1 | |
| if last is None: | |
| last = first + 10 | |
| self.print_list_lines(self.curframe.f_code.co_filename, first, last) | |
| # vds: >> | |
| lineno = first | |
| filename = self.curframe.f_code.co_filename | |
| self.shell.hooks.synchronize_with_editor(filename, lineno, 0) | |
| # vds: << | |
| do_l = do_list | |
| def getsourcelines(self, obj): | |
| lines, lineno = inspect.findsource(obj) | |
| if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj): | |
| # must be a module frame: do not try to cut a block out of it | |
| return lines, 1 | |
| elif inspect.ismodule(obj): | |
| return lines, 1 | |
| return inspect.getblock(lines[lineno:]), lineno+1 | |
| def do_longlist(self, arg): | |
| """Print lines of code from the current stack frame. | |
| Shows more lines than 'list' does. | |
| """ | |
| self.lastcmd = 'longlist' | |
| try: | |
| lines, lineno = self.getsourcelines(self.curframe) | |
| except OSError as err: | |
| self.error(err) | |
| return | |
| last = lineno + len(lines) | |
| self.print_list_lines(self.curframe.f_code.co_filename, lineno, last) | |
| do_ll = do_longlist | |
| def do_debug(self, arg): | |
| """debug code | |
| Enter a recursive debugger that steps through the code | |
| argument (which is an arbitrary expression or statement to be | |
| executed in the current environment). | |
| """ | |
| trace_function = sys.gettrace() | |
| sys.settrace(None) | |
| globals = self.curframe.f_globals | |
| locals = self.curframe_locals | |
| p = self.__class__(completekey=self.completekey, | |
| stdin=self.stdin, stdout=self.stdout) | |
| p.use_rawinput = self.use_rawinput | |
| p.prompt = "(%s) " % self.prompt.strip() | |
| self.message("ENTERING RECURSIVE DEBUGGER") | |
| sys.call_tracing(p.run, (arg, globals, locals)) | |
| self.message("LEAVING RECURSIVE DEBUGGER") | |
| sys.settrace(trace_function) | |
| self.lastcmd = p.lastcmd | |
| def do_pdef(self, arg): | |
| """Print the call signature for any callable object. | |
| The debugger interface to %pdef""" | |
| namespaces = [ | |
| ("Locals", self.curframe_locals), | |
| ("Globals", self.curframe.f_globals), | |
| ] | |
| self.shell.find_line_magic("pdef")(arg, namespaces=namespaces) | |
| def do_pdoc(self, arg): | |
| """Print the docstring for an object. | |
| The debugger interface to %pdoc.""" | |
| namespaces = [ | |
| ("Locals", self.curframe_locals), | |
| ("Globals", self.curframe.f_globals), | |
| ] | |
| self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces) | |
| def do_pfile(self, arg): | |
| """Print (or run through pager) the file where an object is defined. | |
| The debugger interface to %pfile. | |
| """ | |
| namespaces = [ | |
| ("Locals", self.curframe_locals), | |
| ("Globals", self.curframe.f_globals), | |
| ] | |
| self.shell.find_line_magic("pfile")(arg, namespaces=namespaces) | |
| def do_pinfo(self, arg): | |
| """Provide detailed information about an object. | |
| The debugger interface to %pinfo, i.e., obj?.""" | |
| namespaces = [ | |
| ("Locals", self.curframe_locals), | |
| ("Globals", self.curframe.f_globals), | |
| ] | |
| self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces) | |
| def do_pinfo2(self, arg): | |
| """Provide extra detailed information about an object. | |
| The debugger interface to %pinfo2, i.e., obj??.""" | |
| namespaces = [ | |
| ("Locals", self.curframe_locals), | |
| ("Globals", self.curframe.f_globals), | |
| ] | |
| self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces) | |
| def do_psource(self, arg): | |
| """Print (or run through pager) the source code for an object.""" | |
| namespaces = [ | |
| ("Locals", self.curframe_locals), | |
| ("Globals", self.curframe.f_globals), | |
| ] | |
| self.shell.find_line_magic("psource")(arg, namespaces=namespaces) | |
| def do_where(self, arg): | |
| """w(here) | |
| Print a stack trace, with the most recent frame at the bottom. | |
| An arrow indicates the "current frame", which determines the | |
| context of most commands. 'bt' is an alias for this command. | |
| Take a number as argument as an (optional) number of context line to | |
| print""" | |
| if arg: | |
| try: | |
| context = int(arg) | |
| except ValueError as err: | |
| self.error(err) | |
| return | |
| self.print_stack_trace(context) | |
| else: | |
| self.print_stack_trace() | |
| do_w = do_where | |
| def break_anywhere(self, frame): | |
| """ | |
| _stop_in_decorator_internals is overly restrictive, as we may still want | |
| to trace function calls, so we need to also update break_anywhere so | |
| that is we don't `stop_here`, because of debugger skip, we may still | |
| stop at any point inside the function | |
| """ | |
| sup = super().break_anywhere(frame) | |
| if sup: | |
| return sup | |
| if self._predicates["debuggerskip"]: | |
| if DEBUGGERSKIP in frame.f_code.co_varnames: | |
| return True | |
| if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP): | |
| return True | |
| return False | |
| def _is_in_decorator_internal_and_should_skip(self, frame): | |
| """ | |
| Utility to tell us whether we are in a decorator internal and should stop. | |
| """ | |
| # if we are disabled don't skip | |
| if not self._predicates["debuggerskip"]: | |
| return False | |
| # if frame is tagged, skip by default. | |
| if DEBUGGERSKIP in frame.f_code.co_varnames: | |
| return True | |
| # if one of the parent frame value set to True skip as well. | |
| cframe = frame | |
| while getattr(cframe, "f_back", None): | |
| cframe = cframe.f_back | |
| if self._get_frame_locals(cframe).get(DEBUGGERSKIP): | |
| return True | |
| return False | |
| def stop_here(self, frame): | |
| if self._is_in_decorator_internal_and_should_skip(frame) is True: | |
| return False | |
| hidden = False | |
| if self.skip_hidden: | |
| hidden = self._hidden_predicate(frame) | |
| if hidden: | |
| if self.report_skipped: | |
| Colors = self.color_scheme_table.active_colors | |
| ColorsNormal = Colors.Normal | |
| print( | |
| f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n" | |
| ) | |
| return super().stop_here(frame) | |
| def do_up(self, arg): | |
| """u(p) [count] | |
| Move the current frame count (default one) levels up in the | |
| stack trace (to an older frame). | |
| Will skip hidden frames. | |
| """ | |
| # modified version of upstream that skips | |
| # frames with __tracebackhide__ | |
| if self.curindex == 0: | |
| self.error("Oldest frame") | |
| return | |
| try: | |
| count = int(arg or 1) | |
| except ValueError: | |
| self.error("Invalid frame count (%s)" % arg) | |
| return | |
| skipped = 0 | |
| if count < 0: | |
| _newframe = 0 | |
| else: | |
| counter = 0 | |
| hidden_frames = self.hidden_frames(self.stack) | |
| for i in range(self.curindex - 1, -1, -1): | |
| if hidden_frames[i] and self.skip_hidden: | |
| skipped += 1 | |
| continue | |
| counter += 1 | |
| if counter >= count: | |
| break | |
| else: | |
| # if no break occurred. | |
| self.error( | |
| "all frames above hidden, use `skip_hidden False` to get get into those." | |
| ) | |
| return | |
| Colors = self.color_scheme_table.active_colors | |
| ColorsNormal = Colors.Normal | |
| _newframe = i | |
| self._select_frame(_newframe) | |
| if skipped: | |
| print( | |
| f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n" | |
| ) | |
| def do_down(self, arg): | |
| """d(own) [count] | |
| Move the current frame count (default one) levels down in the | |
| stack trace (to a newer frame). | |
| Will skip hidden frames. | |
| """ | |
| if self.curindex + 1 == len(self.stack): | |
| self.error("Newest frame") | |
| return | |
| try: | |
| count = int(arg or 1) | |
| except ValueError: | |
| self.error("Invalid frame count (%s)" % arg) | |
| return | |
| if count < 0: | |
| _newframe = len(self.stack) - 1 | |
| else: | |
| counter = 0 | |
| skipped = 0 | |
| hidden_frames = self.hidden_frames(self.stack) | |
| for i in range(self.curindex + 1, len(self.stack)): | |
| if hidden_frames[i] and self.skip_hidden: | |
| skipped += 1 | |
| continue | |
| counter += 1 | |
| if counter >= count: | |
| break | |
| else: | |
| self.error( | |
| "all frames below hidden, use `skip_hidden False` to get get into those." | |
| ) | |
| return | |
| Colors = self.color_scheme_table.active_colors | |
| ColorsNormal = Colors.Normal | |
| if skipped: | |
| print( | |
| f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n" | |
| ) | |
| _newframe = i | |
| self._select_frame(_newframe) | |
| do_d = do_down | |
| do_u = do_up | |
| def do_context(self, context): | |
| """context number_of_lines | |
| Set the number of lines of source code to show when displaying | |
| stacktrace information. | |
| """ | |
| try: | |
| new_context = int(context) | |
| if new_context <= 0: | |
| raise ValueError() | |
| self.context = new_context | |
| except ValueError: | |
| self.error("The 'context' command requires a positive integer argument.") | |
| class InterruptiblePdb(Pdb): | |
| """Version of debugger where KeyboardInterrupt exits the debugger altogether.""" | |
| def cmdloop(self, intro=None): | |
| """Wrap cmdloop() such that KeyboardInterrupt stops the debugger.""" | |
| try: | |
| return OldPdb.cmdloop(self, intro=intro) | |
| except KeyboardInterrupt: | |
| self.stop_here = lambda frame: False | |
| self.do_quit("") | |
| sys.settrace(None) | |
| self.quitting = False | |
| raise | |
| def _cmdloop(self): | |
| while True: | |
| try: | |
| # keyboard interrupts allow for an easy way to cancel | |
| # the current command, so allow them during interactive input | |
| self.allow_kbdint = True | |
| self.cmdloop() | |
| self.allow_kbdint = False | |
| break | |
| except KeyboardInterrupt: | |
| self.message('--KeyboardInterrupt--') | |
| raise | |
| def set_trace(frame=None): | |
| """ | |
| Start debugging from `frame`. | |
| If frame is not specified, debugging starts from caller's frame. | |
| """ | |
| Pdb().set_trace(frame or sys._getframe().f_back) | |