##// END OF EJS Templates
Reset readline delimiters on exiting debugger...
Thomas Kluyver -
Show More
@@ -1,591 +1,593 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('\n' + self.shell.get_exception_only())
280 self.shell.write('\n' + self.shell.get_exception_only())
281 break
281 break
282 else:
282 else:
283 break
283 break
284
284
285 def new_do_up(self, arg):
285 def new_do_up(self, arg):
286 OldPdb.do_up(self, arg)
286 OldPdb.do_up(self, arg)
287 self.shell.set_completer_frame(self.curframe)
287 self.shell.set_completer_frame(self.curframe)
288 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)
289
289
290 def new_do_down(self, arg):
290 def new_do_down(self, arg):
291 OldPdb.do_down(self, arg)
291 OldPdb.do_down(self, arg)
292 self.shell.set_completer_frame(self.curframe)
292 self.shell.set_completer_frame(self.curframe)
293
293
294 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)
295
295
296 def new_do_frame(self, arg):
296 def new_do_frame(self, arg):
297 OldPdb.do_frame(self, arg)
297 OldPdb.do_frame(self, arg)
298 self.shell.set_completer_frame(self.curframe)
298 self.shell.set_completer_frame(self.curframe)
299
299
300 def new_do_quit(self, arg):
300 def new_do_quit(self, arg):
301
301
302 if hasattr(self, 'old_all_completions'):
302 if hasattr(self, 'old_all_completions'):
303 self.shell.Completer.all_completions=self.old_all_completions
303 self.shell.Completer.all_completions=self.old_all_completions
304
304
305 # Pdb sets readline delimiters, so set them back to our own
306 self.shell.readline.set_completer_delims(self.shell.readline_delims)
305
307
306 return OldPdb.do_quit(self, arg)
308 return OldPdb.do_quit(self, arg)
307
309
308 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
310 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
309
311
310 def new_do_restart(self, arg):
312 def new_do_restart(self, arg):
311 """Restart command. In the context of ipython this is exactly the same
313 """Restart command. In the context of ipython this is exactly the same
312 thing as 'quit'."""
314 thing as 'quit'."""
313 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
315 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
314 return self.do_quit(arg)
316 return self.do_quit(arg)
315
317
316 def postloop(self):
318 def postloop(self):
317 self.shell.set_completer_frame(None)
319 self.shell.set_completer_frame(None)
318
320
319 def print_stack_trace(self):
321 def print_stack_trace(self):
320 try:
322 try:
321 for frame_lineno in self.stack:
323 for frame_lineno in self.stack:
322 self.print_stack_entry(frame_lineno, context = 5)
324 self.print_stack_entry(frame_lineno, context = 5)
323 except KeyboardInterrupt:
325 except KeyboardInterrupt:
324 pass
326 pass
325
327
326 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
328 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
327 context = 3):
329 context = 3):
328 #frame, lineno = frame_lineno
330 #frame, lineno = frame_lineno
329 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
331 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
330
332
331 # vds: >>
333 # vds: >>
332 frame, lineno = frame_lineno
334 frame, lineno = frame_lineno
333 filename = frame.f_code.co_filename
335 filename = frame.f_code.co_filename
334 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
336 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
335 # vds: <<
337 # vds: <<
336
338
337 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
339 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
338 try:
340 try:
339 import reprlib # Py 3
341 import reprlib # Py 3
340 except ImportError:
342 except ImportError:
341 import repr as reprlib # Py 2
343 import repr as reprlib # Py 2
342
344
343 ret = []
345 ret = []
344
346
345 Colors = self.color_scheme_table.active_colors
347 Colors = self.color_scheme_table.active_colors
346 ColorsNormal = Colors.Normal
348 ColorsNormal = Colors.Normal
347 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
349 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
348 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
350 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)
351 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,
352 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
351 ColorsNormal)
353 ColorsNormal)
352
354
353 frame, lineno = frame_lineno
355 frame, lineno = frame_lineno
354
356
355 return_value = ''
357 return_value = ''
356 if '__return__' in frame.f_locals:
358 if '__return__' in frame.f_locals:
357 rv = frame.f_locals['__return__']
359 rv = frame.f_locals['__return__']
358 #return_value += '->'
360 #return_value += '->'
359 return_value += reprlib.repr(rv) + '\n'
361 return_value += reprlib.repr(rv) + '\n'
360 ret.append(return_value)
362 ret.append(return_value)
361
363
362 #s = filename + '(' + `lineno` + ')'
364 #s = filename + '(' + `lineno` + ')'
363 filename = self.canonic(frame.f_code.co_filename)
365 filename = self.canonic(frame.f_code.co_filename)
364 link = tpl_link % py3compat.cast_unicode(filename)
366 link = tpl_link % py3compat.cast_unicode(filename)
365
367
366 if frame.f_code.co_name:
368 if frame.f_code.co_name:
367 func = frame.f_code.co_name
369 func = frame.f_code.co_name
368 else:
370 else:
369 func = "<lambda>"
371 func = "<lambda>"
370
372
371 call = ''
373 call = ''
372 if func != '?':
374 if func != '?':
373 if '__args__' in frame.f_locals:
375 if '__args__' in frame.f_locals:
374 args = reprlib.repr(frame.f_locals['__args__'])
376 args = reprlib.repr(frame.f_locals['__args__'])
375 else:
377 else:
376 args = '()'
378 args = '()'
377 call = tpl_call % (func, args)
379 call = tpl_call % (func, args)
378
380
379 # The level info should be generated in the same format pdb uses, to
381 # The level info should be generated in the same format pdb uses, to
380 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
382 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
381 if frame is self.curframe:
383 if frame is self.curframe:
382 ret.append('> ')
384 ret.append('> ')
383 else:
385 else:
384 ret.append(' ')
386 ret.append(' ')
385 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
387 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
386
388
387 start = lineno - 1 - context//2
389 start = lineno - 1 - context//2
388 lines = ulinecache.getlines(filename)
390 lines = ulinecache.getlines(filename)
389 start = min(start, len(lines) - context)
391 start = min(start, len(lines) - context)
390 start = max(start, 0)
392 start = max(start, 0)
391 lines = lines[start : start + context]
393 lines = lines[start : start + context]
392
394
393 for i,line in enumerate(lines):
395 for i,line in enumerate(lines):
394 show_arrow = (start + 1 + i == lineno)
396 show_arrow = (start + 1 + i == lineno)
395 linetpl = (frame is self.curframe or show_arrow) \
397 linetpl = (frame is self.curframe or show_arrow) \
396 and tpl_line_em \
398 and tpl_line_em \
397 or tpl_line
399 or tpl_line
398 ret.append(self.__format_line(linetpl, filename,
400 ret.append(self.__format_line(linetpl, filename,
399 start + 1 + i, line,
401 start + 1 + i, line,
400 arrow = show_arrow) )
402 arrow = show_arrow) )
401 return ''.join(ret)
403 return ''.join(ret)
402
404
403 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
405 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
404 bp_mark = ""
406 bp_mark = ""
405 bp_mark_color = ""
407 bp_mark_color = ""
406
408
407 scheme = self.color_scheme_table.active_scheme_name
409 scheme = self.color_scheme_table.active_scheme_name
408 new_line, err = self.parser.format2(line, 'str', scheme)
410 new_line, err = self.parser.format2(line, 'str', scheme)
409 if not err: line = new_line
411 if not err: line = new_line
410
412
411 bp = None
413 bp = None
412 if lineno in self.get_file_breaks(filename):
414 if lineno in self.get_file_breaks(filename):
413 bps = self.get_breaks(filename, lineno)
415 bps = self.get_breaks(filename, lineno)
414 bp = bps[-1]
416 bp = bps[-1]
415
417
416 if bp:
418 if bp:
417 Colors = self.color_scheme_table.active_colors
419 Colors = self.color_scheme_table.active_colors
418 bp_mark = str(bp.number)
420 bp_mark = str(bp.number)
419 bp_mark_color = Colors.breakpoint_enabled
421 bp_mark_color = Colors.breakpoint_enabled
420 if not bp.enabled:
422 if not bp.enabled:
421 bp_mark_color = Colors.breakpoint_disabled
423 bp_mark_color = Colors.breakpoint_disabled
422
424
423 numbers_width = 7
425 numbers_width = 7
424 if arrow:
426 if arrow:
425 # This is the line with the error
427 # This is the line with the error
426 pad = numbers_width - len(str(lineno)) - len(bp_mark)
428 pad = numbers_width - len(str(lineno)) - len(bp_mark)
427 if pad >= 3:
429 if pad >= 3:
428 marker = '-'*(pad-3) + '-> '
430 marker = '-'*(pad-3) + '-> '
429 elif pad == 2:
431 elif pad == 2:
430 marker = '> '
432 marker = '> '
431 elif pad == 1:
433 elif pad == 1:
432 marker = '>'
434 marker = '>'
433 else:
435 else:
434 marker = ''
436 marker = ''
435 num = '%s%s' % (marker, str(lineno))
437 num = '%s%s' % (marker, str(lineno))
436 line = tpl_line % (bp_mark_color + bp_mark, num, line)
438 line = tpl_line % (bp_mark_color + bp_mark, num, line)
437 else:
439 else:
438 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
440 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
439 line = tpl_line % (bp_mark_color + bp_mark, num, line)
441 line = tpl_line % (bp_mark_color + bp_mark, num, line)
440
442
441 return line
443 return line
442
444
443 def list_command_pydb(self, arg):
445 def list_command_pydb(self, arg):
444 """List command to use if we have a newer pydb installed"""
446 """List command to use if we have a newer pydb installed"""
445 filename, first, last = OldPdb.parse_list_cmd(self, arg)
447 filename, first, last = OldPdb.parse_list_cmd(self, arg)
446 if filename is not None:
448 if filename is not None:
447 self.print_list_lines(filename, first, last)
449 self.print_list_lines(filename, first, last)
448
450
449 def print_list_lines(self, filename, first, last):
451 def print_list_lines(self, filename, first, last):
450 """The printing (as opposed to the parsing part of a 'list'
452 """The printing (as opposed to the parsing part of a 'list'
451 command."""
453 command."""
452 try:
454 try:
453 Colors = self.color_scheme_table.active_colors
455 Colors = self.color_scheme_table.active_colors
454 ColorsNormal = Colors.Normal
456 ColorsNormal = Colors.Normal
455 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
457 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
456 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
458 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
457 src = []
459 src = []
458 if filename == "<string>" and hasattr(self, "_exec_filename"):
460 if filename == "<string>" and hasattr(self, "_exec_filename"):
459 filename = self._exec_filename
461 filename = self._exec_filename
460
462
461 for lineno in range(first, last+1):
463 for lineno in range(first, last+1):
462 line = ulinecache.getline(filename, lineno)
464 line = ulinecache.getline(filename, lineno)
463 if not line:
465 if not line:
464 break
466 break
465
467
466 if lineno == self.curframe.f_lineno:
468 if lineno == self.curframe.f_lineno:
467 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
469 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
468 else:
470 else:
469 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
471 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
470
472
471 src.append(line)
473 src.append(line)
472 self.lineno = lineno
474 self.lineno = lineno
473
475
474 print(''.join(src), file=io.stdout)
476 print(''.join(src), file=io.stdout)
475
477
476 except KeyboardInterrupt:
478 except KeyboardInterrupt:
477 pass
479 pass
478
480
479 def do_list(self, arg):
481 def do_list(self, arg):
480 self.lastcmd = 'list'
482 self.lastcmd = 'list'
481 last = None
483 last = None
482 if arg:
484 if arg:
483 try:
485 try:
484 x = eval(arg, {}, {})
486 x = eval(arg, {}, {})
485 if type(x) == type(()):
487 if type(x) == type(()):
486 first, last = x
488 first, last = x
487 first = int(first)
489 first = int(first)
488 last = int(last)
490 last = int(last)
489 if last < first:
491 if last < first:
490 # Assume it's a count
492 # Assume it's a count
491 last = first + last
493 last = first + last
492 else:
494 else:
493 first = max(1, int(x) - 5)
495 first = max(1, int(x) - 5)
494 except:
496 except:
495 print('*** Error in argument:', repr(arg))
497 print('*** Error in argument:', repr(arg))
496 return
498 return
497 elif self.lineno is None:
499 elif self.lineno is None:
498 first = max(1, self.curframe.f_lineno - 5)
500 first = max(1, self.curframe.f_lineno - 5)
499 else:
501 else:
500 first = self.lineno + 1
502 first = self.lineno + 1
501 if last is None:
503 if last is None:
502 last = first + 10
504 last = first + 10
503 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
505 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
504
506
505 # vds: >>
507 # vds: >>
506 lineno = first
508 lineno = first
507 filename = self.curframe.f_code.co_filename
509 filename = self.curframe.f_code.co_filename
508 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
510 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
509 # vds: <<
511 # vds: <<
510
512
511 do_l = do_list
513 do_l = do_list
512
514
513 def do_pdef(self, arg):
515 def do_pdef(self, arg):
514 """Print the call signature for any callable object.
516 """Print the call signature for any callable object.
515
517
516 The debugger interface to %pdef"""
518 The debugger interface to %pdef"""
517 namespaces = [('Locals', self.curframe.f_locals),
519 namespaces = [('Locals', self.curframe.f_locals),
518 ('Globals', self.curframe.f_globals)]
520 ('Globals', self.curframe.f_globals)]
519 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
521 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
520
522
521 def do_pdoc(self, arg):
523 def do_pdoc(self, arg):
522 """Print the docstring for an object.
524 """Print the docstring for an object.
523
525
524 The debugger interface to %pdoc."""
526 The debugger interface to %pdoc."""
525 namespaces = [('Locals', self.curframe.f_locals),
527 namespaces = [('Locals', self.curframe.f_locals),
526 ('Globals', self.curframe.f_globals)]
528 ('Globals', self.curframe.f_globals)]
527 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
529 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
528
530
529 def do_pfile(self, arg):
531 def do_pfile(self, arg):
530 """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.
531
533
532 The debugger interface to %pfile.
534 The debugger interface to %pfile.
533 """
535 """
534 namespaces = [('Locals', self.curframe.f_locals),
536 namespaces = [('Locals', self.curframe.f_locals),
535 ('Globals', self.curframe.f_globals)]
537 ('Globals', self.curframe.f_globals)]
536 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
538 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
537
539
538 def do_pinfo(self, arg):
540 def do_pinfo(self, arg):
539 """Provide detailed information about an object.
541 """Provide detailed information about an object.
540
542
541 The debugger interface to %pinfo, i.e., obj?."""
543 The debugger interface to %pinfo, i.e., obj?."""
542 namespaces = [('Locals', self.curframe.f_locals),
544 namespaces = [('Locals', self.curframe.f_locals),
543 ('Globals', self.curframe.f_globals)]
545 ('Globals', self.curframe.f_globals)]
544 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
546 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
545
547
546 def do_pinfo2(self, arg):
548 def do_pinfo2(self, arg):
547 """Provide extra detailed information about an object.
549 """Provide extra detailed information about an object.
548
550
549 The debugger interface to %pinfo2, i.e., obj??."""
551 The debugger interface to %pinfo2, i.e., obj??."""
550 namespaces = [('Locals', self.curframe.f_locals),
552 namespaces = [('Locals', self.curframe.f_locals),
551 ('Globals', self.curframe.f_globals)]
553 ('Globals', self.curframe.f_globals)]
552 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
554 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
553
555
554 def do_psource(self, arg):
556 def do_psource(self, arg):
555 """Print (or run through pager) the source code for an object."""
557 """Print (or run through pager) the source code for an object."""
556 namespaces = [('Locals', self.curframe.f_locals),
558 namespaces = [('Locals', self.curframe.f_locals),
557 ('Globals', self.curframe.f_globals)]
559 ('Globals', self.curframe.f_globals)]
558 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
560 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
559
561
560 def checkline(self, filename, lineno):
562 def checkline(self, filename, lineno):
561 """Check whether specified line seems to be executable.
563 """Check whether specified line seems to be executable.
562
564
563 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
565 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
564 line or EOF). Warning: testing is not comprehensive.
566 line or EOF). Warning: testing is not comprehensive.
565 """
567 """
566 #######################################################################
568 #######################################################################
567 # XXX Hack! Use python-2.5 compatible code for this call, because with
569 # XXX Hack! Use python-2.5 compatible code for this call, because with
568 # all of our changes, we've drifted from the pdb api in 2.6. For now,
570 # all of our changes, we've drifted from the pdb api in 2.6. For now,
569 # changing:
571 # changing:
570 #
572 #
571 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
573 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
572 # to:
574 # to:
573 #
575 #
574 line = linecache.getline(filename, lineno)
576 line = linecache.getline(filename, lineno)
575 #
577 #
576 # does the trick. But in reality, we need to fix this by reconciling
578 # does the trick. But in reality, we need to fix this by reconciling
577 # our updates with the new Pdb APIs in Python 2.6.
579 # our updates with the new Pdb APIs in Python 2.6.
578 #
580 #
579 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
581 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
580 #######################################################################
582 #######################################################################
581
583
582 if not line:
584 if not line:
583 print('End of file', file=self.stdout)
585 print('End of file', file=self.stdout)
584 return 0
586 return 0
585 line = line.strip()
587 line = line.strip()
586 # Don't allow setting breakpoint at a blank line
588 # Don't allow setting breakpoint at a blank line
587 if (not line or (line[0] == '#') or
589 if (not line or (line[0] == '#') or
588 (line[:3] == '"""') or line[:3] == "'''"):
590 (line[:3] == '"""') or line[:3] == "'''"):
589 print('*** Blank or comment', file=self.stdout)
591 print('*** Blank or comment', file=self.stdout)
590 return 0
592 return 0
591 return lineno
593 return lineno
General Comments 0
You need to be logged in to leave comments. Login now