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