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