##// END OF EJS Templates
no CPR
Matthias Bussonnier -
Show More
@@ -1,568 +1,569 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 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
372 373
373 374 child = pexpect.spawn(
374 375 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
375 376 )
376 377 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
377 378
378 379 child.expect("IPython")
379 380 child.expect("\n")
380 381
381 382 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
382 383 child.str_last_chars = 500
383 384
384 385 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
385 386 in_prompt_number = 1
386 387 for cblock in dedented_blocks:
387 388 child.expect_exact(f"In [{in_prompt_number}]:")
388 389 in_prompt_number += 1
389 390 for line in cblock.splitlines():
390 391 child.sendline(line)
391 392 child.expect_exact(line)
392 393 child.sendline("")
393 394 return child
394 395
395 396
396 397 @skip_win32
397 398 def test_decorator_skip():
398 399 """test that decorator frames can be skipped."""
399 400
400 401 child = _decorator_skip_setup()
401 402
402 403 child.expect_exact("3 bar(3, 4)")
403 404 child.expect("ipdb>")
404 405
405 406 child.expect("ipdb>")
406 407 child.sendline("step")
407 408 child.expect_exact("step")
408 409
409 410 child.expect_exact("1 @pdb_skipped_decorator")
410 411
411 412 child.sendline("s")
412 413 child.expect_exact("return x * y")
413 414
414 415 child.close()
415 416
416 417
417 418 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
418 419 @skip_win32
419 420 def test_decorator_skip_disabled():
420 421 """test that decorator frame skipping can be disabled"""
421 422
422 423 child = _decorator_skip_setup()
423 424
424 425 child.expect_exact("3 bar(3, 4)")
425 426
426 427 for input_, expected in [
427 428 ("skip_predicates debuggerskip False", ""),
428 429 ("skip_predicates", "debuggerskip : False"),
429 430 ("step", "---> 2 def wrapped_fn"),
430 431 ("step", "----> 3 __debuggerskip__"),
431 432 ("step", "----> 4 helper_1()"),
432 433 ("step", "---> 1 def helper_1():"),
433 434 ("next", "----> 2 helpers_helper()"),
434 435 ("next", "--Return--"),
435 436 ("next", "----> 5 __debuggerskip__ = False"),
436 437 ]:
437 438 child.expect("ipdb>")
438 439 child.sendline(input_)
439 440 child.expect_exact(input_)
440 441 child.expect_exact(expected)
441 442
442 443 child.close()
443 444
444 445
445 446 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
446 447 @skip_win32
447 448 def test_decorator_skip_with_breakpoint():
448 449 """test that decorator frame skipping can be disabled"""
449 450
450 451 import pexpect
451 452
452 453 env = os.environ.copy()
453 454 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
454 455
455 456 child = pexpect.spawn(
456 457 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
457 458 )
458 459 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
459 460
460 461 child.expect("IPython")
461 462 child.expect("\n")
462 463
463 464 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
464 465
465 466 ### we need a filename, so we need to exec the full block with a filename
466 467 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
467 468
468 469 name = tf.name[:-3].split("/")[-1]
469 470 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
470 471 tf.flush()
471 472 codeblock = f"from {name} import f"
472 473
473 474 dedented_blocks = [
474 475 codeblock,
475 476 "f()",
476 477 ]
477 478
478 479 in_prompt_number = 1
479 480 for cblock in dedented_blocks:
480 481 child.expect_exact(f"In [{in_prompt_number}]:")
481 482 in_prompt_number += 1
482 483 for line in cblock.splitlines():
483 484 child.sendline(line)
484 485 child.expect_exact(line)
485 486 child.sendline("")
486 487
487 488 # as the filename does not exists, we'll rely on the filename prompt
488 489 child.expect_exact("47 bar(3, 4)")
489 490
490 491 for input_, expected in [
491 492 (f"b {name}.py:3", ""),
492 493 ("step", "1---> 3 pass # should not stop here except"),
493 494 ("step", "---> 38 @pdb_skipped_decorator"),
494 495 ("continue", ""),
495 496 ]:
496 497 child.expect("ipdb>")
497 498 child.sendline(input_)
498 499 child.expect_exact(input_)
499 500 child.expect_exact(expected)
500 501
501 502 child.close()
502 503
503 504
504 505 @skip_win32
505 506 def test_where_erase_value():
506 507 """Test that `where` does not access f_locals and erase values."""
507 508 import pexpect
508 509
509 510 env = os.environ.copy()
510 511 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
511 512
512 513 child = pexpect.spawn(
513 514 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
514 515 )
515 516 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
516 517
517 518 child.expect("IPython")
518 519 child.expect("\n")
519 520 child.expect_exact("In [1]")
520 521
521 522 block = dedent(
522 523 """
523 524 def simple_f():
524 525 myvar = 1
525 526 print(myvar)
526 527 1/0
527 528 print(myvar)
528 529 simple_f() """
529 530 )
530 531
531 532 for line in block.splitlines():
532 533 child.sendline(line)
533 534 child.expect_exact(line)
534 535 child.expect_exact("ZeroDivisionError")
535 536 child.expect_exact("In [2]:")
536 537
537 538 child.sendline("%debug")
538 539
539 540 ##
540 541 child.expect("ipdb>")
541 542
542 543 child.sendline("myvar")
543 544 child.expect("1")
544 545
545 546 ##
546 547 child.expect("ipdb>")
547 548
548 549 child.sendline("myvar = 2")
549 550
550 551 ##
551 552 child.expect_exact("ipdb>")
552 553
553 554 child.sendline("myvar")
554 555
555 556 child.expect_exact("2")
556 557
557 558 ##
558 559 child.expect("ipdb>")
559 560 child.sendline("where")
560 561
561 562 ##
562 563 child.expect("ipdb>")
563 564 child.sendline("myvar")
564 565
565 566 child.expect_exact("2")
566 567 child.expect("ipdb>")
567 568
568 569 child.close()
General Comments 0
You need to be logged in to leave comments. Login now