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