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 |
@@ -902,12 +907,16 b' class Pdb(OldPdb):' | |||
|
902 | 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 | 914 | if self._predicates["debuggerskip"]: |
|
906 | 915 | if DEBUGGERSKIP in frame.f_code.co_varnames: |
|
907 | 916 | return True |
|
908 | 917 | if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP): |
|
909 | 918 | return True |
|
910 | return super().break_anywhere(frame) | |
|
919 | return False | |
|
911 | 920 | |
|
912 | 921 | @skip_doctest |
|
913 | 922 | def _is_in_decorator_internal_and_should_skip(self, frame): |
@@ -926,8 +935,12 b' class Pdb(OldPdb):' | |||
|
926 | 935 | if DEBUGGERSKIP in frame.f_code.co_varnames: |
|
927 | 936 | return True |
|
928 | 937 | |
|
929 | # if parent frame value set to True skip as well. | |
|
930 | if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP): | |
|
938 | # if one of the parent frame value set to True skip as well. | |
|
939 | ||
|
940 | cframe = frame | |
|
941 | while getattr(cframe, "f_back", None): | |
|
942 | cframe = cframe.f_back | |
|
943 | if self._get_frame_locals(cframe).get(DEBUGGERSKIP): | |
|
931 | 944 | return True |
|
932 | 945 | |
|
933 | 946 | return False |
@@ -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 |
@@ -325,14 +326,30 b' def test_xmode_skip():' | |||
|
325 | 326 | |
|
326 | 327 | skip_decorators_blocks = ( |
|
327 | 328 | """ |
|
329 | def helpers_helper(): | |
|
330 | pass # should not stop here except breakpoint | |
|
331 | """, | |
|
332 | """ | |
|
328 | 333 | def helper_1(): |
|
329 |
|
|
|
334 | helpers_helper() # should not stop here | |
|
330 | 335 | """, |
|
331 | 336 | """ |
|
332 | 337 | def helper_2(): |
|
333 | 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 | 353 | def pdb_skipped_decorator(function): |
|
337 | 354 | def wrapped_fn(*args, **kwargs): |
|
338 | 355 | __debuggerskip__ = True |
@@ -346,6 +363,7 b' skip_decorators_blocks = (' | |||
|
346 | 363 | """, |
|
347 | 364 | """ |
|
348 | 365 | @pdb_skipped_decorator |
|
366 | @pdb_skipped_decorator2 | |
|
349 | 367 | def bar(x, y): |
|
350 | 368 | return x * y |
|
351 | 369 | """, |
@@ -423,7 +441,7 b' def test_decorator_skip_disabled():' | |||
|
423 | 441 | ("step", "----> 3 __debuggerskip__"), |
|
424 | 442 | ("step", "----> 4 helper_1()"), |
|
425 | 443 | ("step", "---> 1 def helper_1():"), |
|
426 |
("next", "----> 2 |
|
|
444 | ("next", "----> 2 helpers_helper()"), | |
|
427 | 445 | ("next", "--Return--"), |
|
428 | 446 | ("next", "----> 5 __debuggerskip__ = False"), |
|
429 | 447 | ]: |
@@ -436,6 +454,62 b' def test_decorator_skip_disabled():' | |||
|
436 | 454 | |
|
437 | 455 | |
|
438 | 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 | 513 | def test_where_erase_value(): |
|
440 | 514 | """Test that `where` does not access f_locals and erase values.""" |
|
441 | 515 | import pexpect |
General Comments 0
You need to be logged in to leave comments.
Login now