##// END OF EJS Templates
Expand and Fix PDB skip....
Matthias Bussonnier -
Show More
@@ -1,1093 +1,1106 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5
5
6 This is an extension to PDB which adds a number of new features.
6 This is an extension to PDB which adds a number of new features.
7 Note that there is also the `IPython.terminal.debugger` class which provides UI
7 Note that there is also the `IPython.terminal.debugger` class which provides UI
8 improvements.
8 improvements.
9
9
10 We also strongly recommend to use this via the `ipdb` package, which provides
10 We also strongly recommend to use this via the `ipdb` package, which provides
11 extra configuration options.
11 extra configuration options.
12
12
13 Among other things, this subclass of PDB:
13 Among other things, this subclass of PDB:
14 - supports many IPython magics like pdef/psource
14 - supports many IPython magics like pdef/psource
15 - hide frames in tracebacks based on `__tracebackhide__`
15 - hide frames in tracebacks based on `__tracebackhide__`
16 - allows to skip frames based on `__debuggerskip__`
16 - allows to skip frames based on `__debuggerskip__`
17
17
18 The skipping and hiding frames are configurable via the `skip_predicates`
18 The skipping and hiding frames are configurable via the `skip_predicates`
19 command.
19 command.
20
20
21 By default, frames from readonly files will be hidden, frames containing
21 By default, frames from readonly files will be hidden, frames containing
22 ``__tracebackhide__=True`` will be hidden.
22 ``__tracebackhide__=True`` will be hidden.
23
23
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
26
26
27 >>> def helper_1():
27 >>> def helpers_helper():
28 ... pass
29 ...
30 ... def helper_1():
28 ... print("don't step in me")
31 ... print("don't step in me")
32 ... helpers_helpers() # will be stepped over unless breakpoint set.
29 ...
33 ...
30 ...
34 ...
31 ... def helper_2():
35 ... def helper_2():
32 ... print("in me neither")
36 ... print("in me neither")
33 ...
37 ...
34
38
35 One can define a decorator that wraps a function between the two helpers:
39 One can define a decorator that wraps a function between the two helpers:
36
40
37 >>> def pdb_skipped_decorator(function):
41 >>> def pdb_skipped_decorator(function):
38 ...
42 ...
39 ...
43 ...
40 ... def wrapped_fn(*args, **kwargs):
44 ... def wrapped_fn(*args, **kwargs):
41 ... __debuggerskip__ = True
45 ... __debuggerskip__ = True
42 ... helper_1()
46 ... helper_1()
43 ... __debuggerskip__ = False
47 ... __debuggerskip__ = False
44 ... result = function(*args, **kwargs)
48 ... result = function(*args, **kwargs)
45 ... __debuggerskip__ = True
49 ... __debuggerskip__ = True
46 ... helper_2()
50 ... helper_2()
51 ... # setting __debuggerskip__ to False again is not necessary
47 ... return result
52 ... return result
48 ...
53 ...
49 ... return wrapped_fn
54 ... return wrapped_fn
50
55
51 When decorating a function, ipdb will directly step into ``bar()`` by
56 When decorating a function, ipdb will directly step into ``bar()`` by
52 default:
57 default:
53
58
54 >>> @foo_decorator
59 >>> @foo_decorator
55 ... def bar(x, y):
60 ... def bar(x, y):
56 ... return x * y
61 ... return x * y
57
62
58
63
59 You can toggle the behavior with
64 You can toggle the behavior with
60
65
61 ipdb> skip_predicates debuggerskip false
66 ipdb> skip_predicates debuggerskip false
62
67
63 or configure it in your ``.pdbrc``
68 or configure it in your ``.pdbrc``
64
69
65
70
66
71
67 Licencse
72 Licencse
68 --------
73 --------
69
74
70 Modified from the standard pdb.Pdb class to avoid including readline, so that
75 Modified from the standard pdb.Pdb class to avoid including readline, so that
71 the command line completion of other programs which include this isn't
76 the command line completion of other programs which include this isn't
72 damaged.
77 damaged.
73
78
74 In the future, this class will be expanded with improvements over the standard
79 In the future, this class will be expanded with improvements over the standard
75 pdb.
80 pdb.
76
81
77 The original code in this file is mainly lifted out of cmd.py in Python 2.2,
82 The original code in this file is mainly lifted out of cmd.py in Python 2.2,
78 with minor changes. Licensing should therefore be under the standard Python
83 with minor changes. Licensing should therefore be under the standard Python
79 terms. For details on the PSF (Python Software Foundation) standard license,
84 terms. For details on the PSF (Python Software Foundation) standard license,
80 see:
85 see:
81
86
82 https://docs.python.org/2/license.html
87 https://docs.python.org/2/license.html
83
88
84
89
85 All the changes since then are under the same license as IPython.
90 All the changes since then are under the same license as IPython.
86
91
87 """
92 """
88
93
89 #*****************************************************************************
94 #*****************************************************************************
90 #
95 #
91 # This file is licensed under the PSF license.
96 # This file is licensed under the PSF license.
92 #
97 #
93 # Copyright (C) 2001 Python Software Foundation, www.python.org
98 # Copyright (C) 2001 Python Software Foundation, www.python.org
94 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
99 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
95 #
100 #
96 #
101 #
97 #*****************************************************************************
102 #*****************************************************************************
98
103
99 import bdb
104 import bdb
100 import functools
105 import functools
101 import inspect
106 import inspect
102 import linecache
107 import linecache
103 import sys
108 import sys
104 import warnings
109 import warnings
105 import re
110 import re
106 import os
111 import os
107
112
108 from IPython import get_ipython
113 from IPython import get_ipython
109 from IPython.utils import PyColorize
114 from IPython.utils import PyColorize
110 from IPython.utils import coloransi, py3compat
115 from IPython.utils import coloransi, py3compat
111 from IPython.core.excolors import exception_colors
116 from IPython.core.excolors import exception_colors
112 from IPython.testing.skipdoctest import skip_doctest
117 from IPython.testing.skipdoctest import skip_doctest
113
118
114
119
115 prompt = 'ipdb> '
120 prompt = 'ipdb> '
116
121
117 # We have to check this directly from sys.argv, config struct not yet available
122 # We have to check this directly from sys.argv, config struct not yet available
118 from pdb import Pdb as OldPdb
123 from pdb import Pdb as OldPdb
119
124
120 # Allow the set_trace code to operate outside of an ipython instance, even if
125 # Allow the set_trace code to operate outside of an ipython instance, even if
121 # it does so with some limitations. The rest of this support is implemented in
126 # it does so with some limitations. The rest of this support is implemented in
122 # the Tracer constructor.
127 # the Tracer constructor.
123
128
124 DEBUGGERSKIP = "__debuggerskip__"
129 DEBUGGERSKIP = "__debuggerskip__"
125
130
126
131
127 def make_arrow(pad):
132 def make_arrow(pad):
128 """generate the leading arrow in front of traceback or debugger"""
133 """generate the leading arrow in front of traceback or debugger"""
129 if pad >= 2:
134 if pad >= 2:
130 return '-'*(pad-2) + '> '
135 return '-'*(pad-2) + '> '
131 elif pad == 1:
136 elif pad == 1:
132 return '>'
137 return '>'
133 return ''
138 return ''
134
139
135
140
136 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
141 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
137 """Exception hook which handles `BdbQuit` exceptions.
142 """Exception hook which handles `BdbQuit` exceptions.
138
143
139 All other exceptions are processed using the `excepthook`
144 All other exceptions are processed using the `excepthook`
140 parameter.
145 parameter.
141 """
146 """
142 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
147 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
143 DeprecationWarning, stacklevel=2)
148 DeprecationWarning, stacklevel=2)
144 if et == bdb.BdbQuit:
149 if et == bdb.BdbQuit:
145 print('Exiting Debugger.')
150 print('Exiting Debugger.')
146 elif excepthook is not None:
151 elif excepthook is not None:
147 excepthook(et, ev, tb)
152 excepthook(et, ev, tb)
148 else:
153 else:
149 # Backwards compatibility. Raise deprecation warning?
154 # Backwards compatibility. Raise deprecation warning?
150 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
155 BdbQuit_excepthook.excepthook_ori(et, ev, tb)
151
156
152
157
153 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
158 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
154 warnings.warn(
159 warnings.warn(
155 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
160 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
156 DeprecationWarning, stacklevel=2)
161 DeprecationWarning, stacklevel=2)
157 print('Exiting Debugger.')
162 print('Exiting Debugger.')
158
163
159
164
160 class Tracer(object):
165 class Tracer(object):
161 """
166 """
162 DEPRECATED
167 DEPRECATED
163
168
164 Class for local debugging, similar to pdb.set_trace.
169 Class for local debugging, similar to pdb.set_trace.
165
170
166 Instances of this class, when called, behave like pdb.set_trace, but
171 Instances of this class, when called, behave like pdb.set_trace, but
167 providing IPython's enhanced capabilities.
172 providing IPython's enhanced capabilities.
168
173
169 This is implemented as a class which must be initialized in your own code
174 This is implemented as a class which must be initialized in your own code
170 and not as a standalone function because we need to detect at runtime
175 and not as a standalone function because we need to detect at runtime
171 whether IPython is already active or not. That detection is done in the
176 whether IPython is already active or not. That detection is done in the
172 constructor, ensuring that this code plays nicely with a running IPython,
177 constructor, ensuring that this code plays nicely with a running IPython,
173 while functioning acceptably (though with limitations) if outside of it.
178 while functioning acceptably (though with limitations) if outside of it.
174 """
179 """
175
180
176 @skip_doctest
181 @skip_doctest
177 def __init__(self, colors=None):
182 def __init__(self, colors=None):
178 """
183 """
179 DEPRECATED
184 DEPRECATED
180
185
181 Create a local debugger instance.
186 Create a local debugger instance.
182
187
183 Parameters
188 Parameters
184 ----------
189 ----------
185 colors : str, optional
190 colors : str, optional
186 The name of the color scheme to use, it must be one of IPython's
191 The name of the color scheme to use, it must be one of IPython's
187 valid color schemes. If not given, the function will default to
192 valid color schemes. If not given, the function will default to
188 the current IPython scheme when running inside IPython, and to
193 the current IPython scheme when running inside IPython, and to
189 'NoColor' otherwise.
194 'NoColor' otherwise.
190
195
191 Examples
196 Examples
192 --------
197 --------
193 ::
198 ::
194
199
195 from IPython.core.debugger import Tracer; debug_here = Tracer()
200 from IPython.core.debugger import Tracer; debug_here = Tracer()
196
201
197 Later in your code::
202 Later in your code::
198
203
199 debug_here() # -> will open up the debugger at that point.
204 debug_here() # -> will open up the debugger at that point.
200
205
201 Once the debugger activates, you can use all of its regular commands to
206 Once the debugger activates, you can use all of its regular commands to
202 step through code, set breakpoints, etc. See the pdb documentation
207 step through code, set breakpoints, etc. See the pdb documentation
203 from the Python standard library for usage details.
208 from the Python standard library for usage details.
204 """
209 """
205 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
210 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
206 "`IPython.core.debugger.Pdb.set_trace()`",
211 "`IPython.core.debugger.Pdb.set_trace()`",
207 DeprecationWarning, stacklevel=2)
212 DeprecationWarning, stacklevel=2)
208
213
209 ip = get_ipython()
214 ip = get_ipython()
210 if ip is None:
215 if ip is None:
211 # Outside of ipython, we set our own exception hook manually
216 # Outside of ipython, we set our own exception hook manually
212 sys.excepthook = functools.partial(BdbQuit_excepthook,
217 sys.excepthook = functools.partial(BdbQuit_excepthook,
213 excepthook=sys.excepthook)
218 excepthook=sys.excepthook)
214 def_colors = 'NoColor'
219 def_colors = 'NoColor'
215 else:
220 else:
216 # In ipython, we use its custom exception handler mechanism
221 # In ipython, we use its custom exception handler mechanism
217 def_colors = ip.colors
222 def_colors = ip.colors
218 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
223 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
219
224
220 if colors is None:
225 if colors is None:
221 colors = def_colors
226 colors = def_colors
222
227
223 # The stdlib debugger internally uses a modified repr from the `repr`
228 # The stdlib debugger internally uses a modified repr from the `repr`
224 # module, that limits the length of printed strings to a hardcoded
229 # module, that limits the length of printed strings to a hardcoded
225 # limit of 30 characters. That much trimming is too aggressive, let's
230 # limit of 30 characters. That much trimming is too aggressive, let's
226 # at least raise that limit to 80 chars, which should be enough for
231 # at least raise that limit to 80 chars, which should be enough for
227 # most interactive uses.
232 # most interactive uses.
228 try:
233 try:
229 from reprlib import aRepr
234 from reprlib import aRepr
230 aRepr.maxstring = 80
235 aRepr.maxstring = 80
231 except:
236 except:
232 # This is only a user-facing convenience, so any error we encounter
237 # This is only a user-facing convenience, so any error we encounter
233 # here can be warned about but can be otherwise ignored. These
238 # here can be warned about but can be otherwise ignored. These
234 # printouts will tell us about problems if this API changes
239 # printouts will tell us about problems if this API changes
235 import traceback
240 import traceback
236 traceback.print_exc()
241 traceback.print_exc()
237
242
238 self.debugger = Pdb(colors)
243 self.debugger = Pdb(colors)
239
244
240 def __call__(self):
245 def __call__(self):
241 """Starts an interactive debugger at the point where called.
246 """Starts an interactive debugger at the point where called.
242
247
243 This is similar to the pdb.set_trace() function from the std lib, but
248 This is similar to the pdb.set_trace() function from the std lib, but
244 using IPython's enhanced debugger."""
249 using IPython's enhanced debugger."""
245
250
246 self.debugger.set_trace(sys._getframe().f_back)
251 self.debugger.set_trace(sys._getframe().f_back)
247
252
248
253
249 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
254 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
250
255
251
256
252 def strip_indentation(multiline_string):
257 def strip_indentation(multiline_string):
253 return RGX_EXTRA_INDENT.sub('', multiline_string)
258 return RGX_EXTRA_INDENT.sub('', multiline_string)
254
259
255
260
256 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
261 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
257 """Make new_fn have old_fn's doc string. This is particularly useful
262 """Make new_fn have old_fn's doc string. This is particularly useful
258 for the ``do_...`` commands that hook into the help system.
263 for the ``do_...`` commands that hook into the help system.
259 Adapted from from a comp.lang.python posting
264 Adapted from from a comp.lang.python posting
260 by Duncan Booth."""
265 by Duncan Booth."""
261 def wrapper(*args, **kw):
266 def wrapper(*args, **kw):
262 return new_fn(*args, **kw)
267 return new_fn(*args, **kw)
263 if old_fn.__doc__:
268 if old_fn.__doc__:
264 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
269 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
265 return wrapper
270 return wrapper
266
271
267
272
268 class Pdb(OldPdb):
273 class Pdb(OldPdb):
269 """Modified Pdb class, does not load readline.
274 """Modified Pdb class, does not load readline.
270
275
271 for a standalone version that uses prompt_toolkit, see
276 for a standalone version that uses prompt_toolkit, see
272 `IPython.terminal.debugger.TerminalPdb` and
277 `IPython.terminal.debugger.TerminalPdb` and
273 `IPython.terminal.debugger.set_trace()`
278 `IPython.terminal.debugger.set_trace()`
274
279
275
280
276 This debugger can hide and skip frames that are tagged according to some predicates.
281 This debugger can hide and skip frames that are tagged according to some predicates.
277 See the `skip_predicates` commands.
282 See the `skip_predicates` commands.
278
283
279 """
284 """
280
285
281 default_predicates = {
286 default_predicates = {
282 "tbhide": True,
287 "tbhide": True,
283 "readonly": False,
288 "readonly": False,
284 "ipython_internal": True,
289 "ipython_internal": True,
285 "debuggerskip": True,
290 "debuggerskip": True,
286 }
291 }
287
292
288 def __init__(self, color_scheme=None, completekey=None,
293 def __init__(self, color_scheme=None, completekey=None,
289 stdin=None, stdout=None, context=5, **kwargs):
294 stdin=None, stdout=None, context=5, **kwargs):
290 """Create a new IPython debugger.
295 """Create a new IPython debugger.
291
296
292 Parameters
297 Parameters
293 ----------
298 ----------
294 color_scheme : default None
299 color_scheme : default None
295 Deprecated, do not use.
300 Deprecated, do not use.
296 completekey : default None
301 completekey : default None
297 Passed to pdb.Pdb.
302 Passed to pdb.Pdb.
298 stdin : default None
303 stdin : default None
299 Passed to pdb.Pdb.
304 Passed to pdb.Pdb.
300 stdout : default None
305 stdout : default None
301 Passed to pdb.Pdb.
306 Passed to pdb.Pdb.
302 context : int
307 context : int
303 Number of lines of source code context to show when
308 Number of lines of source code context to show when
304 displaying stacktrace information.
309 displaying stacktrace information.
305 **kwargs
310 **kwargs
306 Passed to pdb.Pdb.
311 Passed to pdb.Pdb.
307
312
308 Notes
313 Notes
309 -----
314 -----
310 The possibilities are python version dependent, see the python
315 The possibilities are python version dependent, see the python
311 docs for more info.
316 docs for more info.
312 """
317 """
313
318
314 # Parent constructor:
319 # Parent constructor:
315 try:
320 try:
316 self.context = int(context)
321 self.context = int(context)
317 if self.context <= 0:
322 if self.context <= 0:
318 raise ValueError("Context must be a positive integer")
323 raise ValueError("Context must be a positive integer")
319 except (TypeError, ValueError) as e:
324 except (TypeError, ValueError) as e:
320 raise ValueError("Context must be a positive integer") from e
325 raise ValueError("Context must be a positive integer") from e
321
326
322 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
327 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
323 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
328 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
324
329
325 # IPython changes...
330 # IPython changes...
326 self.shell = get_ipython()
331 self.shell = get_ipython()
327
332
328 if self.shell is None:
333 if self.shell is None:
329 save_main = sys.modules['__main__']
334 save_main = sys.modules['__main__']
330 # No IPython instance running, we must create one
335 # No IPython instance running, we must create one
331 from IPython.terminal.interactiveshell import \
336 from IPython.terminal.interactiveshell import \
332 TerminalInteractiveShell
337 TerminalInteractiveShell
333 self.shell = TerminalInteractiveShell.instance()
338 self.shell = TerminalInteractiveShell.instance()
334 # needed by any code which calls __import__("__main__") after
339 # needed by any code which calls __import__("__main__") after
335 # the debugger was entered. See also #9941.
340 # the debugger was entered. See also #9941.
336 sys.modules["__main__"] = save_main
341 sys.modules["__main__"] = save_main
337
342
338 if color_scheme is not None:
343 if color_scheme is not None:
339 warnings.warn(
344 warnings.warn(
340 "The `color_scheme` argument is deprecated since version 5.1",
345 "The `color_scheme` argument is deprecated since version 5.1",
341 DeprecationWarning, stacklevel=2)
346 DeprecationWarning, stacklevel=2)
342 else:
347 else:
343 color_scheme = self.shell.colors
348 color_scheme = self.shell.colors
344
349
345 self.aliases = {}
350 self.aliases = {}
346
351
347 # Create color table: we copy the default one from the traceback
352 # Create color table: we copy the default one from the traceback
348 # module and add a few attributes needed for debugging
353 # module and add a few attributes needed for debugging
349 self.color_scheme_table = exception_colors()
354 self.color_scheme_table = exception_colors()
350
355
351 # shorthands
356 # shorthands
352 C = coloransi.TermColors
357 C = coloransi.TermColors
353 cst = self.color_scheme_table
358 cst = self.color_scheme_table
354
359
355 cst['NoColor'].colors.prompt = C.NoColor
360 cst['NoColor'].colors.prompt = C.NoColor
356 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
361 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
357 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
362 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
358
363
359 cst['Linux'].colors.prompt = C.Green
364 cst['Linux'].colors.prompt = C.Green
360 cst['Linux'].colors.breakpoint_enabled = C.LightRed
365 cst['Linux'].colors.breakpoint_enabled = C.LightRed
361 cst['Linux'].colors.breakpoint_disabled = C.Red
366 cst['Linux'].colors.breakpoint_disabled = C.Red
362
367
363 cst['LightBG'].colors.prompt = C.Blue
368 cst['LightBG'].colors.prompt = C.Blue
364 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
369 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
365 cst['LightBG'].colors.breakpoint_disabled = C.Red
370 cst['LightBG'].colors.breakpoint_disabled = C.Red
366
371
367 cst['Neutral'].colors.prompt = C.Blue
372 cst['Neutral'].colors.prompt = C.Blue
368 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
373 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
369 cst['Neutral'].colors.breakpoint_disabled = C.Red
374 cst['Neutral'].colors.breakpoint_disabled = C.Red
370
375
371 # Add a python parser so we can syntax highlight source while
376 # Add a python parser so we can syntax highlight source while
372 # debugging.
377 # debugging.
373 self.parser = PyColorize.Parser(style=color_scheme)
378 self.parser = PyColorize.Parser(style=color_scheme)
374 self.set_colors(color_scheme)
379 self.set_colors(color_scheme)
375
380
376 # Set the prompt - the default prompt is '(Pdb)'
381 # Set the prompt - the default prompt is '(Pdb)'
377 self.prompt = prompt
382 self.prompt = prompt
378 self.skip_hidden = True
383 self.skip_hidden = True
379 self.report_skipped = True
384 self.report_skipped = True
380
385
381 # list of predicates we use to skip frames
386 # list of predicates we use to skip frames
382 self._predicates = self.default_predicates
387 self._predicates = self.default_predicates
383
388
384 #
389 #
385 def set_colors(self, scheme):
390 def set_colors(self, scheme):
386 """Shorthand access to the color table scheme selector method."""
391 """Shorthand access to the color table scheme selector method."""
387 self.color_scheme_table.set_active_scheme(scheme)
392 self.color_scheme_table.set_active_scheme(scheme)
388 self.parser.style = scheme
393 self.parser.style = scheme
389
394
390 def set_trace(self, frame=None):
395 def set_trace(self, frame=None):
391 if frame is None:
396 if frame is None:
392 frame = sys._getframe().f_back
397 frame = sys._getframe().f_back
393 self.initial_frame = frame
398 self.initial_frame = frame
394 return super().set_trace(frame)
399 return super().set_trace(frame)
395
400
396 def _hidden_predicate(self, frame):
401 def _hidden_predicate(self, frame):
397 """
402 """
398 Given a frame return whether it it should be hidden or not by IPython.
403 Given a frame return whether it it should be hidden or not by IPython.
399 """
404 """
400
405
401 if self._predicates["readonly"]:
406 if self._predicates["readonly"]:
402 fname = frame.f_code.co_filename
407 fname = frame.f_code.co_filename
403 # we need to check for file existence and interactively define
408 # we need to check for file existence and interactively define
404 # function would otherwise appear as RO.
409 # function would otherwise appear as RO.
405 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
410 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
406 return True
411 return True
407
412
408 if self._predicates["tbhide"]:
413 if self._predicates["tbhide"]:
409 if frame in (self.curframe, getattr(self, "initial_frame", None)):
414 if frame in (self.curframe, getattr(self, "initial_frame", None)):
410 return False
415 return False
411 else:
416 else:
412 return self._get_frame_locals(frame).get("__tracebackhide__", False)
417 return self._get_frame_locals(frame).get("__tracebackhide__", False)
413
418
414 return False
419 return False
415
420
416 def hidden_frames(self, stack):
421 def hidden_frames(self, stack):
417 """
422 """
418 Given an index in the stack return whether it should be skipped.
423 Given an index in the stack return whether it should be skipped.
419
424
420 This is used in up/down and where to skip frames.
425 This is used in up/down and where to skip frames.
421 """
426 """
422 # The f_locals dictionary is updated from the actual frame
427 # The f_locals dictionary is updated from the actual frame
423 # locals whenever the .f_locals accessor is called, so we
428 # locals whenever the .f_locals accessor is called, so we
424 # avoid calling it here to preserve self.curframe_locals.
429 # avoid calling it here to preserve self.curframe_locals.
425 # Futhermore, there is no good reason to hide the current frame.
430 # Futhermore, there is no good reason to hide the current frame.
426 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
431 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
427 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
432 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
428 if ip_start and self._predicates["ipython_internal"]:
433 if ip_start and self._predicates["ipython_internal"]:
429 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
434 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
430 return ip_hide
435 return ip_hide
431
436
432 def interaction(self, frame, traceback):
437 def interaction(self, frame, traceback):
433 try:
438 try:
434 OldPdb.interaction(self, frame, traceback)
439 OldPdb.interaction(self, frame, traceback)
435 except KeyboardInterrupt:
440 except KeyboardInterrupt:
436 self.stdout.write("\n" + self.shell.get_exception_only())
441 self.stdout.write("\n" + self.shell.get_exception_only())
437
442
438 def precmd(self, line):
443 def precmd(self, line):
439 """Perform useful escapes on the command before it is executed."""
444 """Perform useful escapes on the command before it is executed."""
440
445
441 if line.endswith("??"):
446 if line.endswith("??"):
442 line = "pinfo2 " + line[:-2]
447 line = "pinfo2 " + line[:-2]
443 elif line.endswith("?"):
448 elif line.endswith("?"):
444 line = "pinfo " + line[:-1]
449 line = "pinfo " + line[:-1]
445
450
446 line = super().precmd(line)
451 line = super().precmd(line)
447
452
448 return line
453 return line
449
454
450 def new_do_frame(self, arg):
455 def new_do_frame(self, arg):
451 OldPdb.do_frame(self, arg)
456 OldPdb.do_frame(self, arg)
452
457
453 def new_do_quit(self, arg):
458 def new_do_quit(self, arg):
454
459
455 if hasattr(self, 'old_all_completions'):
460 if hasattr(self, 'old_all_completions'):
456 self.shell.Completer.all_completions = self.old_all_completions
461 self.shell.Completer.all_completions = self.old_all_completions
457
462
458 return OldPdb.do_quit(self, arg)
463 return OldPdb.do_quit(self, arg)
459
464
460 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
465 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
461
466
462 def new_do_restart(self, arg):
467 def new_do_restart(self, arg):
463 """Restart command. In the context of ipython this is exactly the same
468 """Restart command. In the context of ipython this is exactly the same
464 thing as 'quit'."""
469 thing as 'quit'."""
465 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
470 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
466 return self.do_quit(arg)
471 return self.do_quit(arg)
467
472
468 def print_stack_trace(self, context=None):
473 def print_stack_trace(self, context=None):
469 Colors = self.color_scheme_table.active_colors
474 Colors = self.color_scheme_table.active_colors
470 ColorsNormal = Colors.Normal
475 ColorsNormal = Colors.Normal
471 if context is None:
476 if context is None:
472 context = self.context
477 context = self.context
473 try:
478 try:
474 context = int(context)
479 context = int(context)
475 if context <= 0:
480 if context <= 0:
476 raise ValueError("Context must be a positive integer")
481 raise ValueError("Context must be a positive integer")
477 except (TypeError, ValueError) as e:
482 except (TypeError, ValueError) as e:
478 raise ValueError("Context must be a positive integer") from e
483 raise ValueError("Context must be a positive integer") from e
479 try:
484 try:
480 skipped = 0
485 skipped = 0
481 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
486 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
482 if hidden and self.skip_hidden:
487 if hidden and self.skip_hidden:
483 skipped += 1
488 skipped += 1
484 continue
489 continue
485 if skipped:
490 if skipped:
486 print(
491 print(
487 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
492 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
488 )
493 )
489 skipped = 0
494 skipped = 0
490 self.print_stack_entry(frame_lineno, context=context)
495 self.print_stack_entry(frame_lineno, context=context)
491 if skipped:
496 if skipped:
492 print(
497 print(
493 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
498 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
494 )
499 )
495 except KeyboardInterrupt:
500 except KeyboardInterrupt:
496 pass
501 pass
497
502
498 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
503 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
499 context=None):
504 context=None):
500 if context is None:
505 if context is None:
501 context = self.context
506 context = self.context
502 try:
507 try:
503 context = int(context)
508 context = int(context)
504 if context <= 0:
509 if context <= 0:
505 raise ValueError("Context must be a positive integer")
510 raise ValueError("Context must be a positive integer")
506 except (TypeError, ValueError) as e:
511 except (TypeError, ValueError) as e:
507 raise ValueError("Context must be a positive integer") from e
512 raise ValueError("Context must be a positive integer") from e
508 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
513 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
509
514
510 # vds: >>
515 # vds: >>
511 frame, lineno = frame_lineno
516 frame, lineno = frame_lineno
512 filename = frame.f_code.co_filename
517 filename = frame.f_code.co_filename
513 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
518 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
514 # vds: <<
519 # vds: <<
515
520
516 def _get_frame_locals(self, frame):
521 def _get_frame_locals(self, frame):
517 """ "
522 """ "
518 Acessing f_local of current frame reset the namespace, so we want to avoid
523 Acessing f_local of current frame reset the namespace, so we want to avoid
519 that or the following can happend
524 that or the following can happend
520
525
521 ipdb> foo
526 ipdb> foo
522 "old"
527 "old"
523 ipdb> foo = "new"
528 ipdb> foo = "new"
524 ipdb> foo
529 ipdb> foo
525 "new"
530 "new"
526 ipdb> where
531 ipdb> where
527 ipdb> foo
532 ipdb> foo
528 "old"
533 "old"
529
534
530 So if frame is self.current_frame we instead return self.curframe_locals
535 So if frame is self.current_frame we instead return self.curframe_locals
531
536
532 """
537 """
533 if frame is self.curframe:
538 if frame is self.curframe:
534 return self.curframe_locals
539 return self.curframe_locals
535 else:
540 else:
536 return frame.f_locals
541 return frame.f_locals
537
542
538 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
543 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
539 if context is None:
544 if context is None:
540 context = self.context
545 context = self.context
541 try:
546 try:
542 context = int(context)
547 context = int(context)
543 if context <= 0:
548 if context <= 0:
544 print("Context must be a positive integer", file=self.stdout)
549 print("Context must be a positive integer", file=self.stdout)
545 except (TypeError, ValueError):
550 except (TypeError, ValueError):
546 print("Context must be a positive integer", file=self.stdout)
551 print("Context must be a positive integer", file=self.stdout)
547
552
548 import reprlib
553 import reprlib
549
554
550 ret = []
555 ret = []
551
556
552 Colors = self.color_scheme_table.active_colors
557 Colors = self.color_scheme_table.active_colors
553 ColorsNormal = Colors.Normal
558 ColorsNormal = Colors.Normal
554 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
559 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
555 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
560 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
556 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
561 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
557 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
562 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
558
563
559 frame, lineno = frame_lineno
564 frame, lineno = frame_lineno
560
565
561 return_value = ''
566 return_value = ''
562 loc_frame = self._get_frame_locals(frame)
567 loc_frame = self._get_frame_locals(frame)
563 if "__return__" in loc_frame:
568 if "__return__" in loc_frame:
564 rv = loc_frame["__return__"]
569 rv = loc_frame["__return__"]
565 # return_value += '->'
570 # return_value += '->'
566 return_value += reprlib.repr(rv) + "\n"
571 return_value += reprlib.repr(rv) + "\n"
567 ret.append(return_value)
572 ret.append(return_value)
568
573
569 #s = filename + '(' + `lineno` + ')'
574 #s = filename + '(' + `lineno` + ')'
570 filename = self.canonic(frame.f_code.co_filename)
575 filename = self.canonic(frame.f_code.co_filename)
571 link = tpl_link % py3compat.cast_unicode(filename)
576 link = tpl_link % py3compat.cast_unicode(filename)
572
577
573 if frame.f_code.co_name:
578 if frame.f_code.co_name:
574 func = frame.f_code.co_name
579 func = frame.f_code.co_name
575 else:
580 else:
576 func = "<lambda>"
581 func = "<lambda>"
577
582
578 call = ""
583 call = ""
579 if func != "?":
584 if func != "?":
580 if "__args__" in loc_frame:
585 if "__args__" in loc_frame:
581 args = reprlib.repr(loc_frame["__args__"])
586 args = reprlib.repr(loc_frame["__args__"])
582 else:
587 else:
583 args = '()'
588 args = '()'
584 call = tpl_call % (func, args)
589 call = tpl_call % (func, args)
585
590
586 # The level info should be generated in the same format pdb uses, to
591 # The level info should be generated in the same format pdb uses, to
587 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
592 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
588 if frame is self.curframe:
593 if frame is self.curframe:
589 ret.append('> ')
594 ret.append('> ')
590 else:
595 else:
591 ret.append(" ")
596 ret.append(" ")
592 ret.append("%s(%s)%s\n" % (link, lineno, call))
597 ret.append("%s(%s)%s\n" % (link, lineno, call))
593
598
594 start = lineno - 1 - context//2
599 start = lineno - 1 - context//2
595 lines = linecache.getlines(filename)
600 lines = linecache.getlines(filename)
596 start = min(start, len(lines) - context)
601 start = min(start, len(lines) - context)
597 start = max(start, 0)
602 start = max(start, 0)
598 lines = lines[start : start + context]
603 lines = lines[start : start + context]
599
604
600 for i, line in enumerate(lines):
605 for i, line in enumerate(lines):
601 show_arrow = start + 1 + i == lineno
606 show_arrow = start + 1 + i == lineno
602 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
607 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
603 ret.append(
608 ret.append(
604 self.__format_line(
609 self.__format_line(
605 linetpl, filename, start + 1 + i, line, arrow=show_arrow
610 linetpl, filename, start + 1 + i, line, arrow=show_arrow
606 )
611 )
607 )
612 )
608 return "".join(ret)
613 return "".join(ret)
609
614
610 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
615 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
611 bp_mark = ""
616 bp_mark = ""
612 bp_mark_color = ""
617 bp_mark_color = ""
613
618
614 new_line, err = self.parser.format2(line, 'str')
619 new_line, err = self.parser.format2(line, 'str')
615 if not err:
620 if not err:
616 line = new_line
621 line = new_line
617
622
618 bp = None
623 bp = None
619 if lineno in self.get_file_breaks(filename):
624 if lineno in self.get_file_breaks(filename):
620 bps = self.get_breaks(filename, lineno)
625 bps = self.get_breaks(filename, lineno)
621 bp = bps[-1]
626 bp = bps[-1]
622
627
623 if bp:
628 if bp:
624 Colors = self.color_scheme_table.active_colors
629 Colors = self.color_scheme_table.active_colors
625 bp_mark = str(bp.number)
630 bp_mark = str(bp.number)
626 bp_mark_color = Colors.breakpoint_enabled
631 bp_mark_color = Colors.breakpoint_enabled
627 if not bp.enabled:
632 if not bp.enabled:
628 bp_mark_color = Colors.breakpoint_disabled
633 bp_mark_color = Colors.breakpoint_disabled
629
634
630 numbers_width = 7
635 numbers_width = 7
631 if arrow:
636 if arrow:
632 # This is the line with the error
637 # This is the line with the error
633 pad = numbers_width - len(str(lineno)) - len(bp_mark)
638 pad = numbers_width - len(str(lineno)) - len(bp_mark)
634 num = '%s%s' % (make_arrow(pad), str(lineno))
639 num = '%s%s' % (make_arrow(pad), str(lineno))
635 else:
640 else:
636 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
641 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
637
642
638 return tpl_line % (bp_mark_color + bp_mark, num, line)
643 return tpl_line % (bp_mark_color + bp_mark, num, line)
639
644
640 def print_list_lines(self, filename, first, last):
645 def print_list_lines(self, filename, first, last):
641 """The printing (as opposed to the parsing part of a 'list'
646 """The printing (as opposed to the parsing part of a 'list'
642 command."""
647 command."""
643 try:
648 try:
644 Colors = self.color_scheme_table.active_colors
649 Colors = self.color_scheme_table.active_colors
645 ColorsNormal = Colors.Normal
650 ColorsNormal = Colors.Normal
646 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
651 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
647 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
652 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
648 src = []
653 src = []
649 if filename == "<string>" and hasattr(self, "_exec_filename"):
654 if filename == "<string>" and hasattr(self, "_exec_filename"):
650 filename = self._exec_filename
655 filename = self._exec_filename
651
656
652 for lineno in range(first, last+1):
657 for lineno in range(first, last+1):
653 line = linecache.getline(filename, lineno)
658 line = linecache.getline(filename, lineno)
654 if not line:
659 if not line:
655 break
660 break
656
661
657 if lineno == self.curframe.f_lineno:
662 if lineno == self.curframe.f_lineno:
658 line = self.__format_line(
663 line = self.__format_line(
659 tpl_line_em, filename, lineno, line, arrow=True
664 tpl_line_em, filename, lineno, line, arrow=True
660 )
665 )
661 else:
666 else:
662 line = self.__format_line(
667 line = self.__format_line(
663 tpl_line, filename, lineno, line, arrow=False
668 tpl_line, filename, lineno, line, arrow=False
664 )
669 )
665
670
666 src.append(line)
671 src.append(line)
667 self.lineno = lineno
672 self.lineno = lineno
668
673
669 print(''.join(src), file=self.stdout)
674 print(''.join(src), file=self.stdout)
670
675
671 except KeyboardInterrupt:
676 except KeyboardInterrupt:
672 pass
677 pass
673
678
674 def do_skip_predicates(self, args):
679 def do_skip_predicates(self, args):
675 """
680 """
676 Turn on/off individual predicates as to whether a frame should be hidden/skip.
681 Turn on/off individual predicates as to whether a frame should be hidden/skip.
677
682
678 The global option to skip (or not) hidden frames is set with skip_hidden
683 The global option to skip (or not) hidden frames is set with skip_hidden
679
684
680 To change the value of a predicate
685 To change the value of a predicate
681
686
682 skip_predicates key [true|false]
687 skip_predicates key [true|false]
683
688
684 Call without arguments to see the current values.
689 Call without arguments to see the current values.
685
690
686 To permanently change the value of an option add the corresponding
691 To permanently change the value of an option add the corresponding
687 command to your ``~/.pdbrc`` file. If you are programmatically using the
692 command to your ``~/.pdbrc`` file. If you are programmatically using the
688 Pdb instance you can also change the ``default_predicates`` class
693 Pdb instance you can also change the ``default_predicates`` class
689 attribute.
694 attribute.
690 """
695 """
691 if not args.strip():
696 if not args.strip():
692 print("current predicates:")
697 print("current predicates:")
693 for (p, v) in self._predicates.items():
698 for (p, v) in self._predicates.items():
694 print(" ", p, ":", v)
699 print(" ", p, ":", v)
695 return
700 return
696 type_value = args.strip().split(" ")
701 type_value = args.strip().split(" ")
697 if len(type_value) != 2:
702 if len(type_value) != 2:
698 print(
703 print(
699 f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
704 f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
700 )
705 )
701 return
706 return
702
707
703 type_, value = type_value
708 type_, value = type_value
704 if type_ not in self._predicates:
709 if type_ not in self._predicates:
705 print(f"{type_!r} not in {set(self._predicates.keys())}")
710 print(f"{type_!r} not in {set(self._predicates.keys())}")
706 return
711 return
707 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
712 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
708 print(
713 print(
709 f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
714 f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
710 )
715 )
711 return
716 return
712
717
713 self._predicates[type_] = value.lower() in ("true", "yes", "1")
718 self._predicates[type_] = value.lower() in ("true", "yes", "1")
714 if not any(self._predicates.values()):
719 if not any(self._predicates.values()):
715 print(
720 print(
716 "Warning, all predicates set to False, skip_hidden may not have any effects."
721 "Warning, all predicates set to False, skip_hidden may not have any effects."
717 )
722 )
718
723
719 def do_skip_hidden(self, arg):
724 def do_skip_hidden(self, arg):
720 """
725 """
721 Change whether or not we should skip frames with the
726 Change whether or not we should skip frames with the
722 __tracebackhide__ attribute.
727 __tracebackhide__ attribute.
723 """
728 """
724 if not arg.strip():
729 if not arg.strip():
725 print(
730 print(
726 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
731 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
727 )
732 )
728 elif arg.strip().lower() in ("true", "yes"):
733 elif arg.strip().lower() in ("true", "yes"):
729 self.skip_hidden = True
734 self.skip_hidden = True
730 elif arg.strip().lower() in ("false", "no"):
735 elif arg.strip().lower() in ("false", "no"):
731 self.skip_hidden = False
736 self.skip_hidden = False
732 if not any(self._predicates.values()):
737 if not any(self._predicates.values()):
733 print(
738 print(
734 "Warning, all predicates set to False, skip_hidden may not have any effects."
739 "Warning, all predicates set to False, skip_hidden may not have any effects."
735 )
740 )
736
741
737 def do_list(self, arg):
742 def do_list(self, arg):
738 """Print lines of code from the current stack frame
743 """Print lines of code from the current stack frame
739 """
744 """
740 self.lastcmd = 'list'
745 self.lastcmd = 'list'
741 last = None
746 last = None
742 if arg:
747 if arg:
743 try:
748 try:
744 x = eval(arg, {}, {})
749 x = eval(arg, {}, {})
745 if type(x) == type(()):
750 if type(x) == type(()):
746 first, last = x
751 first, last = x
747 first = int(first)
752 first = int(first)
748 last = int(last)
753 last = int(last)
749 if last < first:
754 if last < first:
750 # Assume it's a count
755 # Assume it's a count
751 last = first + last
756 last = first + last
752 else:
757 else:
753 first = max(1, int(x) - 5)
758 first = max(1, int(x) - 5)
754 except:
759 except:
755 print('*** Error in argument:', repr(arg), file=self.stdout)
760 print('*** Error in argument:', repr(arg), file=self.stdout)
756 return
761 return
757 elif self.lineno is None:
762 elif self.lineno is None:
758 first = max(1, self.curframe.f_lineno - 5)
763 first = max(1, self.curframe.f_lineno - 5)
759 else:
764 else:
760 first = self.lineno + 1
765 first = self.lineno + 1
761 if last is None:
766 if last is None:
762 last = first + 10
767 last = first + 10
763 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
768 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
764
769
765 # vds: >>
770 # vds: >>
766 lineno = first
771 lineno = first
767 filename = self.curframe.f_code.co_filename
772 filename = self.curframe.f_code.co_filename
768 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
773 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
769 # vds: <<
774 # vds: <<
770
775
771 do_l = do_list
776 do_l = do_list
772
777
773 def getsourcelines(self, obj):
778 def getsourcelines(self, obj):
774 lines, lineno = inspect.findsource(obj)
779 lines, lineno = inspect.findsource(obj)
775 if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj):
780 if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj):
776 # must be a module frame: do not try to cut a block out of it
781 # must be a module frame: do not try to cut a block out of it
777 return lines, 1
782 return lines, 1
778 elif inspect.ismodule(obj):
783 elif inspect.ismodule(obj):
779 return lines, 1
784 return lines, 1
780 return inspect.getblock(lines[lineno:]), lineno+1
785 return inspect.getblock(lines[lineno:]), lineno+1
781
786
782 def do_longlist(self, arg):
787 def do_longlist(self, arg):
783 """Print lines of code from the current stack frame.
788 """Print lines of code from the current stack frame.
784
789
785 Shows more lines than 'list' does.
790 Shows more lines than 'list' does.
786 """
791 """
787 self.lastcmd = 'longlist'
792 self.lastcmd = 'longlist'
788 try:
793 try:
789 lines, lineno = self.getsourcelines(self.curframe)
794 lines, lineno = self.getsourcelines(self.curframe)
790 except OSError as err:
795 except OSError as err:
791 self.error(err)
796 self.error(err)
792 return
797 return
793 last = lineno + len(lines)
798 last = lineno + len(lines)
794 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
799 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
795 do_ll = do_longlist
800 do_ll = do_longlist
796
801
797 def do_debug(self, arg):
802 def do_debug(self, arg):
798 """debug code
803 """debug code
799 Enter a recursive debugger that steps through the code
804 Enter a recursive debugger that steps through the code
800 argument (which is an arbitrary expression or statement to be
805 argument (which is an arbitrary expression or statement to be
801 executed in the current environment).
806 executed in the current environment).
802 """
807 """
803 trace_function = sys.gettrace()
808 trace_function = sys.gettrace()
804 sys.settrace(None)
809 sys.settrace(None)
805 globals = self.curframe.f_globals
810 globals = self.curframe.f_globals
806 locals = self.curframe_locals
811 locals = self.curframe_locals
807 p = self.__class__(completekey=self.completekey,
812 p = self.__class__(completekey=self.completekey,
808 stdin=self.stdin, stdout=self.stdout)
813 stdin=self.stdin, stdout=self.stdout)
809 p.use_rawinput = self.use_rawinput
814 p.use_rawinput = self.use_rawinput
810 p.prompt = "(%s) " % self.prompt.strip()
815 p.prompt = "(%s) " % self.prompt.strip()
811 self.message("ENTERING RECURSIVE DEBUGGER")
816 self.message("ENTERING RECURSIVE DEBUGGER")
812 sys.call_tracing(p.run, (arg, globals, locals))
817 sys.call_tracing(p.run, (arg, globals, locals))
813 self.message("LEAVING RECURSIVE DEBUGGER")
818 self.message("LEAVING RECURSIVE DEBUGGER")
814 sys.settrace(trace_function)
819 sys.settrace(trace_function)
815 self.lastcmd = p.lastcmd
820 self.lastcmd = p.lastcmd
816
821
817 def do_pdef(self, arg):
822 def do_pdef(self, arg):
818 """Print the call signature for any callable object.
823 """Print the call signature for any callable object.
819
824
820 The debugger interface to %pdef"""
825 The debugger interface to %pdef"""
821 namespaces = [
826 namespaces = [
822 ("Locals", self.curframe_locals),
827 ("Locals", self.curframe_locals),
823 ("Globals", self.curframe.f_globals),
828 ("Globals", self.curframe.f_globals),
824 ]
829 ]
825 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
830 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
826
831
827 def do_pdoc(self, arg):
832 def do_pdoc(self, arg):
828 """Print the docstring for an object.
833 """Print the docstring for an object.
829
834
830 The debugger interface to %pdoc."""
835 The debugger interface to %pdoc."""
831 namespaces = [
836 namespaces = [
832 ("Locals", self.curframe_locals),
837 ("Locals", self.curframe_locals),
833 ("Globals", self.curframe.f_globals),
838 ("Globals", self.curframe.f_globals),
834 ]
839 ]
835 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
840 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
836
841
837 def do_pfile(self, arg):
842 def do_pfile(self, arg):
838 """Print (or run through pager) the file where an object is defined.
843 """Print (or run through pager) the file where an object is defined.
839
844
840 The debugger interface to %pfile.
845 The debugger interface to %pfile.
841 """
846 """
842 namespaces = [
847 namespaces = [
843 ("Locals", self.curframe_locals),
848 ("Locals", self.curframe_locals),
844 ("Globals", self.curframe.f_globals),
849 ("Globals", self.curframe.f_globals),
845 ]
850 ]
846 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
851 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
847
852
848 def do_pinfo(self, arg):
853 def do_pinfo(self, arg):
849 """Provide detailed information about an object.
854 """Provide detailed information about an object.
850
855
851 The debugger interface to %pinfo, i.e., obj?."""
856 The debugger interface to %pinfo, i.e., obj?."""
852 namespaces = [
857 namespaces = [
853 ("Locals", self.curframe_locals),
858 ("Locals", self.curframe_locals),
854 ("Globals", self.curframe.f_globals),
859 ("Globals", self.curframe.f_globals),
855 ]
860 ]
856 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
861 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
857
862
858 def do_pinfo2(self, arg):
863 def do_pinfo2(self, arg):
859 """Provide extra detailed information about an object.
864 """Provide extra detailed information about an object.
860
865
861 The debugger interface to %pinfo2, i.e., obj??."""
866 The debugger interface to %pinfo2, i.e., obj??."""
862 namespaces = [
867 namespaces = [
863 ("Locals", self.curframe_locals),
868 ("Locals", self.curframe_locals),
864 ("Globals", self.curframe.f_globals),
869 ("Globals", self.curframe.f_globals),
865 ]
870 ]
866 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
871 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
867
872
868 def do_psource(self, arg):
873 def do_psource(self, arg):
869 """Print (or run through pager) the source code for an object."""
874 """Print (or run through pager) the source code for an object."""
870 namespaces = [
875 namespaces = [
871 ("Locals", self.curframe_locals),
876 ("Locals", self.curframe_locals),
872 ("Globals", self.curframe.f_globals),
877 ("Globals", self.curframe.f_globals),
873 ]
878 ]
874 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
879 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
875
880
876 def do_where(self, arg):
881 def do_where(self, arg):
877 """w(here)
882 """w(here)
878 Print a stack trace, with the most recent frame at the bottom.
883 Print a stack trace, with the most recent frame at the bottom.
879 An arrow indicates the "current frame", which determines the
884 An arrow indicates the "current frame", which determines the
880 context of most commands. 'bt' is an alias for this command.
885 context of most commands. 'bt' is an alias for this command.
881
886
882 Take a number as argument as an (optional) number of context line to
887 Take a number as argument as an (optional) number of context line to
883 print"""
888 print"""
884 if arg:
889 if arg:
885 try:
890 try:
886 context = int(arg)
891 context = int(arg)
887 except ValueError as err:
892 except ValueError as err:
888 self.error(err)
893 self.error(err)
889 return
894 return
890 self.print_stack_trace(context)
895 self.print_stack_trace(context)
891 else:
896 else:
892 self.print_stack_trace()
897 self.print_stack_trace()
893
898
894 do_w = do_where
899 do_w = do_where
895
900
896 def break_anywhere(self, frame):
901 def break_anywhere(self, frame):
897 """
902 """
898
903
899 _stop_in_decorator_internals is overly restrictive, as we may still want
904 _stop_in_decorator_internals is overly restrictive, as we may still want
900 to trace function calls, so we need to also update break_anywhere so
905 to trace function calls, so we need to also update break_anywhere so
901 that is we don't `stop_here`, because of debugger skip, we may still
906 that is we don't `stop_here`, because of debugger skip, we may still
902 stop at any point inside the function
907 stop at any point inside the function
903
908
904 """
909 """
910
911 sup = super().break_anywhere(frame)
912 if sup:
913 return sup
905 if self._predicates["debuggerskip"]:
914 if self._predicates["debuggerskip"]:
906 if DEBUGGERSKIP in frame.f_code.co_varnames:
915 if DEBUGGERSKIP in frame.f_code.co_varnames:
907 return True
916 return True
908 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
917 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
909 return True
918 return True
910 return super().break_anywhere(frame)
919 return False
911
920
912 @skip_doctest
921 @skip_doctest
913 def _is_in_decorator_internal_and_should_skip(self, frame):
922 def _is_in_decorator_internal_and_should_skip(self, frame):
914 """
923 """
915 Utility to tell us whether we are in a decorator internal and should stop.
924 Utility to tell us whether we are in a decorator internal and should stop.
916
925
917
926
918
927
919 """
928 """
920
929
921 # if we are disabled don't skip
930 # if we are disabled don't skip
922 if not self._predicates["debuggerskip"]:
931 if not self._predicates["debuggerskip"]:
923 return False
932 return False
924
933
925 # if frame is tagged, skip by default.
934 # if frame is tagged, skip by default.
926 if DEBUGGERSKIP in frame.f_code.co_varnames:
935 if DEBUGGERSKIP in frame.f_code.co_varnames:
927 return True
936 return True
928
937
929 # if parent frame value set to True skip as well.
938 # if one of the parent frame value set to True skip as well.
930 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
939
931 return True
940 cframe = frame
941 while getattr(cframe, "f_back", None):
942 cframe = cframe.f_back
943 if self._get_frame_locals(cframe).get(DEBUGGERSKIP):
944 return True
932
945
933 return False
946 return False
934
947
935 def stop_here(self, frame):
948 def stop_here(self, frame):
936
949
937 if self._is_in_decorator_internal_and_should_skip(frame) is True:
950 if self._is_in_decorator_internal_and_should_skip(frame) is True:
938 return False
951 return False
939
952
940 hidden = False
953 hidden = False
941 if self.skip_hidden:
954 if self.skip_hidden:
942 hidden = self._hidden_predicate(frame)
955 hidden = self._hidden_predicate(frame)
943 if hidden:
956 if hidden:
944 if self.report_skipped:
957 if self.report_skipped:
945 Colors = self.color_scheme_table.active_colors
958 Colors = self.color_scheme_table.active_colors
946 ColorsNormal = Colors.Normal
959 ColorsNormal = Colors.Normal
947 print(
960 print(
948 f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n"
961 f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n"
949 )
962 )
950 return super().stop_here(frame)
963 return super().stop_here(frame)
951
964
952 def do_up(self, arg):
965 def do_up(self, arg):
953 """u(p) [count]
966 """u(p) [count]
954 Move the current frame count (default one) levels up in the
967 Move the current frame count (default one) levels up in the
955 stack trace (to an older frame).
968 stack trace (to an older frame).
956
969
957 Will skip hidden frames.
970 Will skip hidden frames.
958 """
971 """
959 # modified version of upstream that skips
972 # modified version of upstream that skips
960 # frames with __tracebackhide__
973 # frames with __tracebackhide__
961 if self.curindex == 0:
974 if self.curindex == 0:
962 self.error("Oldest frame")
975 self.error("Oldest frame")
963 return
976 return
964 try:
977 try:
965 count = int(arg or 1)
978 count = int(arg or 1)
966 except ValueError:
979 except ValueError:
967 self.error("Invalid frame count (%s)" % arg)
980 self.error("Invalid frame count (%s)" % arg)
968 return
981 return
969 skipped = 0
982 skipped = 0
970 if count < 0:
983 if count < 0:
971 _newframe = 0
984 _newframe = 0
972 else:
985 else:
973 counter = 0
986 counter = 0
974 hidden_frames = self.hidden_frames(self.stack)
987 hidden_frames = self.hidden_frames(self.stack)
975 for i in range(self.curindex - 1, -1, -1):
988 for i in range(self.curindex - 1, -1, -1):
976 if hidden_frames[i] and self.skip_hidden:
989 if hidden_frames[i] and self.skip_hidden:
977 skipped += 1
990 skipped += 1
978 continue
991 continue
979 counter += 1
992 counter += 1
980 if counter >= count:
993 if counter >= count:
981 break
994 break
982 else:
995 else:
983 # if no break occured.
996 # if no break occured.
984 self.error(
997 self.error(
985 "all frames above hidden, use `skip_hidden False` to get get into those."
998 "all frames above hidden, use `skip_hidden False` to get get into those."
986 )
999 )
987 return
1000 return
988
1001
989 Colors = self.color_scheme_table.active_colors
1002 Colors = self.color_scheme_table.active_colors
990 ColorsNormal = Colors.Normal
1003 ColorsNormal = Colors.Normal
991 _newframe = i
1004 _newframe = i
992 self._select_frame(_newframe)
1005 self._select_frame(_newframe)
993 if skipped:
1006 if skipped:
994 print(
1007 print(
995 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1008 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
996 )
1009 )
997
1010
998 def do_down(self, arg):
1011 def do_down(self, arg):
999 """d(own) [count]
1012 """d(own) [count]
1000 Move the current frame count (default one) levels down in the
1013 Move the current frame count (default one) levels down in the
1001 stack trace (to a newer frame).
1014 stack trace (to a newer frame).
1002
1015
1003 Will skip hidden frames.
1016 Will skip hidden frames.
1004 """
1017 """
1005 if self.curindex + 1 == len(self.stack):
1018 if self.curindex + 1 == len(self.stack):
1006 self.error("Newest frame")
1019 self.error("Newest frame")
1007 return
1020 return
1008 try:
1021 try:
1009 count = int(arg or 1)
1022 count = int(arg or 1)
1010 except ValueError:
1023 except ValueError:
1011 self.error("Invalid frame count (%s)" % arg)
1024 self.error("Invalid frame count (%s)" % arg)
1012 return
1025 return
1013 if count < 0:
1026 if count < 0:
1014 _newframe = len(self.stack) - 1
1027 _newframe = len(self.stack) - 1
1015 else:
1028 else:
1016 counter = 0
1029 counter = 0
1017 skipped = 0
1030 skipped = 0
1018 hidden_frames = self.hidden_frames(self.stack)
1031 hidden_frames = self.hidden_frames(self.stack)
1019 for i in range(self.curindex + 1, len(self.stack)):
1032 for i in range(self.curindex + 1, len(self.stack)):
1020 if hidden_frames[i] and self.skip_hidden:
1033 if hidden_frames[i] and self.skip_hidden:
1021 skipped += 1
1034 skipped += 1
1022 continue
1035 continue
1023 counter += 1
1036 counter += 1
1024 if counter >= count:
1037 if counter >= count:
1025 break
1038 break
1026 else:
1039 else:
1027 self.error(
1040 self.error(
1028 "all frames bellow hidden, use `skip_hidden False` to get get into those."
1041 "all frames bellow hidden, use `skip_hidden False` to get get into those."
1029 )
1042 )
1030 return
1043 return
1031
1044
1032 Colors = self.color_scheme_table.active_colors
1045 Colors = self.color_scheme_table.active_colors
1033 ColorsNormal = Colors.Normal
1046 ColorsNormal = Colors.Normal
1034 if skipped:
1047 if skipped:
1035 print(
1048 print(
1036 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1049 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1037 )
1050 )
1038 _newframe = i
1051 _newframe = i
1039
1052
1040 self._select_frame(_newframe)
1053 self._select_frame(_newframe)
1041
1054
1042 do_d = do_down
1055 do_d = do_down
1043 do_u = do_up
1056 do_u = do_up
1044
1057
1045 def do_context(self, context):
1058 def do_context(self, context):
1046 """context number_of_lines
1059 """context number_of_lines
1047 Set the number of lines of source code to show when displaying
1060 Set the number of lines of source code to show when displaying
1048 stacktrace information.
1061 stacktrace information.
1049 """
1062 """
1050 try:
1063 try:
1051 new_context = int(context)
1064 new_context = int(context)
1052 if new_context <= 0:
1065 if new_context <= 0:
1053 raise ValueError()
1066 raise ValueError()
1054 self.context = new_context
1067 self.context = new_context
1055 except ValueError:
1068 except ValueError:
1056 self.error("The 'context' command requires a positive integer argument.")
1069 self.error("The 'context' command requires a positive integer argument.")
1057
1070
1058
1071
1059 class InterruptiblePdb(Pdb):
1072 class InterruptiblePdb(Pdb):
1060 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
1073 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
1061
1074
1062 def cmdloop(self, intro=None):
1075 def cmdloop(self, intro=None):
1063 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
1076 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
1064 try:
1077 try:
1065 return OldPdb.cmdloop(self, intro=intro)
1078 return OldPdb.cmdloop(self, intro=intro)
1066 except KeyboardInterrupt:
1079 except KeyboardInterrupt:
1067 self.stop_here = lambda frame: False
1080 self.stop_here = lambda frame: False
1068 self.do_quit("")
1081 self.do_quit("")
1069 sys.settrace(None)
1082 sys.settrace(None)
1070 self.quitting = False
1083 self.quitting = False
1071 raise
1084 raise
1072
1085
1073 def _cmdloop(self):
1086 def _cmdloop(self):
1074 while True:
1087 while True:
1075 try:
1088 try:
1076 # keyboard interrupts allow for an easy way to cancel
1089 # keyboard interrupts allow for an easy way to cancel
1077 # the current command, so allow them during interactive input
1090 # the current command, so allow them during interactive input
1078 self.allow_kbdint = True
1091 self.allow_kbdint = True
1079 self.cmdloop()
1092 self.cmdloop()
1080 self.allow_kbdint = False
1093 self.allow_kbdint = False
1081 break
1094 break
1082 except KeyboardInterrupt:
1095 except KeyboardInterrupt:
1083 self.message('--KeyboardInterrupt--')
1096 self.message('--KeyboardInterrupt--')
1084 raise
1097 raise
1085
1098
1086
1099
1087 def set_trace(frame=None):
1100 def set_trace(frame=None):
1088 """
1101 """
1089 Start debugging from `frame`.
1102 Start debugging from `frame`.
1090
1103
1091 If frame is not specified, debugging starts from caller's frame.
1104 If frame is not specified, debugging starts from caller's frame.
1092 """
1105 """
1093 Pdb().set_trace(frame or sys._getframe().f_back)
1106 Pdb().set_trace(frame or sys._getframe().f_back)
@@ -1,502 +1,576 b''
1 """Tests for debugging machinery.
1 """Tests for debugging machinery.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import bdb
7 import bdb
8 import builtins
8 import builtins
9 import os
9 import os
10 import signal
10 import signal
11 import subprocess
11 import subprocess
12 import sys
12 import sys
13 import time
13 import time
14 import warnings
14 import warnings
15
15 from subprocess import PIPE, CalledProcessError, check_output
16 from subprocess import PIPE, CalledProcessError, check_output
16 from tempfile import NamedTemporaryFile
17 from tempfile import NamedTemporaryFile
17 from textwrap import dedent
18 from textwrap import dedent
18 from unittest.mock import patch
19 from unittest.mock import patch
19
20
20 import nose.tools as nt
21 import nose.tools as nt
21
22
22 from IPython.core import debugger
23 from IPython.core import debugger
23 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
24 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
24 from IPython.testing.decorators import skip_win32
25 from IPython.testing.decorators import skip_win32
25
26
26 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
27 # Helper classes, from CPython's Pdb test suite
28 # Helper classes, from CPython's Pdb test suite
28 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
29
30
30 class _FakeInput(object):
31 class _FakeInput(object):
31 """
32 """
32 A fake input stream for pdb's interactive debugger. Whenever a
33 A fake input stream for pdb's interactive debugger. Whenever a
33 line is read, print it (to simulate the user typing it), and then
34 line is read, print it (to simulate the user typing it), and then
34 return it. The set of lines to return is specified in the
35 return it. The set of lines to return is specified in the
35 constructor; they should not have trailing newlines.
36 constructor; they should not have trailing newlines.
36 """
37 """
37 def __init__(self, lines):
38 def __init__(self, lines):
38 self.lines = iter(lines)
39 self.lines = iter(lines)
39
40
40 def readline(self):
41 def readline(self):
41 line = next(self.lines)
42 line = next(self.lines)
42 print(line)
43 print(line)
43 return line+'\n'
44 return line+'\n'
44
45
45 class PdbTestInput(object):
46 class PdbTestInput(object):
46 """Context manager that makes testing Pdb in doctests easier."""
47 """Context manager that makes testing Pdb in doctests easier."""
47
48
48 def __init__(self, input):
49 def __init__(self, input):
49 self.input = input
50 self.input = input
50
51
51 def __enter__(self):
52 def __enter__(self):
52 self.real_stdin = sys.stdin
53 self.real_stdin = sys.stdin
53 sys.stdin = _FakeInput(self.input)
54 sys.stdin = _FakeInput(self.input)
54
55
55 def __exit__(self, *exc):
56 def __exit__(self, *exc):
56 sys.stdin = self.real_stdin
57 sys.stdin = self.real_stdin
57
58
58 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
59 # Tests
60 # Tests
60 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
61
62
62 def test_longer_repr():
63 def test_longer_repr():
63 from reprlib import repr as trepr
64 from reprlib import repr as trepr
64
65
65 a = '1234567890'* 7
66 a = '1234567890'* 7
66 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
67 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
67 a_trunc = "'123456789012...8901234567890'"
68 a_trunc = "'123456789012...8901234567890'"
68 nt.assert_equal(trepr(a), a_trunc)
69 nt.assert_equal(trepr(a), a_trunc)
69 # The creation of our tracer modifies the repr module's repr function
70 # The creation of our tracer modifies the repr module's repr function
70 # in-place, since that global is used directly by the stdlib's pdb module.
71 # in-place, since that global is used directly by the stdlib's pdb module.
71 with warnings.catch_warnings():
72 with warnings.catch_warnings():
72 warnings.simplefilter('ignore', DeprecationWarning)
73 warnings.simplefilter('ignore', DeprecationWarning)
73 debugger.Tracer()
74 debugger.Tracer()
74 nt.assert_equal(trepr(a), ar)
75 nt.assert_equal(trepr(a), ar)
75
76
76 def test_ipdb_magics():
77 def test_ipdb_magics():
77 '''Test calling some IPython magics from ipdb.
78 '''Test calling some IPython magics from ipdb.
78
79
79 First, set up some test functions and classes which we can inspect.
80 First, set up some test functions and classes which we can inspect.
80
81
81 >>> class ExampleClass(object):
82 >>> class ExampleClass(object):
82 ... """Docstring for ExampleClass."""
83 ... """Docstring for ExampleClass."""
83 ... def __init__(self):
84 ... def __init__(self):
84 ... """Docstring for ExampleClass.__init__"""
85 ... """Docstring for ExampleClass.__init__"""
85 ... pass
86 ... pass
86 ... def __str__(self):
87 ... def __str__(self):
87 ... return "ExampleClass()"
88 ... return "ExampleClass()"
88
89
89 >>> def example_function(x, y, z="hello"):
90 >>> def example_function(x, y, z="hello"):
90 ... """Docstring for example_function."""
91 ... """Docstring for example_function."""
91 ... pass
92 ... pass
92
93
93 >>> old_trace = sys.gettrace()
94 >>> old_trace = sys.gettrace()
94
95
95 Create a function which triggers ipdb.
96 Create a function which triggers ipdb.
96
97
97 >>> def trigger_ipdb():
98 >>> def trigger_ipdb():
98 ... a = ExampleClass()
99 ... a = ExampleClass()
99 ... debugger.Pdb().set_trace()
100 ... debugger.Pdb().set_trace()
100
101
101 >>> with PdbTestInput([
102 >>> with PdbTestInput([
102 ... 'pdef example_function',
103 ... 'pdef example_function',
103 ... 'pdoc ExampleClass',
104 ... 'pdoc ExampleClass',
104 ... 'up',
105 ... 'up',
105 ... 'down',
106 ... 'down',
106 ... 'list',
107 ... 'list',
107 ... 'pinfo a',
108 ... 'pinfo a',
108 ... 'll',
109 ... 'll',
109 ... 'continue',
110 ... 'continue',
110 ... ]):
111 ... ]):
111 ... trigger_ipdb()
112 ... trigger_ipdb()
112 --Return--
113 --Return--
113 None
114 None
114 > <doctest ...>(3)trigger_ipdb()
115 > <doctest ...>(3)trigger_ipdb()
115 1 def trigger_ipdb():
116 1 def trigger_ipdb():
116 2 a = ExampleClass()
117 2 a = ExampleClass()
117 ----> 3 debugger.Pdb().set_trace()
118 ----> 3 debugger.Pdb().set_trace()
118 <BLANKLINE>
119 <BLANKLINE>
119 ipdb> pdef example_function
120 ipdb> pdef example_function
120 example_function(x, y, z='hello')
121 example_function(x, y, z='hello')
121 ipdb> pdoc ExampleClass
122 ipdb> pdoc ExampleClass
122 Class docstring:
123 Class docstring:
123 Docstring for ExampleClass.
124 Docstring for ExampleClass.
124 Init docstring:
125 Init docstring:
125 Docstring for ExampleClass.__init__
126 Docstring for ExampleClass.__init__
126 ipdb> up
127 ipdb> up
127 > <doctest ...>(11)<module>()
128 > <doctest ...>(11)<module>()
128 7 'pinfo a',
129 7 'pinfo a',
129 8 'll',
130 8 'll',
130 9 'continue',
131 9 'continue',
131 10 ]):
132 10 ]):
132 ---> 11 trigger_ipdb()
133 ---> 11 trigger_ipdb()
133 <BLANKLINE>
134 <BLANKLINE>
134 ipdb> down
135 ipdb> down
135 None
136 None
136 > <doctest ...>(3)trigger_ipdb()
137 > <doctest ...>(3)trigger_ipdb()
137 1 def trigger_ipdb():
138 1 def trigger_ipdb():
138 2 a = ExampleClass()
139 2 a = ExampleClass()
139 ----> 3 debugger.Pdb().set_trace()
140 ----> 3 debugger.Pdb().set_trace()
140 <BLANKLINE>
141 <BLANKLINE>
141 ipdb> list
142 ipdb> list
142 1 def trigger_ipdb():
143 1 def trigger_ipdb():
143 2 a = ExampleClass()
144 2 a = ExampleClass()
144 ----> 3 debugger.Pdb().set_trace()
145 ----> 3 debugger.Pdb().set_trace()
145 <BLANKLINE>
146 <BLANKLINE>
146 ipdb> pinfo a
147 ipdb> pinfo a
147 Type: ExampleClass
148 Type: ExampleClass
148 String form: ExampleClass()
149 String form: ExampleClass()
149 Namespace: Local...
150 Namespace: Local...
150 Docstring: Docstring for ExampleClass.
151 Docstring: Docstring for ExampleClass.
151 Init docstring: Docstring for ExampleClass.__init__
152 Init docstring: Docstring for ExampleClass.__init__
152 ipdb> ll
153 ipdb> ll
153 1 def trigger_ipdb():
154 1 def trigger_ipdb():
154 2 a = ExampleClass()
155 2 a = ExampleClass()
155 ----> 3 debugger.Pdb().set_trace()
156 ----> 3 debugger.Pdb().set_trace()
156 <BLANKLINE>
157 <BLANKLINE>
157 ipdb> continue
158 ipdb> continue
158
159
159 Restore previous trace function, e.g. for coverage.py
160 Restore previous trace function, e.g. for coverage.py
160
161
161 >>> sys.settrace(old_trace)
162 >>> sys.settrace(old_trace)
162 '''
163 '''
163
164
164 def test_ipdb_magics2():
165 def test_ipdb_magics2():
165 '''Test ipdb with a very short function.
166 '''Test ipdb with a very short function.
166
167
167 >>> old_trace = sys.gettrace()
168 >>> old_trace = sys.gettrace()
168
169
169 >>> def bar():
170 >>> def bar():
170 ... pass
171 ... pass
171
172
172 Run ipdb.
173 Run ipdb.
173
174
174 >>> with PdbTestInput([
175 >>> with PdbTestInput([
175 ... 'continue',
176 ... 'continue',
176 ... ]):
177 ... ]):
177 ... debugger.Pdb().runcall(bar)
178 ... debugger.Pdb().runcall(bar)
178 > <doctest ...>(2)bar()
179 > <doctest ...>(2)bar()
179 1 def bar():
180 1 def bar():
180 ----> 2 pass
181 ----> 2 pass
181 <BLANKLINE>
182 <BLANKLINE>
182 ipdb> continue
183 ipdb> continue
183
184
184 Restore previous trace function, e.g. for coverage.py
185 Restore previous trace function, e.g. for coverage.py
185
186
186 >>> sys.settrace(old_trace)
187 >>> sys.settrace(old_trace)
187 '''
188 '''
188
189
189 def can_quit():
190 def can_quit():
190 '''Test that quit work in ipydb
191 '''Test that quit work in ipydb
191
192
192 >>> old_trace = sys.gettrace()
193 >>> old_trace = sys.gettrace()
193
194
194 >>> def bar():
195 >>> def bar():
195 ... pass
196 ... pass
196
197
197 >>> with PdbTestInput([
198 >>> with PdbTestInput([
198 ... 'quit',
199 ... 'quit',
199 ... ]):
200 ... ]):
200 ... debugger.Pdb().runcall(bar)
201 ... debugger.Pdb().runcall(bar)
201 > <doctest ...>(2)bar()
202 > <doctest ...>(2)bar()
202 1 def bar():
203 1 def bar():
203 ----> 2 pass
204 ----> 2 pass
204 <BLANKLINE>
205 <BLANKLINE>
205 ipdb> quit
206 ipdb> quit
206
207
207 Restore previous trace function, e.g. for coverage.py
208 Restore previous trace function, e.g. for coverage.py
208
209
209 >>> sys.settrace(old_trace)
210 >>> sys.settrace(old_trace)
210 '''
211 '''
211
212
212
213
213 def can_exit():
214 def can_exit():
214 '''Test that quit work in ipydb
215 '''Test that quit work in ipydb
215
216
216 >>> old_trace = sys.gettrace()
217 >>> old_trace = sys.gettrace()
217
218
218 >>> def bar():
219 >>> def bar():
219 ... pass
220 ... pass
220
221
221 >>> with PdbTestInput([
222 >>> with PdbTestInput([
222 ... 'exit',
223 ... 'exit',
223 ... ]):
224 ... ]):
224 ... debugger.Pdb().runcall(bar)
225 ... debugger.Pdb().runcall(bar)
225 > <doctest ...>(2)bar()
226 > <doctest ...>(2)bar()
226 1 def bar():
227 1 def bar():
227 ----> 2 pass
228 ----> 2 pass
228 <BLANKLINE>
229 <BLANKLINE>
229 ipdb> exit
230 ipdb> exit
230
231
231 Restore previous trace function, e.g. for coverage.py
232 Restore previous trace function, e.g. for coverage.py
232
233
233 >>> sys.settrace(old_trace)
234 >>> sys.settrace(old_trace)
234 '''
235 '''
235
236
236
237
237 def test_interruptible_core_debugger():
238 def test_interruptible_core_debugger():
238 """The debugger can be interrupted.
239 """The debugger can be interrupted.
239
240
240 The presumption is there is some mechanism that causes a KeyboardInterrupt
241 The presumption is there is some mechanism that causes a KeyboardInterrupt
241 (this is implemented in ipykernel). We want to ensure the
242 (this is implemented in ipykernel). We want to ensure the
242 KeyboardInterrupt cause debugging to cease.
243 KeyboardInterrupt cause debugging to cease.
243 """
244 """
244 def raising_input(msg="", called=[0]):
245 def raising_input(msg="", called=[0]):
245 called[0] += 1
246 called[0] += 1
246 if called[0] == 1:
247 if called[0] == 1:
247 raise KeyboardInterrupt()
248 raise KeyboardInterrupt()
248 else:
249 else:
249 raise AssertionError("input() should only be called once!")
250 raise AssertionError("input() should only be called once!")
250
251
251 with patch.object(builtins, "input", raising_input):
252 with patch.object(builtins, "input", raising_input):
252 debugger.InterruptiblePdb().set_trace()
253 debugger.InterruptiblePdb().set_trace()
253 # The way this test will fail is by set_trace() never exiting,
254 # The way this test will fail is by set_trace() never exiting,
254 # resulting in a timeout by the test runner. The alternative
255 # resulting in a timeout by the test runner. The alternative
255 # implementation would involve a subprocess, but that adds issues with
256 # implementation would involve a subprocess, but that adds issues with
256 # interrupting subprocesses that are rather complex, so it's simpler
257 # interrupting subprocesses that are rather complex, so it's simpler
257 # just to do it this way.
258 # just to do it this way.
258
259
259 @skip_win32
260 @skip_win32
260 def test_xmode_skip():
261 def test_xmode_skip():
261 """that xmode skip frames
262 """that xmode skip frames
262
263
263 Not as a doctest as pytest does not run doctests.
264 Not as a doctest as pytest does not run doctests.
264 """
265 """
265 import pexpect
266 import pexpect
266 env = os.environ.copy()
267 env = os.environ.copy()
267 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
268 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
268
269
269 child = pexpect.spawn(
270 child = pexpect.spawn(
270 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
271 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
271 )
272 )
272 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
273 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
273
274
274 child.expect("IPython")
275 child.expect("IPython")
275 child.expect("\n")
276 child.expect("\n")
276 child.expect_exact("In [1]")
277 child.expect_exact("In [1]")
277
278
278 block = dedent(
279 block = dedent(
279 """
280 """
280 def f():
281 def f():
281 __tracebackhide__ = True
282 __tracebackhide__ = True
282 g()
283 g()
283
284
284 def g():
285 def g():
285 raise ValueError
286 raise ValueError
286
287
287 f()
288 f()
288 """
289 """
289 )
290 )
290
291
291 for line in block.splitlines():
292 for line in block.splitlines():
292 child.sendline(line)
293 child.sendline(line)
293 child.expect_exact(line)
294 child.expect_exact(line)
294 child.expect_exact("skipping")
295 child.expect_exact("skipping")
295
296
296 block = dedent(
297 block = dedent(
297 """
298 """
298 def f():
299 def f():
299 __tracebackhide__ = True
300 __tracebackhide__ = True
300 g()
301 g()
301
302
302 def g():
303 def g():
303 from IPython.core.debugger import set_trace
304 from IPython.core.debugger import set_trace
304 set_trace()
305 set_trace()
305
306
306 f()
307 f()
307 """
308 """
308 )
309 )
309
310
310 for line in block.splitlines():
311 for line in block.splitlines():
311 child.sendline(line)
312 child.sendline(line)
312 child.expect_exact(line)
313 child.expect_exact(line)
313
314
314 child.expect("ipdb>")
315 child.expect("ipdb>")
315 child.sendline("w")
316 child.sendline("w")
316 child.expect("hidden")
317 child.expect("hidden")
317 child.expect("ipdb>")
318 child.expect("ipdb>")
318 child.sendline("skip_hidden false")
319 child.sendline("skip_hidden false")
319 child.sendline("w")
320 child.sendline("w")
320 child.expect("__traceba")
321 child.expect("__traceba")
321 child.expect("ipdb>")
322 child.expect("ipdb>")
322
323
323 child.close()
324 child.close()
324
325
325
326
326 skip_decorators_blocks = (
327 skip_decorators_blocks = (
327 """
328 """
329 def helpers_helper():
330 pass # should not stop here except breakpoint
331 """,
332 """
328 def helper_1():
333 def helper_1():
329 pass # should not stop here
334 helpers_helper() # should not stop here
330 """,
335 """,
331 """
336 """
332 def helper_2():
337 def helper_2():
333 pass # should not stop here
338 pass # should not stop here
334 """,
339 """,
335 """
340 """
341 def pdb_skipped_decorator2(function):
342 def wrapped_fn(*args, **kwargs):
343 __debuggerskip__ = True
344 helper_2()
345 __debuggerskip__ = False
346 result = function(*args, **kwargs)
347 __debuggerskip__ = True
348 helper_2()
349 return result
350 return wrapped_fn
351 """,
352 """
336 def pdb_skipped_decorator(function):
353 def pdb_skipped_decorator(function):
337 def wrapped_fn(*args, **kwargs):
354 def wrapped_fn(*args, **kwargs):
338 __debuggerskip__ = True
355 __debuggerskip__ = True
339 helper_1()
356 helper_1()
340 __debuggerskip__ = False
357 __debuggerskip__ = False
341 result = function(*args, **kwargs)
358 result = function(*args, **kwargs)
342 __debuggerskip__ = True
359 __debuggerskip__ = True
343 helper_2()
360 helper_2()
344 return result
361 return result
345 return wrapped_fn
362 return wrapped_fn
346 """,
363 """,
347 """
364 """
348 @pdb_skipped_decorator
365 @pdb_skipped_decorator
366 @pdb_skipped_decorator2
349 def bar(x, y):
367 def bar(x, y):
350 return x * y
368 return x * y
351 """,
369 """,
352 """import IPython.terminal.debugger as ipdb""",
370 """import IPython.terminal.debugger as ipdb""",
353 """
371 """
354 def f():
372 def f():
355 ipdb.set_trace()
373 ipdb.set_trace()
356 bar(3, 4)
374 bar(3, 4)
357 """,
375 """,
358 """
376 """
359 f()
377 f()
360 """,
378 """,
361 )
379 )
362
380
363
381
364 def _decorator_skip_setup():
382 def _decorator_skip_setup():
365 import pexpect
383 import pexpect
366
384
367 env = os.environ.copy()
385 env = os.environ.copy()
368 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
386 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
369
387
370 child = pexpect.spawn(
388 child = pexpect.spawn(
371 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
389 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
372 )
390 )
373 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
391 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
374
392
375 child.expect("IPython")
393 child.expect("IPython")
376 child.expect("\n")
394 child.expect("\n")
377
395
378 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
396 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
379 in_prompt_number = 1
397 in_prompt_number = 1
380 for cblock in dedented_blocks:
398 for cblock in dedented_blocks:
381 child.expect_exact(f"In [{in_prompt_number}]:")
399 child.expect_exact(f"In [{in_prompt_number}]:")
382 in_prompt_number += 1
400 in_prompt_number += 1
383 for line in cblock.splitlines():
401 for line in cblock.splitlines():
384 child.sendline(line)
402 child.sendline(line)
385 child.expect_exact(line)
403 child.expect_exact(line)
386 child.sendline("")
404 child.sendline("")
387 return child
405 return child
388
406
389
407
390 @skip_win32
408 @skip_win32
391 def test_decorator_skip():
409 def test_decorator_skip():
392 """test that decorator frames can be skipped."""
410 """test that decorator frames can be skipped."""
393
411
394 child = _decorator_skip_setup()
412 child = _decorator_skip_setup()
395
413
396 child.expect_exact("3 bar(3, 4)")
414 child.expect_exact("3 bar(3, 4)")
397 child.expect("ipdb>")
415 child.expect("ipdb>")
398
416
399 child.expect("ipdb>")
417 child.expect("ipdb>")
400 child.sendline("step")
418 child.sendline("step")
401 child.expect_exact("step")
419 child.expect_exact("step")
402
420
403 child.expect_exact("1 @pdb_skipped_decorator")
421 child.expect_exact("1 @pdb_skipped_decorator")
404
422
405 child.sendline("s")
423 child.sendline("s")
406 child.expect_exact("return x * y")
424 child.expect_exact("return x * y")
407
425
408 child.close()
426 child.close()
409
427
410
428
411 @skip_win32
429 @skip_win32
412 def test_decorator_skip_disabled():
430 def test_decorator_skip_disabled():
413 """test that decorator frame skipping can be disabled"""
431 """test that decorator frame skipping can be disabled"""
414
432
415 child = _decorator_skip_setup()
433 child = _decorator_skip_setup()
416
434
417 child.expect_exact("3 bar(3, 4)")
435 child.expect_exact("3 bar(3, 4)")
418
436
419 for input_, expected in [
437 for input_, expected in [
420 ("skip_predicates debuggerskip False", ""),
438 ("skip_predicates debuggerskip False", ""),
421 ("skip_predicates", "debuggerskip : False"),
439 ("skip_predicates", "debuggerskip : False"),
422 ("step", "---> 2 def wrapped_fn"),
440 ("step", "---> 2 def wrapped_fn"),
423 ("step", "----> 3 __debuggerskip__"),
441 ("step", "----> 3 __debuggerskip__"),
424 ("step", "----> 4 helper_1()"),
442 ("step", "----> 4 helper_1()"),
425 ("step", "---> 1 def helper_1():"),
443 ("step", "---> 1 def helper_1():"),
426 ("next", "----> 2 pass"),
444 ("next", "----> 2 helpers_helper()"),
427 ("next", "--Return--"),
445 ("next", "--Return--"),
428 ("next", "----> 5 __debuggerskip__ = False"),
446 ("next", "----> 5 __debuggerskip__ = False"),
429 ]:
447 ]:
430 child.expect("ipdb>")
448 child.expect("ipdb>")
431 child.sendline(input_)
449 child.sendline(input_)
432 child.expect_exact(input_)
450 child.expect_exact(input_)
433 child.expect_exact(expected)
451 child.expect_exact(expected)
434
452
435 child.close()
453 child.close()
436
454
437
455
438 @skip_win32
456 @skip_win32
457 def test_decorator_skip_with_breakpoint():
458 """test that decorator frame skipping can be disabled"""
459
460 import pexpect
461
462 env = os.environ.copy()
463 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
464
465 child = pexpect.spawn(
466 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
467 )
468 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
469
470 child.expect("IPython")
471 child.expect("\n")
472
473 ### we need a filename, so we need to exec the full block with a filename
474 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
475
476 name = tf.name[:-3].split("/")[-1]
477 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
478 tf.flush()
479 codeblock = f"from {name} import f"
480
481 dedented_blocks = [
482 codeblock,
483 "f()",
484 ]
485
486 in_prompt_number = 1
487 for cblock in dedented_blocks:
488 child.expect_exact(f"In [{in_prompt_number}]:")
489 in_prompt_number += 1
490 for line in cblock.splitlines():
491 child.sendline(line)
492 child.expect_exact(line)
493 child.sendline("")
494
495 # as the filename does not exists, we'll rely on the filename prompt
496 child.expect_exact("47 bar(3, 4)")
497
498 for input_, expected in [
499 (f"b {name}.py:3", ""),
500 ("step", "1---> 3 pass # should not stop here except"),
501 ("step", "---> 38 @pdb_skipped_decorator"),
502 ("continue", ""),
503 ]:
504 child.expect("ipdb>")
505 child.sendline(input_)
506 child.expect_exact(input_)
507 child.expect_exact(expected)
508
509 child.close()
510
511
512 @skip_win32
439 def test_where_erase_value():
513 def test_where_erase_value():
440 """Test that `where` does not access f_locals and erase values."""
514 """Test that `where` does not access f_locals and erase values."""
441 import pexpect
515 import pexpect
442
516
443 env = os.environ.copy()
517 env = os.environ.copy()
444 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
518 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
445
519
446 child = pexpect.spawn(
520 child = pexpect.spawn(
447 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
521 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
448 )
522 )
449 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
523 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
450
524
451 child.expect("IPython")
525 child.expect("IPython")
452 child.expect("\n")
526 child.expect("\n")
453 child.expect_exact("In [1]")
527 child.expect_exact("In [1]")
454
528
455 block = dedent(
529 block = dedent(
456 """
530 """
457 def simple_f():
531 def simple_f():
458 myvar = 1
532 myvar = 1
459 print(myvar)
533 print(myvar)
460 1/0
534 1/0
461 print(myvar)
535 print(myvar)
462 simple_f() """
536 simple_f() """
463 )
537 )
464
538
465 for line in block.splitlines():
539 for line in block.splitlines():
466 child.sendline(line)
540 child.sendline(line)
467 child.expect_exact(line)
541 child.expect_exact(line)
468 child.expect_exact("ZeroDivisionError")
542 child.expect_exact("ZeroDivisionError")
469 child.expect_exact("In [2]:")
543 child.expect_exact("In [2]:")
470
544
471 child.sendline("%debug")
545 child.sendline("%debug")
472
546
473 ##
547 ##
474 child.expect("ipdb>")
548 child.expect("ipdb>")
475
549
476 child.sendline("myvar")
550 child.sendline("myvar")
477 child.expect("1")
551 child.expect("1")
478
552
479 ##
553 ##
480 child.expect("ipdb>")
554 child.expect("ipdb>")
481
555
482 child.sendline("myvar = 2")
556 child.sendline("myvar = 2")
483
557
484 ##
558 ##
485 child.expect_exact("ipdb>")
559 child.expect_exact("ipdb>")
486
560
487 child.sendline("myvar")
561 child.sendline("myvar")
488
562
489 child.expect_exact("2")
563 child.expect_exact("2")
490
564
491 ##
565 ##
492 child.expect("ipdb>")
566 child.expect("ipdb>")
493 child.sendline("where")
567 child.sendline("where")
494
568
495 ##
569 ##
496 child.expect("ipdb>")
570 child.expect("ipdb>")
497 child.sendline("myvar")
571 child.sendline("myvar")
498
572
499 child.expect_exact("2")
573 child.expect_exact("2")
500 child.expect("ipdb>")
574 child.expect("ipdb>")
501
575
502 child.close()
576 child.close()
General Comments 0
You need to be logged in to leave comments. Login now