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