##// END OF EJS Templates
Make recursive pdb properly invoke IPython's enhanced pdb...
Segev Finer -
Show More
@@ -1,618 +1,637 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
35
36 from IPython import get_ipython
36 from IPython import get_ipython
37 from IPython.utils import PyColorize
37 from IPython.utils import PyColorize
38 from IPython.utils import coloransi, py3compat
38 from IPython.utils import coloransi, py3compat
39 from IPython.core.excolors import exception_colors
39 from IPython.core.excolors import exception_colors
40 from IPython.testing.skipdoctest import skip_doctest
40 from IPython.testing.skipdoctest import skip_doctest
41
41
42
42
43 prompt = 'ipdb> '
43 prompt = 'ipdb> '
44
44
45 #We have to check this directly from sys.argv, config struct not yet available
45 #We have to check this directly from sys.argv, config struct not yet available
46 from pdb import Pdb as OldPdb
46 from pdb import Pdb as OldPdb
47
47
48 # Allow the set_trace code to operate outside of an ipython instance, even if
48 # Allow the set_trace code to operate outside of an ipython instance, even if
49 # it does so with some limitations. The rest of this support is implemented in
49 # it does so with some limitations. The rest of this support is implemented in
50 # the Tracer constructor.
50 # the Tracer constructor.
51
51
52 def make_arrow(pad):
52 def make_arrow(pad):
53 """generate the leading arrow in front of traceback or debugger"""
53 """generate the leading arrow in front of traceback or debugger"""
54 if pad >= 2:
54 if pad >= 2:
55 return '-'*(pad-2) + '> '
55 return '-'*(pad-2) + '> '
56 elif pad == 1:
56 elif pad == 1:
57 return '>'
57 return '>'
58 return ''
58 return ''
59
59
60
60
61 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
61 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
62 """Exception hook which handles `BdbQuit` exceptions.
62 """Exception hook which handles `BdbQuit` exceptions.
63
63
64 All other exceptions are processed using the `excepthook`
64 All other exceptions are processed using the `excepthook`
65 parameter.
65 parameter.
66 """
66 """
67 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
67 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
68 DeprecationWarning, stacklevel=2)
68 DeprecationWarning, stacklevel=2)
69 if et==bdb.BdbQuit:
69 if et==bdb.BdbQuit:
70 print('Exiting Debugger.')
70 print('Exiting Debugger.')
71 elif excepthook is not None:
71 elif excepthook is not None:
72 excepthook(et, ev, tb)
72 excepthook(et, ev, tb)
73 else:
73 else:
74 # Backwards compatibility. Raise deprecation warning?
74 # Backwards compatibility. Raise deprecation warning?
75 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
75 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
76
76
77
77
78 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
78 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
79 warnings.warn(
79 warnings.warn(
80 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
80 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
81 DeprecationWarning, stacklevel=2)
81 DeprecationWarning, stacklevel=2)
82 print('Exiting Debugger.')
82 print('Exiting Debugger.')
83
83
84
84
85 class Tracer(object):
85 class Tracer(object):
86 """
86 """
87 DEPRECATED
87 DEPRECATED
88
88
89 Class for local debugging, similar to pdb.set_trace.
89 Class for local debugging, similar to pdb.set_trace.
90
90
91 Instances of this class, when called, behave like pdb.set_trace, but
91 Instances of this class, when called, behave like pdb.set_trace, but
92 providing IPython's enhanced capabilities.
92 providing IPython's enhanced capabilities.
93
93
94 This is implemented as a class which must be initialized in your own code
94 This is implemented as a class which must be initialized in your own code
95 and not as a standalone function because we need to detect at runtime
95 and not as a standalone function because we need to detect at runtime
96 whether IPython is already active or not. That detection is done in the
96 whether IPython is already active or not. That detection is done in the
97 constructor, ensuring that this code plays nicely with a running IPython,
97 constructor, ensuring that this code plays nicely with a running IPython,
98 while functioning acceptably (though with limitations) if outside of it.
98 while functioning acceptably (though with limitations) if outside of it.
99 """
99 """
100
100
101 @skip_doctest
101 @skip_doctest
102 def __init__(self, colors=None):
102 def __init__(self, colors=None):
103 """
103 """
104 DEPRECATED
104 DEPRECATED
105
105
106 Create a local debugger instance.
106 Create a local debugger instance.
107
107
108 Parameters
108 Parameters
109 ----------
109 ----------
110
110
111 colors : str, optional
111 colors : str, optional
112 The name of the color scheme to use, it must be one of IPython's
112 The name of the color scheme to use, it must be one of IPython's
113 valid color schemes. If not given, the function will default to
113 valid color schemes. If not given, the function will default to
114 the current IPython scheme when running inside IPython, and to
114 the current IPython scheme when running inside IPython, and to
115 'NoColor' otherwise.
115 'NoColor' otherwise.
116
116
117 Examples
117 Examples
118 --------
118 --------
119 ::
119 ::
120
120
121 from IPython.core.debugger import Tracer; debug_here = Tracer()
121 from IPython.core.debugger import Tracer; debug_here = Tracer()
122
122
123 Later in your code::
123 Later in your code::
124
124
125 debug_here() # -> will open up the debugger at that point.
125 debug_here() # -> will open up the debugger at that point.
126
126
127 Once the debugger activates, you can use all of its regular commands to
127 Once the debugger activates, you can use all of its regular commands to
128 step through code, set breakpoints, etc. See the pdb documentation
128 step through code, set breakpoints, etc. See the pdb documentation
129 from the Python standard library for usage details.
129 from the Python standard library for usage details.
130 """
130 """
131 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
131 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
132 "`IPython.core.debugger.Pdb.set_trace()`",
132 "`IPython.core.debugger.Pdb.set_trace()`",
133 DeprecationWarning, stacklevel=2)
133 DeprecationWarning, stacklevel=2)
134
134
135 ip = get_ipython()
135 ip = get_ipython()
136 if ip is None:
136 if ip is None:
137 # Outside of ipython, we set our own exception hook manually
137 # Outside of ipython, we set our own exception hook manually
138 sys.excepthook = functools.partial(BdbQuit_excepthook,
138 sys.excepthook = functools.partial(BdbQuit_excepthook,
139 excepthook=sys.excepthook)
139 excepthook=sys.excepthook)
140 def_colors = 'NoColor'
140 def_colors = 'NoColor'
141 else:
141 else:
142 # In ipython, we use its custom exception handler mechanism
142 # In ipython, we use its custom exception handler mechanism
143 def_colors = ip.colors
143 def_colors = ip.colors
144 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
144 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
145
145
146 if colors is None:
146 if colors is None:
147 colors = def_colors
147 colors = def_colors
148
148
149 # The stdlib debugger internally uses a modified repr from the `repr`
149 # The stdlib debugger internally uses a modified repr from the `repr`
150 # module, that limits the length of printed strings to a hardcoded
150 # module, that limits the length of printed strings to a hardcoded
151 # limit of 30 characters. That much trimming is too aggressive, let's
151 # limit of 30 characters. That much trimming is too aggressive, let's
152 # at least raise that limit to 80 chars, which should be enough for
152 # at least raise that limit to 80 chars, which should be enough for
153 # most interactive uses.
153 # most interactive uses.
154 try:
154 try:
155 try:
155 try:
156 from reprlib import aRepr # Py 3
156 from reprlib import aRepr # Py 3
157 except ImportError:
157 except ImportError:
158 from repr import aRepr # Py 2
158 from repr import aRepr # Py 2
159 aRepr.maxstring = 80
159 aRepr.maxstring = 80
160 except:
160 except:
161 # This is only a user-facing convenience, so any error we encounter
161 # This is only a user-facing convenience, so any error we encounter
162 # here can be warned about but can be otherwise ignored. These
162 # here can be warned about but can be otherwise ignored. These
163 # printouts will tell us about problems if this API changes
163 # printouts will tell us about problems if this API changes
164 import traceback
164 import traceback
165 traceback.print_exc()
165 traceback.print_exc()
166
166
167 self.debugger = Pdb(colors)
167 self.debugger = Pdb(colors)
168
168
169 def __call__(self):
169 def __call__(self):
170 """Starts an interactive debugger at the point where called.
170 """Starts an interactive debugger at the point where called.
171
171
172 This is similar to the pdb.set_trace() function from the std lib, but
172 This is similar to the pdb.set_trace() function from the std lib, but
173 using IPython's enhanced debugger."""
173 using IPython's enhanced debugger."""
174
174
175 self.debugger.set_trace(sys._getframe().f_back)
175 self.debugger.set_trace(sys._getframe().f_back)
176
176
177
177
178 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
178 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
179 """Make new_fn have old_fn's doc string. This is particularly useful
179 """Make new_fn have old_fn's doc string. This is particularly useful
180 for the ``do_...`` commands that hook into the help system.
180 for the ``do_...`` commands that hook into the help system.
181 Adapted from from a comp.lang.python posting
181 Adapted from from a comp.lang.python posting
182 by Duncan Booth."""
182 by Duncan Booth."""
183 def wrapper(*args, **kw):
183 def wrapper(*args, **kw):
184 return new_fn(*args, **kw)
184 return new_fn(*args, **kw)
185 if old_fn.__doc__:
185 if old_fn.__doc__:
186 wrapper.__doc__ = old_fn.__doc__ + additional_text
186 wrapper.__doc__ = old_fn.__doc__ + additional_text
187 return wrapper
187 return wrapper
188
188
189
189
190 def _file_lines(fname):
190 def _file_lines(fname):
191 """Return the contents of a named file as a list of lines.
191 """Return the contents of a named file as a list of lines.
192
192
193 This function never raises an IOError exception: if the file can't be
193 This function never raises an IOError exception: if the file can't be
194 read, it simply returns an empty list."""
194 read, it simply returns an empty list."""
195
195
196 try:
196 try:
197 outfile = open(fname)
197 outfile = open(fname)
198 except IOError:
198 except IOError:
199 return []
199 return []
200 else:
200 else:
201 out = outfile.readlines()
201 out = outfile.readlines()
202 outfile.close()
202 outfile.close()
203 return out
203 return out
204
204
205
205
206 class Pdb(OldPdb):
206 class Pdb(OldPdb):
207 """Modified Pdb class, does not load readline.
207 """Modified Pdb class, does not load readline.
208
208
209 for a standalone version that uses prompt_toolkit, see
209 for a standalone version that uses prompt_toolkit, see
210 `IPython.terminal.debugger.TerminalPdb` and
210 `IPython.terminal.debugger.TerminalPdb` and
211 `IPython.terminal.debugger.set_trace()`
211 `IPython.terminal.debugger.set_trace()`
212 """
212 """
213
213
214 def __init__(self, color_scheme=None, completekey=None,
214 def __init__(self, color_scheme=None, completekey=None,
215 stdin=None, stdout=None, context=5):
215 stdin=None, stdout=None, context=5):
216
216
217 # Parent constructor:
217 # Parent constructor:
218 try:
218 try:
219 self.context = int(context)
219 self.context = int(context)
220 if self.context <= 0:
220 if self.context <= 0:
221 raise ValueError("Context must be a positive integer")
221 raise ValueError("Context must be a positive integer")
222 except (TypeError, ValueError):
222 except (TypeError, ValueError):
223 raise ValueError("Context must be a positive integer")
223 raise ValueError("Context must be a positive integer")
224
224
225 OldPdb.__init__(self, completekey, stdin, stdout)
225 OldPdb.__init__(self, completekey, stdin, stdout)
226
226
227 # IPython changes...
227 # IPython changes...
228 self.shell = get_ipython()
228 self.shell = get_ipython()
229
229
230 if self.shell is None:
230 if self.shell is None:
231 save_main = sys.modules['__main__']
231 save_main = sys.modules['__main__']
232 # No IPython instance running, we must create one
232 # No IPython instance running, we must create one
233 from IPython.terminal.interactiveshell import \
233 from IPython.terminal.interactiveshell import \
234 TerminalInteractiveShell
234 TerminalInteractiveShell
235 self.shell = TerminalInteractiveShell.instance()
235 self.shell = TerminalInteractiveShell.instance()
236 # needed by any code which calls __import__("__main__") after
236 # needed by any code which calls __import__("__main__") after
237 # the debugger was entered. See also #9941.
237 # the debugger was entered. See also #9941.
238 sys.modules['__main__'] = save_main
238 sys.modules['__main__'] = save_main
239
239
240 if color_scheme is not None:
240 if color_scheme is not None:
241 warnings.warn(
241 warnings.warn(
242 "The `color_scheme` argument is deprecated since version 5.1",
242 "The `color_scheme` argument is deprecated since version 5.1",
243 DeprecationWarning, stacklevel=2)
243 DeprecationWarning, stacklevel=2)
244 else:
244 else:
245 color_scheme = self.shell.colors
245 color_scheme = self.shell.colors
246
246
247 self.aliases = {}
247 self.aliases = {}
248
248
249 # Create color table: we copy the default one from the traceback
249 # Create color table: we copy the default one from the traceback
250 # module and add a few attributes needed for debugging
250 # module and add a few attributes needed for debugging
251 self.color_scheme_table = exception_colors()
251 self.color_scheme_table = exception_colors()
252
252
253 # shorthands
253 # shorthands
254 C = coloransi.TermColors
254 C = coloransi.TermColors
255 cst = self.color_scheme_table
255 cst = self.color_scheme_table
256
256
257 cst['NoColor'].colors.prompt = C.NoColor
257 cst['NoColor'].colors.prompt = C.NoColor
258 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
258 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
259 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
259 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
260
260
261 cst['Linux'].colors.prompt = C.Green
261 cst['Linux'].colors.prompt = C.Green
262 cst['Linux'].colors.breakpoint_enabled = C.LightRed
262 cst['Linux'].colors.breakpoint_enabled = C.LightRed
263 cst['Linux'].colors.breakpoint_disabled = C.Red
263 cst['Linux'].colors.breakpoint_disabled = C.Red
264
264
265 cst['LightBG'].colors.prompt = C.Blue
265 cst['LightBG'].colors.prompt = C.Blue
266 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
266 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
267 cst['LightBG'].colors.breakpoint_disabled = C.Red
267 cst['LightBG'].colors.breakpoint_disabled = C.Red
268
268
269 cst['Neutral'].colors.prompt = C.Blue
269 cst['Neutral'].colors.prompt = C.Blue
270 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
270 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
271 cst['Neutral'].colors.breakpoint_disabled = C.Red
271 cst['Neutral'].colors.breakpoint_disabled = C.Red
272
272
273
273
274 # Add a python parser so we can syntax highlight source while
274 # Add a python parser so we can syntax highlight source while
275 # debugging.
275 # debugging.
276 self.parser = PyColorize.Parser(style=color_scheme)
276 self.parser = PyColorize.Parser(style=color_scheme)
277 self.set_colors(color_scheme)
277 self.set_colors(color_scheme)
278
278
279 # Set the prompt - the default prompt is '(Pdb)'
279 # Set the prompt - the default prompt is '(Pdb)'
280 self.prompt = prompt
280 self.prompt = prompt
281
281
282 def set_colors(self, scheme):
282 def set_colors(self, scheme):
283 """Shorthand access to the color table scheme selector method."""
283 """Shorthand access to the color table scheme selector method."""
284 self.color_scheme_table.set_active_scheme(scheme)
284 self.color_scheme_table.set_active_scheme(scheme)
285 self.parser.style = scheme
285 self.parser.style = scheme
286
286
287 def interaction(self, frame, traceback):
287 def interaction(self, frame, traceback):
288 try:
288 try:
289 OldPdb.interaction(self, frame, traceback)
289 OldPdb.interaction(self, frame, traceback)
290 except KeyboardInterrupt:
290 except KeyboardInterrupt:
291 sys.stdout.write('\n' + self.shell.get_exception_only())
291 sys.stdout.write('\n' + self.shell.get_exception_only())
292
292
293 def new_do_up(self, arg):
293 def new_do_up(self, arg):
294 OldPdb.do_up(self, arg)
294 OldPdb.do_up(self, arg)
295 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
295 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
296
296
297 def new_do_down(self, arg):
297 def new_do_down(self, arg):
298 OldPdb.do_down(self, arg)
298 OldPdb.do_down(self, arg)
299
299
300 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
300 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
301
301
302 def new_do_frame(self, arg):
302 def new_do_frame(self, arg):
303 OldPdb.do_frame(self, arg)
303 OldPdb.do_frame(self, arg)
304
304
305 def new_do_quit(self, arg):
305 def new_do_quit(self, arg):
306
306
307 if hasattr(self, 'old_all_completions'):
307 if hasattr(self, 'old_all_completions'):
308 self.shell.Completer.all_completions=self.old_all_completions
308 self.shell.Completer.all_completions=self.old_all_completions
309
309
310 return OldPdb.do_quit(self, arg)
310 return OldPdb.do_quit(self, arg)
311
311
312 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
312 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
313
313
314 def new_do_restart(self, arg):
314 def new_do_restart(self, arg):
315 """Restart command. In the context of ipython this is exactly the same
315 """Restart command. In the context of ipython this is exactly the same
316 thing as 'quit'."""
316 thing as 'quit'."""
317 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
317 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
318 return self.do_quit(arg)
318 return self.do_quit(arg)
319
319
320 def print_stack_trace(self, context=None):
320 def print_stack_trace(self, context=None):
321 if context is None:
321 if context is None:
322 context = self.context
322 context = self.context
323 try:
323 try:
324 context=int(context)
324 context=int(context)
325 if context <= 0:
325 if context <= 0:
326 raise ValueError("Context must be a positive integer")
326 raise ValueError("Context must be a positive integer")
327 except (TypeError, ValueError):
327 except (TypeError, ValueError):
328 raise ValueError("Context must be a positive integer")
328 raise ValueError("Context must be a positive integer")
329 try:
329 try:
330 for frame_lineno in self.stack:
330 for frame_lineno in self.stack:
331 self.print_stack_entry(frame_lineno, context=context)
331 self.print_stack_entry(frame_lineno, context=context)
332 except KeyboardInterrupt:
332 except KeyboardInterrupt:
333 pass
333 pass
334
334
335 def print_stack_entry(self,frame_lineno, prompt_prefix='\n-> ',
335 def print_stack_entry(self,frame_lineno, prompt_prefix='\n-> ',
336 context=None):
336 context=None):
337 if context is None:
337 if context is None:
338 context = self.context
338 context = self.context
339 try:
339 try:
340 context=int(context)
340 context=int(context)
341 if context <= 0:
341 if context <= 0:
342 raise ValueError("Context must be a positive integer")
342 raise ValueError("Context must be a positive integer")
343 except (TypeError, ValueError):
343 except (TypeError, ValueError):
344 raise ValueError("Context must be a positive integer")
344 raise ValueError("Context must be a positive integer")
345 print(self.format_stack_entry(frame_lineno, '', context))
345 print(self.format_stack_entry(frame_lineno, '', context))
346
346
347 # vds: >>
347 # vds: >>
348 frame, lineno = frame_lineno
348 frame, lineno = frame_lineno
349 filename = frame.f_code.co_filename
349 filename = frame.f_code.co_filename
350 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
350 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
351 # vds: <<
351 # vds: <<
352
352
353 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
353 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
354 if context is None:
354 if context is None:
355 context = self.context
355 context = self.context
356 try:
356 try:
357 context=int(context)
357 context=int(context)
358 if context <= 0:
358 if context <= 0:
359 print("Context must be a positive integer")
359 print("Context must be a positive integer")
360 except (TypeError, ValueError):
360 except (TypeError, ValueError):
361 print("Context must be a positive integer")
361 print("Context must be a positive integer")
362 try:
362 try:
363 import reprlib # Py 3
363 import reprlib # Py 3
364 except ImportError:
364 except ImportError:
365 import repr as reprlib # Py 2
365 import repr as reprlib # Py 2
366
366
367 ret = []
367 ret = []
368
368
369 Colors = self.color_scheme_table.active_colors
369 Colors = self.color_scheme_table.active_colors
370 ColorsNormal = Colors.Normal
370 ColorsNormal = Colors.Normal
371 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
371 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
372 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
372 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
373 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
373 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
374 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
374 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
375 ColorsNormal)
375 ColorsNormal)
376
376
377 frame, lineno = frame_lineno
377 frame, lineno = frame_lineno
378
378
379 return_value = ''
379 return_value = ''
380 if '__return__' in frame.f_locals:
380 if '__return__' in frame.f_locals:
381 rv = frame.f_locals['__return__']
381 rv = frame.f_locals['__return__']
382 #return_value += '->'
382 #return_value += '->'
383 return_value += reprlib.repr(rv) + '\n'
383 return_value += reprlib.repr(rv) + '\n'
384 ret.append(return_value)
384 ret.append(return_value)
385
385
386 #s = filename + '(' + `lineno` + ')'
386 #s = filename + '(' + `lineno` + ')'
387 filename = self.canonic(frame.f_code.co_filename)
387 filename = self.canonic(frame.f_code.co_filename)
388 link = tpl_link % py3compat.cast_unicode(filename)
388 link = tpl_link % py3compat.cast_unicode(filename)
389
389
390 if frame.f_code.co_name:
390 if frame.f_code.co_name:
391 func = frame.f_code.co_name
391 func = frame.f_code.co_name
392 else:
392 else:
393 func = "<lambda>"
393 func = "<lambda>"
394
394
395 call = ''
395 call = ''
396 if func != '?':
396 if func != '?':
397 if '__args__' in frame.f_locals:
397 if '__args__' in frame.f_locals:
398 args = reprlib.repr(frame.f_locals['__args__'])
398 args = reprlib.repr(frame.f_locals['__args__'])
399 else:
399 else:
400 args = '()'
400 args = '()'
401 call = tpl_call % (func, args)
401 call = tpl_call % (func, args)
402
402
403 # The level info should be generated in the same format pdb uses, to
403 # The level info should be generated in the same format pdb uses, to
404 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
404 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
405 if frame is self.curframe:
405 if frame is self.curframe:
406 ret.append('> ')
406 ret.append('> ')
407 else:
407 else:
408 ret.append(' ')
408 ret.append(' ')
409 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
409 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
410
410
411 start = lineno - 1 - context//2
411 start = lineno - 1 - context//2
412 lines = linecache.getlines(filename)
412 lines = linecache.getlines(filename)
413 start = min(start, len(lines) - context)
413 start = min(start, len(lines) - context)
414 start = max(start, 0)
414 start = max(start, 0)
415 lines = lines[start : start + context]
415 lines = lines[start : start + context]
416
416
417 for i,line in enumerate(lines):
417 for i,line in enumerate(lines):
418 show_arrow = (start + 1 + i == lineno)
418 show_arrow = (start + 1 + i == lineno)
419 linetpl = (frame is self.curframe or show_arrow) \
419 linetpl = (frame is self.curframe or show_arrow) \
420 and tpl_line_em \
420 and tpl_line_em \
421 or tpl_line
421 or tpl_line
422 ret.append(self.__format_line(linetpl, filename,
422 ret.append(self.__format_line(linetpl, filename,
423 start + 1 + i, line,
423 start + 1 + i, line,
424 arrow = show_arrow) )
424 arrow = show_arrow) )
425 return ''.join(ret)
425 return ''.join(ret)
426
426
427 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
427 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
428 bp_mark = ""
428 bp_mark = ""
429 bp_mark_color = ""
429 bp_mark_color = ""
430
430
431 new_line, err = self.parser.format2(line, 'str')
431 new_line, err = self.parser.format2(line, 'str')
432 if not err:
432 if not err:
433 line = new_line
433 line = new_line
434
434
435 bp = None
435 bp = None
436 if lineno in self.get_file_breaks(filename):
436 if lineno in self.get_file_breaks(filename):
437 bps = self.get_breaks(filename, lineno)
437 bps = self.get_breaks(filename, lineno)
438 bp = bps[-1]
438 bp = bps[-1]
439
439
440 if bp:
440 if bp:
441 Colors = self.color_scheme_table.active_colors
441 Colors = self.color_scheme_table.active_colors
442 bp_mark = str(bp.number)
442 bp_mark = str(bp.number)
443 bp_mark_color = Colors.breakpoint_enabled
443 bp_mark_color = Colors.breakpoint_enabled
444 if not bp.enabled:
444 if not bp.enabled:
445 bp_mark_color = Colors.breakpoint_disabled
445 bp_mark_color = Colors.breakpoint_disabled
446
446
447 numbers_width = 7
447 numbers_width = 7
448 if arrow:
448 if arrow:
449 # This is the line with the error
449 # This is the line with the error
450 pad = numbers_width - len(str(lineno)) - len(bp_mark)
450 pad = numbers_width - len(str(lineno)) - len(bp_mark)
451 num = '%s%s' % (make_arrow(pad), str(lineno))
451 num = '%s%s' % (make_arrow(pad), str(lineno))
452 else:
452 else:
453 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
453 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
454
454
455 return tpl_line % (bp_mark_color + bp_mark, num, line)
455 return tpl_line % (bp_mark_color + bp_mark, num, line)
456
456
457
457
458 def print_list_lines(self, filename, first, last):
458 def print_list_lines(self, filename, first, last):
459 """The printing (as opposed to the parsing part of a 'list'
459 """The printing (as opposed to the parsing part of a 'list'
460 command."""
460 command."""
461 try:
461 try:
462 Colors = self.color_scheme_table.active_colors
462 Colors = self.color_scheme_table.active_colors
463 ColorsNormal = Colors.Normal
463 ColorsNormal = Colors.Normal
464 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
464 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
465 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
465 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
466 src = []
466 src = []
467 if filename == "<string>" and hasattr(self, "_exec_filename"):
467 if filename == "<string>" and hasattr(self, "_exec_filename"):
468 filename = self._exec_filename
468 filename = self._exec_filename
469
469
470 for lineno in range(first, last+1):
470 for lineno in range(first, last+1):
471 line = linecache.getline(filename, lineno)
471 line = linecache.getline(filename, lineno)
472 if not line:
472 if not line:
473 break
473 break
474
474
475 if lineno == self.curframe.f_lineno:
475 if lineno == self.curframe.f_lineno:
476 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
476 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
477 else:
477 else:
478 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
478 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
479
479
480 src.append(line)
480 src.append(line)
481 self.lineno = lineno
481 self.lineno = lineno
482
482
483 print(''.join(src))
483 print(''.join(src))
484
484
485 except KeyboardInterrupt:
485 except KeyboardInterrupt:
486 pass
486 pass
487
487
488 def do_list(self, arg):
488 def do_list(self, arg):
489 """Print lines of code from the current stack frame
489 """Print lines of code from the current stack frame
490 """
490 """
491 self.lastcmd = 'list'
491 self.lastcmd = 'list'
492 last = None
492 last = None
493 if arg:
493 if arg:
494 try:
494 try:
495 x = eval(arg, {}, {})
495 x = eval(arg, {}, {})
496 if type(x) == type(()):
496 if type(x) == type(()):
497 first, last = x
497 first, last = x
498 first = int(first)
498 first = int(first)
499 last = int(last)
499 last = int(last)
500 if last < first:
500 if last < first:
501 # Assume it's a count
501 # Assume it's a count
502 last = first + last
502 last = first + last
503 else:
503 else:
504 first = max(1, int(x) - 5)
504 first = max(1, int(x) - 5)
505 except:
505 except:
506 print('*** Error in argument:', repr(arg))
506 print('*** Error in argument:', repr(arg))
507 return
507 return
508 elif self.lineno is None:
508 elif self.lineno is None:
509 first = max(1, self.curframe.f_lineno - 5)
509 first = max(1, self.curframe.f_lineno - 5)
510 else:
510 else:
511 first = self.lineno + 1
511 first = self.lineno + 1
512 if last is None:
512 if last is None:
513 last = first + 10
513 last = first + 10
514 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
514 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
515
515
516 # vds: >>
516 # vds: >>
517 lineno = first
517 lineno = first
518 filename = self.curframe.f_code.co_filename
518 filename = self.curframe.f_code.co_filename
519 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
519 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
520 # vds: <<
520 # vds: <<
521
521
522 do_l = do_list
522 do_l = do_list
523
523
524 def getsourcelines(self, obj):
524 def getsourcelines(self, obj):
525 lines, lineno = inspect.findsource(obj)
525 lines, lineno = inspect.findsource(obj)
526 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
526 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
527 # must be a module frame: do not try to cut a block out of it
527 # must be a module frame: do not try to cut a block out of it
528 return lines, 1
528 return lines, 1
529 elif inspect.ismodule(obj):
529 elif inspect.ismodule(obj):
530 return lines, 1
530 return lines, 1
531 return inspect.getblock(lines[lineno:]), lineno+1
531 return inspect.getblock(lines[lineno:]), lineno+1
532
532
533 def do_longlist(self, arg):
533 def do_longlist(self, arg):
534 """Print lines of code from the current stack frame.
534 """Print lines of code from the current stack frame.
535
535
536 Shows more lines than 'list' does.
536 Shows more lines than 'list' does.
537 """
537 """
538 self.lastcmd = 'longlist'
538 self.lastcmd = 'longlist'
539 try:
539 try:
540 lines, lineno = self.getsourcelines(self.curframe)
540 lines, lineno = self.getsourcelines(self.curframe)
541 except OSError as err:
541 except OSError as err:
542 self.error(err)
542 self.error(err)
543 return
543 return
544 last = lineno + len(lines)
544 last = lineno + len(lines)
545 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
545 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
546 do_ll = do_longlist
546 do_ll = do_longlist
547
547
548 def do_debug(self, arg):
549 """debug code
550 Enter a recursive debugger that steps through the code
551 argument (which is an arbitrary expression or statement to be
552 executed in the current environment).
553 """
554 sys.settrace(None)
555 globals = self.curframe.f_globals
556 locals = self.curframe_locals
557 p = self.__class__(completekey=self.completekey,
558 stdin=self.stdin, stdout=self.stdout)
559 p.use_rawinput = self.use_rawinput
560 p.prompt = "(%s) " % self.prompt.strip()
561 self.message("ENTERING RECURSIVE DEBUGGER")
562 sys.call_tracing(p.run, (arg, globals, locals))
563 self.message("LEAVING RECURSIVE DEBUGGER")
564 sys.settrace(self.trace_dispatch)
565 self.lastcmd = p.lastcmd
566
548 def do_pdef(self, arg):
567 def do_pdef(self, arg):
549 """Print the call signature for any callable object.
568 """Print the call signature for any callable object.
550
569
551 The debugger interface to %pdef"""
570 The debugger interface to %pdef"""
552 namespaces = [('Locals', self.curframe.f_locals),
571 namespaces = [('Locals', self.curframe.f_locals),
553 ('Globals', self.curframe.f_globals)]
572 ('Globals', self.curframe.f_globals)]
554 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
573 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
555
574
556 def do_pdoc(self, arg):
575 def do_pdoc(self, arg):
557 """Print the docstring for an object.
576 """Print the docstring for an object.
558
577
559 The debugger interface to %pdoc."""
578 The debugger interface to %pdoc."""
560 namespaces = [('Locals', self.curframe.f_locals),
579 namespaces = [('Locals', self.curframe.f_locals),
561 ('Globals', self.curframe.f_globals)]
580 ('Globals', self.curframe.f_globals)]
562 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
581 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
563
582
564 def do_pfile(self, arg):
583 def do_pfile(self, arg):
565 """Print (or run through pager) the file where an object is defined.
584 """Print (or run through pager) the file where an object is defined.
566
585
567 The debugger interface to %pfile.
586 The debugger interface to %pfile.
568 """
587 """
569 namespaces = [('Locals', self.curframe.f_locals),
588 namespaces = [('Locals', self.curframe.f_locals),
570 ('Globals', self.curframe.f_globals)]
589 ('Globals', self.curframe.f_globals)]
571 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
590 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
572
591
573 def do_pinfo(self, arg):
592 def do_pinfo(self, arg):
574 """Provide detailed information about an object.
593 """Provide detailed information about an object.
575
594
576 The debugger interface to %pinfo, i.e., obj?."""
595 The debugger interface to %pinfo, i.e., obj?."""
577 namespaces = [('Locals', self.curframe.f_locals),
596 namespaces = [('Locals', self.curframe.f_locals),
578 ('Globals', self.curframe.f_globals)]
597 ('Globals', self.curframe.f_globals)]
579 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
598 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
580
599
581 def do_pinfo2(self, arg):
600 def do_pinfo2(self, arg):
582 """Provide extra detailed information about an object.
601 """Provide extra detailed information about an object.
583
602
584 The debugger interface to %pinfo2, i.e., obj??."""
603 The debugger interface to %pinfo2, i.e., obj??."""
585 namespaces = [('Locals', self.curframe.f_locals),
604 namespaces = [('Locals', self.curframe.f_locals),
586 ('Globals', self.curframe.f_globals)]
605 ('Globals', self.curframe.f_globals)]
587 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
606 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
588
607
589 def do_psource(self, arg):
608 def do_psource(self, arg):
590 """Print (or run through pager) the source code for an object."""
609 """Print (or run through pager) the source code for an object."""
591 namespaces = [('Locals', self.curframe.f_locals),
610 namespaces = [('Locals', self.curframe.f_locals),
592 ('Globals', self.curframe.f_globals)]
611 ('Globals', self.curframe.f_globals)]
593 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
612 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
594
613
595 def do_where(self, arg):
614 def do_where(self, arg):
596 """w(here)
615 """w(here)
597 Print a stack trace, with the most recent frame at the bottom.
616 Print a stack trace, with the most recent frame at the bottom.
598 An arrow indicates the "current frame", which determines the
617 An arrow indicates the "current frame", which determines the
599 context of most commands. 'bt' is an alias for this command.
618 context of most commands. 'bt' is an alias for this command.
600
619
601 Take a number as argument as an (optional) number of context line to
620 Take a number as argument as an (optional) number of context line to
602 print"""
621 print"""
603 if arg:
622 if arg:
604 context = int(arg)
623 context = int(arg)
605 self.print_stack_trace(context)
624 self.print_stack_trace(context)
606 else:
625 else:
607 self.print_stack_trace()
626 self.print_stack_trace()
608
627
609 do_w = do_where
628 do_w = do_where
610
629
611
630
612 def set_trace(frame=None):
631 def set_trace(frame=None):
613 """
632 """
614 Start debugging from `frame`.
633 Start debugging from `frame`.
615
634
616 If frame is not specified, debugging starts from caller's frame.
635 If frame is not specified, debugging starts from caller's frame.
617 """
636 """
618 Pdb().set_trace(frame or sys._getframe().f_back)
637 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now