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