##// END OF EJS Templates
ipdb: accept question mark(s) suffixes
Blazej Michalik -
Show More
@@ -1,828 +1,840 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
36
37 from IPython import get_ipython
37 from IPython import get_ipython
38 from IPython.utils import PyColorize
38 from IPython.utils import PyColorize
39 from IPython.utils import coloransi, py3compat
39 from IPython.utils import coloransi, py3compat
40 from IPython.core.excolors import exception_colors
40 from IPython.core.excolors import exception_colors
41 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.testing.skipdoctest import skip_doctest
42
42
43
43
44 prompt = 'ipdb> '
44 prompt = 'ipdb> '
45
45
46 # We have to check this directly from sys.argv, config struct not yet available
46 # We have to check this directly from sys.argv, config struct not yet available
47 from pdb import Pdb as OldPdb
47 from pdb import Pdb as OldPdb
48
48
49 # Allow the set_trace code to operate outside of an ipython instance, even if
49 # Allow the set_trace code to operate outside of an ipython instance, even if
50 # it does so with some limitations. The rest of this support is implemented in
50 # it does so with some limitations. The rest of this support is implemented in
51 # the Tracer constructor.
51 # the Tracer constructor.
52
52
53
53
54 def make_arrow(pad):
54 def make_arrow(pad):
55 """generate the leading arrow in front of traceback or debugger"""
55 """generate the leading arrow in front of traceback or debugger"""
56 if pad >= 2:
56 if pad >= 2:
57 return '-'*(pad-2) + '> '
57 return '-'*(pad-2) + '> '
58 elif pad == 1:
58 elif pad == 1:
59 return '>'
59 return '>'
60 return ''
60 return ''
61
61
62
62
63 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
63 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
64 """Exception hook which handles `BdbQuit` exceptions.
64 """Exception hook which handles `BdbQuit` exceptions.
65
65
66 All other exceptions are processed using the `excepthook`
66 All other exceptions are processed using the `excepthook`
67 parameter.
67 parameter.
68 """
68 """
69 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
69 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
70 DeprecationWarning, stacklevel=2)
70 DeprecationWarning, stacklevel=2)
71 if et == bdb.BdbQuit:
71 if et == bdb.BdbQuit:
72 print('Exiting Debugger.')
72 print('Exiting Debugger.')
73 elif excepthook is not None:
73 elif excepthook is not None:
74 excepthook(et, ev, tb)
74 excepthook(et, ev, tb)
75 else:
75 else:
76 # Backwards compatibility. Raise deprecation warning?
76 # Backwards compatibility. Raise deprecation warning?
77 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
77 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
78
78
79
79
80 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
80 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
81 warnings.warn(
81 warnings.warn(
82 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
82 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
83 DeprecationWarning, stacklevel=2)
83 DeprecationWarning, stacklevel=2)
84 print('Exiting Debugger.')
84 print('Exiting Debugger.')
85
85
86
86
87 class Tracer(object):
87 class Tracer(object):
88 """
88 """
89 DEPRECATED
89 DEPRECATED
90
90
91 Class for local debugging, similar to pdb.set_trace.
91 Class for local debugging, similar to pdb.set_trace.
92
92
93 Instances of this class, when called, behave like pdb.set_trace, but
93 Instances of this class, when called, behave like pdb.set_trace, but
94 providing IPython's enhanced capabilities.
94 providing IPython's enhanced capabilities.
95
95
96 This is implemented as a class which must be initialized in your own code
96 This is implemented as a class which must be initialized in your own code
97 and not as a standalone function because we need to detect at runtime
97 and not as a standalone function because we need to detect at runtime
98 whether IPython is already active or not. That detection is done in the
98 whether IPython is already active or not. That detection is done in the
99 constructor, ensuring that this code plays nicely with a running IPython,
99 constructor, ensuring that this code plays nicely with a running IPython,
100 while functioning acceptably (though with limitations) if outside of it.
100 while functioning acceptably (though with limitations) if outside of it.
101 """
101 """
102
102
103 @skip_doctest
103 @skip_doctest
104 def __init__(self, colors=None):
104 def __init__(self, colors=None):
105 """
105 """
106 DEPRECATED
106 DEPRECATED
107
107
108 Create a local debugger instance.
108 Create a local debugger instance.
109
109
110 Parameters
110 Parameters
111 ----------
111 ----------
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 def set_colors(self, scheme):
285 def set_colors(self, scheme):
286 """Shorthand access to the color table scheme selector method."""
286 """Shorthand access to the color table scheme selector method."""
287 self.color_scheme_table.set_active_scheme(scheme)
287 self.color_scheme_table.set_active_scheme(scheme)
288 self.parser.style = scheme
288 self.parser.style = scheme
289
289
290 def set_trace(self, frame=None):
290 def set_trace(self, frame=None):
291 if frame is None:
291 if frame is None:
292 frame = sys._getframe().f_back
292 frame = sys._getframe().f_back
293 self.initial_frame = frame
293 self.initial_frame = frame
294 return super().set_trace(frame)
294 return super().set_trace(frame)
295
295
296 def hidden_frames(self, stack):
296 def hidden_frames(self, stack):
297 """
297 """
298 Given an index in the stack return whether it should be skipped.
298 Given an index in the stack return whether it should be skipped.
299
299
300 This is used in up/down and where to skip frames.
300 This is used in up/down and where to skip frames.
301 """
301 """
302 # The f_locals dictionary is updated from the actual frame
302 # The f_locals dictionary is updated from the actual frame
303 # locals whenever the .f_locals accessor is called, so we
303 # locals whenever the .f_locals accessor is called, so we
304 # avoid calling it here to preserve self.curframe_locals.
304 # avoid calling it here to preserve self.curframe_locals.
305 # Futhermore, there is no good reason to hide the current frame.
305 # Futhermore, there is no good reason to hide the current frame.
306 ip_hide = [
306 ip_hide = [
307 False
307 False
308 if s[0] in (self.curframe, getattr(self, "initial_frame", None))
308 if s[0] in (self.curframe, getattr(self, "initial_frame", None))
309 else s[0].f_locals.get("__tracebackhide__", False)
309 else s[0].f_locals.get("__tracebackhide__", False)
310 for s in stack
310 for s in stack
311 ]
311 ]
312 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
312 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
313 if ip_start:
313 if ip_start:
314 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
314 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
315 return ip_hide
315 return ip_hide
316
316
317 def interaction(self, frame, traceback):
317 def interaction(self, frame, traceback):
318 try:
318 try:
319 OldPdb.interaction(self, frame, traceback)
319 OldPdb.interaction(self, frame, traceback)
320 except KeyboardInterrupt:
320 except KeyboardInterrupt:
321 self.stdout.write("\n" + self.shell.get_exception_only())
321 self.stdout.write("\n" + self.shell.get_exception_only())
322
322
323 def precmd(self, line):
324 """Perform useful escapes on the command before it is executed."""
325
326 if line.endswith('??'):
327 line = 'pinfo2 ' + line[:-2]
328 elif line.endswith('?'):
329 line = 'pinfo ' + line[:-1]
330
331 line = super().precmd(line)
332
333 return line
334
323 def new_do_frame(self, arg):
335 def new_do_frame(self, arg):
324 OldPdb.do_frame(self, arg)
336 OldPdb.do_frame(self, arg)
325
337
326 def new_do_quit(self, arg):
338 def new_do_quit(self, arg):
327
339
328 if hasattr(self, 'old_all_completions'):
340 if hasattr(self, 'old_all_completions'):
329 self.shell.Completer.all_completions = self.old_all_completions
341 self.shell.Completer.all_completions = self.old_all_completions
330
342
331 return OldPdb.do_quit(self, arg)
343 return OldPdb.do_quit(self, arg)
332
344
333 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
345 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
334
346
335 def new_do_restart(self, arg):
347 def new_do_restart(self, arg):
336 """Restart command. In the context of ipython this is exactly the same
348 """Restart command. In the context of ipython this is exactly the same
337 thing as 'quit'."""
349 thing as 'quit'."""
338 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
350 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
339 return self.do_quit(arg)
351 return self.do_quit(arg)
340
352
341 def print_stack_trace(self, context=None):
353 def print_stack_trace(self, context=None):
342 Colors = self.color_scheme_table.active_colors
354 Colors = self.color_scheme_table.active_colors
343 ColorsNormal = Colors.Normal
355 ColorsNormal = Colors.Normal
344 if context is None:
356 if context is None:
345 context = self.context
357 context = self.context
346 try:
358 try:
347 context = int(context)
359 context = int(context)
348 if context <= 0:
360 if context <= 0:
349 raise ValueError("Context must be a positive integer")
361 raise ValueError("Context must be a positive integer")
350 except (TypeError, ValueError) as e:
362 except (TypeError, ValueError) as e:
351 raise ValueError("Context must be a positive integer") from e
363 raise ValueError("Context must be a positive integer") from e
352 try:
364 try:
353 skipped = 0
365 skipped = 0
354 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
366 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
355 if hidden and self.skip_hidden:
367 if hidden and self.skip_hidden:
356 skipped += 1
368 skipped += 1
357 continue
369 continue
358 if skipped:
370 if skipped:
359 print(
371 print(
360 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
372 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
361 )
373 )
362 skipped = 0
374 skipped = 0
363 self.print_stack_entry(frame_lineno, context=context)
375 self.print_stack_entry(frame_lineno, context=context)
364 if skipped:
376 if skipped:
365 print(
377 print(
366 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
378 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
367 )
379 )
368 except KeyboardInterrupt:
380 except KeyboardInterrupt:
369 pass
381 pass
370
382
371 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
383 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
372 context=None):
384 context=None):
373 if context is None:
385 if context is None:
374 context = self.context
386 context = self.context
375 try:
387 try:
376 context = int(context)
388 context = int(context)
377 if context <= 0:
389 if context <= 0:
378 raise ValueError("Context must be a positive integer")
390 raise ValueError("Context must be a positive integer")
379 except (TypeError, ValueError) as e:
391 except (TypeError, ValueError) as e:
380 raise ValueError("Context must be a positive integer") from e
392 raise ValueError("Context must be a positive integer") from e
381 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
393 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
382
394
383 # vds: >>
395 # vds: >>
384 frame, lineno = frame_lineno
396 frame, lineno = frame_lineno
385 filename = frame.f_code.co_filename
397 filename = frame.f_code.co_filename
386 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
398 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
387 # vds: <<
399 # vds: <<
388
400
389 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
401 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
390 if context is None:
402 if context is None:
391 context = self.context
403 context = self.context
392 try:
404 try:
393 context = int(context)
405 context = int(context)
394 if context <= 0:
406 if context <= 0:
395 print("Context must be a positive integer", file=self.stdout)
407 print("Context must be a positive integer", file=self.stdout)
396 except (TypeError, ValueError):
408 except (TypeError, ValueError):
397 print("Context must be a positive integer", file=self.stdout)
409 print("Context must be a positive integer", file=self.stdout)
398
410
399 import reprlib
411 import reprlib
400
412
401 ret = []
413 ret = []
402
414
403 Colors = self.color_scheme_table.active_colors
415 Colors = self.color_scheme_table.active_colors
404 ColorsNormal = Colors.Normal
416 ColorsNormal = Colors.Normal
405 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
417 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
406 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
418 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
407 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
419 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
408 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
420 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
409 ColorsNormal)
421 ColorsNormal)
410
422
411 frame, lineno = frame_lineno
423 frame, lineno = frame_lineno
412
424
413 return_value = ''
425 return_value = ''
414 if '__return__' in frame.f_locals:
426 if '__return__' in frame.f_locals:
415 rv = frame.f_locals['__return__']
427 rv = frame.f_locals['__return__']
416 #return_value += '->'
428 #return_value += '->'
417 return_value += reprlib.repr(rv) + '\n'
429 return_value += reprlib.repr(rv) + '\n'
418 ret.append(return_value)
430 ret.append(return_value)
419
431
420 #s = filename + '(' + `lineno` + ')'
432 #s = filename + '(' + `lineno` + ')'
421 filename = self.canonic(frame.f_code.co_filename)
433 filename = self.canonic(frame.f_code.co_filename)
422 link = tpl_link % py3compat.cast_unicode(filename)
434 link = tpl_link % py3compat.cast_unicode(filename)
423
435
424 if frame.f_code.co_name:
436 if frame.f_code.co_name:
425 func = frame.f_code.co_name
437 func = frame.f_code.co_name
426 else:
438 else:
427 func = "<lambda>"
439 func = "<lambda>"
428
440
429 call = ''
441 call = ''
430 if func != '?':
442 if func != '?':
431 if '__args__' in frame.f_locals:
443 if '__args__' in frame.f_locals:
432 args = reprlib.repr(frame.f_locals['__args__'])
444 args = reprlib.repr(frame.f_locals['__args__'])
433 else:
445 else:
434 args = '()'
446 args = '()'
435 call = tpl_call % (func, args)
447 call = tpl_call % (func, args)
436
448
437 # The level info should be generated in the same format pdb uses, to
449 # The level info should be generated in the same format pdb uses, to
438 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
450 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
439 if frame is self.curframe:
451 if frame is self.curframe:
440 ret.append('> ')
452 ret.append('> ')
441 else:
453 else:
442 ret.append(' ')
454 ret.append(' ')
443 ret.append(u'%s(%s)%s\n' % (link, lineno, call))
455 ret.append(u'%s(%s)%s\n' % (link, lineno, call))
444
456
445 start = lineno - 1 - context//2
457 start = lineno - 1 - context//2
446 lines = linecache.getlines(filename)
458 lines = linecache.getlines(filename)
447 start = min(start, len(lines) - context)
459 start = min(start, len(lines) - context)
448 start = max(start, 0)
460 start = max(start, 0)
449 lines = lines[start : start + context]
461 lines = lines[start : start + context]
450
462
451 for i, line in enumerate(lines):
463 for i, line in enumerate(lines):
452 show_arrow = (start + 1 + i == lineno)
464 show_arrow = (start + 1 + i == lineno)
453 linetpl = (frame is self.curframe or show_arrow) \
465 linetpl = (frame is self.curframe or show_arrow) \
454 and tpl_line_em \
466 and tpl_line_em \
455 or tpl_line
467 or tpl_line
456 ret.append(self.__format_line(linetpl, filename,
468 ret.append(self.__format_line(linetpl, filename,
457 start + 1 + i, line,
469 start + 1 + i, line,
458 arrow=show_arrow))
470 arrow=show_arrow))
459 return ''.join(ret)
471 return ''.join(ret)
460
472
461 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
473 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
462 bp_mark = ""
474 bp_mark = ""
463 bp_mark_color = ""
475 bp_mark_color = ""
464
476
465 new_line, err = self.parser.format2(line, 'str')
477 new_line, err = self.parser.format2(line, 'str')
466 if not err:
478 if not err:
467 line = new_line
479 line = new_line
468
480
469 bp = None
481 bp = None
470 if lineno in self.get_file_breaks(filename):
482 if lineno in self.get_file_breaks(filename):
471 bps = self.get_breaks(filename, lineno)
483 bps = self.get_breaks(filename, lineno)
472 bp = bps[-1]
484 bp = bps[-1]
473
485
474 if bp:
486 if bp:
475 Colors = self.color_scheme_table.active_colors
487 Colors = self.color_scheme_table.active_colors
476 bp_mark = str(bp.number)
488 bp_mark = str(bp.number)
477 bp_mark_color = Colors.breakpoint_enabled
489 bp_mark_color = Colors.breakpoint_enabled
478 if not bp.enabled:
490 if not bp.enabled:
479 bp_mark_color = Colors.breakpoint_disabled
491 bp_mark_color = Colors.breakpoint_disabled
480
492
481 numbers_width = 7
493 numbers_width = 7
482 if arrow:
494 if arrow:
483 # This is the line with the error
495 # This is the line with the error
484 pad = numbers_width - len(str(lineno)) - len(bp_mark)
496 pad = numbers_width - len(str(lineno)) - len(bp_mark)
485 num = '%s%s' % (make_arrow(pad), str(lineno))
497 num = '%s%s' % (make_arrow(pad), str(lineno))
486 else:
498 else:
487 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
499 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
488
500
489 return tpl_line % (bp_mark_color + bp_mark, num, line)
501 return tpl_line % (bp_mark_color + bp_mark, num, line)
490
502
491 def print_list_lines(self, filename, first, last):
503 def print_list_lines(self, filename, first, last):
492 """The printing (as opposed to the parsing part of a 'list'
504 """The printing (as opposed to the parsing part of a 'list'
493 command."""
505 command."""
494 try:
506 try:
495 Colors = self.color_scheme_table.active_colors
507 Colors = self.color_scheme_table.active_colors
496 ColorsNormal = Colors.Normal
508 ColorsNormal = Colors.Normal
497 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
509 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
498 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
510 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
499 src = []
511 src = []
500 if filename == "<string>" and hasattr(self, "_exec_filename"):
512 if filename == "<string>" and hasattr(self, "_exec_filename"):
501 filename = self._exec_filename
513 filename = self._exec_filename
502
514
503 for lineno in range(first, last+1):
515 for lineno in range(first, last+1):
504 line = linecache.getline(filename, lineno)
516 line = linecache.getline(filename, lineno)
505 if not line:
517 if not line:
506 break
518 break
507
519
508 if lineno == self.curframe.f_lineno:
520 if lineno == self.curframe.f_lineno:
509 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow=True)
521 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow=True)
510 else:
522 else:
511 line = self.__format_line(tpl_line, filename, lineno, line, arrow=False)
523 line = self.__format_line(tpl_line, filename, lineno, line, arrow=False)
512
524
513 src.append(line)
525 src.append(line)
514 self.lineno = lineno
526 self.lineno = lineno
515
527
516 print(''.join(src), file=self.stdout)
528 print(''.join(src), file=self.stdout)
517
529
518 except KeyboardInterrupt:
530 except KeyboardInterrupt:
519 pass
531 pass
520
532
521 def do_skip_hidden(self, arg):
533 def do_skip_hidden(self, arg):
522 """
534 """
523 Change whether or not we should skip frames with the
535 Change whether or not we should skip frames with the
524 __tracebackhide__ attribute.
536 __tracebackhide__ attribute.
525 """
537 """
526 if arg.strip().lower() in ("true", "yes"):
538 if arg.strip().lower() in ("true", "yes"):
527 self.skip_hidden = True
539 self.skip_hidden = True
528 elif arg.strip().lower() in ("false", "no"):
540 elif arg.strip().lower() in ("false", "no"):
529 self.skip_hidden = False
541 self.skip_hidden = False
530
542
531 def do_list(self, arg):
543 def do_list(self, arg):
532 """Print lines of code from the current stack frame
544 """Print lines of code from the current stack frame
533 """
545 """
534 self.lastcmd = 'list'
546 self.lastcmd = 'list'
535 last = None
547 last = None
536 if arg:
548 if arg:
537 try:
549 try:
538 x = eval(arg, {}, {})
550 x = eval(arg, {}, {})
539 if type(x) == type(()):
551 if type(x) == type(()):
540 first, last = x
552 first, last = x
541 first = int(first)
553 first = int(first)
542 last = int(last)
554 last = int(last)
543 if last < first:
555 if last < first:
544 # Assume it's a count
556 # Assume it's a count
545 last = first + last
557 last = first + last
546 else:
558 else:
547 first = max(1, int(x) - 5)
559 first = max(1, int(x) - 5)
548 except:
560 except:
549 print('*** Error in argument:', repr(arg), file=self.stdout)
561 print('*** Error in argument:', repr(arg), file=self.stdout)
550 return
562 return
551 elif self.lineno is None:
563 elif self.lineno is None:
552 first = max(1, self.curframe.f_lineno - 5)
564 first = max(1, self.curframe.f_lineno - 5)
553 else:
565 else:
554 first = self.lineno + 1
566 first = self.lineno + 1
555 if last is None:
567 if last is None:
556 last = first + 10
568 last = first + 10
557 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
569 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
558
570
559 # vds: >>
571 # vds: >>
560 lineno = first
572 lineno = first
561 filename = self.curframe.f_code.co_filename
573 filename = self.curframe.f_code.co_filename
562 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
574 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
563 # vds: <<
575 # vds: <<
564
576
565 do_l = do_list
577 do_l = do_list
566
578
567 def getsourcelines(self, obj):
579 def getsourcelines(self, obj):
568 lines, lineno = inspect.findsource(obj)
580 lines, lineno = inspect.findsource(obj)
569 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
581 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
570 # must be a module frame: do not try to cut a block out of it
582 # must be a module frame: do not try to cut a block out of it
571 return lines, 1
583 return lines, 1
572 elif inspect.ismodule(obj):
584 elif inspect.ismodule(obj):
573 return lines, 1
585 return lines, 1
574 return inspect.getblock(lines[lineno:]), lineno+1
586 return inspect.getblock(lines[lineno:]), lineno+1
575
587
576 def do_longlist(self, arg):
588 def do_longlist(self, arg):
577 """Print lines of code from the current stack frame.
589 """Print lines of code from the current stack frame.
578
590
579 Shows more lines than 'list' does.
591 Shows more lines than 'list' does.
580 """
592 """
581 self.lastcmd = 'longlist'
593 self.lastcmd = 'longlist'
582 try:
594 try:
583 lines, lineno = self.getsourcelines(self.curframe)
595 lines, lineno = self.getsourcelines(self.curframe)
584 except OSError as err:
596 except OSError as err:
585 self.error(err)
597 self.error(err)
586 return
598 return
587 last = lineno + len(lines)
599 last = lineno + len(lines)
588 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
600 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
589 do_ll = do_longlist
601 do_ll = do_longlist
590
602
591 def do_debug(self, arg):
603 def do_debug(self, arg):
592 """debug code
604 """debug code
593 Enter a recursive debugger that steps through the code
605 Enter a recursive debugger that steps through the code
594 argument (which is an arbitrary expression or statement to be
606 argument (which is an arbitrary expression or statement to be
595 executed in the current environment).
607 executed in the current environment).
596 """
608 """
597 trace_function = sys.gettrace()
609 trace_function = sys.gettrace()
598 sys.settrace(None)
610 sys.settrace(None)
599 globals = self.curframe.f_globals
611 globals = self.curframe.f_globals
600 locals = self.curframe_locals
612 locals = self.curframe_locals
601 p = self.__class__(completekey=self.completekey,
613 p = self.__class__(completekey=self.completekey,
602 stdin=self.stdin, stdout=self.stdout)
614 stdin=self.stdin, stdout=self.stdout)
603 p.use_rawinput = self.use_rawinput
615 p.use_rawinput = self.use_rawinput
604 p.prompt = "(%s) " % self.prompt.strip()
616 p.prompt = "(%s) " % self.prompt.strip()
605 self.message("ENTERING RECURSIVE DEBUGGER")
617 self.message("ENTERING RECURSIVE DEBUGGER")
606 sys.call_tracing(p.run, (arg, globals, locals))
618 sys.call_tracing(p.run, (arg, globals, locals))
607 self.message("LEAVING RECURSIVE DEBUGGER")
619 self.message("LEAVING RECURSIVE DEBUGGER")
608 sys.settrace(trace_function)
620 sys.settrace(trace_function)
609 self.lastcmd = p.lastcmd
621 self.lastcmd = p.lastcmd
610
622
611 def do_pdef(self, arg):
623 def do_pdef(self, arg):
612 """Print the call signature for any callable object.
624 """Print the call signature for any callable object.
613
625
614 The debugger interface to %pdef"""
626 The debugger interface to %pdef"""
615 namespaces = [
627 namespaces = [
616 ("Locals", self.curframe_locals),
628 ("Locals", self.curframe_locals),
617 ("Globals", self.curframe.f_globals),
629 ("Globals", self.curframe.f_globals),
618 ]
630 ]
619 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
631 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
620
632
621 def do_pdoc(self, arg):
633 def do_pdoc(self, arg):
622 """Print the docstring for an object.
634 """Print the docstring for an object.
623
635
624 The debugger interface to %pdoc."""
636 The debugger interface to %pdoc."""
625 namespaces = [
637 namespaces = [
626 ("Locals", self.curframe_locals),
638 ("Locals", self.curframe_locals),
627 ("Globals", self.curframe.f_globals),
639 ("Globals", self.curframe.f_globals),
628 ]
640 ]
629 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
641 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
630
642
631 def do_pfile(self, arg):
643 def do_pfile(self, arg):
632 """Print (or run through pager) the file where an object is defined.
644 """Print (or run through pager) the file where an object is defined.
633
645
634 The debugger interface to %pfile.
646 The debugger interface to %pfile.
635 """
647 """
636 namespaces = [
648 namespaces = [
637 ("Locals", self.curframe_locals),
649 ("Locals", self.curframe_locals),
638 ("Globals", self.curframe.f_globals),
650 ("Globals", self.curframe.f_globals),
639 ]
651 ]
640 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
652 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
641
653
642 def do_pinfo(self, arg):
654 def do_pinfo(self, arg):
643 """Provide detailed information about an object.
655 """Provide detailed information about an object.
644
656
645 The debugger interface to %pinfo, i.e., obj?."""
657 The debugger interface to %pinfo, i.e., obj?."""
646 namespaces = [
658 namespaces = [
647 ("Locals", self.curframe_locals),
659 ("Locals", self.curframe_locals),
648 ("Globals", self.curframe.f_globals),
660 ("Globals", self.curframe.f_globals),
649 ]
661 ]
650 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
662 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
651
663
652 def do_pinfo2(self, arg):
664 def do_pinfo2(self, arg):
653 """Provide extra detailed information about an object.
665 """Provide extra detailed information about an object.
654
666
655 The debugger interface to %pinfo2, i.e., obj??."""
667 The debugger interface to %pinfo2, i.e., obj??."""
656 namespaces = [
668 namespaces = [
657 ("Locals", self.curframe_locals),
669 ("Locals", self.curframe_locals),
658 ("Globals", self.curframe.f_globals),
670 ("Globals", self.curframe.f_globals),
659 ]
671 ]
660 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
672 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
661
673
662 def do_psource(self, arg):
674 def do_psource(self, arg):
663 """Print (or run through pager) the source code for an object."""
675 """Print (or run through pager) the source code for an object."""
664 namespaces = [
676 namespaces = [
665 ("Locals", self.curframe_locals),
677 ("Locals", self.curframe_locals),
666 ("Globals", self.curframe.f_globals),
678 ("Globals", self.curframe.f_globals),
667 ]
679 ]
668 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
680 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
669
681
670 def do_where(self, arg):
682 def do_where(self, arg):
671 """w(here)
683 """w(here)
672 Print a stack trace, with the most recent frame at the bottom.
684 Print a stack trace, with the most recent frame at the bottom.
673 An arrow indicates the "current frame", which determines the
685 An arrow indicates the "current frame", which determines the
674 context of most commands. 'bt' is an alias for this command.
686 context of most commands. 'bt' is an alias for this command.
675
687
676 Take a number as argument as an (optional) number of context line to
688 Take a number as argument as an (optional) number of context line to
677 print"""
689 print"""
678 if arg:
690 if arg:
679 try:
691 try:
680 context = int(arg)
692 context = int(arg)
681 except ValueError as err:
693 except ValueError as err:
682 self.error(err)
694 self.error(err)
683 return
695 return
684 self.print_stack_trace(context)
696 self.print_stack_trace(context)
685 else:
697 else:
686 self.print_stack_trace()
698 self.print_stack_trace()
687
699
688 do_w = do_where
700 do_w = do_where
689
701
690 def stop_here(self, frame):
702 def stop_here(self, frame):
691 hidden = False
703 hidden = False
692 if self.skip_hidden:
704 if self.skip_hidden:
693 hidden = frame.f_locals.get("__tracebackhide__", False)
705 hidden = frame.f_locals.get("__tracebackhide__", False)
694 if hidden:
706 if hidden:
695 Colors = self.color_scheme_table.active_colors
707 Colors = self.color_scheme_table.active_colors
696 ColorsNormal = Colors.Normal
708 ColorsNormal = Colors.Normal
697 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
709 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
698
710
699 return super().stop_here(frame)
711 return super().stop_here(frame)
700
712
701 def do_up(self, arg):
713 def do_up(self, arg):
702 """u(p) [count]
714 """u(p) [count]
703 Move the current frame count (default one) levels up in the
715 Move the current frame count (default one) levels up in the
704 stack trace (to an older frame).
716 stack trace (to an older frame).
705
717
706 Will skip hidden frames.
718 Will skip hidden frames.
707 """
719 """
708 # modified version of upstream that skips
720 # modified version of upstream that skips
709 # frames with __tracebackide__
721 # frames with __tracebackide__
710 if self.curindex == 0:
722 if self.curindex == 0:
711 self.error("Oldest frame")
723 self.error("Oldest frame")
712 return
724 return
713 try:
725 try:
714 count = int(arg or 1)
726 count = int(arg or 1)
715 except ValueError:
727 except ValueError:
716 self.error("Invalid frame count (%s)" % arg)
728 self.error("Invalid frame count (%s)" % arg)
717 return
729 return
718 skipped = 0
730 skipped = 0
719 if count < 0:
731 if count < 0:
720 _newframe = 0
732 _newframe = 0
721 else:
733 else:
722 counter = 0
734 counter = 0
723 hidden_frames = self.hidden_frames(self.stack)
735 hidden_frames = self.hidden_frames(self.stack)
724 for i in range(self.curindex - 1, -1, -1):
736 for i in range(self.curindex - 1, -1, -1):
725 if hidden_frames[i] and self.skip_hidden:
737 if hidden_frames[i] and self.skip_hidden:
726 skipped += 1
738 skipped += 1
727 continue
739 continue
728 counter += 1
740 counter += 1
729 if counter >= count:
741 if counter >= count:
730 break
742 break
731 else:
743 else:
732 # if no break occured.
744 # if no break occured.
733 self.error(
745 self.error(
734 "all frames above hidden, use `skip_hidden False` to get get into those."
746 "all frames above hidden, use `skip_hidden False` to get get into those."
735 )
747 )
736 return
748 return
737
749
738 Colors = self.color_scheme_table.active_colors
750 Colors = self.color_scheme_table.active_colors
739 ColorsNormal = Colors.Normal
751 ColorsNormal = Colors.Normal
740 _newframe = i
752 _newframe = i
741 self._select_frame(_newframe)
753 self._select_frame(_newframe)
742 if skipped:
754 if skipped:
743 print(
755 print(
744 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
756 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
745 )
757 )
746
758
747 def do_down(self, arg):
759 def do_down(self, arg):
748 """d(own) [count]
760 """d(own) [count]
749 Move the current frame count (default one) levels down in the
761 Move the current frame count (default one) levels down in the
750 stack trace (to a newer frame).
762 stack trace (to a newer frame).
751
763
752 Will skip hidden frames.
764 Will skip hidden frames.
753 """
765 """
754 if self.curindex + 1 == len(self.stack):
766 if self.curindex + 1 == len(self.stack):
755 self.error("Newest frame")
767 self.error("Newest frame")
756 return
768 return
757 try:
769 try:
758 count = int(arg or 1)
770 count = int(arg or 1)
759 except ValueError:
771 except ValueError:
760 self.error("Invalid frame count (%s)" % arg)
772 self.error("Invalid frame count (%s)" % arg)
761 return
773 return
762 if count < 0:
774 if count < 0:
763 _newframe = len(self.stack) - 1
775 _newframe = len(self.stack) - 1
764 else:
776 else:
765 counter = 0
777 counter = 0
766 skipped = 0
778 skipped = 0
767 hidden_frames = self.hidden_frames(self.stack)
779 hidden_frames = self.hidden_frames(self.stack)
768 for i in range(self.curindex + 1, len(self.stack)):
780 for i in range(self.curindex + 1, len(self.stack)):
769 if hidden_frames[i] and self.skip_hidden:
781 if hidden_frames[i] and self.skip_hidden:
770 skipped += 1
782 skipped += 1
771 continue
783 continue
772 counter += 1
784 counter += 1
773 if counter >= count:
785 if counter >= count:
774 break
786 break
775 else:
787 else:
776 self.error(
788 self.error(
777 "all frames bellow hidden, use `skip_hidden False` to get get into those."
789 "all frames bellow hidden, use `skip_hidden False` to get get into those."
778 )
790 )
779 return
791 return
780
792
781 Colors = self.color_scheme_table.active_colors
793 Colors = self.color_scheme_table.active_colors
782 ColorsNormal = Colors.Normal
794 ColorsNormal = Colors.Normal
783 if skipped:
795 if skipped:
784 print(
796 print(
785 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
797 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
786 )
798 )
787 _newframe = i
799 _newframe = i
788
800
789 self._select_frame(_newframe)
801 self._select_frame(_newframe)
790
802
791 do_d = do_down
803 do_d = do_down
792 do_u = do_up
804 do_u = do_up
793
805
794 class InterruptiblePdb(Pdb):
806 class InterruptiblePdb(Pdb):
795 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
807 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
796
808
797 def cmdloop(self):
809 def cmdloop(self):
798 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
810 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
799 try:
811 try:
800 return OldPdb.cmdloop(self)
812 return OldPdb.cmdloop(self)
801 except KeyboardInterrupt:
813 except KeyboardInterrupt:
802 self.stop_here = lambda frame: False
814 self.stop_here = lambda frame: False
803 self.do_quit("")
815 self.do_quit("")
804 sys.settrace(None)
816 sys.settrace(None)
805 self.quitting = False
817 self.quitting = False
806 raise
818 raise
807
819
808 def _cmdloop(self):
820 def _cmdloop(self):
809 while True:
821 while True:
810 try:
822 try:
811 # keyboard interrupts allow for an easy way to cancel
823 # keyboard interrupts allow for an easy way to cancel
812 # the current command, so allow them during interactive input
824 # the current command, so allow them during interactive input
813 self.allow_kbdint = True
825 self.allow_kbdint = True
814 self.cmdloop()
826 self.cmdloop()
815 self.allow_kbdint = False
827 self.allow_kbdint = False
816 break
828 break
817 except KeyboardInterrupt:
829 except KeyboardInterrupt:
818 self.message('--KeyboardInterrupt--')
830 self.message('--KeyboardInterrupt--')
819 raise
831 raise
820
832
821
833
822 def set_trace(frame=None):
834 def set_trace(frame=None):
823 """
835 """
824 Start debugging from `frame`.
836 Start debugging from `frame`.
825
837
826 If frame is not specified, debugging starts from caller's frame.
838 If frame is not specified, debugging starts from caller's frame.
827 """
839 """
828 Pdb().set_trace(frame or sys._getframe().f_back)
840 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now