Show More
@@ -24,8 +24,12 b' By default, frames from readonly files will be hidden, frames containing' | |||
|
24 | 24 | Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent |
|
25 | 25 | frames value of ``__debuggerskip__`` is ``True`` will be skipped. |
|
26 | 26 | |
|
27 |
>>> def helper |
|
|
27 | >>> def helpers_helper(): | |
|
28 | ... pass | |
|
29 | ... | |
|
30 | ... def helper_1(): | |
|
28 | 31 | ... print("don't step in me") |
|
32 | ... helpers_helpers() # will be stepped over unless breakpoint set. | |
|
29 | 33 | ... |
|
30 | 34 | ... |
|
31 | 35 | ... def helper_2(): |
@@ -44,6 +48,7 b' One can define a decorator that wraps a function between the two helpers:' | |||
|
44 | 48 | ... result = function(*args, **kwargs) |
|
45 | 49 | ... __debuggerskip__ = True |
|
46 | 50 | ... helper_2() |
|
51 | ... # setting __debuggerskip__ to False again is not necessary | |
|
47 | 52 | ... return result |
|
48 | 53 | ... |
|
49 | 54 | ... return wrapped_fn |
@@ -892,12 +897,16 b' class Pdb(OldPdb):' | |||
|
892 | 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 | 904 | if self._predicates["debuggerskip"]: |
|
896 | 905 | if DEBUGGERSKIP in frame.f_code.co_varnames: |
|
897 | 906 | return True |
|
898 | 907 | if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP): |
|
899 | 908 | return True |
|
900 | return super().break_anywhere(frame) | |
|
909 | return False | |
|
901 | 910 | |
|
902 | 911 | @skip_doctest |
|
903 | 912 | def _is_in_decorator_internal_and_should_skip(self, frame): |
@@ -916,9 +925,13 b' class Pdb(OldPdb):' | |||
|
916 | 925 | if DEBUGGERSKIP in frame.f_code.co_varnames: |
|
917 | 926 | return True |
|
918 | 927 | |
|
919 | # if parent frame value set to True skip as well. | |
|
920 | if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP): | |
|
921 | return True | |
|
928 | # if one of the parent frame value set to True skip as well. | |
|
929 | ||
|
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 | 936 | return False |
|
924 | 937 |
@@ -12,6 +12,7 b' import subprocess' | |||
|
12 | 12 | import sys |
|
13 | 13 | import time |
|
14 | 14 | import warnings |
|
15 | ||
|
15 | 16 | from subprocess import PIPE, CalledProcessError, check_output |
|
16 | 17 | from tempfile import NamedTemporaryFile |
|
17 | 18 | from textwrap import dedent |
@@ -328,14 +329,30 b' def test_xmode_skip():' | |||
|
328 | 329 | |
|
329 | 330 | skip_decorators_blocks = ( |
|
330 | 331 | """ |
|
332 | def helpers_helper(): | |
|
333 | pass # should not stop here except breakpoint | |
|
334 | """, | |
|
335 | """ | |
|
331 | 336 | def helper_1(): |
|
332 |
|
|
|
337 | helpers_helper() # should not stop here | |
|
333 | 338 | """, |
|
334 | 339 | """ |
|
335 | 340 | def helper_2(): |
|
336 | 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 | 356 | def pdb_skipped_decorator(function): |
|
340 | 357 | def wrapped_fn(*args, **kwargs): |
|
341 | 358 | __debuggerskip__ = True |
@@ -349,6 +366,7 b' skip_decorators_blocks = (' | |||
|
349 | 366 | """, |
|
350 | 367 | """ |
|
351 | 368 | @pdb_skipped_decorator |
|
369 | @pdb_skipped_decorator2 | |
|
352 | 370 | def bar(x, y): |
|
353 | 371 | return x * y |
|
354 | 372 | """, |
@@ -426,7 +444,7 b' def test_decorator_skip_disabled():' | |||
|
426 | 444 | ("step", "----> 3 __debuggerskip__"), |
|
427 | 445 | ("step", "----> 4 helper_1()"), |
|
428 | 446 | ("step", "---> 1 def helper_1():"), |
|
429 |
("next", "----> 2 |
|
|
447 | ("next", "----> 2 helpers_helper()"), | |
|
430 | 448 | ("next", "--Return--"), |
|
431 | 449 | ("next", "----> 5 __debuggerskip__ = False"), |
|
432 | 450 | ]: |
@@ -439,6 +457,62 b' def test_decorator_skip_disabled():' | |||
|
439 | 457 | |
|
440 | 458 | |
|
441 | 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 | 516 | def test_where_erase_value(): |
|
443 | 517 | """Test that `where` does not access f_locals and erase values.""" |
|
444 | 518 | import pexpect |
General Comments 0
You need to be logged in to leave comments.
Login now