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