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