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