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