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