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