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