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