##// END OF EJS Templates
f_locals might not have get
Quentin Peter -
Show More
@@ -1,1108 +1,1109 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5
5
6 This is an extension to PDB which adds a number of new features.
6 This is an extension to PDB which adds a number of new features.
7 Note that there is also the `IPython.terminal.debugger` class which provides UI
7 Note that there is also the `IPython.terminal.debugger` class which provides UI
8 improvements.
8 improvements.
9
9
10 We also strongly recommend to use this via the `ipdb` package, which provides
10 We also strongly recommend to use this via the `ipdb` package, which provides
11 extra configuration options.
11 extra configuration options.
12
12
13 Among other things, this subclass of PDB:
13 Among other things, this subclass of PDB:
14 - supports many IPython magics like pdef/psource
14 - supports many IPython magics like pdef/psource
15 - hide frames in tracebacks based on `__tracebackhide__`
15 - hide frames in tracebacks based on `__tracebackhide__`
16 - allows to skip frames based on `__debuggerskip__`
16 - allows to skip frames based on `__debuggerskip__`
17
17
18 The skipping and hiding frames are configurable via the `skip_predicates`
18 The skipping and hiding frames are configurable via the `skip_predicates`
19 command.
19 command.
20
20
21 By default, frames from readonly files will be hidden, frames containing
21 By default, frames from readonly files will be hidden, frames containing
22 ``__tracebackhide__=True`` will be hidden.
22 ``__tracebackhide__=True`` will be hidden.
23
23
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
26
26
27 >>> def helpers_helper():
27 >>> def helpers_helper():
28 ... pass
28 ... pass
29 ...
29 ...
30 ... def helper_1():
30 ... def helper_1():
31 ... print("don't step in me")
31 ... print("don't step in me")
32 ... helpers_helpers() # will be stepped over unless breakpoint set.
32 ... helpers_helpers() # will be stepped over unless breakpoint set.
33 ...
33 ...
34 ...
34 ...
35 ... def helper_2():
35 ... def helper_2():
36 ... print("in me neither")
36 ... print("in me neither")
37 ...
37 ...
38
38
39 One can define a decorator that wraps a function between the two helpers:
39 One can define a decorator that wraps a function between the two helpers:
40
40
41 >>> def pdb_skipped_decorator(function):
41 >>> def pdb_skipped_decorator(function):
42 ...
42 ...
43 ...
43 ...
44 ... def wrapped_fn(*args, **kwargs):
44 ... def wrapped_fn(*args, **kwargs):
45 ... __debuggerskip__ = True
45 ... __debuggerskip__ = True
46 ... helper_1()
46 ... helper_1()
47 ... __debuggerskip__ = False
47 ... __debuggerskip__ = False
48 ... result = function(*args, **kwargs)
48 ... result = function(*args, **kwargs)
49 ... __debuggerskip__ = True
49 ... __debuggerskip__ = True
50 ... helper_2()
50 ... helper_2()
51 ... # setting __debuggerskip__ to False again is not necessary
51 ... # setting __debuggerskip__ to False again is not necessary
52 ... return result
52 ... return result
53 ...
53 ...
54 ... return wrapped_fn
54 ... return wrapped_fn
55
55
56 When decorating a function, ipdb will directly step into ``bar()`` by
56 When decorating a function, ipdb will directly step into ``bar()`` by
57 default:
57 default:
58
58
59 >>> @foo_decorator
59 >>> @foo_decorator
60 ... def bar(x, y):
60 ... def bar(x, y):
61 ... return x * y
61 ... return x * y
62
62
63
63
64 You can toggle the behavior with
64 You can toggle the behavior with
65
65
66 ipdb> skip_predicates debuggerskip false
66 ipdb> skip_predicates debuggerskip false
67
67
68 or configure it in your ``.pdbrc``
68 or configure it in your ``.pdbrc``
69
69
70
70
71
71
72 License
72 License
73 -------
73 -------
74
74
75 Modified from the standard pdb.Pdb class to avoid including readline, so that
75 Modified from the standard pdb.Pdb class to avoid including readline, so that
76 the command line completion of other programs which include this isn't
76 the command line completion of other programs which include this isn't
77 damaged.
77 damaged.
78
78
79 In the future, this class will be expanded with improvements over the standard
79 In the future, this class will be expanded with improvements over the standard
80 pdb.
80 pdb.
81
81
82 The original code in this file is mainly lifted out of cmd.py in Python 2.2,
82 The original code in this file is mainly lifted out of cmd.py in Python 2.2,
83 with minor changes. Licensing should therefore be under the standard Python
83 with minor changes. Licensing should therefore be under the standard Python
84 terms. For details on the PSF (Python Software Foundation) standard license,
84 terms. For details on the PSF (Python Software Foundation) standard license,
85 see:
85 see:
86
86
87 https://docs.python.org/2/license.html
87 https://docs.python.org/2/license.html
88
88
89
89
90 All the changes since then are under the same license as IPython.
90 All the changes since then are under the same license as IPython.
91
91
92 """
92 """
93
93
94 #*****************************************************************************
94 #*****************************************************************************
95 #
95 #
96 # This file is licensed under the PSF license.
96 # This file is licensed under the PSF license.
97 #
97 #
98 # Copyright (C) 2001 Python Software Foundation, www.python.org
98 # Copyright (C) 2001 Python Software Foundation, www.python.org
99 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
99 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
100 #
100 #
101 #
101 #
102 #*****************************************************************************
102 #*****************************************************************************
103
103
104 import bdb
104 import bdb
105 import functools
105 import functools
106 import inspect
106 import inspect
107 import linecache
107 import linecache
108 import sys
108 import sys
109 import warnings
109 import warnings
110 import re
110 import re
111 import os
111 import os
112
112
113 from IPython import get_ipython
113 from IPython import get_ipython
114 from IPython.utils import PyColorize
114 from IPython.utils import PyColorize
115 from IPython.utils import coloransi, py3compat
115 from IPython.utils import coloransi, py3compat
116 from IPython.core.excolors import exception_colors
116 from IPython.core.excolors import exception_colors
117 from IPython.testing.skipdoctest import skip_doctest
117 from IPython.testing.skipdoctest import skip_doctest
118
118
119 # skip module docstests
119 # skip module docstests
120 __skip_doctest__ = True
120 __skip_doctest__ = True
121
121
122 prompt = 'ipdb> '
122 prompt = 'ipdb> '
123
123
124 # We have to check this directly from sys.argv, config struct not yet available
124 # We have to check this directly from sys.argv, config struct not yet available
125 from pdb import Pdb as OldPdb
125 from pdb import Pdb as OldPdb
126
126
127 # Allow the set_trace code to operate outside of an ipython instance, even if
127 # Allow the set_trace code to operate outside of an ipython instance, even if
128 # it does so with some limitations. The rest of this support is implemented in
128 # it does so with some limitations. The rest of this support is implemented in
129 # the Tracer constructor.
129 # the Tracer constructor.
130
130
131 DEBUGGERSKIP = "__debuggerskip__"
131 DEBUGGERSKIP = "__debuggerskip__"
132
132
133
133
134 def make_arrow(pad):
134 def make_arrow(pad):
135 """generate the leading arrow in front of traceback or debugger"""
135 """generate the leading arrow in front of traceback or debugger"""
136 if pad >= 2:
136 if pad >= 2:
137 return '-'*(pad-2) + '> '
137 return '-'*(pad-2) + '> '
138 elif pad == 1:
138 elif pad == 1:
139 return '>'
139 return '>'
140 return ''
140 return ''
141
141
142
142
143 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
143 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
144 """Exception hook which handles `BdbQuit` exceptions.
144 """Exception hook which handles `BdbQuit` exceptions.
145
145
146 All other exceptions are processed using the `excepthook`
146 All other exceptions are processed using the `excepthook`
147 parameter.
147 parameter.
148 """
148 """
149 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
149 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
150 DeprecationWarning, stacklevel=2)
150 DeprecationWarning, stacklevel=2)
151 if et == bdb.BdbQuit:
151 if et == bdb.BdbQuit:
152 print('Exiting Debugger.')
152 print('Exiting Debugger.')
153 elif excepthook is not None:
153 elif excepthook is not None:
154 excepthook(et, ev, tb)
154 excepthook(et, ev, tb)
155 else:
155 else:
156 # Backwards compatibility. Raise deprecation warning?
156 # Backwards compatibility. Raise deprecation warning?
157 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
157 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
158
158
159
159
160 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
160 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
161 warnings.warn(
161 warnings.warn(
162 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
162 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
163 DeprecationWarning, stacklevel=2)
163 DeprecationWarning, stacklevel=2)
164 print('Exiting Debugger.')
164 print('Exiting Debugger.')
165
165
166
166
167 class Tracer(object):
167 class Tracer(object):
168 """
168 """
169 DEPRECATED
169 DEPRECATED
170
170
171 Class for local debugging, similar to pdb.set_trace.
171 Class for local debugging, similar to pdb.set_trace.
172
172
173 Instances of this class, when called, behave like pdb.set_trace, but
173 Instances of this class, when called, behave like pdb.set_trace, but
174 providing IPython's enhanced capabilities.
174 providing IPython's enhanced capabilities.
175
175
176 This is implemented as a class which must be initialized in your own code
176 This is implemented as a class which must be initialized in your own code
177 and not as a standalone function because we need to detect at runtime
177 and not as a standalone function because we need to detect at runtime
178 whether IPython is already active or not. That detection is done in the
178 whether IPython is already active or not. That detection is done in the
179 constructor, ensuring that this code plays nicely with a running IPython,
179 constructor, ensuring that this code plays nicely with a running IPython,
180 while functioning acceptably (though with limitations) if outside of it.
180 while functioning acceptably (though with limitations) if outside of it.
181 """
181 """
182
182
183 @skip_doctest
183 @skip_doctest
184 def __init__(self, colors=None):
184 def __init__(self, colors=None):
185 """
185 """
186 DEPRECATED
186 DEPRECATED
187
187
188 Create a local debugger instance.
188 Create a local debugger instance.
189
189
190 Parameters
190 Parameters
191 ----------
191 ----------
192 colors : str, optional
192 colors : str, optional
193 The name of the color scheme to use, it must be one of IPython's
193 The name of the color scheme to use, it must be one of IPython's
194 valid color schemes. If not given, the function will default to
194 valid color schemes. If not given, the function will default to
195 the current IPython scheme when running inside IPython, and to
195 the current IPython scheme when running inside IPython, and to
196 'NoColor' otherwise.
196 'NoColor' otherwise.
197
197
198 Examples
198 Examples
199 --------
199 --------
200 ::
200 ::
201
201
202 from IPython.core.debugger import Tracer; debug_here = Tracer()
202 from IPython.core.debugger import Tracer; debug_here = Tracer()
203
203
204 Later in your code::
204 Later in your code::
205
205
206 debug_here() # -> will open up the debugger at that point.
206 debug_here() # -> will open up the debugger at that point.
207
207
208 Once the debugger activates, you can use all of its regular commands to
208 Once the debugger activates, you can use all of its regular commands to
209 step through code, set breakpoints, etc. See the pdb documentation
209 step through code, set breakpoints, etc. See the pdb documentation
210 from the Python standard library for usage details.
210 from the Python standard library for usage details.
211 """
211 """
212 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
212 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
213 "`IPython.core.debugger.Pdb.set_trace()`",
213 "`IPython.core.debugger.Pdb.set_trace()`",
214 DeprecationWarning, stacklevel=2)
214 DeprecationWarning, stacklevel=2)
215
215
216 ip = get_ipython()
216 ip = get_ipython()
217 if ip is None:
217 if ip is None:
218 # Outside of ipython, we set our own exception hook manually
218 # Outside of ipython, we set our own exception hook manually
219 sys.excepthook = functools.partial(BdbQuit_excepthook,
219 sys.excepthook = functools.partial(BdbQuit_excepthook,
220 excepthook=sys.excepthook)
220 excepthook=sys.excepthook)
221 def_colors = 'NoColor'
221 def_colors = 'NoColor'
222 else:
222 else:
223 # In ipython, we use its custom exception handler mechanism
223 # In ipython, we use its custom exception handler mechanism
224 def_colors = ip.colors
224 def_colors = ip.colors
225 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
225 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
226
226
227 if colors is None:
227 if colors is None:
228 colors = def_colors
228 colors = def_colors
229
229
230 # The stdlib debugger internally uses a modified repr from the `repr`
230 # The stdlib debugger internally uses a modified repr from the `repr`
231 # module, that limits the length of printed strings to a hardcoded
231 # module, that limits the length of printed strings to a hardcoded
232 # limit of 30 characters. That much trimming is too aggressive, let's
232 # limit of 30 characters. That much trimming is too aggressive, let's
233 # at least raise that limit to 80 chars, which should be enough for
233 # at least raise that limit to 80 chars, which should be enough for
234 # most interactive uses.
234 # most interactive uses.
235 try:
235 try:
236 from reprlib import aRepr
236 from reprlib import aRepr
237 aRepr.maxstring = 80
237 aRepr.maxstring = 80
238 except:
238 except:
239 # This is only a user-facing convenience, so any error we encounter
239 # This is only a user-facing convenience, so any error we encounter
240 # here can be warned about but can be otherwise ignored. These
240 # here can be warned about but can be otherwise ignored. These
241 # printouts will tell us about problems if this API changes
241 # printouts will tell us about problems if this API changes
242 import traceback
242 import traceback
243 traceback.print_exc()
243 traceback.print_exc()
244
244
245 self.debugger = Pdb(colors)
245 self.debugger = Pdb(colors)
246
246
247 def __call__(self):
247 def __call__(self):
248 """Starts an interactive debugger at the point where called.
248 """Starts an interactive debugger at the point where called.
249
249
250 This is similar to the pdb.set_trace() function from the std lib, but
250 This is similar to the pdb.set_trace() function from the std lib, but
251 using IPython's enhanced debugger."""
251 using IPython's enhanced debugger."""
252
252
253 self.debugger.set_trace(sys._getframe().f_back)
253 self.debugger.set_trace(sys._getframe().f_back)
254
254
255
255
256 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
256 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
257
257
258
258
259 def strip_indentation(multiline_string):
259 def strip_indentation(multiline_string):
260 return RGX_EXTRA_INDENT.sub('', multiline_string)
260 return RGX_EXTRA_INDENT.sub('', multiline_string)
261
261
262
262
263 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
263 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
264 """Make new_fn have old_fn's doc string. This is particularly useful
264 """Make new_fn have old_fn's doc string. This is particularly useful
265 for the ``do_...`` commands that hook into the help system.
265 for the ``do_...`` commands that hook into the help system.
266 Adapted from from a comp.lang.python posting
266 Adapted from from a comp.lang.python posting
267 by Duncan Booth."""
267 by Duncan Booth."""
268 def wrapper(*args, **kw):
268 def wrapper(*args, **kw):
269 return new_fn(*args, **kw)
269 return new_fn(*args, **kw)
270 if old_fn.__doc__:
270 if old_fn.__doc__:
271 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
271 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
272 return wrapper
272 return wrapper
273
273
274
274
275 class Pdb(OldPdb):
275 class Pdb(OldPdb):
276 """Modified Pdb class, does not load readline.
276 """Modified Pdb class, does not load readline.
277
277
278 for a standalone version that uses prompt_toolkit, see
278 for a standalone version that uses prompt_toolkit, see
279 `IPython.terminal.debugger.TerminalPdb` and
279 `IPython.terminal.debugger.TerminalPdb` and
280 `IPython.terminal.debugger.set_trace()`
280 `IPython.terminal.debugger.set_trace()`
281
281
282
282
283 This debugger can hide and skip frames that are tagged according to some predicates.
283 This debugger can hide and skip frames that are tagged according to some predicates.
284 See the `skip_predicates` commands.
284 See the `skip_predicates` commands.
285
285
286 """
286 """
287
287
288 default_predicates = {
288 default_predicates = {
289 "tbhide": True,
289 "tbhide": True,
290 "readonly": False,
290 "readonly": False,
291 "ipython_internal": True,
291 "ipython_internal": True,
292 "debuggerskip": True,
292 "debuggerskip": True,
293 }
293 }
294
294
295 def __init__(self, color_scheme=None, completekey=None,
295 def __init__(self, color_scheme=None, completekey=None,
296 stdin=None, stdout=None, context=5, **kwargs):
296 stdin=None, stdout=None, context=5, **kwargs):
297 """Create a new IPython debugger.
297 """Create a new IPython debugger.
298
298
299 Parameters
299 Parameters
300 ----------
300 ----------
301 color_scheme : default None
301 color_scheme : default None
302 Deprecated, do not use.
302 Deprecated, do not use.
303 completekey : default None
303 completekey : default None
304 Passed to pdb.Pdb.
304 Passed to pdb.Pdb.
305 stdin : default None
305 stdin : default None
306 Passed to pdb.Pdb.
306 Passed to pdb.Pdb.
307 stdout : default None
307 stdout : default None
308 Passed to pdb.Pdb.
308 Passed to pdb.Pdb.
309 context : int
309 context : int
310 Number of lines of source code context to show when
310 Number of lines of source code context to show when
311 displaying stacktrace information.
311 displaying stacktrace information.
312 **kwargs
312 **kwargs
313 Passed to pdb.Pdb.
313 Passed to pdb.Pdb.
314
314
315 Notes
315 Notes
316 -----
316 -----
317 The possibilities are python version dependent, see the python
317 The possibilities are python version dependent, see the python
318 docs for more info.
318 docs for more info.
319 """
319 """
320
320
321 # Parent constructor:
321 # Parent constructor:
322 try:
322 try:
323 self.context = int(context)
323 self.context = int(context)
324 if self.context <= 0:
324 if self.context <= 0:
325 raise ValueError("Context must be a positive integer")
325 raise ValueError("Context must be a positive integer")
326 except (TypeError, ValueError) as e:
326 except (TypeError, ValueError) as e:
327 raise ValueError("Context must be a positive integer") from e
327 raise ValueError("Context must be a positive integer") from e
328
328
329 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
329 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
330 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
330 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
331
331
332 # IPython changes...
332 # IPython changes...
333 self.shell = get_ipython()
333 self.shell = get_ipython()
334
334
335 if self.shell is None:
335 if self.shell is None:
336 save_main = sys.modules['__main__']
336 save_main = sys.modules['__main__']
337 # No IPython instance running, we must create one
337 # No IPython instance running, we must create one
338 from IPython.terminal.interactiveshell import \
338 from IPython.terminal.interactiveshell import \
339 TerminalInteractiveShell
339 TerminalInteractiveShell
340 self.shell = TerminalInteractiveShell.instance()
340 self.shell = TerminalInteractiveShell.instance()
341 # needed by any code which calls __import__("__main__") after
341 # needed by any code which calls __import__("__main__") after
342 # the debugger was entered. See also #9941.
342 # the debugger was entered. See also #9941.
343 sys.modules["__main__"] = save_main
343 sys.modules["__main__"] = save_main
344
344
345 if color_scheme is not None:
345 if color_scheme is not None:
346 warnings.warn(
346 warnings.warn(
347 "The `color_scheme` argument is deprecated since version 5.1",
347 "The `color_scheme` argument is deprecated since version 5.1",
348 DeprecationWarning, stacklevel=2)
348 DeprecationWarning, stacklevel=2)
349 else:
349 else:
350 color_scheme = self.shell.colors
350 color_scheme = self.shell.colors
351
351
352 self.aliases = {}
352 self.aliases = {}
353
353
354 # Create color table: we copy the default one from the traceback
354 # Create color table: we copy the default one from the traceback
355 # module and add a few attributes needed for debugging
355 # module and add a few attributes needed for debugging
356 self.color_scheme_table = exception_colors()
356 self.color_scheme_table = exception_colors()
357
357
358 # shorthands
358 # shorthands
359 C = coloransi.TermColors
359 C = coloransi.TermColors
360 cst = self.color_scheme_table
360 cst = self.color_scheme_table
361
361
362 cst['NoColor'].colors.prompt = C.NoColor
362 cst['NoColor'].colors.prompt = C.NoColor
363 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
363 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
364 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
364 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
365
365
366 cst['Linux'].colors.prompt = C.Green
366 cst['Linux'].colors.prompt = C.Green
367 cst['Linux'].colors.breakpoint_enabled = C.LightRed
367 cst['Linux'].colors.breakpoint_enabled = C.LightRed
368 cst['Linux'].colors.breakpoint_disabled = C.Red
368 cst['Linux'].colors.breakpoint_disabled = C.Red
369
369
370 cst['LightBG'].colors.prompt = C.Blue
370 cst['LightBG'].colors.prompt = C.Blue
371 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
371 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
372 cst['LightBG'].colors.breakpoint_disabled = C.Red
372 cst['LightBG'].colors.breakpoint_disabled = C.Red
373
373
374 cst['Neutral'].colors.prompt = C.Blue
374 cst['Neutral'].colors.prompt = C.Blue
375 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
375 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
376 cst['Neutral'].colors.breakpoint_disabled = C.Red
376 cst['Neutral'].colors.breakpoint_disabled = C.Red
377
377
378 # Add a python parser so we can syntax highlight source while
378 # Add a python parser so we can syntax highlight source while
379 # debugging.
379 # debugging.
380 self.parser = PyColorize.Parser(style=color_scheme)
380 self.parser = PyColorize.Parser(style=color_scheme)
381 self.set_colors(color_scheme)
381 self.set_colors(color_scheme)
382
382
383 # Set the prompt - the default prompt is '(Pdb)'
383 # Set the prompt - the default prompt is '(Pdb)'
384 self.prompt = prompt
384 self.prompt = prompt
385 self.skip_hidden = True
385 self.skip_hidden = True
386 self.report_skipped = True
386 self.report_skipped = True
387
387
388 # list of predicates we use to skip frames
388 # list of predicates we use to skip frames
389 self._predicates = self.default_predicates
389 self._predicates = self.default_predicates
390
390
391 #
391 #
392 def set_colors(self, scheme):
392 def set_colors(self, scheme):
393 """Shorthand access to the color table scheme selector method."""
393 """Shorthand access to the color table scheme selector method."""
394 self.color_scheme_table.set_active_scheme(scheme)
394 self.color_scheme_table.set_active_scheme(scheme)
395 self.parser.style = scheme
395 self.parser.style = scheme
396
396
397 def set_trace(self, frame=None):
397 def set_trace(self, frame=None):
398 if frame is None:
398 if frame is None:
399 frame = sys._getframe().f_back
399 frame = sys._getframe().f_back
400 self.initial_frame = frame
400 self.initial_frame = frame
401 return super().set_trace(frame)
401 return super().set_trace(frame)
402
402
403 def _hidden_predicate(self, frame):
403 def _hidden_predicate(self, frame):
404 """
404 """
405 Given a frame return whether it it should be hidden or not by IPython.
405 Given a frame return whether it it should be hidden or not by IPython.
406 """
406 """
407
407
408 if self._predicates["readonly"]:
408 if self._predicates["readonly"]:
409 fname = frame.f_code.co_filename
409 fname = frame.f_code.co_filename
410 # we need to check for file existence and interactively define
410 # we need to check for file existence and interactively define
411 # function would otherwise appear as RO.
411 # function would otherwise appear as RO.
412 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
412 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
413 return True
413 return True
414
414
415 if self._predicates["tbhide"]:
415 if self._predicates["tbhide"]:
416 if frame in (self.curframe, getattr(self, "initial_frame", None)):
416 if frame in (self.curframe, getattr(self, "initial_frame", None)):
417 return False
417 return False
418 else:
418 frame_locals = self._get_frame_locals(frame)
419 return self._get_frame_locals(frame).get("__tracebackhide__", False)
419 if "__tracebackhide__" not in frame_locals:
420
420 return False
421 return frame_locals["__tracebackhide__"]
421 return False
422 return False
422
423
423 def hidden_frames(self, stack):
424 def hidden_frames(self, stack):
424 """
425 """
425 Given an index in the stack return whether it should be skipped.
426 Given an index in the stack return whether it should be skipped.
426
427
427 This is used in up/down and where to skip frames.
428 This is used in up/down and where to skip frames.
428 """
429 """
429 # The f_locals dictionary is updated from the actual frame
430 # The f_locals dictionary is updated from the actual frame
430 # locals whenever the .f_locals accessor is called, so we
431 # locals whenever the .f_locals accessor is called, so we
431 # avoid calling it here to preserve self.curframe_locals.
432 # avoid calling it here to preserve self.curframe_locals.
432 # Furthermore, there is no good reason to hide the current frame.
433 # Furthermore, there is no good reason to hide the current frame.
433 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
434 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
434 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
435 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
435 if ip_start and self._predicates["ipython_internal"]:
436 if ip_start and self._predicates["ipython_internal"]:
436 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
437 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
437 return ip_hide
438 return ip_hide
438
439
439 def interaction(self, frame, traceback):
440 def interaction(self, frame, traceback):
440 try:
441 try:
441 OldPdb.interaction(self, frame, traceback)
442 OldPdb.interaction(self, frame, traceback)
442 except KeyboardInterrupt:
443 except KeyboardInterrupt:
443 self.stdout.write("\n" + self.shell.get_exception_only())
444 self.stdout.write("\n" + self.shell.get_exception_only())
444
445
445 def precmd(self, line):
446 def precmd(self, line):
446 """Perform useful escapes on the command before it is executed."""
447 """Perform useful escapes on the command before it is executed."""
447
448
448 if line.endswith("??"):
449 if line.endswith("??"):
449 line = "pinfo2 " + line[:-2]
450 line = "pinfo2 " + line[:-2]
450 elif line.endswith("?"):
451 elif line.endswith("?"):
451 line = "pinfo " + line[:-1]
452 line = "pinfo " + line[:-1]
452
453
453 line = super().precmd(line)
454 line = super().precmd(line)
454
455
455 return line
456 return line
456
457
457 def new_do_frame(self, arg):
458 def new_do_frame(self, arg):
458 OldPdb.do_frame(self, arg)
459 OldPdb.do_frame(self, arg)
459
460
460 def new_do_quit(self, arg):
461 def new_do_quit(self, arg):
461
462
462 if hasattr(self, 'old_all_completions'):
463 if hasattr(self, 'old_all_completions'):
463 self.shell.Completer.all_completions = self.old_all_completions
464 self.shell.Completer.all_completions = self.old_all_completions
464
465
465 return OldPdb.do_quit(self, arg)
466 return OldPdb.do_quit(self, arg)
466
467
467 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
468 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
468
469
469 def new_do_restart(self, arg):
470 def new_do_restart(self, arg):
470 """Restart command. In the context of ipython this is exactly the same
471 """Restart command. In the context of ipython this is exactly the same
471 thing as 'quit'."""
472 thing as 'quit'."""
472 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
473 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
473 return self.do_quit(arg)
474 return self.do_quit(arg)
474
475
475 def print_stack_trace(self, context=None):
476 def print_stack_trace(self, context=None):
476 Colors = self.color_scheme_table.active_colors
477 Colors = self.color_scheme_table.active_colors
477 ColorsNormal = Colors.Normal
478 ColorsNormal = Colors.Normal
478 if context is None:
479 if context is None:
479 context = self.context
480 context = self.context
480 try:
481 try:
481 context = int(context)
482 context = int(context)
482 if context <= 0:
483 if context <= 0:
483 raise ValueError("Context must be a positive integer")
484 raise ValueError("Context must be a positive integer")
484 except (TypeError, ValueError) as e:
485 except (TypeError, ValueError) as e:
485 raise ValueError("Context must be a positive integer") from e
486 raise ValueError("Context must be a positive integer") from e
486 try:
487 try:
487 skipped = 0
488 skipped = 0
488 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
489 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
489 if hidden and self.skip_hidden:
490 if hidden and self.skip_hidden:
490 skipped += 1
491 skipped += 1
491 continue
492 continue
492 if skipped:
493 if skipped:
493 print(
494 print(
494 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
495 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
495 )
496 )
496 skipped = 0
497 skipped = 0
497 self.print_stack_entry(frame_lineno, context=context)
498 self.print_stack_entry(frame_lineno, context=context)
498 if skipped:
499 if skipped:
499 print(
500 print(
500 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
501 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
501 )
502 )
502 except KeyboardInterrupt:
503 except KeyboardInterrupt:
503 pass
504 pass
504
505
505 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
506 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
506 context=None):
507 context=None):
507 if context is None:
508 if context is None:
508 context = self.context
509 context = self.context
509 try:
510 try:
510 context = int(context)
511 context = int(context)
511 if context <= 0:
512 if context <= 0:
512 raise ValueError("Context must be a positive integer")
513 raise ValueError("Context must be a positive integer")
513 except (TypeError, ValueError) as e:
514 except (TypeError, ValueError) as e:
514 raise ValueError("Context must be a positive integer") from e
515 raise ValueError("Context must be a positive integer") from e
515 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
516 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
516
517
517 # vds: >>
518 # vds: >>
518 frame, lineno = frame_lineno
519 frame, lineno = frame_lineno
519 filename = frame.f_code.co_filename
520 filename = frame.f_code.co_filename
520 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
521 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
521 # vds: <<
522 # vds: <<
522
523
523 def _get_frame_locals(self, frame):
524 def _get_frame_locals(self, frame):
524 """ "
525 """ "
525 Accessing f_local of current frame reset the namespace, so we want to avoid
526 Accessing f_local of current frame reset the namespace, so we want to avoid
526 that or the following can happen
527 that or the following can happen
527
528
528 ipdb> foo
529 ipdb> foo
529 "old"
530 "old"
530 ipdb> foo = "new"
531 ipdb> foo = "new"
531 ipdb> foo
532 ipdb> foo
532 "new"
533 "new"
533 ipdb> where
534 ipdb> where
534 ipdb> foo
535 ipdb> foo
535 "old"
536 "old"
536
537
537 So if frame is self.current_frame we instead return self.curframe_locals
538 So if frame is self.current_frame we instead return self.curframe_locals
538
539
539 """
540 """
540 if frame is self.curframe:
541 if frame is self.curframe:
541 return self.curframe_locals
542 return self.curframe_locals
542 else:
543 else:
543 return frame.f_locals
544 return frame.f_locals
544
545
545 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
546 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
546 if context is None:
547 if context is None:
547 context = self.context
548 context = self.context
548 try:
549 try:
549 context = int(context)
550 context = int(context)
550 if context <= 0:
551 if context <= 0:
551 print("Context must be a positive integer", file=self.stdout)
552 print("Context must be a positive integer", file=self.stdout)
552 except (TypeError, ValueError):
553 except (TypeError, ValueError):
553 print("Context must be a positive integer", file=self.stdout)
554 print("Context must be a positive integer", file=self.stdout)
554
555
555 import reprlib
556 import reprlib
556
557
557 ret = []
558 ret = []
558
559
559 Colors = self.color_scheme_table.active_colors
560 Colors = self.color_scheme_table.active_colors
560 ColorsNormal = Colors.Normal
561 ColorsNormal = Colors.Normal
561 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
562 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
562 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
563 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
563 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
564 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
564 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
565 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
565
566
566 frame, lineno = frame_lineno
567 frame, lineno = frame_lineno
567
568
568 return_value = ''
569 return_value = ''
569 loc_frame = self._get_frame_locals(frame)
570 loc_frame = self._get_frame_locals(frame)
570 if "__return__" in loc_frame:
571 if "__return__" in loc_frame:
571 rv = loc_frame["__return__"]
572 rv = loc_frame["__return__"]
572 # return_value += '->'
573 # return_value += '->'
573 return_value += reprlib.repr(rv) + "\n"
574 return_value += reprlib.repr(rv) + "\n"
574 ret.append(return_value)
575 ret.append(return_value)
575
576
576 #s = filename + '(' + `lineno` + ')'
577 #s = filename + '(' + `lineno` + ')'
577 filename = self.canonic(frame.f_code.co_filename)
578 filename = self.canonic(frame.f_code.co_filename)
578 link = tpl_link % py3compat.cast_unicode(filename)
579 link = tpl_link % py3compat.cast_unicode(filename)
579
580
580 if frame.f_code.co_name:
581 if frame.f_code.co_name:
581 func = frame.f_code.co_name
582 func = frame.f_code.co_name
582 else:
583 else:
583 func = "<lambda>"
584 func = "<lambda>"
584
585
585 call = ""
586 call = ""
586 if func != "?":
587 if func != "?":
587 if "__args__" in loc_frame:
588 if "__args__" in loc_frame:
588 args = reprlib.repr(loc_frame["__args__"])
589 args = reprlib.repr(loc_frame["__args__"])
589 else:
590 else:
590 args = '()'
591 args = '()'
591 call = tpl_call % (func, args)
592 call = tpl_call % (func, args)
592
593
593 # The level info should be generated in the same format pdb uses, to
594 # The level info should be generated in the same format pdb uses, to
594 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
595 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
595 if frame is self.curframe:
596 if frame is self.curframe:
596 ret.append('> ')
597 ret.append('> ')
597 else:
598 else:
598 ret.append(" ")
599 ret.append(" ")
599 ret.append("%s(%s)%s\n" % (link, lineno, call))
600 ret.append("%s(%s)%s\n" % (link, lineno, call))
600
601
601 start = lineno - 1 - context//2
602 start = lineno - 1 - context//2
602 lines = linecache.getlines(filename)
603 lines = linecache.getlines(filename)
603 start = min(start, len(lines) - context)
604 start = min(start, len(lines) - context)
604 start = max(start, 0)
605 start = max(start, 0)
605 lines = lines[start : start + context]
606 lines = lines[start : start + context]
606
607
607 for i, line in enumerate(lines):
608 for i, line in enumerate(lines):
608 show_arrow = start + 1 + i == lineno
609 show_arrow = start + 1 + i == lineno
609 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
610 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
610 ret.append(
611 ret.append(
611 self.__format_line(
612 self.__format_line(
612 linetpl, filename, start + 1 + i, line, arrow=show_arrow
613 linetpl, filename, start + 1 + i, line, arrow=show_arrow
613 )
614 )
614 )
615 )
615 return "".join(ret)
616 return "".join(ret)
616
617
617 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
618 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
618 bp_mark = ""
619 bp_mark = ""
619 bp_mark_color = ""
620 bp_mark_color = ""
620
621
621 new_line, err = self.parser.format2(line, 'str')
622 new_line, err = self.parser.format2(line, 'str')
622 if not err:
623 if not err:
623 line = new_line
624 line = new_line
624
625
625 bp = None
626 bp = None
626 if lineno in self.get_file_breaks(filename):
627 if lineno in self.get_file_breaks(filename):
627 bps = self.get_breaks(filename, lineno)
628 bps = self.get_breaks(filename, lineno)
628 bp = bps[-1]
629 bp = bps[-1]
629
630
630 if bp:
631 if bp:
631 Colors = self.color_scheme_table.active_colors
632 Colors = self.color_scheme_table.active_colors
632 bp_mark = str(bp.number)
633 bp_mark = str(bp.number)
633 bp_mark_color = Colors.breakpoint_enabled
634 bp_mark_color = Colors.breakpoint_enabled
634 if not bp.enabled:
635 if not bp.enabled:
635 bp_mark_color = Colors.breakpoint_disabled
636 bp_mark_color = Colors.breakpoint_disabled
636
637
637 numbers_width = 7
638 numbers_width = 7
638 if arrow:
639 if arrow:
639 # This is the line with the error
640 # This is the line with the error
640 pad = numbers_width - len(str(lineno)) - len(bp_mark)
641 pad = numbers_width - len(str(lineno)) - len(bp_mark)
641 num = '%s%s' % (make_arrow(pad), str(lineno))
642 num = '%s%s' % (make_arrow(pad), str(lineno))
642 else:
643 else:
643 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
644 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
644
645
645 return tpl_line % (bp_mark_color + bp_mark, num, line)
646 return tpl_line % (bp_mark_color + bp_mark, num, line)
646
647
647 def print_list_lines(self, filename, first, last):
648 def print_list_lines(self, filename, first, last):
648 """The printing (as opposed to the parsing part of a 'list'
649 """The printing (as opposed to the parsing part of a 'list'
649 command."""
650 command."""
650 try:
651 try:
651 Colors = self.color_scheme_table.active_colors
652 Colors = self.color_scheme_table.active_colors
652 ColorsNormal = Colors.Normal
653 ColorsNormal = Colors.Normal
653 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
654 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
654 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
655 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
655 src = []
656 src = []
656 if filename == "<string>" and hasattr(self, "_exec_filename"):
657 if filename == "<string>" and hasattr(self, "_exec_filename"):
657 filename = self._exec_filename
658 filename = self._exec_filename
658
659
659 for lineno in range(first, last+1):
660 for lineno in range(first, last+1):
660 line = linecache.getline(filename, lineno)
661 line = linecache.getline(filename, lineno)
661 if not line:
662 if not line:
662 break
663 break
663
664
664 if lineno == self.curframe.f_lineno:
665 if lineno == self.curframe.f_lineno:
665 line = self.__format_line(
666 line = self.__format_line(
666 tpl_line_em, filename, lineno, line, arrow=True
667 tpl_line_em, filename, lineno, line, arrow=True
667 )
668 )
668 else:
669 else:
669 line = self.__format_line(
670 line = self.__format_line(
670 tpl_line, filename, lineno, line, arrow=False
671 tpl_line, filename, lineno, line, arrow=False
671 )
672 )
672
673
673 src.append(line)
674 src.append(line)
674 self.lineno = lineno
675 self.lineno = lineno
675
676
676 print(''.join(src), file=self.stdout)
677 print(''.join(src), file=self.stdout)
677
678
678 except KeyboardInterrupt:
679 except KeyboardInterrupt:
679 pass
680 pass
680
681
681 def do_skip_predicates(self, args):
682 def do_skip_predicates(self, args):
682 """
683 """
683 Turn on/off individual predicates as to whether a frame should be hidden/skip.
684 Turn on/off individual predicates as to whether a frame should be hidden/skip.
684
685
685 The global option to skip (or not) hidden frames is set with skip_hidden
686 The global option to skip (or not) hidden frames is set with skip_hidden
686
687
687 To change the value of a predicate
688 To change the value of a predicate
688
689
689 skip_predicates key [true|false]
690 skip_predicates key [true|false]
690
691
691 Call without arguments to see the current values.
692 Call without arguments to see the current values.
692
693
693 To permanently change the value of an option add the corresponding
694 To permanently change the value of an option add the corresponding
694 command to your ``~/.pdbrc`` file. If you are programmatically using the
695 command to your ``~/.pdbrc`` file. If you are programmatically using the
695 Pdb instance you can also change the ``default_predicates`` class
696 Pdb instance you can also change the ``default_predicates`` class
696 attribute.
697 attribute.
697 """
698 """
698 if not args.strip():
699 if not args.strip():
699 print("current predicates:")
700 print("current predicates:")
700 for (p, v) in self._predicates.items():
701 for (p, v) in self._predicates.items():
701 print(" ", p, ":", v)
702 print(" ", p, ":", v)
702 return
703 return
703 type_value = args.strip().split(" ")
704 type_value = args.strip().split(" ")
704 if len(type_value) != 2:
705 if len(type_value) != 2:
705 print(
706 print(
706 f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
707 f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
707 )
708 )
708 return
709 return
709
710
710 type_, value = type_value
711 type_, value = type_value
711 if type_ not in self._predicates:
712 if type_ not in self._predicates:
712 print(f"{type_!r} not in {set(self._predicates.keys())}")
713 print(f"{type_!r} not in {set(self._predicates.keys())}")
713 return
714 return
714 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
715 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
715 print(
716 print(
716 f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
717 f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
717 )
718 )
718 return
719 return
719
720
720 self._predicates[type_] = value.lower() in ("true", "yes", "1")
721 self._predicates[type_] = value.lower() in ("true", "yes", "1")
721 if not any(self._predicates.values()):
722 if not any(self._predicates.values()):
722 print(
723 print(
723 "Warning, all predicates set to False, skip_hidden may not have any effects."
724 "Warning, all predicates set to False, skip_hidden may not have any effects."
724 )
725 )
725
726
726 def do_skip_hidden(self, arg):
727 def do_skip_hidden(self, arg):
727 """
728 """
728 Change whether or not we should skip frames with the
729 Change whether or not we should skip frames with the
729 __tracebackhide__ attribute.
730 __tracebackhide__ attribute.
730 """
731 """
731 if not arg.strip():
732 if not arg.strip():
732 print(
733 print(
733 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
734 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
734 )
735 )
735 elif arg.strip().lower() in ("true", "yes"):
736 elif arg.strip().lower() in ("true", "yes"):
736 self.skip_hidden = True
737 self.skip_hidden = True
737 elif arg.strip().lower() in ("false", "no"):
738 elif arg.strip().lower() in ("false", "no"):
738 self.skip_hidden = False
739 self.skip_hidden = False
739 if not any(self._predicates.values()):
740 if not any(self._predicates.values()):
740 print(
741 print(
741 "Warning, all predicates set to False, skip_hidden may not have any effects."
742 "Warning, all predicates set to False, skip_hidden may not have any effects."
742 )
743 )
743
744
744 def do_list(self, arg):
745 def do_list(self, arg):
745 """Print lines of code from the current stack frame
746 """Print lines of code from the current stack frame
746 """
747 """
747 self.lastcmd = 'list'
748 self.lastcmd = 'list'
748 last = None
749 last = None
749 if arg:
750 if arg:
750 try:
751 try:
751 x = eval(arg, {}, {})
752 x = eval(arg, {}, {})
752 if type(x) == type(()):
753 if type(x) == type(()):
753 first, last = x
754 first, last = x
754 first = int(first)
755 first = int(first)
755 last = int(last)
756 last = int(last)
756 if last < first:
757 if last < first:
757 # Assume it's a count
758 # Assume it's a count
758 last = first + last
759 last = first + last
759 else:
760 else:
760 first = max(1, int(x) - 5)
761 first = max(1, int(x) - 5)
761 except:
762 except:
762 print('*** Error in argument:', repr(arg), file=self.stdout)
763 print('*** Error in argument:', repr(arg), file=self.stdout)
763 return
764 return
764 elif self.lineno is None:
765 elif self.lineno is None:
765 first = max(1, self.curframe.f_lineno - 5)
766 first = max(1, self.curframe.f_lineno - 5)
766 else:
767 else:
767 first = self.lineno + 1
768 first = self.lineno + 1
768 if last is None:
769 if last is None:
769 last = first + 10
770 last = first + 10
770 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
771 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
771
772
772 # vds: >>
773 # vds: >>
773 lineno = first
774 lineno = first
774 filename = self.curframe.f_code.co_filename
775 filename = self.curframe.f_code.co_filename
775 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
776 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
776 # vds: <<
777 # vds: <<
777
778
778 do_l = do_list
779 do_l = do_list
779
780
780 def getsourcelines(self, obj):
781 def getsourcelines(self, obj):
781 lines, lineno = inspect.findsource(obj)
782 lines, lineno = inspect.findsource(obj)
782 if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj):
783 if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj):
783 # must be a module frame: do not try to cut a block out of it
784 # must be a module frame: do not try to cut a block out of it
784 return lines, 1
785 return lines, 1
785 elif inspect.ismodule(obj):
786 elif inspect.ismodule(obj):
786 return lines, 1
787 return lines, 1
787 return inspect.getblock(lines[lineno:]), lineno+1
788 return inspect.getblock(lines[lineno:]), lineno+1
788
789
789 def do_longlist(self, arg):
790 def do_longlist(self, arg):
790 """Print lines of code from the current stack frame.
791 """Print lines of code from the current stack frame.
791
792
792 Shows more lines than 'list' does.
793 Shows more lines than 'list' does.
793 """
794 """
794 self.lastcmd = 'longlist'
795 self.lastcmd = 'longlist'
795 try:
796 try:
796 lines, lineno = self.getsourcelines(self.curframe)
797 lines, lineno = self.getsourcelines(self.curframe)
797 except OSError as err:
798 except OSError as err:
798 self.error(err)
799 self.error(err)
799 return
800 return
800 last = lineno + len(lines)
801 last = lineno + len(lines)
801 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
802 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
802 do_ll = do_longlist
803 do_ll = do_longlist
803
804
804 def do_debug(self, arg):
805 def do_debug(self, arg):
805 """debug code
806 """debug code
806 Enter a recursive debugger that steps through the code
807 Enter a recursive debugger that steps through the code
807 argument (which is an arbitrary expression or statement to be
808 argument (which is an arbitrary expression or statement to be
808 executed in the current environment).
809 executed in the current environment).
809 """
810 """
810 trace_function = sys.gettrace()
811 trace_function = sys.gettrace()
811 sys.settrace(None)
812 sys.settrace(None)
812 globals = self.curframe.f_globals
813 globals = self.curframe.f_globals
813 locals = self.curframe_locals
814 locals = self.curframe_locals
814 p = self.__class__(completekey=self.completekey,
815 p = self.__class__(completekey=self.completekey,
815 stdin=self.stdin, stdout=self.stdout)
816 stdin=self.stdin, stdout=self.stdout)
816 p.use_rawinput = self.use_rawinput
817 p.use_rawinput = self.use_rawinput
817 p.prompt = "(%s) " % self.prompt.strip()
818 p.prompt = "(%s) " % self.prompt.strip()
818 self.message("ENTERING RECURSIVE DEBUGGER")
819 self.message("ENTERING RECURSIVE DEBUGGER")
819 sys.call_tracing(p.run, (arg, globals, locals))
820 sys.call_tracing(p.run, (arg, globals, locals))
820 self.message("LEAVING RECURSIVE DEBUGGER")
821 self.message("LEAVING RECURSIVE DEBUGGER")
821 sys.settrace(trace_function)
822 sys.settrace(trace_function)
822 self.lastcmd = p.lastcmd
823 self.lastcmd = p.lastcmd
823
824
824 def do_pdef(self, arg):
825 def do_pdef(self, arg):
825 """Print the call signature for any callable object.
826 """Print the call signature for any callable object.
826
827
827 The debugger interface to %pdef"""
828 The debugger interface to %pdef"""
828 namespaces = [
829 namespaces = [
829 ("Locals", self.curframe_locals),
830 ("Locals", self.curframe_locals),
830 ("Globals", self.curframe.f_globals),
831 ("Globals", self.curframe.f_globals),
831 ]
832 ]
832 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
833 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
833
834
834 def do_pdoc(self, arg):
835 def do_pdoc(self, arg):
835 """Print the docstring for an object.
836 """Print the docstring for an object.
836
837
837 The debugger interface to %pdoc."""
838 The debugger interface to %pdoc."""
838 namespaces = [
839 namespaces = [
839 ("Locals", self.curframe_locals),
840 ("Locals", self.curframe_locals),
840 ("Globals", self.curframe.f_globals),
841 ("Globals", self.curframe.f_globals),
841 ]
842 ]
842 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
843 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
843
844
844 def do_pfile(self, arg):
845 def do_pfile(self, arg):
845 """Print (or run through pager) the file where an object is defined.
846 """Print (or run through pager) the file where an object is defined.
846
847
847 The debugger interface to %pfile.
848 The debugger interface to %pfile.
848 """
849 """
849 namespaces = [
850 namespaces = [
850 ("Locals", self.curframe_locals),
851 ("Locals", self.curframe_locals),
851 ("Globals", self.curframe.f_globals),
852 ("Globals", self.curframe.f_globals),
852 ]
853 ]
853 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
854 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
854
855
855 def do_pinfo(self, arg):
856 def do_pinfo(self, arg):
856 """Provide detailed information about an object.
857 """Provide detailed information about an object.
857
858
858 The debugger interface to %pinfo, i.e., obj?."""
859 The debugger interface to %pinfo, i.e., obj?."""
859 namespaces = [
860 namespaces = [
860 ("Locals", self.curframe_locals),
861 ("Locals", self.curframe_locals),
861 ("Globals", self.curframe.f_globals),
862 ("Globals", self.curframe.f_globals),
862 ]
863 ]
863 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
864 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
864
865
865 def do_pinfo2(self, arg):
866 def do_pinfo2(self, arg):
866 """Provide extra detailed information about an object.
867 """Provide extra detailed information about an object.
867
868
868 The debugger interface to %pinfo2, i.e., obj??."""
869 The debugger interface to %pinfo2, i.e., obj??."""
869 namespaces = [
870 namespaces = [
870 ("Locals", self.curframe_locals),
871 ("Locals", self.curframe_locals),
871 ("Globals", self.curframe.f_globals),
872 ("Globals", self.curframe.f_globals),
872 ]
873 ]
873 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
874 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
874
875
875 def do_psource(self, arg):
876 def do_psource(self, arg):
876 """Print (or run through pager) the source code for an object."""
877 """Print (or run through pager) the source code for an object."""
877 namespaces = [
878 namespaces = [
878 ("Locals", self.curframe_locals),
879 ("Locals", self.curframe_locals),
879 ("Globals", self.curframe.f_globals),
880 ("Globals", self.curframe.f_globals),
880 ]
881 ]
881 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
882 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
882
883
883 def do_where(self, arg):
884 def do_where(self, arg):
884 """w(here)
885 """w(here)
885 Print a stack trace, with the most recent frame at the bottom.
886 Print a stack trace, with the most recent frame at the bottom.
886 An arrow indicates the "current frame", which determines the
887 An arrow indicates the "current frame", which determines the
887 context of most commands. 'bt' is an alias for this command.
888 context of most commands. 'bt' is an alias for this command.
888
889
889 Take a number as argument as an (optional) number of context line to
890 Take a number as argument as an (optional) number of context line to
890 print"""
891 print"""
891 if arg:
892 if arg:
892 try:
893 try:
893 context = int(arg)
894 context = int(arg)
894 except ValueError as err:
895 except ValueError as err:
895 self.error(err)
896 self.error(err)
896 return
897 return
897 self.print_stack_trace(context)
898 self.print_stack_trace(context)
898 else:
899 else:
899 self.print_stack_trace()
900 self.print_stack_trace()
900
901
901 do_w = do_where
902 do_w = do_where
902
903
903 def break_anywhere(self, frame):
904 def break_anywhere(self, frame):
904 """
905 """
905
906
906 _stop_in_decorator_internals is overly restrictive, as we may still want
907 _stop_in_decorator_internals is overly restrictive, as we may still want
907 to trace function calls, so we need to also update break_anywhere so
908 to trace function calls, so we need to also update break_anywhere so
908 that is we don't `stop_here`, because of debugger skip, we may still
909 that is we don't `stop_here`, because of debugger skip, we may still
909 stop at any point inside the function
910 stop at any point inside the function
910
911
911 """
912 """
912
913
913 sup = super().break_anywhere(frame)
914 sup = super().break_anywhere(frame)
914 if sup:
915 if sup:
915 return sup
916 return sup
916 if self._predicates["debuggerskip"]:
917 if self._predicates["debuggerskip"]:
917 if DEBUGGERSKIP in frame.f_code.co_varnames:
918 if DEBUGGERSKIP in frame.f_code.co_varnames:
918 return True
919 return True
919 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
920 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
920 return True
921 return True
921 return False
922 return False
922
923
923 @skip_doctest
924 @skip_doctest
924 def _is_in_decorator_internal_and_should_skip(self, frame):
925 def _is_in_decorator_internal_and_should_skip(self, frame):
925 """
926 """
926 Utility to tell us whether we are in a decorator internal and should stop.
927 Utility to tell us whether we are in a decorator internal and should stop.
927
928
928
929
929
930
930 """
931 """
931
932
932 # if we are disabled don't skip
933 # if we are disabled don't skip
933 if not self._predicates["debuggerskip"]:
934 if not self._predicates["debuggerskip"]:
934 return False
935 return False
935
936
936 # if frame is tagged, skip by default.
937 # if frame is tagged, skip by default.
937 if DEBUGGERSKIP in frame.f_code.co_varnames:
938 if DEBUGGERSKIP in frame.f_code.co_varnames:
938 return True
939 return True
939
940
940 # if one of the parent frame value set to True skip as well.
941 # if one of the parent frame value set to True skip as well.
941
942
942 cframe = frame
943 cframe = frame
943 while getattr(cframe, "f_back", None):
944 while getattr(cframe, "f_back", None):
944 cframe = cframe.f_back
945 cframe = cframe.f_back
945 if self._get_frame_locals(cframe).get(DEBUGGERSKIP):
946 if self._get_frame_locals(cframe).get(DEBUGGERSKIP):
946 return True
947 return True
947
948
948 return False
949 return False
949
950
950 def stop_here(self, frame):
951 def stop_here(self, frame):
951
952
952 if self._is_in_decorator_internal_and_should_skip(frame) is True:
953 if self._is_in_decorator_internal_and_should_skip(frame) is True:
953 return False
954 return False
954
955
955 hidden = False
956 hidden = False
956 if self.skip_hidden:
957 if self.skip_hidden:
957 hidden = self._hidden_predicate(frame)
958 hidden = self._hidden_predicate(frame)
958 if hidden:
959 if hidden:
959 if self.report_skipped:
960 if self.report_skipped:
960 Colors = self.color_scheme_table.active_colors
961 Colors = self.color_scheme_table.active_colors
961 ColorsNormal = Colors.Normal
962 ColorsNormal = Colors.Normal
962 print(
963 print(
963 f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n"
964 f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n"
964 )
965 )
965 return super().stop_here(frame)
966 return super().stop_here(frame)
966
967
967 def do_up(self, arg):
968 def do_up(self, arg):
968 """u(p) [count]
969 """u(p) [count]
969 Move the current frame count (default one) levels up in the
970 Move the current frame count (default one) levels up in the
970 stack trace (to an older frame).
971 stack trace (to an older frame).
971
972
972 Will skip hidden frames.
973 Will skip hidden frames.
973 """
974 """
974 # modified version of upstream that skips
975 # modified version of upstream that skips
975 # frames with __tracebackhide__
976 # frames with __tracebackhide__
976 if self.curindex == 0:
977 if self.curindex == 0:
977 self.error("Oldest frame")
978 self.error("Oldest frame")
978 return
979 return
979 try:
980 try:
980 count = int(arg or 1)
981 count = int(arg or 1)
981 except ValueError:
982 except ValueError:
982 self.error("Invalid frame count (%s)" % arg)
983 self.error("Invalid frame count (%s)" % arg)
983 return
984 return
984 skipped = 0
985 skipped = 0
985 if count < 0:
986 if count < 0:
986 _newframe = 0
987 _newframe = 0
987 else:
988 else:
988 counter = 0
989 counter = 0
989 hidden_frames = self.hidden_frames(self.stack)
990 hidden_frames = self.hidden_frames(self.stack)
990 for i in range(self.curindex - 1, -1, -1):
991 for i in range(self.curindex - 1, -1, -1):
991 if hidden_frames[i] and self.skip_hidden:
992 if hidden_frames[i] and self.skip_hidden:
992 skipped += 1
993 skipped += 1
993 continue
994 continue
994 counter += 1
995 counter += 1
995 if counter >= count:
996 if counter >= count:
996 break
997 break
997 else:
998 else:
998 # if no break occurred.
999 # if no break occurred.
999 self.error(
1000 self.error(
1000 "all frames above hidden, use `skip_hidden False` to get get into those."
1001 "all frames above hidden, use `skip_hidden False` to get get into those."
1001 )
1002 )
1002 return
1003 return
1003
1004
1004 Colors = self.color_scheme_table.active_colors
1005 Colors = self.color_scheme_table.active_colors
1005 ColorsNormal = Colors.Normal
1006 ColorsNormal = Colors.Normal
1006 _newframe = i
1007 _newframe = i
1007 self._select_frame(_newframe)
1008 self._select_frame(_newframe)
1008 if skipped:
1009 if skipped:
1009 print(
1010 print(
1010 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1011 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1011 )
1012 )
1012
1013
1013 def do_down(self, arg):
1014 def do_down(self, arg):
1014 """d(own) [count]
1015 """d(own) [count]
1015 Move the current frame count (default one) levels down in the
1016 Move the current frame count (default one) levels down in the
1016 stack trace (to a newer frame).
1017 stack trace (to a newer frame).
1017
1018
1018 Will skip hidden frames.
1019 Will skip hidden frames.
1019 """
1020 """
1020 if self.curindex + 1 == len(self.stack):
1021 if self.curindex + 1 == len(self.stack):
1021 self.error("Newest frame")
1022 self.error("Newest frame")
1022 return
1023 return
1023 try:
1024 try:
1024 count = int(arg or 1)
1025 count = int(arg or 1)
1025 except ValueError:
1026 except ValueError:
1026 self.error("Invalid frame count (%s)" % arg)
1027 self.error("Invalid frame count (%s)" % arg)
1027 return
1028 return
1028 if count < 0:
1029 if count < 0:
1029 _newframe = len(self.stack) - 1
1030 _newframe = len(self.stack) - 1
1030 else:
1031 else:
1031 counter = 0
1032 counter = 0
1032 skipped = 0
1033 skipped = 0
1033 hidden_frames = self.hidden_frames(self.stack)
1034 hidden_frames = self.hidden_frames(self.stack)
1034 for i in range(self.curindex + 1, len(self.stack)):
1035 for i in range(self.curindex + 1, len(self.stack)):
1035 if hidden_frames[i] and self.skip_hidden:
1036 if hidden_frames[i] and self.skip_hidden:
1036 skipped += 1
1037 skipped += 1
1037 continue
1038 continue
1038 counter += 1
1039 counter += 1
1039 if counter >= count:
1040 if counter >= count:
1040 break
1041 break
1041 else:
1042 else:
1042 self.error(
1043 self.error(
1043 "all frames below hidden, use `skip_hidden False` to get get into those."
1044 "all frames below hidden, use `skip_hidden False` to get get into those."
1044 )
1045 )
1045 return
1046 return
1046
1047
1047 Colors = self.color_scheme_table.active_colors
1048 Colors = self.color_scheme_table.active_colors
1048 ColorsNormal = Colors.Normal
1049 ColorsNormal = Colors.Normal
1049 if skipped:
1050 if skipped:
1050 print(
1051 print(
1051 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1052 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1052 )
1053 )
1053 _newframe = i
1054 _newframe = i
1054
1055
1055 self._select_frame(_newframe)
1056 self._select_frame(_newframe)
1056
1057
1057 do_d = do_down
1058 do_d = do_down
1058 do_u = do_up
1059 do_u = do_up
1059
1060
1060 def do_context(self, context):
1061 def do_context(self, context):
1061 """context number_of_lines
1062 """context number_of_lines
1062 Set the number of lines of source code to show when displaying
1063 Set the number of lines of source code to show when displaying
1063 stacktrace information.
1064 stacktrace information.
1064 """
1065 """
1065 try:
1066 try:
1066 new_context = int(context)
1067 new_context = int(context)
1067 if new_context <= 0:
1068 if new_context <= 0:
1068 raise ValueError()
1069 raise ValueError()
1069 self.context = new_context
1070 self.context = new_context
1070 except ValueError:
1071 except ValueError:
1071 self.error("The 'context' command requires a positive integer argument.")
1072 self.error("The 'context' command requires a positive integer argument.")
1072
1073
1073
1074
1074 class InterruptiblePdb(Pdb):
1075 class InterruptiblePdb(Pdb):
1075 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
1076 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
1076
1077
1077 def cmdloop(self, intro=None):
1078 def cmdloop(self, intro=None):
1078 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
1079 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
1079 try:
1080 try:
1080 return OldPdb.cmdloop(self, intro=intro)
1081 return OldPdb.cmdloop(self, intro=intro)
1081 except KeyboardInterrupt:
1082 except KeyboardInterrupt:
1082 self.stop_here = lambda frame: False
1083 self.stop_here = lambda frame: False
1083 self.do_quit("")
1084 self.do_quit("")
1084 sys.settrace(None)
1085 sys.settrace(None)
1085 self.quitting = False
1086 self.quitting = False
1086 raise
1087 raise
1087
1088
1088 def _cmdloop(self):
1089 def _cmdloop(self):
1089 while True:
1090 while True:
1090 try:
1091 try:
1091 # keyboard interrupts allow for an easy way to cancel
1092 # keyboard interrupts allow for an easy way to cancel
1092 # the current command, so allow them during interactive input
1093 # the current command, so allow them during interactive input
1093 self.allow_kbdint = True
1094 self.allow_kbdint = True
1094 self.cmdloop()
1095 self.cmdloop()
1095 self.allow_kbdint = False
1096 self.allow_kbdint = False
1096 break
1097 break
1097 except KeyboardInterrupt:
1098 except KeyboardInterrupt:
1098 self.message('--KeyboardInterrupt--')
1099 self.message('--KeyboardInterrupt--')
1099 raise
1100 raise
1100
1101
1101
1102
1102 def set_trace(frame=None):
1103 def set_trace(frame=None):
1103 """
1104 """
1104 Start debugging from `frame`.
1105 Start debugging from `frame`.
1105
1106
1106 If frame is not specified, debugging starts from caller's frame.
1107 If frame is not specified, debugging starts from caller's frame.
1107 """
1108 """
1108 Pdb().set_trace(frame or sys._getframe().f_back)
1109 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now