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