##// END OF EJS Templates
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
@@ -902,12 +907,16 b' class Pdb(OldPdb):'
902 stop at any point inside the function
907 stop at any point inside the function
903
908
904 """
909 """
910
911 sup = super().break_anywhere(frame)
912 if sup:
913 return sup
905 if self._predicates["debuggerskip"]:
914 if self._predicates["debuggerskip"]:
906 if DEBUGGERSKIP in frame.f_code.co_varnames:
915 if DEBUGGERSKIP in frame.f_code.co_varnames:
907 return True
916 return True
908 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
917 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
909 return True
918 return True
910 return super().break_anywhere(frame)
919 return False
911
920
912 @skip_doctest
921 @skip_doctest
913 def _is_in_decorator_internal_and_should_skip(self, frame):
922 def _is_in_decorator_internal_and_should_skip(self, frame):
@@ -926,9 +935,13 b' class Pdb(OldPdb):'
926 if DEBUGGERSKIP in frame.f_code.co_varnames:
935 if DEBUGGERSKIP in frame.f_code.co_varnames:
927 return True
936 return True
928
937
929 # if parent frame value set to True skip as well.
938 # if one of the parent frame value set to True skip as well.
930 if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
939
931 return True
940 cframe = frame
941 while getattr(cframe, "f_back", None):
942 cframe = cframe.f_back
943 if self._get_frame_locals(cframe).get(DEBUGGERSKIP):
944 return True
932
945
933 return False
946 return False
934
947
@@ -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
@@ -325,14 +326,30 b' def test_xmode_skip():'
325
326
326 skip_decorators_blocks = (
327 skip_decorators_blocks = (
327 """
328 """
329 def helpers_helper():
330 pass # should not stop here except breakpoint
331 """,
332 """
328 def helper_1():
333 def helper_1():
329 pass # should not stop here
334 helpers_helper() # should not stop here
330 """,
335 """,
331 """
336 """
332 def helper_2():
337 def helper_2():
333 pass # should not stop here
338 pass # should not stop here
334 """,
339 """,
335 """
340 """
341 def pdb_skipped_decorator2(function):
342 def wrapped_fn(*args, **kwargs):
343 __debuggerskip__ = True
344 helper_2()
345 __debuggerskip__ = False
346 result = function(*args, **kwargs)
347 __debuggerskip__ = True
348 helper_2()
349 return result
350 return wrapped_fn
351 """,
352 """
336 def pdb_skipped_decorator(function):
353 def pdb_skipped_decorator(function):
337 def wrapped_fn(*args, **kwargs):
354 def wrapped_fn(*args, **kwargs):
338 __debuggerskip__ = True
355 __debuggerskip__ = True
@@ -346,6 +363,7 b' skip_decorators_blocks = ('
346 """,
363 """,
347 """
364 """
348 @pdb_skipped_decorator
365 @pdb_skipped_decorator
366 @pdb_skipped_decorator2
349 def bar(x, y):
367 def bar(x, y):
350 return x * y
368 return x * y
351 """,
369 """,
@@ -423,7 +441,7 b' def test_decorator_skip_disabled():'
423 ("step", "----> 3 __debuggerskip__"),
441 ("step", "----> 3 __debuggerskip__"),
424 ("step", "----> 4 helper_1()"),
442 ("step", "----> 4 helper_1()"),
425 ("step", "---> 1 def helper_1():"),
443 ("step", "---> 1 def helper_1():"),
426 ("next", "----> 2 pass"),
444 ("next", "----> 2 helpers_helper()"),
427 ("next", "--Return--"),
445 ("next", "--Return--"),
428 ("next", "----> 5 __debuggerskip__ = False"),
446 ("next", "----> 5 __debuggerskip__ = False"),
429 ]:
447 ]:
@@ -436,6 +454,62 b' def test_decorator_skip_disabled():'
436
454
437
455
438 @skip_win32
456 @skip_win32
457 def test_decorator_skip_with_breakpoint():
458 """test that decorator frame skipping can be disabled"""
459
460 import pexpect
461
462 env = os.environ.copy()
463 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
464
465 child = pexpect.spawn(
466 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
467 )
468 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
469
470 child.expect("IPython")
471 child.expect("\n")
472
473 ### we need a filename, so we need to exec the full block with a filename
474 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
475
476 name = tf.name[:-3].split("/")[-1]
477 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
478 tf.flush()
479 codeblock = f"from {name} import f"
480
481 dedented_blocks = [
482 codeblock,
483 "f()",
484 ]
485
486 in_prompt_number = 1
487 for cblock in dedented_blocks:
488 child.expect_exact(f"In [{in_prompt_number}]:")
489 in_prompt_number += 1
490 for line in cblock.splitlines():
491 child.sendline(line)
492 child.expect_exact(line)
493 child.sendline("")
494
495 # as the filename does not exists, we'll rely on the filename prompt
496 child.expect_exact("47 bar(3, 4)")
497
498 for input_, expected in [
499 (f"b {name}.py:3", ""),
500 ("step", "1---> 3 pass # should not stop here except"),
501 ("step", "---> 38 @pdb_skipped_decorator"),
502 ("continue", ""),
503 ]:
504 child.expect("ipdb>")
505 child.sendline(input_)
506 child.expect_exact(input_)
507 child.expect_exact(expected)
508
509 child.close()
510
511
512 @skip_win32
439 def test_where_erase_value():
513 def test_where_erase_value():
440 """Test that `where` does not access f_locals and erase values."""
514 """Test that `where` does not access f_locals and erase values."""
441 import pexpect
515 import pexpect
General Comments 0
You need to be logged in to leave comments. Login now