##// END OF EJS Templates
Backport PR #13175: Expand and Fix PDB skip.
Matthias Bussonnier -
Show More
@@ -24,8 +24,12 b' By default, frames from readonly files will be hidden, frames containing'
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
26
26
27 >>> def helper_1():
27 >>> def helpers_helper():
28 ... pass
29 ...
30 ... def helper_1():
28 ... print("don't step in me")
31 ... print("don't step in me")
32 ... helpers_helpers() # will be stepped over unless breakpoint set.
29 ...
33 ...
30 ...
34 ...
31 ... def helper_2():
35 ... def helper_2():
@@ -44,6 +48,7 b' One can define a decorator that wraps a function between the two helpers:'
44 ... result = function(*args, **kwargs)
48 ... result = function(*args, **kwargs)
45 ... __debuggerskip__ = True
49 ... __debuggerskip__ = True
46 ... helper_2()
50 ... helper_2()
51 ... # setting __debuggerskip__ to False again is not necessary
47 ... return result
52 ... return result
48 ...
53 ...
49 ... return wrapped_fn
54 ... return wrapped_fn
@@ -892,12 +897,16 b' class Pdb(OldPdb):'
892 stop at any point inside the function
897 stop at any point inside the function
893
898
894 """
899 """
900
901 sup = super().break_anywhere(frame)
902 if sup:
903 return sup
895 if self._predicates["debuggerskip"]:
904 if self._predicates["debuggerskip"]:
896 if DEBUGGERSKIP in frame.f_code.co_varnames:
905 if DEBUGGERSKIP in frame.f_code.co_varnames:
897 return True
906 return True
898 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
907 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
899 return True
908 return True
900 return super().break_anywhere(frame)
909 return False
901
910
902 @skip_doctest
911 @skip_doctest
903 def _is_in_decorator_internal_and_should_skip(self, frame):
912 def _is_in_decorator_internal_and_should_skip(self, frame):
@@ -916,9 +925,13 b' class Pdb(OldPdb):'
916 if DEBUGGERSKIP in frame.f_code.co_varnames:
925 if DEBUGGERSKIP in frame.f_code.co_varnames:
917 return True
926 return True
918
927
919 # if parent frame value set to True skip as well.
928 # if one of the parent frame value set to True skip as well.
920 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
929
921 return True
930 cframe = frame
931 while getattr(cframe, "f_back", None):
932 cframe = cframe.f_back
933 if self._get_frame_locals(cframe).get(DEBUGGERSKIP):
934 return True
922
935
923 return False
936 return False
924
937
@@ -12,6 +12,7 b' import subprocess'
12 import sys
12 import sys
13 import time
13 import time
14 import warnings
14 import warnings
15
15 from subprocess import PIPE, CalledProcessError, check_output
16 from subprocess import PIPE, CalledProcessError, check_output
16 from tempfile import NamedTemporaryFile
17 from tempfile import NamedTemporaryFile
17 from textwrap import dedent
18 from textwrap import dedent
@@ -328,14 +329,30 b' def test_xmode_skip():'
328
329
329 skip_decorators_blocks = (
330 skip_decorators_blocks = (
330 """
331 """
332 def helpers_helper():
333 pass # should not stop here except breakpoint
334 """,
335 """
331 def helper_1():
336 def helper_1():
332 pass # should not stop here
337 helpers_helper() # should not stop here
333 """,
338 """,
334 """
339 """
335 def helper_2():
340 def helper_2():
336 pass # should not stop here
341 pass # should not stop here
337 """,
342 """,
338 """
343 """
344 def pdb_skipped_decorator2(function):
345 def wrapped_fn(*args, **kwargs):
346 __debuggerskip__ = True
347 helper_2()
348 __debuggerskip__ = False
349 result = function(*args, **kwargs)
350 __debuggerskip__ = True
351 helper_2()
352 return result
353 return wrapped_fn
354 """,
355 """
339 def pdb_skipped_decorator(function):
356 def pdb_skipped_decorator(function):
340 def wrapped_fn(*args, **kwargs):
357 def wrapped_fn(*args, **kwargs):
341 __debuggerskip__ = True
358 __debuggerskip__ = True
@@ -349,6 +366,7 b' skip_decorators_blocks = ('
349 """,
366 """,
350 """
367 """
351 @pdb_skipped_decorator
368 @pdb_skipped_decorator
369 @pdb_skipped_decorator2
352 def bar(x, y):
370 def bar(x, y):
353 return x * y
371 return x * y
354 """,
372 """,
@@ -426,7 +444,7 b' def test_decorator_skip_disabled():'
426 ("step", "----> 3 __debuggerskip__"),
444 ("step", "----> 3 __debuggerskip__"),
427 ("step", "----> 4 helper_1()"),
445 ("step", "----> 4 helper_1()"),
428 ("step", "---> 1 def helper_1():"),
446 ("step", "---> 1 def helper_1():"),
429 ("next", "----> 2 pass"),
447 ("next", "----> 2 helpers_helper()"),
430 ("next", "--Return--"),
448 ("next", "--Return--"),
431 ("next", "----> 5 __debuggerskip__ = False"),
449 ("next", "----> 5 __debuggerskip__ = False"),
432 ]:
450 ]:
@@ -439,6 +457,62 b' def test_decorator_skip_disabled():'
439
457
440
458
441 @skip_win32
459 @skip_win32
460 def test_decorator_skip_with_breakpoint():
461 """test that decorator frame skipping can be disabled"""
462
463 import pexpect
464
465 env = os.environ.copy()
466 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
467
468 child = pexpect.spawn(
469 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
470 )
471 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
472
473 child.expect("IPython")
474 child.expect("\n")
475
476 ### we need a filename, so we need to exec the full block with a filename
477 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
478
479 name = tf.name[:-3].split("/")[-1]
480 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
481 tf.flush()
482 codeblock = f"from {name} import f"
483
484 dedented_blocks = [
485 codeblock,
486 "f()",
487 ]
488
489 in_prompt_number = 1
490 for cblock in dedented_blocks:
491 child.expect_exact(f"In [{in_prompt_number}]:")
492 in_prompt_number += 1
493 for line in cblock.splitlines():
494 child.sendline(line)
495 child.expect_exact(line)
496 child.sendline("")
497
498 # as the filename does not exists, we'll rely on the filename prompt
499 child.expect_exact("47 bar(3, 4)")
500
501 for input_, expected in [
502 (f"b {name}.py:3", ""),
503 ("step", "1---> 3 pass # should not stop here except"),
504 ("step", "---> 38 @pdb_skipped_decorator"),
505 ("continue", ""),
506 ]:
507 child.expect("ipdb>")
508 child.sendline(input_)
509 child.expect_exact(input_)
510 child.expect_exact(expected)
511
512 child.close()
513
514
515 @skip_win32
442 def test_where_erase_value():
516 def test_where_erase_value():
443 """Test that `where` does not access f_locals and erase values."""
517 """Test that `where` does not access f_locals and erase values."""
444 import pexpect
518 import pexpect
General Comments 0
You need to be logged in to leave comments. Login now