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