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