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