debugger.py
669 lines
| 23.2 KiB
| text/x-python
|
PythonLexer
fperez
|
r0 | # -*- coding: utf-8 -*- | ||
""" | ||||
Pdb debugger class. | ||||
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 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: | ||||
Thomas Kluyver
|
r23220 | https://docs.python.org/2/license.html | ||
""" | ||||
fperez
|
r88 | |||
#***************************************************************************** | ||||
# | ||||
vivainio
|
r911 | # This file is licensed under the PSF license. | ||
fperez
|
r88 | # | ||
# Copyright (C) 2001 Python Software Foundation, www.python.org | ||||
# Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu> | ||||
# | ||||
# | ||||
#***************************************************************************** | ||||
fperez
|
r52 | import bdb | ||
Bradley M. Froehle
|
r8679 | import functools | ||
Victor Ramirez
|
r21395 | import inspect | ||
Srinivas Reddy Thatiparthy
|
r23116 | import linecache | ||
fperez
|
r52 | import sys | ||
Antony Lee
|
r22687 | import warnings | ||
Corey McCandless
|
r24092 | import re | ||
fperez
|
r52 | |||
MinRK
|
r10580 | from IPython import get_ipython | ||
Srinivas Reddy Thatiparthy
|
r23116 | from IPython.utils import PyColorize | ||
Thomas Kluyver
|
r22192 | from IPython.utils import coloransi, py3compat | ||
Brian Granger
|
r2021 | from IPython.core.excolors import exception_colors | ||
Thomas Kluyver
|
r12286 | from IPython.testing.skipdoctest import skip_doctest | ||
Matthias Bussonnier
|
r22390 | |||
Matthias Bussonnier
|
r22383 | |||
fperez
|
r552 | prompt = 'ipdb> ' | ||
Matthias Bussonnier
|
r22359 | |||
vivainio
|
r922 | #We have to check this directly from sys.argv, config struct not yet available | ||
Matthias Bussonnier
|
r22359 | from pdb import Pdb as OldPdb | ||
vivainio
|
r393 | |||
fperez
|
r506 | # 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. | ||||
Matthias Bussonnier
|
r22083 | |||
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 '' | ||||
Bradley M. Froehle
|
r8679 | def BdbQuit_excepthook(et, ev, tb, excepthook=None): | ||
"""Exception hook which handles `BdbQuit` exceptions. | ||||
All other exceptions are processed using the `excepthook` | ||||
parameter. | ||||
""" | ||||
Antony Lee
|
r22687 | warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1", | ||
Matthias Bussonnier
|
r22994 | DeprecationWarning, stacklevel=2) | ||
fperez
|
r506 | if et==bdb.BdbQuit: | ||
Matthias BUSSONNIER
|
r7817 | print('Exiting Debugger.') | ||
Bradley M. Froehle
|
r8679 | elif excepthook is not None: | ||
excepthook(et, ev, tb) | ||||
fperez
|
r506 | else: | ||
Bradley M. Froehle
|
r8679 | # Backwards compatibility. Raise deprecation warning? | ||
jdh2358
|
r615 | BdbQuit_excepthook.excepthook_ori(et,ev,tb) | ||
fperez
|
r506 | |||
Antony Lee
|
r22687 | |||
MinRK
|
r4991 | def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None): | ||
Antony Lee
|
r22687 | warnings.warn( | ||
"`BdbQuit_IPython_excepthook` is deprecated since version 5.1", | ||||
Matthias Bussonnier
|
r22994 | DeprecationWarning, stacklevel=2) | ||
Matthias BUSSONNIER
|
r7817 | print('Exiting Debugger.') | ||
fperez
|
r506 | |||
Brian Granger
|
r2290 | |||
fperez
|
r506 | class Tracer(object): | ||
Matthias Bussonnier
|
r22724 | """ | ||
DEPRECATED | ||||
Class for local debugging, similar to pdb.set_trace. | ||||
fperez
|
r506 | |||
Instances of this class, when called, behave like pdb.set_trace, but | ||||
providing IPython's enhanced capabilities. | ||||
This is implemented as a class which must be initialized in your own code | ||||
and not as a standalone function because we need to detect at runtime | ||||
whether IPython is already active or not. That detection is done in the | ||||
constructor, ensuring that this code plays nicely with a running IPython, | ||||
while functioning acceptably (though with limitations) if outside of it. | ||||
""" | ||||
Thomas Kluyver
|
r12286 | @skip_doctest | ||
JamshedVesuna
|
r21876 | def __init__(self, colors=None): | ||
Matthias Bussonnier
|
r22724 | """ | ||
DEPRECATED | ||||
Create a local debugger instance. | ||||
fperez
|
r506 | |||
Thomas Kluyver
|
r12553 | Parameters | ||
---------- | ||||
fperez
|
r506 | |||
Thomas Kluyver
|
r12553 | colors : str, optional | ||
The name of the color scheme to use, it must be one of IPython's | ||||
valid color schemes. If not given, the function will default to | ||||
the current IPython scheme when running inside IPython, and to | ||||
'NoColor' otherwise. | ||||
fperez
|
r506 | |||
Thomas Kluyver
|
r12553 | Examples | ||
-------- | ||||
:: | ||||
fperez
|
r506 | |||
Thomas Kluyver
|
r12553 | from IPython.core.debugger import Tracer; debug_here = Tracer() | ||
fperez
|
r506 | |||
Thomas Kluyver
|
r12553 | Later in your code:: | ||
Gábor Luk
|
r21692 | |||
Thomas Kluyver
|
r12553 | debug_here() # -> will open up the debugger at that point. | ||
fperez
|
r506 | |||
Once the debugger activates, you can use all of its regular commands to | ||||
step through code, set breakpoints, etc. See the pdb documentation | ||||
from the Python standard library for usage details. | ||||
""" | ||||
Antony Lee
|
r22687 | warnings.warn("`Tracer` is deprecated since version 5.1, directly use " | ||
"`IPython.core.debugger.Pdb.set_trace()`", | ||||
Matthias Bussonnier
|
r22994 | DeprecationWarning, stacklevel=2) | ||
fperez
|
r506 | |||
MinRK
|
r10580 | ip = get_ipython() | ||
if ip is None: | ||||
fperez
|
r506 | # Outside of ipython, we set our own exception hook manually | ||
Bradley M. Froehle
|
r8679 | sys.excepthook = functools.partial(BdbQuit_excepthook, | ||
excepthook=sys.excepthook) | ||||
fperez
|
r506 | def_colors = 'NoColor' | ||
else: | ||||
# In ipython, we use its custom exception handler mechanism | ||||
Brian Granger
|
r2205 | def_colors = ip.colors | ||
Brian Granger
|
r2290 | ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook) | ||
fperez
|
r506 | |||
if colors is None: | ||||
colors = def_colors | ||||
Fernando Perez
|
r7083 | |||
# The stdlib debugger internally uses a modified repr from the `repr` | ||||
# module, that limits the length of printed strings to a hardcoded | ||||
# limit of 30 characters. That much trimming is too aggressive, let's | ||||
# at least raise that limit to 80 chars, which should be enough for | ||||
# most interactive uses. | ||||
try: | ||||
Matthias Bussonnier
|
r25369 | from reprlib import aRepr | ||
Fernando Perez
|
r7083 | aRepr.maxstring = 80 | ||
except: | ||||
# This is only a user-facing convenience, so any error we encounter | ||||
# here can be warned about but can be otherwise ignored. These | ||||
DamianHeard
|
r8678 | # printouts will tell us about problems if this API changes | ||
Fernando Perez
|
r7083 | import traceback | ||
traceback.print_exc() | ||||
fperez
|
r506 | self.debugger = Pdb(colors) | ||
def __call__(self): | ||||
"""Starts an interactive debugger at the point where called. | ||||
This is similar to the pdb.set_trace() function from the std lib, but | ||||
using IPython's enhanced debugger.""" | ||||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r506 | self.debugger.set_trace(sys._getframe().f_back) | ||
Brian Granger
|
r2290 | |||
Matthias Bussonnier
|
r24451 | RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+') | ||
Corey McCandless
|
r24093 | |||
Corey McCandless
|
r24092 | def strip_indentation(multiline_string): | ||
return RGX_EXTRA_INDENT.sub('', multiline_string) | ||||
vivainio
|
r393 | def decorate_fn_with_doc(new_fn, old_fn, additional_text=""): | ||
"""Make new_fn have old_fn's doc string. This is particularly useful | ||||
Thomas Kluyver
|
r9244 | for the ``do_...`` commands that hook into the help system. | ||
vivainio
|
r393 | Adapted from from a comp.lang.python posting | ||
by Duncan Booth.""" | ||||
def wrapper(*args, **kw): | ||||
return new_fn(*args, **kw) | ||||
if old_fn.__doc__: | ||||
Corey McCandless
|
r24092 | wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text | ||
vivainio
|
r393 | return wrapper | ||
Brian Granger
|
r2290 | |||
Thomas Kluyver
|
r23003 | class Pdb(OldPdb): | ||
Matthias Bussonnier
|
r22724 | """Modified Pdb class, does not load readline. | ||
Thomas Kluyver
|
r22731 | for a standalone version that uses prompt_toolkit, see | ||
Matthias Bussonnier
|
r22724 | `IPython.terminal.debugger.TerminalPdb` and | ||
`IPython.terminal.debugger.set_trace()` | ||||
""" | ||||
fperez
|
r122 | |||
Antony Lee
|
r22687 | def __init__(self, color_scheme=None, completekey=None, | ||
Terry Davis
|
r25172 | stdin=None, stdout=None, context=5, **kwargs): | ||
Terry Davis
|
r25173 | """Create a new IPython debugger. | ||
:param color_scheme: Deprecated, do not use. | ||||
:param completekey: Passed to pdb.Pdb. | ||||
:param stdin: Passed to pdb.Pdb. | ||||
:param stdout: Passed to pdb.Pdb. | ||||
:param context: Number of lines of source code context to show when | ||||
displaying stacktrace information. | ||||
:param kwargs: Passed to pdb.Pdb. | ||||
The possibilities are python version dependent, see the python | ||||
docs for more info. | ||||
""" | ||||
fperez
|
r367 | |||
Brian Granger
|
r2290 | # Parent constructor: | ||
JamshedVesuna
|
r21876 | try: | ||
Antony Lee
|
r22687 | self.context = int(context) | ||
JamshedVesuna
|
r21876 | if self.context <= 0: | ||
raise ValueError("Context must be a positive integer") | ||||
except (TypeError, ValueError): | ||||
raise ValueError("Context must be a positive integer") | ||||
Terry Davis
|
r25176 | |||
Terry Davis
|
r25172 | # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`. | ||
OldPdb.__init__(self, completekey, stdin, stdout, **kwargs) | ||||
Bernardo B. Marques
|
r4872 | |||
Brian Granger
|
r2290 | # IPython changes... | ||
MinRK
|
r10581 | self.shell = get_ipython() | ||
fperez
|
r367 | |||
Puneeth Chaganti
|
r11114 | if self.shell is None: | ||
mbyt
|
r22907 | save_main = sys.modules['__main__'] | ||
Puneeth Chaganti
|
r11114 | # No IPython instance running, we must create one | ||
from IPython.terminal.interactiveshell import \ | ||||
TerminalInteractiveShell | ||||
self.shell = TerminalInteractiveShell.instance() | ||||
mbyt
|
r22907 | # needed by any code which calls __import__("__main__") after | ||
# the debugger was entered. See also #9941. | ||||
sys.modules['__main__'] = save_main | ||||
Puneeth Chaganti
|
r11114 | |||
Antony Lee
|
r22687 | if color_scheme is not None: | ||
warnings.warn( | ||||
"The `color_scheme` argument is deprecated since version 5.1", | ||||
Matthias Bussonnier
|
r22911 | DeprecationWarning, stacklevel=2) | ||
Antony Lee
|
r22687 | else: | ||
color_scheme = self.shell.colors | ||||
Brian Granger
|
r2290 | self.aliases = {} | ||
fperez
|
r553 | |||
Brian Granger
|
r2290 | # 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() | ||||
fperez
|
r367 | |||
Bernardo B. Marques
|
r4872 | # shorthands | ||
Brian Granger
|
r2290 | C = coloransi.TermColors | ||
cst = self.color_scheme_table | ||||
fperez
|
r367 | |||
Gábor Luk
|
r21692 | cst['NoColor'].colors.prompt = C.NoColor | ||
Brian Granger
|
r2290 | cst['NoColor'].colors.breakpoint_enabled = C.NoColor | ||
cst['NoColor'].colors.breakpoint_disabled = C.NoColor | ||||
fperez
|
r367 | |||
Gábor Luk
|
r21692 | cst['Linux'].colors.prompt = C.Green | ||
Brian Granger
|
r2290 | cst['Linux'].colors.breakpoint_enabled = C.LightRed | ||
cst['Linux'].colors.breakpoint_disabled = C.Red | ||||
fperez
|
r367 | |||
Gábor Luk
|
r21692 | cst['LightBG'].colors.prompt = C.Blue | ||
Brian Granger
|
r2290 | cst['LightBG'].colors.breakpoint_enabled = C.LightRed | ||
cst['LightBG'].colors.breakpoint_disabled = C.Red | ||||
fperez
|
r367 | |||
Matthias Bussonnier
|
r22609 | cst['Neutral'].colors.prompt = C.Blue | ||
cst['Neutral'].colors.breakpoint_enabled = C.LightRed | ||||
cst['Neutral'].colors.breakpoint_disabled = C.Red | ||||
fperez
|
r367 | |||
Brian Granger
|
r2290 | # Add a python parser so we can syntax highlight source while | ||
# debugging. | ||||
Matthias Bussonnier
|
r22911 | self.parser = PyColorize.Parser(style=color_scheme) | ||
self.set_colors(color_scheme) | ||||
fperez
|
r553 | |||
Thomas Kluyver
|
r22094 | # Set the prompt - the default prompt is '(Pdb)' | ||
Matthias Bussonnier
|
r22383 | self.prompt = prompt | ||
Gábor Luk
|
r21692 | |||
fperez
|
r46 | def set_colors(self, scheme): | ||
"""Shorthand access to the color table scheme selector method.""" | ||||
self.color_scheme_table.set_active_scheme(scheme) | ||||
Matthias Bussonnier
|
r22911 | self.parser.style = scheme | ||
fperez
|
r46 | |||
def interaction(self, frame, traceback): | ||||
Thomas Kluyver
|
r22385 | try: | ||
OldPdb.interaction(self, frame, traceback) | ||||
except KeyboardInterrupt: | ||||
Maor Kleinberger
|
r25083 | self.stdout.write('\n' + self.shell.get_exception_only()) | ||
vivainio
|
r393 | |||
def new_do_up(self, arg): | ||||
OldPdb.do_up(self, arg) | ||||
do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up) | ||||
fperez
|
r46 | |||
vivainio
|
r393 | def new_do_down(self, arg): | ||
OldPdb.do_down(self, arg) | ||||
fperez
|
r46 | |||
vivainio
|
r393 | do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down) | ||
def new_do_frame(self, arg): | ||||
OldPdb.do_frame(self, arg) | ||||
def new_do_quit(self, arg): | ||||
Bernardo B. Marques
|
r4872 | |||
vivainio
|
r465 | if hasattr(self, 'old_all_completions'): | ||
Brian Granger
|
r2290 | self.shell.Completer.all_completions=self.old_all_completions | ||
Bernardo B. Marques
|
r4872 | |||
vivainio
|
r393 | 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) | ||||
fperez
|
r46 | |||
JamshedVesuna
|
r21876 | def print_stack_trace(self, 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): | ||||
raise ValueError("Context must be a positive integer") | ||||
fperez
|
r46 | try: | ||
for frame_lineno in self.stack: | ||||
JamshedVesuna
|
r21876 | self.print_stack_entry(frame_lineno, context=context) | ||
fperez
|
r46 | except KeyboardInterrupt: | ||
fperez
|
r0 | pass | ||
fperez
|
r46 | |||
Maor Kleinberger
|
r25083 | def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ', | ||
JamshedVesuna
|
r21876 | 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): | ||||
raise ValueError("Context must be a positive integer") | ||||
Maor Kleinberger
|
r25083 | print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout) | ||
fperez
|
r46 | |||
vds
|
r1241 | # vds: >> | ||
frame, lineno = frame_lineno | ||||
filename = frame.f_code.co_filename | ||||
Brian Granger
|
r2290 | self.shell.hooks.synchronize_with_editor(filename, lineno, 0) | ||
vds
|
r1241 | # vds: << | ||
JamshedVesuna
|
r21876 | def format_stack_entry(self, frame_lineno, lprefix=': ', context=None): | ||
if context is None: | ||||
context = self.context | ||||
try: | ||||
context=int(context) | ||||
if context <= 0: | ||||
Maor Kleinberger
|
r25083 | print("Context must be a positive integer", file=self.stdout) | ||
JamshedVesuna
|
r21876 | except (TypeError, ValueError): | ||
Maor Kleinberger
|
r25083 | print("Context must be a positive integer", file=self.stdout) | ||
Terry Davis
|
r25516 | |||
import reprlib | ||||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r294 | ret = [] | ||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | Colors = self.color_scheme_table.active_colors | ||
ColorsNormal = Colors.Normal | ||||
Thomas Kluyver
|
r8327 | tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal) | ||
tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal) | ||||
tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal) | ||||
tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, | ||||
fperez
|
r46 | ColorsNormal) | ||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | frame, lineno = frame_lineno | ||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | return_value = '' | ||
if '__return__' in frame.f_locals: | ||||
rv = frame.f_locals['__return__'] | ||||
#return_value += '->' | ||||
Thomas Kluyver
|
r13354 | return_value += reprlib.repr(rv) + '\n' | ||
fperez
|
r294 | ret.append(return_value) | ||
fperez
|
r46 | |||
#s = filename + '(' + `lineno` + ')' | ||||
filename = self.canonic(frame.f_code.co_filename) | ||||
Thomas Kluyver
|
r8327 | link = tpl_link % py3compat.cast_unicode(filename) | ||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | if frame.f_code.co_name: | ||
func = frame.f_code.co_name | ||||
else: | ||||
func = "<lambda>" | ||||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | call = '' | ||
Bernardo B. Marques
|
r4872 | if func != '?': | ||
fperez
|
r46 | if '__args__' in frame.f_locals: | ||
Thomas Kluyver
|
r13354 | args = reprlib.repr(frame.f_locals['__args__']) | ||
fperez
|
r46 | else: | ||
args = '()' | ||||
call = tpl_call % (func, args) | ||||
fperez
|
r294 | |||
# The level info should be generated in the same format pdb uses, to | ||||
# avoid breaking the pdbtrack functionality of python-mode in *emacs. | ||||
fperez
|
r552 | if frame is self.curframe: | ||
ret.append('> ') | ||||
else: | ||||
ret.append(' ') | ||||
Thomas Kluyver
|
r8327 | ret.append(u'%s(%s)%s\n' % (link,lineno,call)) | ||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | start = lineno - 1 - context//2 | ||
Srinivas Reddy Thatiparthy
|
r23116 | lines = linecache.getlines(filename) | ||
fperez
|
r46 | start = min(start, len(lines) - context) | ||
tcmulcahy
|
r8895 | start = max(start, 0) | ||
fperez
|
r46 | lines = lines[start : start + context] | ||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r294 | for i,line in enumerate(lines): | ||
show_arrow = (start + 1 + i == lineno) | ||||
fperez
|
r552 | linetpl = (frame is self.curframe or show_arrow) \ | ||
and tpl_line_em \ | ||||
or tpl_line | ||||
ret.append(self.__format_line(linetpl, filename, | ||||
Thomas Kluyver
|
r8324 | start + 1 + i, line, | ||
fperez
|
r294 | arrow = show_arrow) ) | ||
return ''.join(ret) | ||||
fperez
|
r46 | |||
def __format_line(self, tpl_line, filename, lineno, line, arrow = False): | ||||
bp_mark = "" | ||||
bp_mark_color = "" | ||||
Matthias Bussonnier
|
r22911 | new_line, err = self.parser.format2(line, 'str') | ||
if not err: | ||||
line = new_line | ||||
fperez
|
r553 | |||
fperez
|
r46 | bp = None | ||
if lineno in self.get_file_breaks(filename): | ||||
bps = self.get_breaks(filename, lineno) | ||||
bp = bps[-1] | ||||
Bernardo B. Marques
|
r4872 | |||
fperez
|
r46 | 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) | ||||
Matthias Bussonnier
|
r22083 | num = '%s%s' % (make_arrow(pad), str(lineno)) | ||
fperez
|
r46 | else: | ||
num = '%*s' % (numbers_width - len(bp_mark), str(lineno)) | ||||
Bernardo B. Marques
|
r4872 | |||
Matthias Bussonnier
|
r22083 | return tpl_line % (bp_mark_color + bp_mark, num, line) | ||
fperez
|
r46 | |||
vivainio
|
r393 | 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 = [] | ||||
Jörgen Stenarson
|
r8317 | if filename == "<string>" and hasattr(self, "_exec_filename"): | ||
Thomas Kluyver
|
r8324 | filename = self._exec_filename | ||
DamianHeard
|
r8678 | |||
vivainio
|
r393 | for lineno in range(first, last+1): | ||
Srinivas Reddy Thatiparthy
|
r23116 | line = linecache.getline(filename, lineno) | ||
vivainio
|
r393 | 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 | ||||
Maor Kleinberger
|
r25083 | print(''.join(src), file=self.stdout) | ||
vivainio
|
r393 | |||
except KeyboardInterrupt: | ||||
pass | ||||
fperez
|
r46 | def do_list(self, arg): | ||
Thomas Kluyver
|
r23488 | """Print lines of code from the current stack frame | ||
""" | ||||
fperez
|
r46 | 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: | ||||
Maor Kleinberger
|
r25083 | print('*** Error in argument:', repr(arg), file=self.stdout) | ||
fperez
|
r46 | return | ||
elif self.lineno is None: | ||||
first = max(1, self.curframe.f_lineno - 5) | ||||
fperez
|
r0 | else: | ||
fperez
|
r46 | first = self.lineno + 1 | ||
if last is None: | ||||
last = first + 10 | ||||
vivainio
|
r393 | self.print_list_lines(self.curframe.f_code.co_filename, first, last) | ||
fperez
|
r46 | |||
vds
|
r1241 | # vds: >> | ||
lineno = first | ||||
filename = self.curframe.f_code.co_filename | ||||
Brian Granger
|
r2290 | self.shell.hooks.synchronize_with_editor(filename, lineno, 0) | ||
vds
|
r1241 | # vds: << | ||
fperez
|
r46 | do_l = do_list | ||
vivainio
|
r393 | |||
Victor Ramirez
|
r21395 | def getsourcelines(self, obj): | ||
lines, lineno = inspect.findsource(obj) | ||||
if inspect.isframe(obj) and obj.f_globals is obj.f_locals: | ||||
# 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): | ||||
Thomas Kluyver
|
r23488 | """Print lines of code from the current stack frame. | ||
Shows more lines than 'list' does. | ||||
""" | ||||
Victor Ramirez
|
r21395 | 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 | ||||
Segev Finer
|
r23823 | 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). | ||||
""" | ||||
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(self.trace_dispatch) | ||||
self.lastcmd = p.lastcmd | ||||
vivainio
|
r393 | def do_pdef(self, arg): | ||
Bradley M. Froehle
|
r8707 | """Print the call signature for any callable object. | ||
Bradley M. Froehle
|
r8698 | |||
The debugger interface to %pdef""" | ||||
vivainio
|
r393 | namespaces = [('Locals', self.curframe.f_locals), | ||
('Globals', self.curframe.f_globals)] | ||||
Bradley M. Froehle
|
r7904 | self.shell.find_line_magic('pdef')(arg, namespaces=namespaces) | ||
vivainio
|
r393 | |||
def do_pdoc(self, arg): | ||||
Bradley M. Froehle
|
r8698 | """Print the docstring for an object. | ||
The debugger interface to %pdoc.""" | ||||
vivainio
|
r393 | namespaces = [('Locals', self.curframe.f_locals), | ||
('Globals', self.curframe.f_globals)] | ||||
Bradley M. Froehle
|
r7904 | self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces) | ||
vivainio
|
r393 | |||
Bradley M. Froehle
|
r8699 | 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.f_locals), | ||||
('Globals', self.curframe.f_globals)] | ||||
self.shell.find_line_magic('pfile')(arg, namespaces=namespaces) | ||||
vivainio
|
r393 | def do_pinfo(self, arg): | ||
Bradley M. Froehle
|
r8698 | """Provide detailed information about an object. | ||
The debugger interface to %pinfo, i.e., obj?.""" | ||||
vivainio
|
r393 | namespaces = [('Locals', self.curframe.f_locals), | ||
('Globals', self.curframe.f_globals)] | ||||
Bradley M. Froehle
|
r8701 | 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.f_locals), | ||||
('Globals', self.curframe.f_globals)] | ||||
self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces) | ||||
Fernando Perez
|
r2372 | |||
Bradley M. Froehle
|
r8700 | def do_psource(self, arg): | ||
"""Print (or run through pager) the source code for an object.""" | ||||
namespaces = [('Locals', self.curframe.f_locals), | ||||
('Globals', self.curframe.f_globals)] | ||||
self.shell.find_line_magic('psource')(arg, namespaces=namespaces) | ||||
JamshedVesuna
|
r21876 | |||
Paul Ivanov
|
r22959 | 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: | ||||
Quentin Peter
|
r25620 | try: | ||
context = int(arg) | ||||
Quentin Peter
|
r25622 | except ValueError as err: | ||
self.error(err) | ||||
Quentin Peter
|
r25620 | return | ||
Paul Ivanov
|
r22959 | self.print_stack_trace(context) | ||
else: | ||||
self.print_stack_trace() | ||||
JamshedVesuna
|
r21876 | |||
Paul Ivanov
|
r22959 | do_w = do_where | ||
tillahoffmann
|
r22871 | |||
Itamar Turner-Trauring
|
r25649 | class InterruptiblePdb(Pdb): | ||
"""Version of debugger where KeyboardInterrupt exits the debugger altogether.""" | ||||
def cmdloop(self): | ||||
"""Wrap cmdloop() such that KeyboardInterrupt stops the debugger.""" | ||||
try: | ||||
return OldPdb.cmdloop(self) | ||||
except KeyboardInterrupt: | ||||
self.stop_here = lambda frame: False | ||||
self.do_quit("") | ||||
sys.settrace(None) | ||||
self.quitting = False | ||||
raise | ||||
Itamar Turner-Trauring
|
r25568 | 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: | ||||
Itamar Turner-Trauring
|
r25649 | self.message('--KeyboardInterrupt--') | ||
Itamar Turner-Trauring
|
r25568 | raise | ||
tillahoffmann
|
r22871 | |||
tillahoffmann
|
r22872 | def set_trace(frame=None): | ||
""" | ||||
Start debugging from `frame`. | ||||
If frame is not specified, debugging starts from caller's frame. | ||||
""" | ||||
tillahoffmann
|
r22873 | Pdb().set_trace(frame or sys._getframe().f_back) | ||