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