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