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