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