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