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