##// END OF EJS Templates
Autoformat with darker
Thomas Kluyver -
Show More
@@ -1,588 +1,592 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 builtins
7 import builtins
8 import os
8 import os
9 import sys
9 import sys
10 import platform
10 import platform
11
11
12 from tempfile import NamedTemporaryFile
12 from tempfile import NamedTemporaryFile
13 from textwrap import dedent
13 from textwrap import dedent
14 from unittest.mock import patch
14 from unittest.mock import patch
15
15
16 from IPython.core import debugger
16 from IPython.core import debugger
17 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
17 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
18 from IPython.testing.decorators import skip_win32
18 from IPython.testing.decorators import skip_win32
19 import pytest
19 import pytest
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Helper classes, from CPython's Pdb test suite
22 # Helper classes, from CPython's Pdb test suite
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class _FakeInput(object):
25 class _FakeInput(object):
26 """
26 """
27 A fake input stream for pdb's interactive debugger. Whenever a
27 A fake input stream for pdb's interactive debugger. Whenever a
28 line is read, print it (to simulate the user typing it), and then
28 line is read, print it (to simulate the user typing it), and then
29 return it. The set of lines to return is specified in the
29 return it. The set of lines to return is specified in the
30 constructor; they should not have trailing newlines.
30 constructor; they should not have trailing newlines.
31 """
31 """
32 def __init__(self, lines):
32 def __init__(self, lines):
33 self.lines = iter(lines)
33 self.lines = iter(lines)
34
34
35 def readline(self):
35 def readline(self):
36 line = next(self.lines)
36 line = next(self.lines)
37 print(line)
37 print(line)
38 return line+'\n'
38 return line+'\n'
39
39
40 class PdbTestInput(object):
40 class PdbTestInput(object):
41 """Context manager that makes testing Pdb in doctests easier."""
41 """Context manager that makes testing Pdb in doctests easier."""
42
42
43 def __init__(self, input):
43 def __init__(self, input):
44 self.input = input
44 self.input = input
45
45
46 def __enter__(self):
46 def __enter__(self):
47 self.real_stdin = sys.stdin
47 self.real_stdin = sys.stdin
48 sys.stdin = _FakeInput(self.input)
48 sys.stdin = _FakeInput(self.input)
49
49
50 def __exit__(self, *exc):
50 def __exit__(self, *exc):
51 sys.stdin = self.real_stdin
51 sys.stdin = self.real_stdin
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Tests
54 # Tests
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 def test_ipdb_magics():
57 def test_ipdb_magics():
58 '''Test calling some IPython magics from ipdb.
58 '''Test calling some IPython magics from ipdb.
59
59
60 First, set up some test functions and classes which we can inspect.
60 First, set up some test functions and classes which we can inspect.
61
61
62 In [1]: class ExampleClass(object):
62 In [1]: class ExampleClass(object):
63 ...: """Docstring for ExampleClass."""
63 ...: """Docstring for ExampleClass."""
64 ...: def __init__(self):
64 ...: def __init__(self):
65 ...: """Docstring for ExampleClass.__init__"""
65 ...: """Docstring for ExampleClass.__init__"""
66 ...: pass
66 ...: pass
67 ...: def __str__(self):
67 ...: def __str__(self):
68 ...: return "ExampleClass()"
68 ...: return "ExampleClass()"
69
69
70 In [2]: def example_function(x, y, z="hello"):
70 In [2]: def example_function(x, y, z="hello"):
71 ...: """Docstring for example_function."""
71 ...: """Docstring for example_function."""
72 ...: pass
72 ...: pass
73
73
74 In [3]: old_trace = sys.gettrace()
74 In [3]: old_trace = sys.gettrace()
75
75
76 Create a function which triggers ipdb.
76 Create a function which triggers ipdb.
77
77
78 In [4]: def trigger_ipdb():
78 In [4]: def trigger_ipdb():
79 ...: a = ExampleClass()
79 ...: a = ExampleClass()
80 ...: debugger.Pdb().set_trace()
80 ...: debugger.Pdb().set_trace()
81
81
82 Run ipdb with faked input & check output. Because of a difference between
82 Run ipdb with faked input & check output. Because of a difference between
83 Python 3.13 & older versions, the first bit of the output is inconsistent.
83 Python 3.13 & older versions, the first bit of the output is inconsistent.
84 We need to use ... to accommodate that, so the examples have to use IPython
84 We need to use ... to accommodate that, so the examples have to use IPython
85 prompts so that ... is distinct from the Python PS2 prompt.
85 prompts so that ... is distinct from the Python PS2 prompt.
86
86
87 In [5]: with PdbTestInput([
87 In [5]: with PdbTestInput([
88 ...: 'pdef example_function',
88 ...: 'pdef example_function',
89 ...: 'pdoc ExampleClass',
89 ...: 'pdoc ExampleClass',
90 ...: 'up',
90 ...: 'up',
91 ...: 'down',
91 ...: 'down',
92 ...: 'list',
92 ...: 'list',
93 ...: 'pinfo a',
93 ...: 'pinfo a',
94 ...: 'll',
94 ...: 'll',
95 ...: 'continue',
95 ...: 'continue',
96 ...: ]):
96 ...: ]):
97 ...: trigger_ipdb()
97 ...: trigger_ipdb()
98 ...> <doctest ...>(3)trigger_ipdb()
98 ...> <doctest ...>(3)trigger_ipdb()
99 1 def trigger_ipdb():
99 1 def trigger_ipdb():
100 2 a = ExampleClass()
100 2 a = ExampleClass()
101 ----> 3 debugger.Pdb().set_trace()
101 ----> 3 debugger.Pdb().set_trace()
102 <BLANKLINE>
102 <BLANKLINE>
103 ipdb> pdef example_function
103 ipdb> pdef example_function
104 example_function(x, y, z='hello')
104 example_function(x, y, z='hello')
105 ipdb> pdoc ExampleClass
105 ipdb> pdoc ExampleClass
106 Class docstring:
106 Class docstring:
107 Docstring for ExampleClass.
107 Docstring for ExampleClass.
108 Init docstring:
108 Init docstring:
109 Docstring for ExampleClass.__init__
109 Docstring for ExampleClass.__init__
110 ipdb> up
110 ipdb> up
111 > <doctest ...>(11)<module>()
111 > <doctest ...>(11)<module>()
112 7 'pinfo a',
112 7 'pinfo a',
113 8 'll',
113 8 'll',
114 9 'continue',
114 9 'continue',
115 10 ]):
115 10 ]):
116 ---> 11 trigger_ipdb()
116 ---> 11 trigger_ipdb()
117 <BLANKLINE>
117 <BLANKLINE>
118 ipdb> down...
118 ipdb> down...
119 > <doctest ...>(3)trigger_ipdb()
119 > <doctest ...>(3)trigger_ipdb()
120 1 def trigger_ipdb():
120 1 def trigger_ipdb():
121 2 a = ExampleClass()
121 2 a = ExampleClass()
122 ----> 3 debugger.Pdb().set_trace()
122 ----> 3 debugger.Pdb().set_trace()
123 <BLANKLINE>
123 <BLANKLINE>
124 ipdb> list
124 ipdb> list
125 1 def trigger_ipdb():
125 1 def trigger_ipdb():
126 2 a = ExampleClass()
126 2 a = ExampleClass()
127 ----> 3 debugger.Pdb().set_trace()
127 ----> 3 debugger.Pdb().set_trace()
128 <BLANKLINE>
128 <BLANKLINE>
129 ipdb> pinfo a
129 ipdb> pinfo a
130 Type: ExampleClass
130 Type: ExampleClass
131 String form: ExampleClass()
131 String form: ExampleClass()
132 Namespace: Local...
132 Namespace: Local...
133 Docstring: Docstring for ExampleClass.
133 Docstring: Docstring for ExampleClass.
134 Init docstring: Docstring for ExampleClass.__init__
134 Init docstring: Docstring for ExampleClass.__init__
135 ipdb> ll
135 ipdb> ll
136 1 def trigger_ipdb():
136 1 def trigger_ipdb():
137 2 a = ExampleClass()
137 2 a = ExampleClass()
138 ----> 3 debugger.Pdb().set_trace()
138 ----> 3 debugger.Pdb().set_trace()
139 <BLANKLINE>
139 <BLANKLINE>
140 ipdb> continue
140 ipdb> continue
141
141
142 Restore previous trace function, e.g. for coverage.py
142 Restore previous trace function, e.g. for coverage.py
143
143
144 In [6]: sys.settrace(old_trace)
144 In [6]: sys.settrace(old_trace)
145 '''
145 '''
146
146
147 def test_ipdb_magics2():
147 def test_ipdb_magics2():
148 '''Test ipdb with a very short function.
148 '''Test ipdb with a very short function.
149
149
150 >>> old_trace = sys.gettrace()
150 >>> old_trace = sys.gettrace()
151
151
152 >>> def bar():
152 >>> def bar():
153 ... pass
153 ... pass
154
154
155 Run ipdb.
155 Run ipdb.
156
156
157 >>> with PdbTestInput([
157 >>> with PdbTestInput([
158 ... 'continue',
158 ... 'continue',
159 ... ]):
159 ... ]):
160 ... debugger.Pdb().runcall(bar)
160 ... debugger.Pdb().runcall(bar)
161 > <doctest ...>(2)bar()
161 > <doctest ...>(2)bar()
162 1 def bar():
162 1 def bar():
163 ----> 2 pass
163 ----> 2 pass
164 <BLANKLINE>
164 <BLANKLINE>
165 ipdb> continue
165 ipdb> continue
166
166
167 Restore previous trace function, e.g. for coverage.py
167 Restore previous trace function, e.g. for coverage.py
168
168
169 >>> sys.settrace(old_trace)
169 >>> sys.settrace(old_trace)
170 '''
170 '''
171
171
172 def can_quit():
172 def can_quit():
173 '''Test that quit work in ipydb
173 '''Test that quit work in ipydb
174
174
175 >>> old_trace = sys.gettrace()
175 >>> old_trace = sys.gettrace()
176
176
177 >>> def bar():
177 >>> def bar():
178 ... pass
178 ... pass
179
179
180 >>> with PdbTestInput([
180 >>> with PdbTestInput([
181 ... 'quit',
181 ... 'quit',
182 ... ]):
182 ... ]):
183 ... debugger.Pdb().runcall(bar)
183 ... debugger.Pdb().runcall(bar)
184 > <doctest ...>(2)bar()
184 > <doctest ...>(2)bar()
185 1 def bar():
185 1 def bar():
186 ----> 2 pass
186 ----> 2 pass
187 <BLANKLINE>
187 <BLANKLINE>
188 ipdb> quit
188 ipdb> quit
189
189
190 Restore previous trace function, e.g. for coverage.py
190 Restore previous trace function, e.g. for coverage.py
191
191
192 >>> sys.settrace(old_trace)
192 >>> sys.settrace(old_trace)
193 '''
193 '''
194
194
195
195
196 def can_exit():
196 def can_exit():
197 '''Test that quit work in ipydb
197 '''Test that quit work in ipydb
198
198
199 >>> old_trace = sys.gettrace()
199 >>> old_trace = sys.gettrace()
200
200
201 >>> def bar():
201 >>> def bar():
202 ... pass
202 ... pass
203
203
204 >>> with PdbTestInput([
204 >>> with PdbTestInput([
205 ... 'exit',
205 ... 'exit',
206 ... ]):
206 ... ]):
207 ... debugger.Pdb().runcall(bar)
207 ... debugger.Pdb().runcall(bar)
208 > <doctest ...>(2)bar()
208 > <doctest ...>(2)bar()
209 1 def bar():
209 1 def bar():
210 ----> 2 pass
210 ----> 2 pass
211 <BLANKLINE>
211 <BLANKLINE>
212 ipdb> exit
212 ipdb> exit
213
213
214 Restore previous trace function, e.g. for coverage.py
214 Restore previous trace function, e.g. for coverage.py
215
215
216 >>> sys.settrace(old_trace)
216 >>> sys.settrace(old_trace)
217 '''
217 '''
218
218
219
219
220 def test_interruptible_core_debugger():
220 def test_interruptible_core_debugger():
221 """The debugger can be interrupted.
221 """The debugger can be interrupted.
222
222
223 The presumption is there is some mechanism that causes a KeyboardInterrupt
223 The presumption is there is some mechanism that causes a KeyboardInterrupt
224 (this is implemented in ipykernel). We want to ensure the
224 (this is implemented in ipykernel). We want to ensure the
225 KeyboardInterrupt cause debugging to cease.
225 KeyboardInterrupt cause debugging to cease.
226 """
226 """
227 def raising_input(msg="", called=[0]):
227 def raising_input(msg="", called=[0]):
228 called[0] += 1
228 called[0] += 1
229 assert called[0] == 1, "input() should only be called once!"
229 assert called[0] == 1, "input() should only be called once!"
230 raise KeyboardInterrupt()
230 raise KeyboardInterrupt()
231
231
232 tracer_orig = sys.gettrace()
232 tracer_orig = sys.gettrace()
233 try:
233 try:
234 with patch.object(builtins, "input", raising_input):
234 with patch.object(builtins, "input", raising_input):
235 debugger.InterruptiblePdb().set_trace()
235 debugger.InterruptiblePdb().set_trace()
236 # The way this test will fail is by set_trace() never exiting,
236 # The way this test will fail is by set_trace() never exiting,
237 # resulting in a timeout by the test runner. The alternative
237 # resulting in a timeout by the test runner. The alternative
238 # implementation would involve a subprocess, but that adds issues
238 # implementation would involve a subprocess, but that adds issues
239 # with interrupting subprocesses that are rather complex, so it's
239 # with interrupting subprocesses that are rather complex, so it's
240 # simpler just to do it this way.
240 # simpler just to do it this way.
241 finally:
241 finally:
242 # restore the original trace function
242 # restore the original trace function
243 sys.settrace(tracer_orig)
243 sys.settrace(tracer_orig)
244
244
245
245
246 @skip_win32
246 @skip_win32
247 def test_xmode_skip():
247 def test_xmode_skip():
248 """that xmode skip frames
248 """that xmode skip frames
249
249
250 Not as a doctest as pytest does not run doctests.
250 Not as a doctest as pytest does not run doctests.
251 """
251 """
252 import pexpect
252 import pexpect
253 env = os.environ.copy()
253 env = os.environ.copy()
254 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
254 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
255
255
256 child = pexpect.spawn(
256 child = pexpect.spawn(
257 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
257 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
258 )
258 )
259 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
259 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
260
260
261 child.expect("IPython")
261 child.expect("IPython")
262 child.expect("\n")
262 child.expect("\n")
263 child.expect_exact("In [1]")
263 child.expect_exact("In [1]")
264
264
265 block = dedent(
265 block = dedent(
266 """
266 """
267 def f():
267 def f():
268 __tracebackhide__ = True
268 __tracebackhide__ = True
269 g()
269 g()
270
270
271 def g():
271 def g():
272 raise ValueError
272 raise ValueError
273
273
274 f()
274 f()
275 """
275 """
276 )
276 )
277
277
278 for line in block.splitlines():
278 for line in block.splitlines():
279 child.sendline(line)
279 child.sendline(line)
280 child.expect_exact(line)
280 child.expect_exact(line)
281 child.expect_exact("skipping")
281 child.expect_exact("skipping")
282
282
283 block = dedent(
283 block = dedent(
284 """
284 """
285 def f():
285 def f():
286 __tracebackhide__ = True
286 __tracebackhide__ = True
287 g()
287 g()
288
288
289 def g():
289 def g():
290 from IPython.core.debugger import set_trace
290 from IPython.core.debugger import set_trace
291 set_trace()
291 set_trace()
292
292
293 f()
293 f()
294 """
294 """
295 )
295 )
296
296
297 for line in block.splitlines():
297 for line in block.splitlines():
298 child.sendline(line)
298 child.sendline(line)
299 child.expect_exact(line)
299 child.expect_exact(line)
300
300
301 child.expect("ipdb>")
301 child.expect("ipdb>")
302 child.sendline("w")
302 child.sendline("w")
303 child.expect("hidden")
303 child.expect("hidden")
304 child.expect("ipdb>")
304 child.expect("ipdb>")
305 child.sendline("skip_hidden false")
305 child.sendline("skip_hidden false")
306 child.sendline("w")
306 child.sendline("w")
307 child.expect("__traceba")
307 child.expect("__traceba")
308 child.expect("ipdb>")
308 child.expect("ipdb>")
309
309
310 child.close()
310 child.close()
311
311
312
312
313 skip_decorators_blocks = (
313 skip_decorators_blocks = (
314 """
314 """
315 def helpers_helper():
315 def helpers_helper():
316 pass # should not stop here except breakpoint
316 pass # should not stop here except breakpoint
317 """,
317 """,
318 """
318 """
319 def helper_1():
319 def helper_1():
320 helpers_helper() # should not stop here
320 helpers_helper() # should not stop here
321 """,
321 """,
322 """
322 """
323 def helper_2():
323 def helper_2():
324 pass # should not stop here
324 pass # should not stop here
325 """,
325 """,
326 """
326 """
327 def pdb_skipped_decorator2(function):
327 def pdb_skipped_decorator2(function):
328 def wrapped_fn(*args, **kwargs):
328 def wrapped_fn(*args, **kwargs):
329 __debuggerskip__ = True
329 __debuggerskip__ = True
330 helper_2()
330 helper_2()
331 __debuggerskip__ = False
331 __debuggerskip__ = False
332 result = function(*args, **kwargs)
332 result = function(*args, **kwargs)
333 __debuggerskip__ = True
333 __debuggerskip__ = True
334 helper_2()
334 helper_2()
335 return result
335 return result
336 return wrapped_fn
336 return wrapped_fn
337 """,
337 """,
338 """
338 """
339 def pdb_skipped_decorator(function):
339 def pdb_skipped_decorator(function):
340 def wrapped_fn(*args, **kwargs):
340 def wrapped_fn(*args, **kwargs):
341 __debuggerskip__ = True
341 __debuggerskip__ = True
342 helper_1()
342 helper_1()
343 __debuggerskip__ = False
343 __debuggerskip__ = False
344 result = function(*args, **kwargs)
344 result = function(*args, **kwargs)
345 __debuggerskip__ = True
345 __debuggerskip__ = True
346 helper_2()
346 helper_2()
347 return result
347 return result
348 return wrapped_fn
348 return wrapped_fn
349 """,
349 """,
350 """
350 """
351 @pdb_skipped_decorator
351 @pdb_skipped_decorator
352 @pdb_skipped_decorator2
352 @pdb_skipped_decorator2
353 def bar(x, y):
353 def bar(x, y):
354 return x * y
354 return x * y
355 """,
355 """,
356 """import IPython.terminal.debugger as ipdb""",
356 """import IPython.terminal.debugger as ipdb""",
357 """
357 """
358 def f():
358 def f():
359 ipdb.set_trace()
359 ipdb.set_trace()
360 bar(3, 4)
360 bar(3, 4)
361 """,
361 """,
362 """
362 """
363 f()
363 f()
364 """,
364 """,
365 )
365 )
366
366
367
367
368 def _decorator_skip_setup():
368 def _decorator_skip_setup():
369 import pexpect
369 import pexpect
370
370
371 env = os.environ.copy()
371 env = os.environ.copy()
372 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
372 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
373 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
373 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
374
374
375 child = pexpect.spawn(
375 child = pexpect.spawn(
376 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
376 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
377 )
377 )
378 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
378 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
379
379
380 child.expect("IPython")
380 child.expect("IPython")
381 child.expect("\n")
381 child.expect("\n")
382
382
383 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
383 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
384 child.str_last_chars = 500
384 child.str_last_chars = 500
385
385
386 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
386 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
387 in_prompt_number = 1
387 in_prompt_number = 1
388 for cblock in dedented_blocks:
388 for cblock in dedented_blocks:
389 child.expect_exact(f"In [{in_prompt_number}]:")
389 child.expect_exact(f"In [{in_prompt_number}]:")
390 in_prompt_number += 1
390 in_prompt_number += 1
391 for line in cblock.splitlines():
391 for line in cblock.splitlines():
392 child.sendline(line)
392 child.sendline(line)
393 child.expect_exact(line)
393 child.expect_exact(line)
394 child.sendline("")
394 child.sendline("")
395 return child
395 return child
396
396
397
397
398 @pytest.mark.skip(reason="recently fail for unknown reason on CI")
398 @pytest.mark.skip(reason="recently fail for unknown reason on CI")
399 @skip_win32
399 @skip_win32
400 def test_decorator_skip():
400 def test_decorator_skip():
401 """test that decorator frames can be skipped."""
401 """test that decorator frames can be skipped."""
402
402
403 child = _decorator_skip_setup()
403 child = _decorator_skip_setup()
404
404
405 child.expect_exact("ipython-input-8")
405 child.expect_exact("ipython-input-8")
406 child.expect_exact("3 bar(3, 4)")
406 child.expect_exact("3 bar(3, 4)")
407 child.expect("ipdb>")
407 child.expect("ipdb>")
408
408
409 child.expect("ipdb>")
409 child.expect("ipdb>")
410 child.sendline("step")
410 child.sendline("step")
411 child.expect_exact("step")
411 child.expect_exact("step")
412 child.expect_exact("--Call--")
412 child.expect_exact("--Call--")
413 child.expect_exact("ipython-input-6")
413 child.expect_exact("ipython-input-6")
414
414
415 child.expect_exact("1 @pdb_skipped_decorator")
415 child.expect_exact("1 @pdb_skipped_decorator")
416
416
417 child.sendline("s")
417 child.sendline("s")
418 child.expect_exact("return x * y")
418 child.expect_exact("return x * y")
419
419
420 child.close()
420 child.close()
421
421
422
422
423 @pytest.mark.skip(reason="recently fail for unknown reason on CI")
423 @pytest.mark.skip(reason="recently fail for unknown reason on CI")
424 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
424 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
425 @skip_win32
425 @skip_win32
426 def test_decorator_skip_disabled():
426 def test_decorator_skip_disabled():
427 """test that decorator frame skipping can be disabled"""
427 """test that decorator frame skipping can be disabled"""
428
428
429 child = _decorator_skip_setup()
429 child = _decorator_skip_setup()
430
430
431 child.expect_exact("3 bar(3, 4)")
431 child.expect_exact("3 bar(3, 4)")
432
432
433 for input_, expected in [
433 for input_, expected in [
434 ("skip_predicates debuggerskip False", ""),
434 ("skip_predicates debuggerskip False", ""),
435 ("skip_predicates", "debuggerskip : False"),
435 ("skip_predicates", "debuggerskip : False"),
436 ("step", "---> 2 def wrapped_fn"),
436 ("step", "---> 2 def wrapped_fn"),
437 ("step", "----> 3 __debuggerskip__"),
437 ("step", "----> 3 __debuggerskip__"),
438 ("step", "----> 4 helper_1()"),
438 ("step", "----> 4 helper_1()"),
439 ("step", "---> 1 def helper_1():"),
439 ("step", "---> 1 def helper_1():"),
440 ("next", "----> 2 helpers_helper()"),
440 ("next", "----> 2 helpers_helper()"),
441 ("next", "--Return--"),
441 ("next", "--Return--"),
442 ("next", "----> 5 __debuggerskip__ = False"),
442 ("next", "----> 5 __debuggerskip__ = False"),
443 ]:
443 ]:
444 child.expect("ipdb>")
444 child.expect("ipdb>")
445 child.sendline(input_)
445 child.sendline(input_)
446 child.expect_exact(input_)
446 child.expect_exact(input_)
447 child.expect_exact(expected)
447 child.expect_exact(expected)
448
448
449 child.close()
449 child.close()
450
450
451
451
452 @pytest.mark.xfail(
452 @pytest.mark.xfail(
453 sys.version_info.releaselevel not in ("final", "candidate"),
453 sys.version_info.releaselevel not in ("final", "candidate"),
454 reason="fails on 3.13.dev",
454 reason="fails on 3.13.dev",
455 strict=True,
455 strict=True,
456 )
456 )
457 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
457 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
458 @skip_win32
458 @skip_win32
459 def test_decorator_skip_with_breakpoint():
459 def test_decorator_skip_with_breakpoint():
460 """test that decorator frame skipping can be disabled"""
460 """test that decorator frame skipping can be disabled"""
461
461
462 import pexpect
462 import pexpect
463
463
464 env = os.environ.copy()
464 env = os.environ.copy()
465 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
465 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
466 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
466 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
467
467
468 child = pexpect.spawn(
468 child = pexpect.spawn(
469 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
469 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
470 )
470 )
471 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
471 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
472 child.str_last_chars = 500
472 child.str_last_chars = 500
473
473
474 child.expect("IPython")
474 child.expect("IPython")
475 child.expect("\n")
475 child.expect("\n")
476
476
477 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
477 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
478
478
479 ### we need a filename, so we need to exec the full block with a filename
479 ### we need a filename, so we need to exec the full block with a filename
480 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
480 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
481 name = tf.name[:-3].split("/")[-1]
481 name = tf.name[:-3].split("/")[-1]
482 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
482 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
483 tf.flush()
483 tf.flush()
484 codeblock = f"from {name} import f"
484 codeblock = f"from {name} import f"
485
485
486 dedented_blocks = [
486 dedented_blocks = [
487 codeblock,
487 codeblock,
488 "f()",
488 "f()",
489 ]
489 ]
490
490
491 in_prompt_number = 1
491 in_prompt_number = 1
492 for cblock in dedented_blocks:
492 for cblock in dedented_blocks:
493 child.expect_exact(f"In [{in_prompt_number}]:")
493 child.expect_exact(f"In [{in_prompt_number}]:")
494 in_prompt_number += 1
494 in_prompt_number += 1
495 for line in cblock.splitlines():
495 for line in cblock.splitlines():
496 child.sendline(line)
496 child.sendline(line)
497 child.expect_exact(line)
497 child.expect_exact(line)
498 child.sendline("")
498 child.sendline("")
499
499
500 # From 3.13, set_trace()/breakpoint() stop on the line where they're
500 # From 3.13, set_trace()/breakpoint() stop on the line where they're
501 # called, instead of the next line.
501 # called, instead of the next line.
502 if sys.version_info >= (3, 13):
502 if sys.version_info >= (3, 13):
503 child.expect_exact("--> 46 ipdb.set_trace()")
503 child.expect_exact("--> 46 ipdb.set_trace()")
504 extra_step = [("step", "--> 47 bar(3, 4)")]
504 extra_step = [("step", "--> 47 bar(3, 4)")]
505 else:
505 else:
506 child.expect_exact("--> 47 bar(3, 4)")
506 child.expect_exact("--> 47 bar(3, 4)")
507 extra_step = []
507 extra_step = []
508
508
509 for input_, expected in [
509 for input_, expected in (
510 (f"b {name}.py:3", ""),
510 [
511 ] + extra_step + [
511 (f"b {name}.py:3", ""),
512 ("step", "1---> 3 pass # should not stop here except"),
512 ]
513 ("step", "---> 38 @pdb_skipped_decorator"),
513 + extra_step
514 ("continue", ""),
514 + [
515 ]:
515 ("step", "1---> 3 pass # should not stop here except"),
516 ("step", "---> 38 @pdb_skipped_decorator"),
517 ("continue", ""),
518 ]
519 ):
516 child.expect("ipdb>")
520 child.expect("ipdb>")
517 child.sendline(input_)
521 child.sendline(input_)
518 child.expect_exact(input_)
522 child.expect_exact(input_)
519 child.expect_exact(expected)
523 child.expect_exact(expected)
520
524
521 child.close()
525 child.close()
522
526
523
527
524 @skip_win32
528 @skip_win32
525 def test_where_erase_value():
529 def test_where_erase_value():
526 """Test that `where` does not access f_locals and erase values."""
530 """Test that `where` does not access f_locals and erase values."""
527 import pexpect
531 import pexpect
528
532
529 env = os.environ.copy()
533 env = os.environ.copy()
530 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
534 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
531
535
532 child = pexpect.spawn(
536 child = pexpect.spawn(
533 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
537 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
534 )
538 )
535 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
539 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
536
540
537 child.expect("IPython")
541 child.expect("IPython")
538 child.expect("\n")
542 child.expect("\n")
539 child.expect_exact("In [1]")
543 child.expect_exact("In [1]")
540
544
541 block = dedent(
545 block = dedent(
542 """
546 """
543 def simple_f():
547 def simple_f():
544 myvar = 1
548 myvar = 1
545 print(myvar)
549 print(myvar)
546 1/0
550 1/0
547 print(myvar)
551 print(myvar)
548 simple_f() """
552 simple_f() """
549 )
553 )
550
554
551 for line in block.splitlines():
555 for line in block.splitlines():
552 child.sendline(line)
556 child.sendline(line)
553 child.expect_exact(line)
557 child.expect_exact(line)
554 child.expect_exact("ZeroDivisionError")
558 child.expect_exact("ZeroDivisionError")
555 child.expect_exact("In [2]:")
559 child.expect_exact("In [2]:")
556
560
557 child.sendline("%debug")
561 child.sendline("%debug")
558
562
559 ##
563 ##
560 child.expect("ipdb>")
564 child.expect("ipdb>")
561
565
562 child.sendline("myvar")
566 child.sendline("myvar")
563 child.expect("1")
567 child.expect("1")
564
568
565 ##
569 ##
566 child.expect("ipdb>")
570 child.expect("ipdb>")
567
571
568 child.sendline("myvar = 2")
572 child.sendline("myvar = 2")
569
573
570 ##
574 ##
571 child.expect_exact("ipdb>")
575 child.expect_exact("ipdb>")
572
576
573 child.sendline("myvar")
577 child.sendline("myvar")
574
578
575 child.expect_exact("2")
579 child.expect_exact("2")
576
580
577 ##
581 ##
578 child.expect("ipdb>")
582 child.expect("ipdb>")
579 child.sendline("where")
583 child.sendline("where")
580
584
581 ##
585 ##
582 child.expect("ipdb>")
586 child.expect("ipdb>")
583 child.sendline("myvar")
587 child.sendline("myvar")
584
588
585 child.expect_exact("2")
589 child.expect_exact("2")
586 child.expect("ipdb>")
590 child.expect("ipdb>")
587
591
588 child.close()
592 child.close()
General Comments 0
You need to be logged in to leave comments. Login now