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