Show More
@@ -33,6 +33,7 b' import linecache' | |||
|
33 | 33 | import sys |
|
34 | 34 | import warnings |
|
35 | 35 | import re |
|
36 | import os | |
|
36 | 37 | |
|
37 | 38 | from IPython import get_ipython |
|
38 | 39 | from IPython.utils import PyColorize |
@@ -282,6 +283,9 b' class Pdb(OldPdb):' | |||
|
282 | 283 | self.prompt = prompt |
|
283 | 284 | self.skip_hidden = True |
|
284 | 285 | |
|
286 | # list of predicates we use to skip frames | |
|
287 | self._predicates = {"tbhide": True, "readonly": True, "ipython_internal": True} | |
|
288 | ||
|
285 | 289 | def set_colors(self, scheme): |
|
286 | 290 | """Shorthand access to the color table scheme selector method.""" |
|
287 | 291 | self.color_scheme_table.set_active_scheme(scheme) |
@@ -293,6 +297,26 b' class Pdb(OldPdb):' | |||
|
293 | 297 | self.initial_frame = frame |
|
294 | 298 | return super().set_trace(frame) |
|
295 | 299 | |
|
300 | def _hidden_predicate(self, frame): | |
|
301 | """ | |
|
302 | Given a frame return whether it it should be hidden or not by IPython. | |
|
303 | """ | |
|
304 | ||
|
305 | if self._predicates["readonly"]: | |
|
306 | fname = frame.f_code.co_filename | |
|
307 | # we need to check for file existence and interactively define | |
|
308 | # function would otherwise appear as RO. | |
|
309 | if os.path.isfile(fname) and not os.access(fname, os.W_OK): | |
|
310 | return True | |
|
311 | ||
|
312 | if self._predicates["tbhide"]: | |
|
313 | if frame in (self.curframe, getattr(self, "initial_frame", None)): | |
|
314 | return False | |
|
315 | else: | |
|
316 | return frame.f_locals.get("__tracebackhide__", False) | |
|
317 | ||
|
318 | return False | |
|
319 | ||
|
296 | 320 | def hidden_frames(self, stack): |
|
297 | 321 | """ |
|
298 | 322 | Given an index in the stack return wether it should be skipped. |
@@ -303,14 +327,9 b' class Pdb(OldPdb):' | |||
|
303 | 327 | # locals whenever the .f_locals accessor is called, so we |
|
304 | 328 | # avoid calling it here to preserve self.curframe_locals. |
|
305 | 329 | # Futhermore, there is no good reason to hide the current frame. |
|
306 | ip_hide = [ | |
|
307 | False | |
|
308 | if s[0] in (self.curframe, getattr(self, "initial_frame", None)) | |
|
309 | else s[0].f_locals.get("__tracebackhide__", False) | |
|
310 | for s in stack | |
|
311 | ] | |
|
330 | ip_hide = [self._hidden_predicate(s[0]) for s in stack] | |
|
312 | 331 | ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"] |
|
313 | if ip_start: | |
|
332 | if ip_start and self._predicates["ipython_internal"]: | |
|
314 | 333 | ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)] |
|
315 | 334 | return ip_hide |
|
316 | 335 | |
@@ -521,15 +540,64 b' class Pdb(OldPdb):' | |||
|
521 | 540 | except KeyboardInterrupt: |
|
522 | 541 | pass |
|
523 | 542 | |
|
543 | def do_skip_predicates(self, args): | |
|
544 | """ | |
|
545 | Turn on/off individual predicates as to whether a frame should be hidden/skip. | |
|
546 | ||
|
547 | The global option to skip (or not) hidden frames is set with skip_hidden | |
|
548 | ||
|
549 | To change the value of a predicate | |
|
550 | ||
|
551 | skip_predicates key [true|false] | |
|
552 | ||
|
553 | Call without arguments to see the current values. | |
|
554 | ||
|
555 | """ | |
|
556 | if not args.strip(): | |
|
557 | print("current predicates:") | |
|
558 | for (p, v) in self._predicates.items(): | |
|
559 | print(" ", p, ":", v) | |
|
560 | return | |
|
561 | type_value = args.strip().split(" ") | |
|
562 | if len(type_value) != 2: | |
|
563 | print( | |
|
564 | f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}" | |
|
565 | ) | |
|
566 | return | |
|
567 | ||
|
568 | type_, value = type_value | |
|
569 | if type_ not in self._predicates: | |
|
570 | print(f"{type_!r} not in {set(self._predicates.keys())}") | |
|
571 | return | |
|
572 | if value.lower() not in ("true", "yes", "1", "no", "false", "0"): | |
|
573 | print( | |
|
574 | f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')" | |
|
575 | ) | |
|
576 | return | |
|
577 | ||
|
578 | self._predicates[type_] = value.lower() in ("true", "yes", "1") | |
|
579 | if not any(self._predicates.values()): | |
|
580 | print( | |
|
581 | "Warning, all predicates set to False, skip_hidden may not have any effects." | |
|
582 | ) | |
|
583 | ||
|
524 | 584 | def do_skip_hidden(self, arg): |
|
525 | 585 | """ |
|
526 | 586 | Change whether or not we should skip frames with the |
|
527 | 587 | __tracebackhide__ attribute. |
|
528 | 588 | """ |
|
529 | if arg.strip().lower() in ("true", "yes"): | |
|
589 | if not arg.strip(): | |
|
590 | print( | |
|
591 | f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change." | |
|
592 | ) | |
|
593 | elif arg.strip().lower() in ("true", "yes"): | |
|
530 | 594 | self.skip_hidden = True |
|
531 | 595 | elif arg.strip().lower() in ("false", "no"): |
|
532 | 596 | self.skip_hidden = False |
|
597 | if not any(self._predicates.values()): | |
|
598 | print( | |
|
599 | "Warning, all predicates set to False, skip_hidden may not have any effects." | |
|
600 | ) | |
|
533 | 601 | |
|
534 | 602 | def do_list(self, arg): |
|
535 | 603 | """Print lines of code from the current stack frame |
@@ -694,9 +762,12 b' class Pdb(OldPdb):' | |||
|
694 | 762 | """Check if pdb should stop here""" |
|
695 | 763 | if not super().stop_here(frame): |
|
696 | 764 | return False |
|
697 | if self.skip_hidden and frame.f_locals.get("__tracebackhide__", False): | |
|
765 | hidden = False | |
|
766 | if self.skip_hidden: | |
|
767 | hidden = self._hidden_predicate(frame) | |
|
698 | 768 | if self._wait_for_mainpyfile: |
|
699 | 769 | return False |
|
770 | if hidden: | |
|
700 | 771 | Colors = self.color_scheme_table.active_colors |
|
701 | 772 | ColorsNormal = Colors.Normal |
|
702 | 773 | print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n") |
@@ -710,8 +781,8 b' class Pdb(OldPdb):' | |||
|
710 | 781 | |
|
711 | 782 | Will skip hidden frames. |
|
712 | 783 | """ |
|
713 |
|
|
|
714 | # frames with __tracebackide__ | |
|
784 | # modified version of upstream that skips | |
|
785 | # frames with __tracebackhide__ | |
|
715 | 786 | if self.curindex == 0: |
|
716 | 787 | self.error("Oldest frame") |
|
717 | 788 | return |
@@ -2,6 +2,50 b'' | |||
|
2 | 2 | 7.x Series |
|
3 | 3 | ============ |
|
4 | 4 | |
|
5 | ||
|
6 | The debugger (and ``%debug`` magic) have been improved to skip and hide frames | |
|
7 | originating from files that are not writable to the user, as these are less | |
|
8 | likely to be the source of errors, or be part of system files. | |
|
9 | ||
|
10 | In addition to the global ``skip_hidden True|False`` command, the debugger has | |
|
11 | gained finer grained control of predicates as to whether to a frame should be | |
|
12 | considered hidden. So far 3 predicates are available and activated by default: | |
|
13 | ||
|
14 | - ``tbhide``: frames containing the local variable ``__tracebackhide__`` set to | |
|
15 | True. | |
|
16 | - ``readonly``: frames originating from readonly files. | |
|
17 | - ``ipython_internal``: frames that are likely to be from IPython internal code. | |
|
18 | ||
|
19 | You can toggle individual predicates during a session with | |
|
20 | ||
|
21 | .. code-block:: | |
|
22 | ||
|
23 | ipdb> skip_predicates readonly False | |
|
24 | ||
|
25 | Read-only files will not be considered hidden frames. | |
|
26 | ||
|
27 | ||
|
28 | You can call ``skip_predicates`` without arguments to see the states of current | |
|
29 | predicates: | |
|
30 | ||
|
31 | .. code-block:: | |
|
32 | ||
|
33 | ipdb> skip_predicates | |
|
34 | current predicates: | |
|
35 | tbhide : True | |
|
36 | readonly : True | |
|
37 | ipython_internal : True | |
|
38 | ||
|
39 | If all predicates are set to ``False``, ``skip_hidden`` will practically have | |
|
40 | no effect. We attempt to warn you when all predicates are False. | |
|
41 | ||
|
42 | Note that the ``readonly`` predicate may increase disk access as we check for | |
|
43 | file access permission for all frames on many command invocation, but is usually | |
|
44 | cached by operating system. Let us know if you encounter any issues. | |
|
45 | ||
|
46 | ||
|
47 | ||
|
48 | ||
|
5 | 49 | .. _version 7.23: |
|
6 | 50 | |
|
7 | 51 | IPython 7.23 |
General Comments 0
You need to be logged in to leave comments.
Login now