##// END OF EJS Templates
ipdb: fix formatting in core.debugger
Blazej Michalik -
Show More
@@ -1,833 +1,832 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 def make_arrow(pad):
54 def make_arrow(pad):
54 """generate the leading arrow in front of traceback or debugger"""
55 """generate the leading arrow in front of traceback or debugger"""
55 if pad >= 2:
56 if pad >= 2:
56 return '-'*(pad-2) + '> '
57 return '-'*(pad-2) + '> '
57 elif pad == 1:
58 elif pad == 1:
58 return '>'
59 return '>'
59 return ''
60 return ''
60
61
61
62
62 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
63 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
63 """Exception hook which handles `BdbQuit` exceptions.
64 """Exception hook which handles `BdbQuit` exceptions.
64
65
65 All other exceptions are processed using the `excepthook`
66 All other exceptions are processed using the `excepthook`
66 parameter.
67 parameter.
67 """
68 """
68 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
69 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
69 DeprecationWarning, stacklevel=2)
70 DeprecationWarning, stacklevel=2)
70 if et==bdb.BdbQuit:
71 if et == bdb.BdbQuit:
71 print('Exiting Debugger.')
72 print('Exiting Debugger.')
72 elif excepthook is not None:
73 elif excepthook is not None:
73 excepthook(et, ev, tb)
74 excepthook(et, ev, tb)
74 else:
75 else:
75 # Backwards compatibility. Raise deprecation warning?
76 # Backwards compatibility. Raise deprecation warning?
76 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
77 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
77
78
78
79
79 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
80 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
80 warnings.warn(
81 warnings.warn(
81 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
82 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
82 DeprecationWarning, stacklevel=2)
83 DeprecationWarning, stacklevel=2)
83 print('Exiting Debugger.')
84 print('Exiting Debugger.')
84
85
85
86
86 class Tracer(object):
87 class Tracer(object):
87 """
88 """
88 DEPRECATED
89 DEPRECATED
89
90
90 Class for local debugging, similar to pdb.set_trace.
91 Class for local debugging, similar to pdb.set_trace.
91
92
92 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
93 providing IPython's enhanced capabilities.
94 providing IPython's enhanced capabilities.
94
95
95 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
96 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
97 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
98 constructor, ensuring that this code plays nicely with a running IPython,
99 constructor, ensuring that this code plays nicely with a running IPython,
99 while functioning acceptably (though with limitations) if outside of it.
100 while functioning acceptably (though with limitations) if outside of it.
100 """
101 """
101
102
102 @skip_doctest
103 @skip_doctest
103 def __init__(self, colors=None):
104 def __init__(self, colors=None):
104 """
105 """
105 DEPRECATED
106 DEPRECATED
106
107
107 Create a local debugger instance.
108 Create a local debugger instance.
108
109
109 Parameters
110 Parameters
110 ----------
111 ----------
111
112
112 colors : str, optional
113 colors : str, optional
113 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
114 valid color schemes. If not given, the function will default to
115 valid color schemes. If not given, the function will default to
115 the current IPython scheme when running inside IPython, and to
116 the current IPython scheme when running inside IPython, and to
116 'NoColor' otherwise.
117 'NoColor' otherwise.
117
118
118 Examples
119 Examples
119 --------
120 --------
120 ::
121 ::
121
122
122 from IPython.core.debugger import Tracer; debug_here = Tracer()
123 from IPython.core.debugger import Tracer; debug_here = Tracer()
123
124
124 Later in your code::
125 Later in your code::
125
126
126 debug_here() # -> will open up the debugger at that point.
127 debug_here() # -> will open up the debugger at that point.
127
128
128 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
129 step through code, set breakpoints, etc. See the pdb documentation
130 step through code, set breakpoints, etc. See the pdb documentation
130 from the Python standard library for usage details.
131 from the Python standard library for usage details.
131 """
132 """
132 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
133 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
133 "`IPython.core.debugger.Pdb.set_trace()`",
134 "`IPython.core.debugger.Pdb.set_trace()`",
134 DeprecationWarning, stacklevel=2)
135 DeprecationWarning, stacklevel=2)
135
136
136 ip = get_ipython()
137 ip = get_ipython()
137 if ip is None:
138 if ip is None:
138 # Outside of ipython, we set our own exception hook manually
139 # Outside of ipython, we set our own exception hook manually
139 sys.excepthook = functools.partial(BdbQuit_excepthook,
140 sys.excepthook = functools.partial(BdbQuit_excepthook,
140 excepthook=sys.excepthook)
141 excepthook=sys.excepthook)
141 def_colors = 'NoColor'
142 def_colors = 'NoColor'
142 else:
143 else:
143 # In ipython, we use its custom exception handler mechanism
144 # In ipython, we use its custom exception handler mechanism
144 def_colors = ip.colors
145 def_colors = ip.colors
145 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
146 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
146
147
147 if colors is None:
148 if colors is None:
148 colors = def_colors
149 colors = def_colors
149
150
150 # The stdlib debugger internally uses a modified repr from the `repr`
151 # The stdlib debugger internally uses a modified repr from the `repr`
151 # module, that limits the length of printed strings to a hardcoded
152 # module, that limits the length of printed strings to a hardcoded
152 # 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
153 # 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
154 # most interactive uses.
155 # most interactive uses.
155 try:
156 try:
156 from reprlib import aRepr
157 from reprlib import aRepr
157 aRepr.maxstring = 80
158 aRepr.maxstring = 80
158 except:
159 except:
159 # 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
160 # here can be warned about but can be otherwise ignored. These
161 # here can be warned about but can be otherwise ignored. These
161 # printouts will tell us about problems if this API changes
162 # printouts will tell us about problems if this API changes
162 import traceback
163 import traceback
163 traceback.print_exc()
164 traceback.print_exc()
164
165
165 self.debugger = Pdb(colors)
166 self.debugger = Pdb(colors)
166
167
167 def __call__(self):
168 def __call__(self):
168 """Starts an interactive debugger at the point where called.
169 """Starts an interactive debugger at the point where called.
169
170
170 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
171 using IPython's enhanced debugger."""
172 using IPython's enhanced debugger."""
172
173
173 self.debugger.set_trace(sys._getframe().f_back)
174 self.debugger.set_trace(sys._getframe().f_back)
174
175
175
176
176 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
177 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
177
178
178
179
179 def strip_indentation(multiline_string):
180 def strip_indentation(multiline_string):
180 return RGX_EXTRA_INDENT.sub('', multiline_string)
181 return RGX_EXTRA_INDENT.sub('', multiline_string)
181
182
182
183
183 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
184 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
184 """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
185 for the ``do_...`` commands that hook into the help system.
186 for the ``do_...`` commands that hook into the help system.
186 Adapted from from a comp.lang.python posting
187 Adapted from from a comp.lang.python posting
187 by Duncan Booth."""
188 by Duncan Booth."""
188 def wrapper(*args, **kw):
189 def wrapper(*args, **kw):
189 return new_fn(*args, **kw)
190 return new_fn(*args, **kw)
190 if old_fn.__doc__:
191 if old_fn.__doc__:
191 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
192 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
192 return wrapper
193 return wrapper
193
194
194
195
195 class Pdb(OldPdb):
196 class Pdb(OldPdb):
196 """Modified Pdb class, does not load readline.
197 """Modified Pdb class, does not load readline.
197
198
198 for a standalone version that uses prompt_toolkit, see
199 for a standalone version that uses prompt_toolkit, see
199 `IPython.terminal.debugger.TerminalPdb` and
200 `IPython.terminal.debugger.TerminalPdb` and
200 `IPython.terminal.debugger.set_trace()`
201 `IPython.terminal.debugger.set_trace()`
201 """
202 """
202
203
203 def __init__(self, color_scheme=None, completekey=None,
204 def __init__(self, color_scheme=None, completekey=None,
204 stdin=None, stdout=None, context=5, **kwargs):
205 stdin=None, stdout=None, context=5, **kwargs):
205 """Create a new IPython debugger.
206 """Create a new IPython debugger.
206
207
207 :param color_scheme: Deprecated, do not use.
208 :param color_scheme: Deprecated, do not use.
208 :param completekey: Passed to pdb.Pdb.
209 :param completekey: Passed to pdb.Pdb.
209 :param stdin: Passed to pdb.Pdb.
210 :param stdin: Passed to pdb.Pdb.
210 :param stdout: Passed to pdb.Pdb.
211 :param stdout: Passed to pdb.Pdb.
211 :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
212 displaying stacktrace information.
213 displaying stacktrace information.
213 :param kwargs: Passed to pdb.Pdb.
214 :param kwargs: Passed to pdb.Pdb.
214 The possibilities are python version dependent, see the python
215 The possibilities are python version dependent, see the python
215 docs for more info.
216 docs for more info.
216 """
217 """
217
218
218 # Parent constructor:
219 # Parent constructor:
219 try:
220 try:
220 self.context = int(context)
221 self.context = int(context)
221 if self.context <= 0:
222 if self.context <= 0:
222 raise ValueError("Context must be a positive integer")
223 raise ValueError("Context must be a positive integer")
223 except (TypeError, ValueError) as e:
224 except (TypeError, ValueError) as e:
224 raise ValueError("Context must be a positive integer") from e
225 raise ValueError("Context must be a positive integer") from e
225
226
226 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
227 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
227 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
228 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
228
229
229 # IPython changes...
230 # IPython changes...
230 self.shell = get_ipython()
231 self.shell = get_ipython()
231
232
232 if self.shell is None:
233 if self.shell is None:
233 save_main = sys.modules['__main__']
234 save_main = sys.modules['__main__']
234 # No IPython instance running, we must create one
235 # No IPython instance running, we must create one
235 from IPython.terminal.interactiveshell import \
236 from IPython.terminal.interactiveshell import \
236 TerminalInteractiveShell
237 TerminalInteractiveShell
237 self.shell = TerminalInteractiveShell.instance()
238 self.shell = TerminalInteractiveShell.instance()
238 # needed by any code which calls __import__("__main__") after
239 # needed by any code which calls __import__("__main__") after
239 # the debugger was entered. See also #9941.
240 # the debugger was entered. See also #9941.
240 sys.modules['__main__'] = save_main
241 sys.modules['__main__'] = save_main
241
242
242 if color_scheme is not None:
243 if color_scheme is not None:
243 warnings.warn(
244 warnings.warn(
244 "The `color_scheme` argument is deprecated since version 5.1",
245 "The `color_scheme` argument is deprecated since version 5.1",
245 DeprecationWarning, stacklevel=2)
246 DeprecationWarning, stacklevel=2)
246 else:
247 else:
247 color_scheme = self.shell.colors
248 color_scheme = self.shell.colors
248
249
249 self.aliases = {}
250 self.aliases = {}
250
251
251 # Create color table: we copy the default one from the traceback
252 # Create color table: we copy the default one from the traceback
252 # module and add a few attributes needed for debugging
253 # module and add a few attributes needed for debugging
253 self.color_scheme_table = exception_colors()
254 self.color_scheme_table = exception_colors()
254
255
255 # shorthands
256 # shorthands
256 C = coloransi.TermColors
257 C = coloransi.TermColors
257 cst = self.color_scheme_table
258 cst = self.color_scheme_table
258
259
259 cst['NoColor'].colors.prompt = C.NoColor
260 cst['NoColor'].colors.prompt = C.NoColor
260 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
261 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
261 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
262 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
262
263
263 cst['Linux'].colors.prompt = C.Green
264 cst['Linux'].colors.prompt = C.Green
264 cst['Linux'].colors.breakpoint_enabled = C.LightRed
265 cst['Linux'].colors.breakpoint_enabled = C.LightRed
265 cst['Linux'].colors.breakpoint_disabled = C.Red
266 cst['Linux'].colors.breakpoint_disabled = C.Red
266
267
267 cst['LightBG'].colors.prompt = C.Blue
268 cst['LightBG'].colors.prompt = C.Blue
268 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 cst['LightBG'].colors.breakpoint_disabled = C.Red
270 cst['LightBG'].colors.breakpoint_disabled = C.Red
270
271
271 cst['Neutral'].colors.prompt = C.Blue
272 cst['Neutral'].colors.prompt = C.Blue
272 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
273 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
273 cst['Neutral'].colors.breakpoint_disabled = C.Red
274 cst['Neutral'].colors.breakpoint_disabled = C.Red
274
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 new_do_frame(self, arg):
323 def new_do_frame(self, arg):
324 OldPdb.do_frame(self, arg)
324 OldPdb.do_frame(self, arg)
325
325
326 def new_do_quit(self, arg):
326 def new_do_quit(self, arg):
327
327
328 if hasattr(self, 'old_all_completions'):
328 if hasattr(self, 'old_all_completions'):
329 self.shell.Completer.all_completions=self.old_all_completions
329 self.shell.Completer.all_completions = self.old_all_completions
330
330
331 return OldPdb.do_quit(self, arg)
331 return OldPdb.do_quit(self, arg)
332
332
333 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
333 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
334
334
335 def new_do_restart(self, arg):
335 def new_do_restart(self, arg):
336 """Restart command. In the context of ipython this is exactly the same
336 """Restart command. In the context of ipython this is exactly the same
337 thing as 'quit'."""
337 thing as 'quit'."""
338 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
338 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
339 return self.do_quit(arg)
339 return self.do_quit(arg)
340
340
341 def print_stack_trace(self, context=None):
341 def print_stack_trace(self, context=None):
342 Colors = self.color_scheme_table.active_colors
342 Colors = self.color_scheme_table.active_colors
343 ColorsNormal = Colors.Normal
343 ColorsNormal = Colors.Normal
344 if context is None:
344 if context is None:
345 context = self.context
345 context = self.context
346 try:
346 try:
347 context=int(context)
347 context = int(context)
348 if context <= 0:
348 if context <= 0:
349 raise ValueError("Context must be a positive integer")
349 raise ValueError("Context must be a positive integer")
350 except (TypeError, ValueError) as e:
350 except (TypeError, ValueError) as e:
351 raise ValueError("Context must be a positive integer") from e
351 raise ValueError("Context must be a positive integer") from e
352 try:
352 try:
353 skipped = 0
353 skipped = 0
354 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
354 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
355 if hidden and self.skip_hidden:
355 if hidden and self.skip_hidden:
356 skipped += 1
356 skipped += 1
357 continue
357 continue
358 if skipped:
358 if skipped:
359 print(
359 print(
360 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
360 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
361 )
361 )
362 skipped = 0
362 skipped = 0
363 self.print_stack_entry(frame_lineno, context=context)
363 self.print_stack_entry(frame_lineno, context=context)
364 if skipped:
364 if skipped:
365 print(
365 print(
366 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
366 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
367 )
367 )
368 except KeyboardInterrupt:
368 except KeyboardInterrupt:
369 pass
369 pass
370
370
371 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
371 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
372 context=None):
372 context=None):
373 if context is None:
373 if context is None:
374 context = self.context
374 context = self.context
375 try:
375 try:
376 context=int(context)
376 context = int(context)
377 if context <= 0:
377 if context <= 0:
378 raise ValueError("Context must be a positive integer")
378 raise ValueError("Context must be a positive integer")
379 except (TypeError, ValueError) as e:
379 except (TypeError, ValueError) as e:
380 raise ValueError("Context must be a positive integer") from e
380 raise ValueError("Context must be a positive integer") from e
381 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
381 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
382
382
383 # vds: >>
383 # vds: >>
384 frame, lineno = frame_lineno
384 frame, lineno = frame_lineno
385 filename = frame.f_code.co_filename
385 filename = frame.f_code.co_filename
386 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
386 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
387 # vds: <<
387 # vds: <<
388
388
389 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
389 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
390 if context is None:
390 if context is None:
391 context = self.context
391 context = self.context
392 try:
392 try:
393 context=int(context)
393 context = int(context)
394 if context <= 0:
394 if context <= 0:
395 print("Context must be a positive integer", file=self.stdout)
395 print("Context must be a positive integer", file=self.stdout)
396 except (TypeError, ValueError):
396 except (TypeError, ValueError):
397 print("Context must be a positive integer", file=self.stdout)
397 print("Context must be a positive integer", file=self.stdout)
398
398
399 import reprlib
399 import reprlib
400
400
401 ret = []
401 ret = []
402
402
403 Colors = self.color_scheme_table.active_colors
403 Colors = self.color_scheme_table.active_colors
404 ColorsNormal = Colors.Normal
404 ColorsNormal = Colors.Normal
405 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
405 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
406 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
406 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)
407 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,
408 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
409 ColorsNormal)
409 ColorsNormal)
410
410
411 frame, lineno = frame_lineno
411 frame, lineno = frame_lineno
412
412
413 return_value = ''
413 return_value = ''
414 if '__return__' in frame.f_locals:
414 if '__return__' in frame.f_locals:
415 rv = frame.f_locals['__return__']
415 rv = frame.f_locals['__return__']
416 #return_value += '->'
416 #return_value += '->'
417 return_value += reprlib.repr(rv) + '\n'
417 return_value += reprlib.repr(rv) + '\n'
418 ret.append(return_value)
418 ret.append(return_value)
419
419
420 #s = filename + '(' + `lineno` + ')'
420 #s = filename + '(' + `lineno` + ')'
421 filename = self.canonic(frame.f_code.co_filename)
421 filename = self.canonic(frame.f_code.co_filename)
422 link = tpl_link % py3compat.cast_unicode(filename)
422 link = tpl_link % py3compat.cast_unicode(filename)
423
423
424 if frame.f_code.co_name:
424 if frame.f_code.co_name:
425 func = frame.f_code.co_name
425 func = frame.f_code.co_name
426 else:
426 else:
427 func = "<lambda>"
427 func = "<lambda>"
428
428
429 call = ''
429 call = ''
430 if func != '?':
430 if func != '?':
431 if '__args__' in frame.f_locals:
431 if '__args__' in frame.f_locals:
432 args = reprlib.repr(frame.f_locals['__args__'])
432 args = reprlib.repr(frame.f_locals['__args__'])
433 else:
433 else:
434 args = '()'
434 args = '()'
435 call = tpl_call % (func, args)
435 call = tpl_call % (func, args)
436
436
437 # The level info should be generated in the same format pdb uses, to
437 # The level info should be generated in the same format pdb uses, to
438 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
438 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
439 if frame is self.curframe:
439 if frame is self.curframe:
440 ret.append('> ')
440 ret.append('> ')
441 else:
441 else:
442 ret.append(' ')
442 ret.append(' ')
443 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
443 ret.append(u'%s(%s)%s\n' % (link, lineno, call))
444
444
445 start = lineno - 1 - context//2
445 start = lineno - 1 - context//2
446 lines = linecache.getlines(filename)
446 lines = linecache.getlines(filename)
447 start = min(start, len(lines) - context)
447 start = min(start, len(lines) - context)
448 start = max(start, 0)
448 start = max(start, 0)
449 lines = lines[start : start + context]
449 lines = lines[start : start + context]
450
450
451 for i,line in enumerate(lines):
451 for i, line in enumerate(lines):
452 show_arrow = (start + 1 + i == lineno)
452 show_arrow = (start + 1 + i == lineno)
453 linetpl = (frame is self.curframe or show_arrow) \
453 linetpl = (frame is self.curframe or show_arrow) \
454 and tpl_line_em \
454 and tpl_line_em \
455 or tpl_line
455 or tpl_line
456 ret.append(self.__format_line(linetpl, filename,
456 ret.append(self.__format_line(linetpl, filename,
457 start + 1 + i, line,
457 start + 1 + i, line,
458 arrow = show_arrow) )
458 arrow=show_arrow))
459 return ''.join(ret)
459 return ''.join(ret)
460
460
461 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
461 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
462 bp_mark = ""
462 bp_mark = ""
463 bp_mark_color = ""
463 bp_mark_color = ""
464
464
465 new_line, err = self.parser.format2(line, 'str')
465 new_line, err = self.parser.format2(line, 'str')
466 if not err:
466 if not err:
467 line = new_line
467 line = new_line
468
468
469 bp = None
469 bp = None
470 if lineno in self.get_file_breaks(filename):
470 if lineno in self.get_file_breaks(filename):
471 bps = self.get_breaks(filename, lineno)
471 bps = self.get_breaks(filename, lineno)
472 bp = bps[-1]
472 bp = bps[-1]
473
473
474 if bp:
474 if bp:
475 Colors = self.color_scheme_table.active_colors
475 Colors = self.color_scheme_table.active_colors
476 bp_mark = str(bp.number)
476 bp_mark = str(bp.number)
477 bp_mark_color = Colors.breakpoint_enabled
477 bp_mark_color = Colors.breakpoint_enabled
478 if not bp.enabled:
478 if not bp.enabled:
479 bp_mark_color = Colors.breakpoint_disabled
479 bp_mark_color = Colors.breakpoint_disabled
480
480
481 numbers_width = 7
481 numbers_width = 7
482 if arrow:
482 if arrow:
483 # This is the line with the error
483 # This is the line with the error
484 pad = numbers_width - len(str(lineno)) - len(bp_mark)
484 pad = numbers_width - len(str(lineno)) - len(bp_mark)
485 num = '%s%s' % (make_arrow(pad), str(lineno))
485 num = '%s%s' % (make_arrow(pad), str(lineno))
486 else:
486 else:
487 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
487 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
488
488
489 return tpl_line % (bp_mark_color + bp_mark, num, line)
489 return tpl_line % (bp_mark_color + bp_mark, num, line)
490
490
491
492 def print_list_lines(self, filename, first, last):
491 def print_list_lines(self, filename, first, last):
493 """The printing (as opposed to the parsing part of a 'list'
492 """The printing (as opposed to the parsing part of a 'list'
494 command."""
493 command."""
495 try:
494 try:
496 Colors = self.color_scheme_table.active_colors
495 Colors = self.color_scheme_table.active_colors
497 ColorsNormal = Colors.Normal
496 ColorsNormal = Colors.Normal
498 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
497 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
499 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
498 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
500 src = []
499 src = []
501 if filename == "<string>" and hasattr(self, "_exec_filename"):
500 if filename == "<string>" and hasattr(self, "_exec_filename"):
502 filename = self._exec_filename
501 filename = self._exec_filename
503
502
504 for lineno in range(first, last+1):
503 for lineno in range(first, last+1):
505 line = linecache.getline(filename, lineno)
504 line = linecache.getline(filename, lineno)
506 if not line:
505 if not line:
507 break
506 break
508
507
509 if lineno == self.curframe.f_lineno:
508 if lineno == self.curframe.f_lineno:
510 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
509 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow=True)
511 else:
510 else:
512 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
511 line = self.__format_line(tpl_line, filename, lineno, line, arrow=False)
513
512
514 src.append(line)
513 src.append(line)
515 self.lineno = lineno
514 self.lineno = lineno
516
515
517 print(''.join(src), file=self.stdout)
516 print(''.join(src), file=self.stdout)
518
517
519 except KeyboardInterrupt:
518 except KeyboardInterrupt:
520 pass
519 pass
521
520
522 def do_skip_hidden(self, arg):
521 def do_skip_hidden(self, arg):
523 """
522 """
524 Change whether or not we should skip frames with the
523 Change whether or not we should skip frames with the
525 __tracebackhide__ attribute.
524 __tracebackhide__ attribute.
526 """
525 """
527 if arg.strip().lower() in ("true", "yes"):
526 if arg.strip().lower() in ("true", "yes"):
528 self.skip_hidden = True
527 self.skip_hidden = True
529 elif arg.strip().lower() in ("false", "no"):
528 elif arg.strip().lower() in ("false", "no"):
530 self.skip_hidden = False
529 self.skip_hidden = False
531
530
532 def do_list(self, arg):
531 def do_list(self, arg):
533 """Print lines of code from the current stack frame
532 """Print lines of code from the current stack frame
534 """
533 """
535 self.lastcmd = 'list'
534 self.lastcmd = 'list'
536 last = None
535 last = None
537 if arg:
536 if arg:
538 try:
537 try:
539 x = eval(arg, {}, {})
538 x = eval(arg, {}, {})
540 if type(x) == type(()):
539 if type(x) == type(()):
541 first, last = x
540 first, last = x
542 first = int(first)
541 first = int(first)
543 last = int(last)
542 last = int(last)
544 if last < first:
543 if last < first:
545 # Assume it's a count
544 # Assume it's a count
546 last = first + last
545 last = first + last
547 else:
546 else:
548 first = max(1, int(x) - 5)
547 first = max(1, int(x) - 5)
549 except:
548 except:
550 print('*** Error in argument:', repr(arg), file=self.stdout)
549 print('*** Error in argument:', repr(arg), file=self.stdout)
551 return
550 return
552 elif self.lineno is None:
551 elif self.lineno is None:
553 first = max(1, self.curframe.f_lineno - 5)
552 first = max(1, self.curframe.f_lineno - 5)
554 else:
553 else:
555 first = self.lineno + 1
554 first = self.lineno + 1
556 if last is None:
555 if last is None:
557 last = first + 10
556 last = first + 10
558 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
557 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
559
558
560 # vds: >>
559 # vds: >>
561 lineno = first
560 lineno = first
562 filename = self.curframe.f_code.co_filename
561 filename = self.curframe.f_code.co_filename
563 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
562 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
564 # vds: <<
563 # vds: <<
565
564
566 do_l = do_list
565 do_l = do_list
567
566
568 def getsourcelines(self, obj):
567 def getsourcelines(self, obj):
569 lines, lineno = inspect.findsource(obj)
568 lines, lineno = inspect.findsource(obj)
570 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
569 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
571 # must be a module frame: do not try to cut a block out of it
570 # must be a module frame: do not try to cut a block out of it
572 return lines, 1
571 return lines, 1
573 elif inspect.ismodule(obj):
572 elif inspect.ismodule(obj):
574 return lines, 1
573 return lines, 1
575 return inspect.getblock(lines[lineno:]), lineno+1
574 return inspect.getblock(lines[lineno:]), lineno+1
576
575
577 def do_longlist(self, arg):
576 def do_longlist(self, arg):
578 """Print lines of code from the current stack frame.
577 """Print lines of code from the current stack frame.
579
578
580 Shows more lines than 'list' does.
579 Shows more lines than 'list' does.
581 """
580 """
582 self.lastcmd = 'longlist'
581 self.lastcmd = 'longlist'
583 try:
582 try:
584 lines, lineno = self.getsourcelines(self.curframe)
583 lines, lineno = self.getsourcelines(self.curframe)
585 except OSError as err:
584 except OSError as err:
586 self.error(err)
585 self.error(err)
587 return
586 return
588 last = lineno + len(lines)
587 last = lineno + len(lines)
589 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
588 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
590 do_ll = do_longlist
589 do_ll = do_longlist
591
590
592 def do_debug(self, arg):
591 def do_debug(self, arg):
593 """debug code
592 """debug code
594 Enter a recursive debugger that steps through the code
593 Enter a recursive debugger that steps through the code
595 argument (which is an arbitrary expression or statement to be
594 argument (which is an arbitrary expression or statement to be
596 executed in the current environment).
595 executed in the current environment).
597 """
596 """
598 trace_function = sys.gettrace()
597 trace_function = sys.gettrace()
599 sys.settrace(None)
598 sys.settrace(None)
600 globals = self.curframe.f_globals
599 globals = self.curframe.f_globals
601 locals = self.curframe_locals
600 locals = self.curframe_locals
602 p = self.__class__(completekey=self.completekey,
601 p = self.__class__(completekey=self.completekey,
603 stdin=self.stdin, stdout=self.stdout)
602 stdin=self.stdin, stdout=self.stdout)
604 p.use_rawinput = self.use_rawinput
603 p.use_rawinput = self.use_rawinput
605 p.prompt = "(%s) " % self.prompt.strip()
604 p.prompt = "(%s) " % self.prompt.strip()
606 self.message("ENTERING RECURSIVE DEBUGGER")
605 self.message("ENTERING RECURSIVE DEBUGGER")
607 sys.call_tracing(p.run, (arg, globals, locals))
606 sys.call_tracing(p.run, (arg, globals, locals))
608 self.message("LEAVING RECURSIVE DEBUGGER")
607 self.message("LEAVING RECURSIVE DEBUGGER")
609 sys.settrace(trace_function)
608 sys.settrace(trace_function)
610 self.lastcmd = p.lastcmd
609 self.lastcmd = p.lastcmd
611
610
612 def do_pdef(self, arg):
611 def do_pdef(self, arg):
613 """Print the call signature for any callable object.
612 """Print the call signature for any callable object.
614
613
615 The debugger interface to %pdef"""
614 The debugger interface to %pdef"""
616 namespaces = [
615 namespaces = [
617 ("Locals", self.curframe_locals),
616 ("Locals", self.curframe_locals),
618 ("Globals", self.curframe.f_globals),
617 ("Globals", self.curframe.f_globals),
619 ]
618 ]
620 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
619 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
621
620
622 def do_pdoc(self, arg):
621 def do_pdoc(self, arg):
623 """Print the docstring for an object.
622 """Print the docstring for an object.
624
623
625 The debugger interface to %pdoc."""
624 The debugger interface to %pdoc."""
626 namespaces = [
625 namespaces = [
627 ("Locals", self.curframe_locals),
626 ("Locals", self.curframe_locals),
628 ("Globals", self.curframe.f_globals),
627 ("Globals", self.curframe.f_globals),
629 ]
628 ]
630 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
629 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
631
630
632 def do_pfile(self, arg):
631 def do_pfile(self, arg):
633 """Print (or run through pager) the file where an object is defined.
632 """Print (or run through pager) the file where an object is defined.
634
633
635 The debugger interface to %pfile.
634 The debugger interface to %pfile.
636 """
635 """
637 namespaces = [
636 namespaces = [
638 ("Locals", self.curframe_locals),
637 ("Locals", self.curframe_locals),
639 ("Globals", self.curframe.f_globals),
638 ("Globals", self.curframe.f_globals),
640 ]
639 ]
641 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
640 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
642
641
643 def do_pinfo(self, arg):
642 def do_pinfo(self, arg):
644 """Provide detailed information about an object.
643 """Provide detailed information about an object.
645
644
646 The debugger interface to %pinfo, i.e., obj?."""
645 The debugger interface to %pinfo, i.e., obj?."""
647 namespaces = [
646 namespaces = [
648 ("Locals", self.curframe_locals),
647 ("Locals", self.curframe_locals),
649 ("Globals", self.curframe.f_globals),
648 ("Globals", self.curframe.f_globals),
650 ]
649 ]
651 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
650 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
652
651
653 def do_pinfo2(self, arg):
652 def do_pinfo2(self, arg):
654 """Provide extra detailed information about an object.
653 """Provide extra detailed information about an object.
655
654
656 The debugger interface to %pinfo2, i.e., obj??."""
655 The debugger interface to %pinfo2, i.e., obj??."""
657 namespaces = [
656 namespaces = [
658 ("Locals", self.curframe_locals),
657 ("Locals", self.curframe_locals),
659 ("Globals", self.curframe.f_globals),
658 ("Globals", self.curframe.f_globals),
660 ]
659 ]
661 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
660 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
662
661
663 def do_psource(self, arg):
662 def do_psource(self, arg):
664 """Print (or run through pager) the source code for an object."""
663 """Print (or run through pager) the source code for an object."""
665 namespaces = [
664 namespaces = [
666 ("Locals", self.curframe_locals),
665 ("Locals", self.curframe_locals),
667 ("Globals", self.curframe.f_globals),
666 ("Globals", self.curframe.f_globals),
668 ]
667 ]
669 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
668 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
670
669
671 def do_where(self, arg):
670 def do_where(self, arg):
672 """w(here)
671 """w(here)
673 Print a stack trace, with the most recent frame at the bottom.
672 Print a stack trace, with the most recent frame at the bottom.
674 An arrow indicates the "current frame", which determines the
673 An arrow indicates the "current frame", which determines the
675 context of most commands. 'bt' is an alias for this command.
674 context of most commands. 'bt' is an alias for this command.
676
675
677 Take a number as argument as an (optional) number of context line to
676 Take a number as argument as an (optional) number of context line to
678 print"""
677 print"""
679 if arg:
678 if arg:
680 try:
679 try:
681 context = int(arg)
680 context = int(arg)
682 except ValueError as err:
681 except ValueError as err:
683 self.error(err)
682 self.error(err)
684 return
683 return
685 self.print_stack_trace(context)
684 self.print_stack_trace(context)
686 else:
685 else:
687 self.print_stack_trace()
686 self.print_stack_trace()
688
687
689 do_w = do_where
688 do_w = do_where
690
689
691 def stop_here(self, frame):
690 def stop_here(self, frame):
692 hidden = False
691 hidden = False
693 if self.skip_hidden:
692 if self.skip_hidden:
694 hidden = frame.f_locals.get("__tracebackhide__", False)
693 hidden = frame.f_locals.get("__tracebackhide__", False)
695 if hidden:
694 if hidden:
696 Colors = self.color_scheme_table.active_colors
695 Colors = self.color_scheme_table.active_colors
697 ColorsNormal = Colors.Normal
696 ColorsNormal = Colors.Normal
698 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
697 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
699
698
700 return super().stop_here(frame)
699 return super().stop_here(frame)
701
700
702 def do_up(self, arg):
701 def do_up(self, arg):
703 """u(p) [count]
702 """u(p) [count]
704 Move the current frame count (default one) levels up in the
703 Move the current frame count (default one) levels up in the
705 stack trace (to an older frame).
704 stack trace (to an older frame).
706
705
707 Will skip hidden frames.
706 Will skip hidden frames.
708 """
707 """
709 ## modified version of upstream that skips
708 # modified version of upstream that skips
710 # frames with __tracebackide__
709 # frames with __tracebackide__
711 if self.curindex == 0:
710 if self.curindex == 0:
712 self.error("Oldest frame")
711 self.error("Oldest frame")
713 return
712 return
714 try:
713 try:
715 count = int(arg or 1)
714 count = int(arg or 1)
716 except ValueError:
715 except ValueError:
717 self.error("Invalid frame count (%s)" % arg)
716 self.error("Invalid frame count (%s)" % arg)
718 return
717 return
719 skipped = 0
718 skipped = 0
720 if count < 0:
719 if count < 0:
721 _newframe = 0
720 _newframe = 0
722 else:
721 else:
723 _newindex = self.curindex
722 _newindex = self.curindex
724 counter = 0
723 counter = 0
725 hidden_frames = self.hidden_frames(self.stack)
724 hidden_frames = self.hidden_frames(self.stack)
726 for i in range(self.curindex - 1, -1, -1):
725 for i in range(self.curindex - 1, -1, -1):
727 frame = self.stack[i][0]
726 frame = self.stack[i][0]
728 if hidden_frames[i] and self.skip_hidden:
727 if hidden_frames[i] and self.skip_hidden:
729 skipped += 1
728 skipped += 1
730 continue
729 continue
731 counter += 1
730 counter += 1
732 if counter >= count:
731 if counter >= count:
733 break
732 break
734 else:
733 else:
735 # if no break occured.
734 # if no break occured.
736 self.error(
735 self.error(
737 "all frames above hidden, use `skip_hidden False` to get get into those."
736 "all frames above hidden, use `skip_hidden False` to get get into those."
738 )
737 )
739 return
738 return
740
739
741 Colors = self.color_scheme_table.active_colors
740 Colors = self.color_scheme_table.active_colors
742 ColorsNormal = Colors.Normal
741 ColorsNormal = Colors.Normal
743 _newframe = i
742 _newframe = i
744 self._select_frame(_newframe)
743 self._select_frame(_newframe)
745 if skipped:
744 if skipped:
746 print(
745 print(
747 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
746 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
748 )
747 )
749
748
750 def do_down(self, arg):
749 def do_down(self, arg):
751 """d(own) [count]
750 """d(own) [count]
752 Move the current frame count (default one) levels down in the
751 Move the current frame count (default one) levels down in the
753 stack trace (to a newer frame).
752 stack trace (to a newer frame).
754
753
755 Will skip hidden frames.
754 Will skip hidden frames.
756 """
755 """
757 if self.curindex + 1 == len(self.stack):
756 if self.curindex + 1 == len(self.stack):
758 self.error("Newest frame")
757 self.error("Newest frame")
759 return
758 return
760 try:
759 try:
761 count = int(arg or 1)
760 count = int(arg or 1)
762 except ValueError:
761 except ValueError:
763 self.error("Invalid frame count (%s)" % arg)
762 self.error("Invalid frame count (%s)" % arg)
764 return
763 return
765 if count < 0:
764 if count < 0:
766 _newframe = len(self.stack) - 1
765 _newframe = len(self.stack) - 1
767 else:
766 else:
768 _newindex = self.curindex
767 _newindex = self.curindex
769 counter = 0
768 counter = 0
770 skipped = 0
769 skipped = 0
771 hidden_frames = self.hidden_frames(self.stack)
770 hidden_frames = self.hidden_frames(self.stack)
772 for i in range(self.curindex + 1, len(self.stack)):
771 for i in range(self.curindex + 1, len(self.stack)):
773 frame = self.stack[i][0]
772 frame = self.stack[i][0]
774 if hidden_frames[i] and self.skip_hidden:
773 if hidden_frames[i] and self.skip_hidden:
775 skipped += 1
774 skipped += 1
776 continue
775 continue
777 counter += 1
776 counter += 1
778 if counter >= count:
777 if counter >= count:
779 break
778 break
780 else:
779 else:
781 self.error(
780 self.error(
782 "all frames bellow hidden, use `skip_hidden False` to get get into those."
781 "all frames bellow hidden, use `skip_hidden False` to get get into those."
783 )
782 )
784 return
783 return
785
784
786 Colors = self.color_scheme_table.active_colors
785 Colors = self.color_scheme_table.active_colors
787 ColorsNormal = Colors.Normal
786 ColorsNormal = Colors.Normal
788 if skipped:
787 if skipped:
789 print(
788 print(
790 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
789 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
791 )
790 )
792 _newframe = i
791 _newframe = i
793
792
794 self._select_frame(_newframe)
793 self._select_frame(_newframe)
795
794
796 do_d = do_down
795 do_d = do_down
797 do_u = do_up
796 do_u = do_up
798
797
799 class InterruptiblePdb(Pdb):
798 class InterruptiblePdb(Pdb):
800 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
799 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
801
800
802 def cmdloop(self):
801 def cmdloop(self):
803 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
802 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
804 try:
803 try:
805 return OldPdb.cmdloop(self)
804 return OldPdb.cmdloop(self)
806 except KeyboardInterrupt:
805 except KeyboardInterrupt:
807 self.stop_here = lambda frame: False
806 self.stop_here = lambda frame: False
808 self.do_quit("")
807 self.do_quit("")
809 sys.settrace(None)
808 sys.settrace(None)
810 self.quitting = False
809 self.quitting = False
811 raise
810 raise
812
811
813 def _cmdloop(self):
812 def _cmdloop(self):
814 while True:
813 while True:
815 try:
814 try:
816 # keyboard interrupts allow for an easy way to cancel
815 # keyboard interrupts allow for an easy way to cancel
817 # the current command, so allow them during interactive input
816 # the current command, so allow them during interactive input
818 self.allow_kbdint = True
817 self.allow_kbdint = True
819 self.cmdloop()
818 self.cmdloop()
820 self.allow_kbdint = False
819 self.allow_kbdint = False
821 break
820 break
822 except KeyboardInterrupt:
821 except KeyboardInterrupt:
823 self.message('--KeyboardInterrupt--')
822 self.message('--KeyboardInterrupt--')
824 raise
823 raise
825
824
826
825
827 def set_trace(frame=None):
826 def set_trace(frame=None):
828 """
827 """
829 Start debugging from `frame`.
828 Start debugging from `frame`.
830
829
831 If frame is not specified, debugging starts from caller's frame.
830 If frame is not specified, debugging starts from caller's frame.
832 """
831 """
833 Pdb().set_trace(frame or sys._getframe().f_back)
832 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now