##// END OF EJS Templates
improve error message
Matthias Bussonnier -
Show More
@@ -1,922 +1,924 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 def __init__(self, color_scheme=None, completekey=None,
204 def __init__(self, color_scheme=None, completekey=None,
205 stdin=None, stdout=None, context=5, **kwargs):
205 stdin=None, stdout=None, context=5, **kwargs):
206 """Create a new IPython debugger.
206 """Create a new IPython debugger.
207
207
208 :param color_scheme: Deprecated, do not use.
208 :param color_scheme: Deprecated, do not use.
209 :param completekey: Passed to pdb.Pdb.
209 :param completekey: Passed to pdb.Pdb.
210 :param stdin: Passed to pdb.Pdb.
210 :param stdin: Passed to pdb.Pdb.
211 :param stdout: Passed to pdb.Pdb.
211 :param stdout: Passed to pdb.Pdb.
212 :param context: Number of lines of source code context to show when
212 :param context: Number of lines of source code context to show when
213 displaying stacktrace information.
213 displaying stacktrace information.
214 :param kwargs: Passed to pdb.Pdb.
214 :param kwargs: Passed to pdb.Pdb.
215 The possibilities are python version dependent, see the python
215 The possibilities are python version dependent, see the python
216 docs for more info.
216 docs for more info.
217 """
217 """
218
218
219 # Parent constructor:
219 # Parent constructor:
220 try:
220 try:
221 self.context = int(context)
221 self.context = int(context)
222 if self.context <= 0:
222 if self.context <= 0:
223 raise ValueError("Context must be a positive integer")
223 raise ValueError("Context must be a positive integer")
224 except (TypeError, ValueError) as e:
224 except (TypeError, ValueError) as e:
225 raise ValueError("Context must be a positive integer") from e
225 raise ValueError("Context must be a positive integer") from e
226
226
227 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
227 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
228 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
228 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
229
229
230 # IPython changes...
230 # IPython changes...
231 self.shell = get_ipython()
231 self.shell = get_ipython()
232
232
233 if self.shell is None:
233 if self.shell is None:
234 save_main = sys.modules['__main__']
234 save_main = sys.modules['__main__']
235 # No IPython instance running, we must create one
235 # No IPython instance running, we must create one
236 from IPython.terminal.interactiveshell import \
236 from IPython.terminal.interactiveshell import \
237 TerminalInteractiveShell
237 TerminalInteractiveShell
238 self.shell = TerminalInteractiveShell.instance()
238 self.shell = TerminalInteractiveShell.instance()
239 # needed by any code which calls __import__("__main__") after
239 # needed by any code which calls __import__("__main__") after
240 # the debugger was entered. See also #9941.
240 # the debugger was entered. See also #9941.
241 sys.modules["__main__"] = save_main
241 sys.modules["__main__"] = save_main
242
242
243 if color_scheme is not None:
243 if color_scheme is not None:
244 warnings.warn(
244 warnings.warn(
245 "The `color_scheme` argument is deprecated since version 5.1",
245 "The `color_scheme` argument is deprecated since version 5.1",
246 DeprecationWarning, stacklevel=2)
246 DeprecationWarning, stacklevel=2)
247 else:
247 else:
248 color_scheme = self.shell.colors
248 color_scheme = self.shell.colors
249
249
250 self.aliases = {}
250 self.aliases = {}
251
251
252 # Create color table: we copy the default one from the traceback
252 # Create color table: we copy the default one from the traceback
253 # module and add a few attributes needed for debugging
253 # module and add a few attributes needed for debugging
254 self.color_scheme_table = exception_colors()
254 self.color_scheme_table = exception_colors()
255
255
256 # shorthands
256 # shorthands
257 C = coloransi.TermColors
257 C = coloransi.TermColors
258 cst = self.color_scheme_table
258 cst = self.color_scheme_table
259
259
260 cst['NoColor'].colors.prompt = C.NoColor
260 cst['NoColor'].colors.prompt = C.NoColor
261 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
261 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
262 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
262 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
263
263
264 cst['Linux'].colors.prompt = C.Green
264 cst['Linux'].colors.prompt = C.Green
265 cst['Linux'].colors.breakpoint_enabled = C.LightRed
265 cst['Linux'].colors.breakpoint_enabled = C.LightRed
266 cst['Linux'].colors.breakpoint_disabled = C.Red
266 cst['Linux'].colors.breakpoint_disabled = C.Red
267
267
268 cst['LightBG'].colors.prompt = C.Blue
268 cst['LightBG'].colors.prompt = C.Blue
269 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
270 cst['LightBG'].colors.breakpoint_disabled = C.Red
270 cst['LightBG'].colors.breakpoint_disabled = C.Red
271
271
272 cst['Neutral'].colors.prompt = C.Blue
272 cst['Neutral'].colors.prompt = C.Blue
273 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
273 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
274 cst['Neutral'].colors.breakpoint_disabled = C.Red
274 cst['Neutral'].colors.breakpoint_disabled = C.Red
275
275
276 # Add a python parser so we can syntax highlight source while
276 # Add a python parser so we can syntax highlight source while
277 # debugging.
277 # debugging.
278 self.parser = PyColorize.Parser(style=color_scheme)
278 self.parser = PyColorize.Parser(style=color_scheme)
279 self.set_colors(color_scheme)
279 self.set_colors(color_scheme)
280
280
281 # Set the prompt - the default prompt is '(Pdb)'
281 # Set the prompt - the default prompt is '(Pdb)'
282 self.prompt = prompt
282 self.prompt = prompt
283 self.skip_hidden = True
283 self.skip_hidden = True
284
284
285 # list of predicates we use to skip frames
285 # list of predicates we use to skip frames
286 self._predicates = {"tbhide": True, "readonly": True, "ipython_internal": True}
286 self._predicates = {"tbhide": True, "readonly": True, "ipython_internal": True}
287
287
288 def set_colors(self, scheme):
288 def set_colors(self, scheme):
289 """Shorthand access to the color table scheme selector method."""
289 """Shorthand access to the color table scheme selector method."""
290 self.color_scheme_table.set_active_scheme(scheme)
290 self.color_scheme_table.set_active_scheme(scheme)
291 self.parser.style = scheme
291 self.parser.style = scheme
292
292
293 def set_trace(self, frame=None):
293 def set_trace(self, frame=None):
294 if frame is None:
294 if frame is None:
295 frame = sys._getframe().f_back
295 frame = sys._getframe().f_back
296 self.initial_frame = frame
296 self.initial_frame = frame
297 return super().set_trace(frame)
297 return super().set_trace(frame)
298
298
299 def _hidden_predicate(self, frame):
299 def _hidden_predicate(self, frame):
300 """
300 """
301 Given a frame return whether it it should be hidden or not by IPython.
301 Given a frame return whether it it should be hidden or not by IPython.
302 """
302 """
303
303
304 if self._predicates["readonly"]:
304 if self._predicates["readonly"]:
305 fname = frame.f_code.co_filename
305 fname = frame.f_code.co_filename
306 # we need to check for file existence and interactively define
306 # we need to check for file existence and interactively define
307 # function would otherwise appear as RO.
307 # function would otherwise appear as RO.
308 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
308 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
309 return True
309 return True
310
310
311 if self._predicates["tbhide"]:
311 if self._predicates["tbhide"]:
312 if frame in (self.curframe, getattr(self, "initial_frame", None)):
312 if frame in (self.curframe, getattr(self, "initial_frame", None)):
313 return False
313 return False
314 else:
314 else:
315 return frame.f_locals.get("__tracebackhide__", False)
315 return frame.f_locals.get("__tracebackhide__", False)
316
316
317 return False
317 return False
318
318
319 def hidden_frames(self, stack):
319 def hidden_frames(self, stack):
320 """
320 """
321 Given an index in the stack return whether it should be skipped.
321 Given an index in the stack return whether it should be skipped.
322
322
323 This is used in up/down and where to skip frames.
323 This is used in up/down and where to skip frames.
324 """
324 """
325 # The f_locals dictionary is updated from the actual frame
325 # The f_locals dictionary is updated from the actual frame
326 # locals whenever the .f_locals accessor is called, so we
326 # locals whenever the .f_locals accessor is called, so we
327 # avoid calling it here to preserve self.curframe_locals.
327 # avoid calling it here to preserve self.curframe_locals.
328 # Futhermore, there is no good reason to hide the current frame.
328 # Futhermore, there is no good reason to hide the current frame.
329 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
329 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
330 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
330 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
331 if ip_start and self._predicates["ipython_internal"]:
331 if ip_start and self._predicates["ipython_internal"]:
332 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
332 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
333 return ip_hide
333 return ip_hide
334
334
335 def interaction(self, frame, traceback):
335 def interaction(self, frame, traceback):
336 try:
336 try:
337 OldPdb.interaction(self, frame, traceback)
337 OldPdb.interaction(self, frame, traceback)
338 except KeyboardInterrupt:
338 except KeyboardInterrupt:
339 self.stdout.write("\n" + self.shell.get_exception_only())
339 self.stdout.write("\n" + self.shell.get_exception_only())
340
340
341 def precmd(self, line):
341 def precmd(self, line):
342 """Perform useful escapes on the command before it is executed."""
342 """Perform useful escapes on the command before it is executed."""
343
343
344 if line.endswith("??"):
344 if line.endswith("??"):
345 line = "pinfo2 " + line[:-2]
345 line = "pinfo2 " + line[:-2]
346 elif line.endswith("?"):
346 elif line.endswith("?"):
347 line = "pinfo " + line[:-1]
347 line = "pinfo " + line[:-1]
348
348
349 line = super().precmd(line)
349 line = super().precmd(line)
350
350
351 return line
351 return line
352
352
353 def new_do_frame(self, arg):
353 def new_do_frame(self, arg):
354 OldPdb.do_frame(self, arg)
354 OldPdb.do_frame(self, arg)
355
355
356 def new_do_quit(self, arg):
356 def new_do_quit(self, arg):
357
357
358 if hasattr(self, 'old_all_completions'):
358 if hasattr(self, 'old_all_completions'):
359 self.shell.Completer.all_completions = self.old_all_completions
359 self.shell.Completer.all_completions = self.old_all_completions
360
360
361 return OldPdb.do_quit(self, arg)
361 return OldPdb.do_quit(self, arg)
362
362
363 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
363 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
364
364
365 def new_do_restart(self, arg):
365 def new_do_restart(self, arg):
366 """Restart command. In the context of ipython this is exactly the same
366 """Restart command. In the context of ipython this is exactly the same
367 thing as 'quit'."""
367 thing as 'quit'."""
368 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
368 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
369 return self.do_quit(arg)
369 return self.do_quit(arg)
370
370
371 def print_stack_trace(self, context=None):
371 def print_stack_trace(self, context=None):
372 Colors = self.color_scheme_table.active_colors
372 Colors = self.color_scheme_table.active_colors
373 ColorsNormal = Colors.Normal
373 ColorsNormal = Colors.Normal
374 if context is None:
374 if context is None:
375 context = self.context
375 context = self.context
376 try:
376 try:
377 context = int(context)
377 context = int(context)
378 if context <= 0:
378 if context <= 0:
379 raise ValueError("Context must be a positive integer")
379 raise ValueError("Context must be a positive integer")
380 except (TypeError, ValueError) as e:
380 except (TypeError, ValueError) as e:
381 raise ValueError("Context must be a positive integer") from e
381 raise ValueError("Context must be a positive integer") from e
382 try:
382 try:
383 skipped = 0
383 skipped = 0
384 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
384 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
385 if hidden and self.skip_hidden:
385 if hidden and self.skip_hidden:
386 skipped += 1
386 skipped += 1
387 continue
387 continue
388 if skipped:
388 if skipped:
389 print(
389 print(
390 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
390 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
391 )
391 )
392 skipped = 0
392 skipped = 0
393 self.print_stack_entry(frame_lineno, context=context)
393 self.print_stack_entry(frame_lineno, context=context)
394 if skipped:
394 if skipped:
395 print(
395 print(
396 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
396 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
397 )
397 )
398 except KeyboardInterrupt:
398 except KeyboardInterrupt:
399 pass
399 pass
400
400
401 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
401 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
402 context=None):
402 context=None):
403 if context is None:
403 if context is None:
404 context = self.context
404 context = self.context
405 try:
405 try:
406 context = int(context)
406 context = int(context)
407 if context <= 0:
407 if context <= 0:
408 raise ValueError("Context must be a positive integer")
408 raise ValueError("Context must be a positive integer")
409 except (TypeError, ValueError) as e:
409 except (TypeError, ValueError) as e:
410 raise ValueError("Context must be a positive integer") from e
410 raise ValueError("Context must be a positive integer") from e
411 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
411 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
412
412
413 # vds: >>
413 # vds: >>
414 frame, lineno = frame_lineno
414 frame, lineno = frame_lineno
415 filename = frame.f_code.co_filename
415 filename = frame.f_code.co_filename
416 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
416 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
417 # vds: <<
417 # vds: <<
418
418
419 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
419 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
420 if context is None:
420 if context is None:
421 context = self.context
421 context = self.context
422 try:
422 try:
423 context = int(context)
423 context = int(context)
424 if context <= 0:
424 if context <= 0:
425 print("Context must be a positive integer", file=self.stdout)
425 print("Context must be a positive integer", file=self.stdout)
426 except (TypeError, ValueError):
426 except (TypeError, ValueError):
427 print("Context must be a positive integer", file=self.stdout)
427 print("Context must be a positive integer", file=self.stdout)
428
428
429 import reprlib
429 import reprlib
430
430
431 ret = []
431 ret = []
432
432
433 Colors = self.color_scheme_table.active_colors
433 Colors = self.color_scheme_table.active_colors
434 ColorsNormal = Colors.Normal
434 ColorsNormal = Colors.Normal
435 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
435 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
436 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
436 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
437 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
437 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
438 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
438 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
439
439
440 frame, lineno = frame_lineno
440 frame, lineno = frame_lineno
441
441
442 return_value = ''
442 return_value = ''
443 if '__return__' in frame.f_locals:
443 if '__return__' in frame.f_locals:
444 rv = frame.f_locals['__return__']
444 rv = frame.f_locals['__return__']
445 #return_value += '->'
445 #return_value += '->'
446 return_value += reprlib.repr(rv) + '\n'
446 return_value += reprlib.repr(rv) + '\n'
447 ret.append(return_value)
447 ret.append(return_value)
448
448
449 #s = filename + '(' + `lineno` + ')'
449 #s = filename + '(' + `lineno` + ')'
450 filename = self.canonic(frame.f_code.co_filename)
450 filename = self.canonic(frame.f_code.co_filename)
451 link = tpl_link % py3compat.cast_unicode(filename)
451 link = tpl_link % py3compat.cast_unicode(filename)
452
452
453 if frame.f_code.co_name:
453 if frame.f_code.co_name:
454 func = frame.f_code.co_name
454 func = frame.f_code.co_name
455 else:
455 else:
456 func = "<lambda>"
456 func = "<lambda>"
457
457
458 call = ''
458 call = ''
459 if func != '?':
459 if func != '?':
460 if '__args__' in frame.f_locals:
460 if '__args__' in frame.f_locals:
461 args = reprlib.repr(frame.f_locals['__args__'])
461 args = reprlib.repr(frame.f_locals['__args__'])
462 else:
462 else:
463 args = '()'
463 args = '()'
464 call = tpl_call % (func, args)
464 call = tpl_call % (func, args)
465
465
466 # The level info should be generated in the same format pdb uses, to
466 # The level info should be generated in the same format pdb uses, to
467 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
467 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
468 if frame is self.curframe:
468 if frame is self.curframe:
469 ret.append('> ')
469 ret.append('> ')
470 else:
470 else:
471 ret.append(" ")
471 ret.append(" ")
472 ret.append("%s(%s)%s\n" % (link, lineno, call))
472 ret.append("%s(%s)%s\n" % (link, lineno, call))
473
473
474 start = lineno - 1 - context//2
474 start = lineno - 1 - context//2
475 lines = linecache.getlines(filename)
475 lines = linecache.getlines(filename)
476 start = min(start, len(lines) - context)
476 start = min(start, len(lines) - context)
477 start = max(start, 0)
477 start = max(start, 0)
478 lines = lines[start : start + context]
478 lines = lines[start : start + context]
479
479
480 for i, line in enumerate(lines):
480 for i, line in enumerate(lines):
481 show_arrow = start + 1 + i == lineno
481 show_arrow = start + 1 + i == lineno
482 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
482 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
483 ret.append(
483 ret.append(
484 self.__format_line(
484 self.__format_line(
485 linetpl, filename, start + 1 + i, line, arrow=show_arrow
485 linetpl, filename, start + 1 + i, line, arrow=show_arrow
486 )
486 )
487 )
487 )
488 return "".join(ret)
488 return "".join(ret)
489
489
490 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
490 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
491 bp_mark = ""
491 bp_mark = ""
492 bp_mark_color = ""
492 bp_mark_color = ""
493
493
494 new_line, err = self.parser.format2(line, 'str')
494 new_line, err = self.parser.format2(line, 'str')
495 if not err:
495 if not err:
496 line = new_line
496 line = new_line
497
497
498 bp = None
498 bp = None
499 if lineno in self.get_file_breaks(filename):
499 if lineno in self.get_file_breaks(filename):
500 bps = self.get_breaks(filename, lineno)
500 bps = self.get_breaks(filename, lineno)
501 bp = bps[-1]
501 bp = bps[-1]
502
502
503 if bp:
503 if bp:
504 Colors = self.color_scheme_table.active_colors
504 Colors = self.color_scheme_table.active_colors
505 bp_mark = str(bp.number)
505 bp_mark = str(bp.number)
506 bp_mark_color = Colors.breakpoint_enabled
506 bp_mark_color = Colors.breakpoint_enabled
507 if not bp.enabled:
507 if not bp.enabled:
508 bp_mark_color = Colors.breakpoint_disabled
508 bp_mark_color = Colors.breakpoint_disabled
509
509
510 numbers_width = 7
510 numbers_width = 7
511 if arrow:
511 if arrow:
512 # This is the line with the error
512 # This is the line with the error
513 pad = numbers_width - len(str(lineno)) - len(bp_mark)
513 pad = numbers_width - len(str(lineno)) - len(bp_mark)
514 num = '%s%s' % (make_arrow(pad), str(lineno))
514 num = '%s%s' % (make_arrow(pad), str(lineno))
515 else:
515 else:
516 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
516 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
517
517
518 return tpl_line % (bp_mark_color + bp_mark, num, line)
518 return tpl_line % (bp_mark_color + bp_mark, num, line)
519
519
520 def print_list_lines(self, filename, first, last):
520 def print_list_lines(self, filename, first, last):
521 """The printing (as opposed to the parsing part of a 'list'
521 """The printing (as opposed to the parsing part of a 'list'
522 command."""
522 command."""
523 try:
523 try:
524 Colors = self.color_scheme_table.active_colors
524 Colors = self.color_scheme_table.active_colors
525 ColorsNormal = Colors.Normal
525 ColorsNormal = Colors.Normal
526 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
526 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
527 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
527 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
528 src = []
528 src = []
529 if filename == "<string>" and hasattr(self, "_exec_filename"):
529 if filename == "<string>" and hasattr(self, "_exec_filename"):
530 filename = self._exec_filename
530 filename = self._exec_filename
531
531
532 for lineno in range(first, last+1):
532 for lineno in range(first, last+1):
533 line = linecache.getline(filename, lineno)
533 line = linecache.getline(filename, lineno)
534 if not line:
534 if not line:
535 break
535 break
536
536
537 if lineno == self.curframe.f_lineno:
537 if lineno == self.curframe.f_lineno:
538 line = self.__format_line(
538 line = self.__format_line(
539 tpl_line_em, filename, lineno, line, arrow=True
539 tpl_line_em, filename, lineno, line, arrow=True
540 )
540 )
541 else:
541 else:
542 line = self.__format_line(
542 line = self.__format_line(
543 tpl_line, filename, lineno, line, arrow=False
543 tpl_line, filename, lineno, line, arrow=False
544 )
544 )
545
545
546 src.append(line)
546 src.append(line)
547 self.lineno = lineno
547 self.lineno = lineno
548
548
549 print(''.join(src), file=self.stdout)
549 print(''.join(src), file=self.stdout)
550
550
551 except KeyboardInterrupt:
551 except KeyboardInterrupt:
552 pass
552 pass
553
553
554 def do_skip_predicates(self, args):
554 def do_skip_predicates(self, args):
555 """
555 """
556 Turn on/off individual predicates as to whether a frame should be hidden/skip.
556 Turn on/off individual predicates as to whether a frame should be hidden/skip.
557
557
558 The global option to skip (or not) hidden frames is set with skip_hidden
558 The global option to skip (or not) hidden frames is set with skip_hidden
559
559
560 To change the value of a predicate
560 To change the value of a predicate
561
561
562 skip_predicates key [true|false]
562 skip_predicates key [true|false]
563
563
564 Call without arguments to see the current values.
564 Call without arguments to see the current values.
565
565
566 """
566 """
567 if not args.strip():
567 if not args.strip():
568 print("current predicates:")
568 print("current predicates:")
569 for (p, v) in self._predicates.items():
569 for (p, v) in self._predicates.items():
570 print(" ", p, ":", v)
570 print(" ", p, ":", v)
571 return
571 return
572 type_value = args.strip().split(" ")
572 type_value = args.strip().split(" ")
573 if len(type_value) != 2:
573 if len(type_value) != 2:
574 print("Usage: skip_predicates <type> <value>")
574 print(
575 f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
576 )
575 return
577 return
576
578
577 type_, value = type_value
579 type_, value = type_value
578 if type_ not in self._predicates:
580 if type_ not in self._predicates:
579 print(f"{type_!r} not in {set(self._predicates.keys())}")
581 print(f"{type_!r} not in {set(self._predicates.keys())}")
580 return
582 return
581 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
583 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
582 print(
584 print(
583 f"{repr(value)} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
585 f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
584 )
586 )
585 return
587 return
586
588
587 self._predicates[type_] = value.lower() in ("true", "yes", "1")
589 self._predicates[type_] = value.lower() in ("true", "yes", "1")
588 if not any(self._predicates.values()):
590 if not any(self._predicates.values()):
589 print(
591 print(
590 "Warning, all predicates set to False, skip_hidden may not have any effects."
592 "Warning, all predicates set to False, skip_hidden may not have any effects."
591 )
593 )
592
594
593 def do_skip_hidden(self, arg):
595 def do_skip_hidden(self, arg):
594 """
596 """
595 Change whether or not we should skip frames with the
597 Change whether or not we should skip frames with the
596 __tracebackhide__ attribute.
598 __tracebackhide__ attribute.
597 """
599 """
598 if not arg.strip():
600 if not arg.strip():
599 print(
601 print(
600 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
602 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
601 )
603 )
602 elif arg.strip().lower() in ("true", "yes"):
604 elif arg.strip().lower() in ("true", "yes"):
603 self.skip_hidden = True
605 self.skip_hidden = True
604 elif arg.strip().lower() in ("false", "no"):
606 elif arg.strip().lower() in ("false", "no"):
605 self.skip_hidden = False
607 self.skip_hidden = False
606 if not any(self._predicates.values()):
608 if not any(self._predicates.values()):
607 print(
609 print(
608 "Warning, all predicates set to False, skip_hidden may not have any effects."
610 "Warning, all predicates set to False, skip_hidden may not have any effects."
609 )
611 )
610
612
611 def do_list(self, arg):
613 def do_list(self, arg):
612 """Print lines of code from the current stack frame
614 """Print lines of code from the current stack frame
613 """
615 """
614 self.lastcmd = 'list'
616 self.lastcmd = 'list'
615 last = None
617 last = None
616 if arg:
618 if arg:
617 try:
619 try:
618 x = eval(arg, {}, {})
620 x = eval(arg, {}, {})
619 if type(x) == type(()):
621 if type(x) == type(()):
620 first, last = x
622 first, last = x
621 first = int(first)
623 first = int(first)
622 last = int(last)
624 last = int(last)
623 if last < first:
625 if last < first:
624 # Assume it's a count
626 # Assume it's a count
625 last = first + last
627 last = first + last
626 else:
628 else:
627 first = max(1, int(x) - 5)
629 first = max(1, int(x) - 5)
628 except:
630 except:
629 print('*** Error in argument:', repr(arg), file=self.stdout)
631 print('*** Error in argument:', repr(arg), file=self.stdout)
630 return
632 return
631 elif self.lineno is None:
633 elif self.lineno is None:
632 first = max(1, self.curframe.f_lineno - 5)
634 first = max(1, self.curframe.f_lineno - 5)
633 else:
635 else:
634 first = self.lineno + 1
636 first = self.lineno + 1
635 if last is None:
637 if last is None:
636 last = first + 10
638 last = first + 10
637 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
639 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
638
640
639 # vds: >>
641 # vds: >>
640 lineno = first
642 lineno = first
641 filename = self.curframe.f_code.co_filename
643 filename = self.curframe.f_code.co_filename
642 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
644 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
643 # vds: <<
645 # vds: <<
644
646
645 do_l = do_list
647 do_l = do_list
646
648
647 def getsourcelines(self, obj):
649 def getsourcelines(self, obj):
648 lines, lineno = inspect.findsource(obj)
650 lines, lineno = inspect.findsource(obj)
649 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
651 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
650 # must be a module frame: do not try to cut a block out of it
652 # must be a module frame: do not try to cut a block out of it
651 return lines, 1
653 return lines, 1
652 elif inspect.ismodule(obj):
654 elif inspect.ismodule(obj):
653 return lines, 1
655 return lines, 1
654 return inspect.getblock(lines[lineno:]), lineno+1
656 return inspect.getblock(lines[lineno:]), lineno+1
655
657
656 def do_longlist(self, arg):
658 def do_longlist(self, arg):
657 """Print lines of code from the current stack frame.
659 """Print lines of code from the current stack frame.
658
660
659 Shows more lines than 'list' does.
661 Shows more lines than 'list' does.
660 """
662 """
661 self.lastcmd = 'longlist'
663 self.lastcmd = 'longlist'
662 try:
664 try:
663 lines, lineno = self.getsourcelines(self.curframe)
665 lines, lineno = self.getsourcelines(self.curframe)
664 except OSError as err:
666 except OSError as err:
665 self.error(err)
667 self.error(err)
666 return
668 return
667 last = lineno + len(lines)
669 last = lineno + len(lines)
668 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
670 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
669 do_ll = do_longlist
671 do_ll = do_longlist
670
672
671 def do_debug(self, arg):
673 def do_debug(self, arg):
672 """debug code
674 """debug code
673 Enter a recursive debugger that steps through the code
675 Enter a recursive debugger that steps through the code
674 argument (which is an arbitrary expression or statement to be
676 argument (which is an arbitrary expression or statement to be
675 executed in the current environment).
677 executed in the current environment).
676 """
678 """
677 trace_function = sys.gettrace()
679 trace_function = sys.gettrace()
678 sys.settrace(None)
680 sys.settrace(None)
679 globals = self.curframe.f_globals
681 globals = self.curframe.f_globals
680 locals = self.curframe_locals
682 locals = self.curframe_locals
681 p = self.__class__(completekey=self.completekey,
683 p = self.__class__(completekey=self.completekey,
682 stdin=self.stdin, stdout=self.stdout)
684 stdin=self.stdin, stdout=self.stdout)
683 p.use_rawinput = self.use_rawinput
685 p.use_rawinput = self.use_rawinput
684 p.prompt = "(%s) " % self.prompt.strip()
686 p.prompt = "(%s) " % self.prompt.strip()
685 self.message("ENTERING RECURSIVE DEBUGGER")
687 self.message("ENTERING RECURSIVE DEBUGGER")
686 sys.call_tracing(p.run, (arg, globals, locals))
688 sys.call_tracing(p.run, (arg, globals, locals))
687 self.message("LEAVING RECURSIVE DEBUGGER")
689 self.message("LEAVING RECURSIVE DEBUGGER")
688 sys.settrace(trace_function)
690 sys.settrace(trace_function)
689 self.lastcmd = p.lastcmd
691 self.lastcmd = p.lastcmd
690
692
691 def do_pdef(self, arg):
693 def do_pdef(self, arg):
692 """Print the call signature for any callable object.
694 """Print the call signature for any callable object.
693
695
694 The debugger interface to %pdef"""
696 The debugger interface to %pdef"""
695 namespaces = [
697 namespaces = [
696 ("Locals", self.curframe_locals),
698 ("Locals", self.curframe_locals),
697 ("Globals", self.curframe.f_globals),
699 ("Globals", self.curframe.f_globals),
698 ]
700 ]
699 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
701 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
700
702
701 def do_pdoc(self, arg):
703 def do_pdoc(self, arg):
702 """Print the docstring for an object.
704 """Print the docstring for an object.
703
705
704 The debugger interface to %pdoc."""
706 The debugger interface to %pdoc."""
705 namespaces = [
707 namespaces = [
706 ("Locals", self.curframe_locals),
708 ("Locals", self.curframe_locals),
707 ("Globals", self.curframe.f_globals),
709 ("Globals", self.curframe.f_globals),
708 ]
710 ]
709 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
711 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
710
712
711 def do_pfile(self, arg):
713 def do_pfile(self, arg):
712 """Print (or run through pager) the file where an object is defined.
714 """Print (or run through pager) the file where an object is defined.
713
715
714 The debugger interface to %pfile.
716 The debugger interface to %pfile.
715 """
717 """
716 namespaces = [
718 namespaces = [
717 ("Locals", self.curframe_locals),
719 ("Locals", self.curframe_locals),
718 ("Globals", self.curframe.f_globals),
720 ("Globals", self.curframe.f_globals),
719 ]
721 ]
720 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
722 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
721
723
722 def do_pinfo(self, arg):
724 def do_pinfo(self, arg):
723 """Provide detailed information about an object.
725 """Provide detailed information about an object.
724
726
725 The debugger interface to %pinfo, i.e., obj?."""
727 The debugger interface to %pinfo, i.e., obj?."""
726 namespaces = [
728 namespaces = [
727 ("Locals", self.curframe_locals),
729 ("Locals", self.curframe_locals),
728 ("Globals", self.curframe.f_globals),
730 ("Globals", self.curframe.f_globals),
729 ]
731 ]
730 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
732 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
731
733
732 def do_pinfo2(self, arg):
734 def do_pinfo2(self, arg):
733 """Provide extra detailed information about an object.
735 """Provide extra detailed information about an object.
734
736
735 The debugger interface to %pinfo2, i.e., obj??."""
737 The debugger interface to %pinfo2, i.e., obj??."""
736 namespaces = [
738 namespaces = [
737 ("Locals", self.curframe_locals),
739 ("Locals", self.curframe_locals),
738 ("Globals", self.curframe.f_globals),
740 ("Globals", self.curframe.f_globals),
739 ]
741 ]
740 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
742 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
741
743
742 def do_psource(self, arg):
744 def do_psource(self, arg):
743 """Print (or run through pager) the source code for an object."""
745 """Print (or run through pager) the source code for an object."""
744 namespaces = [
746 namespaces = [
745 ("Locals", self.curframe_locals),
747 ("Locals", self.curframe_locals),
746 ("Globals", self.curframe.f_globals),
748 ("Globals", self.curframe.f_globals),
747 ]
749 ]
748 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
750 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
749
751
750 def do_where(self, arg):
752 def do_where(self, arg):
751 """w(here)
753 """w(here)
752 Print a stack trace, with the most recent frame at the bottom.
754 Print a stack trace, with the most recent frame at the bottom.
753 An arrow indicates the "current frame", which determines the
755 An arrow indicates the "current frame", which determines the
754 context of most commands. 'bt' is an alias for this command.
756 context of most commands. 'bt' is an alias for this command.
755
757
756 Take a number as argument as an (optional) number of context line to
758 Take a number as argument as an (optional) number of context line to
757 print"""
759 print"""
758 if arg:
760 if arg:
759 try:
761 try:
760 context = int(arg)
762 context = int(arg)
761 except ValueError as err:
763 except ValueError as err:
762 self.error(err)
764 self.error(err)
763 return
765 return
764 self.print_stack_trace(context)
766 self.print_stack_trace(context)
765 else:
767 else:
766 self.print_stack_trace()
768 self.print_stack_trace()
767
769
768 do_w = do_where
770 do_w = do_where
769
771
770 def stop_here(self, frame):
772 def stop_here(self, frame):
771 hidden = False
773 hidden = False
772 if self.skip_hidden:
774 if self.skip_hidden:
773 hidden = self._hidden_predicate(frame)
775 hidden = self._hidden_predicate(frame)
774 if hidden:
776 if hidden:
775 Colors = self.color_scheme_table.active_colors
777 Colors = self.color_scheme_table.active_colors
776 ColorsNormal = Colors.Normal
778 ColorsNormal = Colors.Normal
777 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
779 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
778
780
779 return super().stop_here(frame)
781 return super().stop_here(frame)
780
782
781 def do_up(self, arg):
783 def do_up(self, arg):
782 """u(p) [count]
784 """u(p) [count]
783 Move the current frame count (default one) levels up in the
785 Move the current frame count (default one) levels up in the
784 stack trace (to an older frame).
786 stack trace (to an older frame).
785
787
786 Will skip hidden frames.
788 Will skip hidden frames.
787 """
789 """
788 # modified version of upstream that skips
790 # modified version of upstream that skips
789 # frames with __tracebackhide__
791 # frames with __tracebackhide__
790 if self.curindex == 0:
792 if self.curindex == 0:
791 self.error("Oldest frame")
793 self.error("Oldest frame")
792 return
794 return
793 try:
795 try:
794 count = int(arg or 1)
796 count = int(arg or 1)
795 except ValueError:
797 except ValueError:
796 self.error("Invalid frame count (%s)" % arg)
798 self.error("Invalid frame count (%s)" % arg)
797 return
799 return
798 skipped = 0
800 skipped = 0
799 if count < 0:
801 if count < 0:
800 _newframe = 0
802 _newframe = 0
801 else:
803 else:
802 counter = 0
804 counter = 0
803 hidden_frames = self.hidden_frames(self.stack)
805 hidden_frames = self.hidden_frames(self.stack)
804 for i in range(self.curindex - 1, -1, -1):
806 for i in range(self.curindex - 1, -1, -1):
805 if hidden_frames[i] and self.skip_hidden:
807 if hidden_frames[i] and self.skip_hidden:
806 skipped += 1
808 skipped += 1
807 continue
809 continue
808 counter += 1
810 counter += 1
809 if counter >= count:
811 if counter >= count:
810 break
812 break
811 else:
813 else:
812 # if no break occured.
814 # if no break occured.
813 self.error(
815 self.error(
814 "all frames above hidden, use `skip_hidden False` to get get into those."
816 "all frames above hidden, use `skip_hidden False` to get get into those."
815 )
817 )
816 return
818 return
817
819
818 Colors = self.color_scheme_table.active_colors
820 Colors = self.color_scheme_table.active_colors
819 ColorsNormal = Colors.Normal
821 ColorsNormal = Colors.Normal
820 _newframe = i
822 _newframe = i
821 self._select_frame(_newframe)
823 self._select_frame(_newframe)
822 if skipped:
824 if skipped:
823 print(
825 print(
824 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
826 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
825 )
827 )
826
828
827 def do_down(self, arg):
829 def do_down(self, arg):
828 """d(own) [count]
830 """d(own) [count]
829 Move the current frame count (default one) levels down in the
831 Move the current frame count (default one) levels down in the
830 stack trace (to a newer frame).
832 stack trace (to a newer frame).
831
833
832 Will skip hidden frames.
834 Will skip hidden frames.
833 """
835 """
834 if self.curindex + 1 == len(self.stack):
836 if self.curindex + 1 == len(self.stack):
835 self.error("Newest frame")
837 self.error("Newest frame")
836 return
838 return
837 try:
839 try:
838 count = int(arg or 1)
840 count = int(arg or 1)
839 except ValueError:
841 except ValueError:
840 self.error("Invalid frame count (%s)" % arg)
842 self.error("Invalid frame count (%s)" % arg)
841 return
843 return
842 if count < 0:
844 if count < 0:
843 _newframe = len(self.stack) - 1
845 _newframe = len(self.stack) - 1
844 else:
846 else:
845 counter = 0
847 counter = 0
846 skipped = 0
848 skipped = 0
847 hidden_frames = self.hidden_frames(self.stack)
849 hidden_frames = self.hidden_frames(self.stack)
848 for i in range(self.curindex + 1, len(self.stack)):
850 for i in range(self.curindex + 1, len(self.stack)):
849 if hidden_frames[i] and self.skip_hidden:
851 if hidden_frames[i] and self.skip_hidden:
850 skipped += 1
852 skipped += 1
851 continue
853 continue
852 counter += 1
854 counter += 1
853 if counter >= count:
855 if counter >= count:
854 break
856 break
855 else:
857 else:
856 self.error(
858 self.error(
857 "all frames bellow hidden, use `skip_hidden False` to get get into those."
859 "all frames bellow hidden, use `skip_hidden False` to get get into those."
858 )
860 )
859 return
861 return
860
862
861 Colors = self.color_scheme_table.active_colors
863 Colors = self.color_scheme_table.active_colors
862 ColorsNormal = Colors.Normal
864 ColorsNormal = Colors.Normal
863 if skipped:
865 if skipped:
864 print(
866 print(
865 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
867 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
866 )
868 )
867 _newframe = i
869 _newframe = i
868
870
869 self._select_frame(_newframe)
871 self._select_frame(_newframe)
870
872
871 do_d = do_down
873 do_d = do_down
872 do_u = do_up
874 do_u = do_up
873
875
874 def do_context(self, context):
876 def do_context(self, context):
875 """context number_of_lines
877 """context number_of_lines
876 Set the number of lines of source code to show when displaying
878 Set the number of lines of source code to show when displaying
877 stacktrace information.
879 stacktrace information.
878 """
880 """
879 try:
881 try:
880 new_context = int(context)
882 new_context = int(context)
881 if new_context <= 0:
883 if new_context <= 0:
882 raise ValueError()
884 raise ValueError()
883 self.context = new_context
885 self.context = new_context
884 except ValueError:
886 except ValueError:
885 self.error("The 'context' command requires a positive integer argument.")
887 self.error("The 'context' command requires a positive integer argument.")
886
888
887
889
888 class InterruptiblePdb(Pdb):
890 class InterruptiblePdb(Pdb):
889 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
891 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
890
892
891 def cmdloop(self):
893 def cmdloop(self):
892 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
894 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
893 try:
895 try:
894 return OldPdb.cmdloop(self)
896 return OldPdb.cmdloop(self)
895 except KeyboardInterrupt:
897 except KeyboardInterrupt:
896 self.stop_here = lambda frame: False
898 self.stop_here = lambda frame: False
897 self.do_quit("")
899 self.do_quit("")
898 sys.settrace(None)
900 sys.settrace(None)
899 self.quitting = False
901 self.quitting = False
900 raise
902 raise
901
903
902 def _cmdloop(self):
904 def _cmdloop(self):
903 while True:
905 while True:
904 try:
906 try:
905 # keyboard interrupts allow for an easy way to cancel
907 # keyboard interrupts allow for an easy way to cancel
906 # the current command, so allow them during interactive input
908 # the current command, so allow them during interactive input
907 self.allow_kbdint = True
909 self.allow_kbdint = True
908 self.cmdloop()
910 self.cmdloop()
909 self.allow_kbdint = False
911 self.allow_kbdint = False
910 break
912 break
911 except KeyboardInterrupt:
913 except KeyboardInterrupt:
912 self.message('--KeyboardInterrupt--')
914 self.message('--KeyboardInterrupt--')
913 raise
915 raise
914
916
915
917
916 def set_trace(frame=None):
918 def set_trace(frame=None):
917 """
919 """
918 Start debugging from `frame`.
920 Start debugging from `frame`.
919
921
920 If frame is not specified, debugging starts from caller's frame.
922 If frame is not specified, debugging starts from caller's frame.
921 """
923 """
922 Pdb().set_trace(frame or sys._getframe().f_back)
924 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now