##// END OF EJS Templates
Merge pull request #11777 from kmaork/bugfix/debugger-stdout...
Matthias Bussonnier -
r25084:257e4c45 merge
parent child Browse files
Show More
@@ -1,644 +1,644 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 def _file_lines(fname):
198 def _file_lines(fname):
199 """Return the contents of a named file as a list of lines.
199 """Return the contents of a named file as a list of lines.
200
200
201 This function never raises an IOError exception: if the file can't be
201 This function never raises an IOError exception: if the file can't be
202 read, it simply returns an empty list."""
202 read, it simply returns an empty list."""
203
203
204 try:
204 try:
205 outfile = open(fname)
205 outfile = open(fname)
206 except IOError:
206 except IOError:
207 return []
207 return []
208 else:
208 else:
209 with out:
209 with out:
210 return outfile.readlines()
210 return outfile.readlines()
211
211
212
212
213 class Pdb(OldPdb):
213 class Pdb(OldPdb):
214 """Modified Pdb class, does not load readline.
214 """Modified Pdb class, does not load readline.
215
215
216 for a standalone version that uses prompt_toolkit, see
216 for a standalone version that uses prompt_toolkit, see
217 `IPython.terminal.debugger.TerminalPdb` and
217 `IPython.terminal.debugger.TerminalPdb` and
218 `IPython.terminal.debugger.set_trace()`
218 `IPython.terminal.debugger.set_trace()`
219 """
219 """
220
220
221 def __init__(self, color_scheme=None, completekey=None,
221 def __init__(self, color_scheme=None, completekey=None,
222 stdin=None, stdout=None, context=5):
222 stdin=None, stdout=None, context=5):
223
223
224 # Parent constructor:
224 # Parent constructor:
225 try:
225 try:
226 self.context = int(context)
226 self.context = int(context)
227 if self.context <= 0:
227 if self.context <= 0:
228 raise ValueError("Context must be a positive integer")
228 raise ValueError("Context must be a positive integer")
229 except (TypeError, ValueError):
229 except (TypeError, ValueError):
230 raise ValueError("Context must be a positive integer")
230 raise ValueError("Context must be a positive integer")
231
231
232 OldPdb.__init__(self, completekey, stdin, stdout)
232 OldPdb.__init__(self, completekey, stdin, stdout)
233
233
234 # IPython changes...
234 # IPython changes...
235 self.shell = get_ipython()
235 self.shell = get_ipython()
236
236
237 if self.shell is None:
237 if self.shell is None:
238 save_main = sys.modules['__main__']
238 save_main = sys.modules['__main__']
239 # No IPython instance running, we must create one
239 # No IPython instance running, we must create one
240 from IPython.terminal.interactiveshell import \
240 from IPython.terminal.interactiveshell import \
241 TerminalInteractiveShell
241 TerminalInteractiveShell
242 self.shell = TerminalInteractiveShell.instance()
242 self.shell = TerminalInteractiveShell.instance()
243 # needed by any code which calls __import__("__main__") after
243 # needed by any code which calls __import__("__main__") after
244 # the debugger was entered. See also #9941.
244 # the debugger was entered. See also #9941.
245 sys.modules['__main__'] = save_main
245 sys.modules['__main__'] = save_main
246
246
247 if color_scheme is not None:
247 if color_scheme is not None:
248 warnings.warn(
248 warnings.warn(
249 "The `color_scheme` argument is deprecated since version 5.1",
249 "The `color_scheme` argument is deprecated since version 5.1",
250 DeprecationWarning, stacklevel=2)
250 DeprecationWarning, stacklevel=2)
251 else:
251 else:
252 color_scheme = self.shell.colors
252 color_scheme = self.shell.colors
253
253
254 self.aliases = {}
254 self.aliases = {}
255
255
256 # Create color table: we copy the default one from the traceback
256 # Create color table: we copy the default one from the traceback
257 # module and add a few attributes needed for debugging
257 # module and add a few attributes needed for debugging
258 self.color_scheme_table = exception_colors()
258 self.color_scheme_table = exception_colors()
259
259
260 # shorthands
260 # shorthands
261 C = coloransi.TermColors
261 C = coloransi.TermColors
262 cst = self.color_scheme_table
262 cst = self.color_scheme_table
263
263
264 cst['NoColor'].colors.prompt = C.NoColor
264 cst['NoColor'].colors.prompt = C.NoColor
265 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
265 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
266 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
266 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
267
267
268 cst['Linux'].colors.prompt = C.Green
268 cst['Linux'].colors.prompt = C.Green
269 cst['Linux'].colors.breakpoint_enabled = C.LightRed
269 cst['Linux'].colors.breakpoint_enabled = C.LightRed
270 cst['Linux'].colors.breakpoint_disabled = C.Red
270 cst['Linux'].colors.breakpoint_disabled = C.Red
271
271
272 cst['LightBG'].colors.prompt = C.Blue
272 cst['LightBG'].colors.prompt = C.Blue
273 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
273 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
274 cst['LightBG'].colors.breakpoint_disabled = C.Red
274 cst['LightBG'].colors.breakpoint_disabled = C.Red
275
275
276 cst['Neutral'].colors.prompt = C.Blue
276 cst['Neutral'].colors.prompt = C.Blue
277 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
277 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
278 cst['Neutral'].colors.breakpoint_disabled = C.Red
278 cst['Neutral'].colors.breakpoint_disabled = C.Red
279
279
280
280
281 # Add a python parser so we can syntax highlight source while
281 # Add a python parser so we can syntax highlight source while
282 # debugging.
282 # debugging.
283 self.parser = PyColorize.Parser(style=color_scheme)
283 self.parser = PyColorize.Parser(style=color_scheme)
284 self.set_colors(color_scheme)
284 self.set_colors(color_scheme)
285
285
286 # Set the prompt - the default prompt is '(Pdb)'
286 # Set the prompt - the default prompt is '(Pdb)'
287 self.prompt = prompt
287 self.prompt = prompt
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 interaction(self, frame, traceback):
294 def interaction(self, frame, traceback):
295 try:
295 try:
296 OldPdb.interaction(self, frame, traceback)
296 OldPdb.interaction(self, frame, traceback)
297 except KeyboardInterrupt:
297 except KeyboardInterrupt:
298 sys.stdout.write('\n' + self.shell.get_exception_only())
298 self.stdout.write('\n' + self.shell.get_exception_only())
299
299
300 def new_do_up(self, arg):
300 def new_do_up(self, arg):
301 OldPdb.do_up(self, arg)
301 OldPdb.do_up(self, arg)
302 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
302 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
303
303
304 def new_do_down(self, arg):
304 def new_do_down(self, arg):
305 OldPdb.do_down(self, arg)
305 OldPdb.do_down(self, arg)
306
306
307 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
307 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
308
308
309 def new_do_frame(self, arg):
309 def new_do_frame(self, arg):
310 OldPdb.do_frame(self, arg)
310 OldPdb.do_frame(self, arg)
311
311
312 def new_do_quit(self, arg):
312 def new_do_quit(self, arg):
313
313
314 if hasattr(self, 'old_all_completions'):
314 if hasattr(self, 'old_all_completions'):
315 self.shell.Completer.all_completions=self.old_all_completions
315 self.shell.Completer.all_completions=self.old_all_completions
316
316
317 return OldPdb.do_quit(self, arg)
317 return OldPdb.do_quit(self, arg)
318
318
319 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
319 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
320
320
321 def new_do_restart(self, arg):
321 def new_do_restart(self, arg):
322 """Restart command. In the context of ipython this is exactly the same
322 """Restart command. In the context of ipython this is exactly the same
323 thing as 'quit'."""
323 thing as 'quit'."""
324 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
324 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
325 return self.do_quit(arg)
325 return self.do_quit(arg)
326
326
327 def print_stack_trace(self, context=None):
327 def print_stack_trace(self, context=None):
328 if context is None:
328 if context is None:
329 context = self.context
329 context = self.context
330 try:
330 try:
331 context=int(context)
331 context=int(context)
332 if context <= 0:
332 if context <= 0:
333 raise ValueError("Context must be a positive integer")
333 raise ValueError("Context must be a positive integer")
334 except (TypeError, ValueError):
334 except (TypeError, ValueError):
335 raise ValueError("Context must be a positive integer")
335 raise ValueError("Context must be a positive integer")
336 try:
336 try:
337 for frame_lineno in self.stack:
337 for frame_lineno in self.stack:
338 self.print_stack_entry(frame_lineno, context=context)
338 self.print_stack_entry(frame_lineno, context=context)
339 except KeyboardInterrupt:
339 except KeyboardInterrupt:
340 pass
340 pass
341
341
342 def print_stack_entry(self,frame_lineno, prompt_prefix='\n-> ',
342 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
343 context=None):
343 context=None):
344 if context is None:
344 if context is None:
345 context = self.context
345 context = self.context
346 try:
346 try:
347 context=int(context)
347 context=int(context)
348 if context <= 0:
348 if context <= 0:
349 raise ValueError("Context must be a positive integer")
349 raise ValueError("Context must be a positive integer")
350 except (TypeError, ValueError):
350 except (TypeError, ValueError):
351 raise ValueError("Context must be a positive integer")
351 raise ValueError("Context must be a positive integer")
352 print(self.format_stack_entry(frame_lineno, '', context))
352 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
353
353
354 # vds: >>
354 # vds: >>
355 frame, lineno = frame_lineno
355 frame, lineno = frame_lineno
356 filename = frame.f_code.co_filename
356 filename = frame.f_code.co_filename
357 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
357 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
358 # vds: <<
358 # vds: <<
359
359
360 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
360 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
361 if context is None:
361 if context is None:
362 context = self.context
362 context = self.context
363 try:
363 try:
364 context=int(context)
364 context=int(context)
365 if context <= 0:
365 if context <= 0:
366 print("Context must be a positive integer")
366 print("Context must be a positive integer", file=self.stdout)
367 except (TypeError, ValueError):
367 except (TypeError, ValueError):
368 print("Context must be a positive integer")
368 print("Context must be a positive integer", file=self.stdout)
369 try:
369 try:
370 import reprlib # Py 3
370 import reprlib # Py 3
371 except ImportError:
371 except ImportError:
372 import repr as reprlib # Py 2
372 import repr as reprlib # Py 2
373
373
374 ret = []
374 ret = []
375
375
376 Colors = self.color_scheme_table.active_colors
376 Colors = self.color_scheme_table.active_colors
377 ColorsNormal = Colors.Normal
377 ColorsNormal = Colors.Normal
378 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
378 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
379 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
379 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
380 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
380 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
381 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
381 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
382 ColorsNormal)
382 ColorsNormal)
383
383
384 frame, lineno = frame_lineno
384 frame, lineno = frame_lineno
385
385
386 return_value = ''
386 return_value = ''
387 if '__return__' in frame.f_locals:
387 if '__return__' in frame.f_locals:
388 rv = frame.f_locals['__return__']
388 rv = frame.f_locals['__return__']
389 #return_value += '->'
389 #return_value += '->'
390 return_value += reprlib.repr(rv) + '\n'
390 return_value += reprlib.repr(rv) + '\n'
391 ret.append(return_value)
391 ret.append(return_value)
392
392
393 #s = filename + '(' + `lineno` + ')'
393 #s = filename + '(' + `lineno` + ')'
394 filename = self.canonic(frame.f_code.co_filename)
394 filename = self.canonic(frame.f_code.co_filename)
395 link = tpl_link % py3compat.cast_unicode(filename)
395 link = tpl_link % py3compat.cast_unicode(filename)
396
396
397 if frame.f_code.co_name:
397 if frame.f_code.co_name:
398 func = frame.f_code.co_name
398 func = frame.f_code.co_name
399 else:
399 else:
400 func = "<lambda>"
400 func = "<lambda>"
401
401
402 call = ''
402 call = ''
403 if func != '?':
403 if func != '?':
404 if '__args__' in frame.f_locals:
404 if '__args__' in frame.f_locals:
405 args = reprlib.repr(frame.f_locals['__args__'])
405 args = reprlib.repr(frame.f_locals['__args__'])
406 else:
406 else:
407 args = '()'
407 args = '()'
408 call = tpl_call % (func, args)
408 call = tpl_call % (func, args)
409
409
410 # The level info should be generated in the same format pdb uses, to
410 # The level info should be generated in the same format pdb uses, to
411 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
411 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
412 if frame is self.curframe:
412 if frame is self.curframe:
413 ret.append('> ')
413 ret.append('> ')
414 else:
414 else:
415 ret.append(' ')
415 ret.append(' ')
416 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
416 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
417
417
418 start = lineno - 1 - context//2
418 start = lineno - 1 - context//2
419 lines = linecache.getlines(filename)
419 lines = linecache.getlines(filename)
420 start = min(start, len(lines) - context)
420 start = min(start, len(lines) - context)
421 start = max(start, 0)
421 start = max(start, 0)
422 lines = lines[start : start + context]
422 lines = lines[start : start + context]
423
423
424 for i,line in enumerate(lines):
424 for i,line in enumerate(lines):
425 show_arrow = (start + 1 + i == lineno)
425 show_arrow = (start + 1 + i == lineno)
426 linetpl = (frame is self.curframe or show_arrow) \
426 linetpl = (frame is self.curframe or show_arrow) \
427 and tpl_line_em \
427 and tpl_line_em \
428 or tpl_line
428 or tpl_line
429 ret.append(self.__format_line(linetpl, filename,
429 ret.append(self.__format_line(linetpl, filename,
430 start + 1 + i, line,
430 start + 1 + i, line,
431 arrow = show_arrow) )
431 arrow = show_arrow) )
432 return ''.join(ret)
432 return ''.join(ret)
433
433
434 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
434 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
435 bp_mark = ""
435 bp_mark = ""
436 bp_mark_color = ""
436 bp_mark_color = ""
437
437
438 new_line, err = self.parser.format2(line, 'str')
438 new_line, err = self.parser.format2(line, 'str')
439 if not err:
439 if not err:
440 line = new_line
440 line = new_line
441
441
442 bp = None
442 bp = None
443 if lineno in self.get_file_breaks(filename):
443 if lineno in self.get_file_breaks(filename):
444 bps = self.get_breaks(filename, lineno)
444 bps = self.get_breaks(filename, lineno)
445 bp = bps[-1]
445 bp = bps[-1]
446
446
447 if bp:
447 if bp:
448 Colors = self.color_scheme_table.active_colors
448 Colors = self.color_scheme_table.active_colors
449 bp_mark = str(bp.number)
449 bp_mark = str(bp.number)
450 bp_mark_color = Colors.breakpoint_enabled
450 bp_mark_color = Colors.breakpoint_enabled
451 if not bp.enabled:
451 if not bp.enabled:
452 bp_mark_color = Colors.breakpoint_disabled
452 bp_mark_color = Colors.breakpoint_disabled
453
453
454 numbers_width = 7
454 numbers_width = 7
455 if arrow:
455 if arrow:
456 # This is the line with the error
456 # This is the line with the error
457 pad = numbers_width - len(str(lineno)) - len(bp_mark)
457 pad = numbers_width - len(str(lineno)) - len(bp_mark)
458 num = '%s%s' % (make_arrow(pad), str(lineno))
458 num = '%s%s' % (make_arrow(pad), str(lineno))
459 else:
459 else:
460 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
460 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
461
461
462 return tpl_line % (bp_mark_color + bp_mark, num, line)
462 return tpl_line % (bp_mark_color + bp_mark, num, line)
463
463
464
464
465 def print_list_lines(self, filename, first, last):
465 def print_list_lines(self, filename, first, last):
466 """The printing (as opposed to the parsing part of a 'list'
466 """The printing (as opposed to the parsing part of a 'list'
467 command."""
467 command."""
468 try:
468 try:
469 Colors = self.color_scheme_table.active_colors
469 Colors = self.color_scheme_table.active_colors
470 ColorsNormal = Colors.Normal
470 ColorsNormal = Colors.Normal
471 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
471 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
472 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
472 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
473 src = []
473 src = []
474 if filename == "<string>" and hasattr(self, "_exec_filename"):
474 if filename == "<string>" and hasattr(self, "_exec_filename"):
475 filename = self._exec_filename
475 filename = self._exec_filename
476
476
477 for lineno in range(first, last+1):
477 for lineno in range(first, last+1):
478 line = linecache.getline(filename, lineno)
478 line = linecache.getline(filename, lineno)
479 if not line:
479 if not line:
480 break
480 break
481
481
482 if lineno == self.curframe.f_lineno:
482 if lineno == self.curframe.f_lineno:
483 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
483 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
484 else:
484 else:
485 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
485 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
486
486
487 src.append(line)
487 src.append(line)
488 self.lineno = lineno
488 self.lineno = lineno
489
489
490 print(''.join(src))
490 print(''.join(src), file=self.stdout)
491
491
492 except KeyboardInterrupt:
492 except KeyboardInterrupt:
493 pass
493 pass
494
494
495 def do_list(self, arg):
495 def do_list(self, arg):
496 """Print lines of code from the current stack frame
496 """Print lines of code from the current stack frame
497 """
497 """
498 self.lastcmd = 'list'
498 self.lastcmd = 'list'
499 last = None
499 last = None
500 if arg:
500 if arg:
501 try:
501 try:
502 x = eval(arg, {}, {})
502 x = eval(arg, {}, {})
503 if type(x) == type(()):
503 if type(x) == type(()):
504 first, last = x
504 first, last = x
505 first = int(first)
505 first = int(first)
506 last = int(last)
506 last = int(last)
507 if last < first:
507 if last < first:
508 # Assume it's a count
508 # Assume it's a count
509 last = first + last
509 last = first + last
510 else:
510 else:
511 first = max(1, int(x) - 5)
511 first = max(1, int(x) - 5)
512 except:
512 except:
513 print('*** Error in argument:', repr(arg))
513 print('*** Error in argument:', repr(arg), file=self.stdout)
514 return
514 return
515 elif self.lineno is None:
515 elif self.lineno is None:
516 first = max(1, self.curframe.f_lineno - 5)
516 first = max(1, self.curframe.f_lineno - 5)
517 else:
517 else:
518 first = self.lineno + 1
518 first = self.lineno + 1
519 if last is None:
519 if last is None:
520 last = first + 10
520 last = first + 10
521 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
521 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
522
522
523 # vds: >>
523 # vds: >>
524 lineno = first
524 lineno = first
525 filename = self.curframe.f_code.co_filename
525 filename = self.curframe.f_code.co_filename
526 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
526 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
527 # vds: <<
527 # vds: <<
528
528
529 do_l = do_list
529 do_l = do_list
530
530
531 def getsourcelines(self, obj):
531 def getsourcelines(self, obj):
532 lines, lineno = inspect.findsource(obj)
532 lines, lineno = inspect.findsource(obj)
533 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
533 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
534 # must be a module frame: do not try to cut a block out of it
534 # must be a module frame: do not try to cut a block out of it
535 return lines, 1
535 return lines, 1
536 elif inspect.ismodule(obj):
536 elif inspect.ismodule(obj):
537 return lines, 1
537 return lines, 1
538 return inspect.getblock(lines[lineno:]), lineno+1
538 return inspect.getblock(lines[lineno:]), lineno+1
539
539
540 def do_longlist(self, arg):
540 def do_longlist(self, arg):
541 """Print lines of code from the current stack frame.
541 """Print lines of code from the current stack frame.
542
542
543 Shows more lines than 'list' does.
543 Shows more lines than 'list' does.
544 """
544 """
545 self.lastcmd = 'longlist'
545 self.lastcmd = 'longlist'
546 try:
546 try:
547 lines, lineno = self.getsourcelines(self.curframe)
547 lines, lineno = self.getsourcelines(self.curframe)
548 except OSError as err:
548 except OSError as err:
549 self.error(err)
549 self.error(err)
550 return
550 return
551 last = lineno + len(lines)
551 last = lineno + len(lines)
552 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
552 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
553 do_ll = do_longlist
553 do_ll = do_longlist
554
554
555 def do_debug(self, arg):
555 def do_debug(self, arg):
556 """debug code
556 """debug code
557 Enter a recursive debugger that steps through the code
557 Enter a recursive debugger that steps through the code
558 argument (which is an arbitrary expression or statement to be
558 argument (which is an arbitrary expression or statement to be
559 executed in the current environment).
559 executed in the current environment).
560 """
560 """
561 sys.settrace(None)
561 sys.settrace(None)
562 globals = self.curframe.f_globals
562 globals = self.curframe.f_globals
563 locals = self.curframe_locals
563 locals = self.curframe_locals
564 p = self.__class__(completekey=self.completekey,
564 p = self.__class__(completekey=self.completekey,
565 stdin=self.stdin, stdout=self.stdout)
565 stdin=self.stdin, stdout=self.stdout)
566 p.use_rawinput = self.use_rawinput
566 p.use_rawinput = self.use_rawinput
567 p.prompt = "(%s) " % self.prompt.strip()
567 p.prompt = "(%s) " % self.prompt.strip()
568 self.message("ENTERING RECURSIVE DEBUGGER")
568 self.message("ENTERING RECURSIVE DEBUGGER")
569 sys.call_tracing(p.run, (arg, globals, locals))
569 sys.call_tracing(p.run, (arg, globals, locals))
570 self.message("LEAVING RECURSIVE DEBUGGER")
570 self.message("LEAVING RECURSIVE DEBUGGER")
571 sys.settrace(self.trace_dispatch)
571 sys.settrace(self.trace_dispatch)
572 self.lastcmd = p.lastcmd
572 self.lastcmd = p.lastcmd
573
573
574 def do_pdef(self, arg):
574 def do_pdef(self, arg):
575 """Print the call signature for any callable object.
575 """Print the call signature for any callable object.
576
576
577 The debugger interface to %pdef"""
577 The debugger interface to %pdef"""
578 namespaces = [('Locals', self.curframe.f_locals),
578 namespaces = [('Locals', self.curframe.f_locals),
579 ('Globals', self.curframe.f_globals)]
579 ('Globals', self.curframe.f_globals)]
580 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
580 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
581
581
582 def do_pdoc(self, arg):
582 def do_pdoc(self, arg):
583 """Print the docstring for an object.
583 """Print the docstring for an object.
584
584
585 The debugger interface to %pdoc."""
585 The debugger interface to %pdoc."""
586 namespaces = [('Locals', self.curframe.f_locals),
586 namespaces = [('Locals', self.curframe.f_locals),
587 ('Globals', self.curframe.f_globals)]
587 ('Globals', self.curframe.f_globals)]
588 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
588 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
589
589
590 def do_pfile(self, arg):
590 def do_pfile(self, arg):
591 """Print (or run through pager) the file where an object is defined.
591 """Print (or run through pager) the file where an object is defined.
592
592
593 The debugger interface to %pfile.
593 The debugger interface to %pfile.
594 """
594 """
595 namespaces = [('Locals', self.curframe.f_locals),
595 namespaces = [('Locals', self.curframe.f_locals),
596 ('Globals', self.curframe.f_globals)]
596 ('Globals', self.curframe.f_globals)]
597 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
597 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
598
598
599 def do_pinfo(self, arg):
599 def do_pinfo(self, arg):
600 """Provide detailed information about an object.
600 """Provide detailed information about an object.
601
601
602 The debugger interface to %pinfo, i.e., obj?."""
602 The debugger interface to %pinfo, i.e., obj?."""
603 namespaces = [('Locals', self.curframe.f_locals),
603 namespaces = [('Locals', self.curframe.f_locals),
604 ('Globals', self.curframe.f_globals)]
604 ('Globals', self.curframe.f_globals)]
605 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
605 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
606
606
607 def do_pinfo2(self, arg):
607 def do_pinfo2(self, arg):
608 """Provide extra detailed information about an object.
608 """Provide extra detailed information about an object.
609
609
610 The debugger interface to %pinfo2, i.e., obj??."""
610 The debugger interface to %pinfo2, i.e., obj??."""
611 namespaces = [('Locals', self.curframe.f_locals),
611 namespaces = [('Locals', self.curframe.f_locals),
612 ('Globals', self.curframe.f_globals)]
612 ('Globals', self.curframe.f_globals)]
613 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
613 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
614
614
615 def do_psource(self, arg):
615 def do_psource(self, arg):
616 """Print (or run through pager) the source code for an object."""
616 """Print (or run through pager) the source code for an object."""
617 namespaces = [('Locals', self.curframe.f_locals),
617 namespaces = [('Locals', self.curframe.f_locals),
618 ('Globals', self.curframe.f_globals)]
618 ('Globals', self.curframe.f_globals)]
619 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
619 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
620
620
621 def do_where(self, arg):
621 def do_where(self, arg):
622 """w(here)
622 """w(here)
623 Print a stack trace, with the most recent frame at the bottom.
623 Print a stack trace, with the most recent frame at the bottom.
624 An arrow indicates the "current frame", which determines the
624 An arrow indicates the "current frame", which determines the
625 context of most commands. 'bt' is an alias for this command.
625 context of most commands. 'bt' is an alias for this command.
626
626
627 Take a number as argument as an (optional) number of context line to
627 Take a number as argument as an (optional) number of context line to
628 print"""
628 print"""
629 if arg:
629 if arg:
630 context = int(arg)
630 context = int(arg)
631 self.print_stack_trace(context)
631 self.print_stack_trace(context)
632 else:
632 else:
633 self.print_stack_trace()
633 self.print_stack_trace()
634
634
635 do_w = do_where
635 do_w = do_where
636
636
637
637
638 def set_trace(frame=None):
638 def set_trace(frame=None):
639 """
639 """
640 Start debugging from `frame`.
640 Start debugging from `frame`.
641
641
642 If frame is not specified, debugging starts from caller's frame.
642 If frame is not specified, debugging starts from caller's frame.
643 """
643 """
644 Pdb().set_trace(frame or sys._getframe().f_back)
644 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now