##// END OF EJS Templates
Implement more predicates to skip frames in debugger....
Matthias Bussonnier -
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
@@ -281,6 +282,9 b' class Pdb(OldPdb):'
281 282 self.prompt = prompt
282 283 self.skip_hidden = True
283 284
285 # list of predicates we use to skip frames
286 self._predicates = {"tbhide": True, "readonly": True, "ipython_internal": True}
287
284 288 def set_colors(self, scheme):
285 289 """Shorthand access to the color table scheme selector method."""
286 290 self.color_scheme_table.set_active_scheme(scheme)
@@ -292,6 +296,26 b' class Pdb(OldPdb):'
292 296 self.initial_frame = frame
293 297 return super().set_trace(frame)
294 298
299 def _hidden_predicate(self, frame):
300 """
301 Given a frame return whether it it should be hidden or not by IPython.
302 """
303
304 if self._predicates["readonly"]:
305 fname = frame.f_code.co_filename
306 # we need to check for file existence and interactively define
307 # function would otherwise appear as RO.
308 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
309 return True
310
311 if self._predicates["tbhide"]:
312 if frame in (self.curframe, getattr(self, "initial_frame", None)):
313 return False
314 else:
315 return frame.f_locals.get("__tracebackhide__", False)
316
317 return False
318
295 319 def hidden_frames(self, stack):
296 320 """
297 321 Given an index in the stack return whether it should be skipped.
@@ -302,14 +326,9 b' class Pdb(OldPdb):'
302 326 # locals whenever the .f_locals accessor is called, so we
303 327 # avoid calling it here to preserve self.curframe_locals.
304 328 # Futhermore, there is no good reason to hide the current frame.
305 ip_hide = [
306 False
307 if s[0] in (self.curframe, getattr(self, "initial_frame", None))
308 else s[0].f_locals.get("__tracebackhide__", False)
309 for s in stack
310 ]
329 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
311 330 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
312 if ip_start:
331 if ip_start and self._predicates["ipython_internal"]:
313 332 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
314 333 return ip_hide
315 334
@@ -532,15 +551,62 b' class Pdb(OldPdb):'
532 551 except KeyboardInterrupt:
533 552 pass
534 553
554 def do_skip_predicates(self, args):
555 """
556 Turn on/off individual predicates as to whether a frame should be hidden/skip.
557
558 The global option to skip (or not) hidden frames is set with skip_hidden
559
560 To change the value of a predicate
561
562 skip_predicates key [true|false]
563
564 Call without arguments to see the current values.
565
566 """
567 if not args.strip():
568 print("current predicates:")
569 for (p, v) in self._predicates.items():
570 print(" ", p, ":", v)
571 return
572 type_value = args.strip().split(" ")
573 if len(type_value) != 2:
574 print("Usage: skip_predicates <type> <value>")
575 return
576
577 type_, value = type_value
578 if type_ not in self._predicates:
579 print(f"{type_!r} not in {set(self._predicates.keys())}")
580 return
581 if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
582 print(
583 f"{value} invalid use one of ('true', 'yes', '1', 'no', 'false', '0')"
584 )
585 return
586
587 self._predicates[type_] = value.lower() in ("true", "yes", "1")
588 if not any(self._predicates.values()):
589 print(
590 "Warning, all predicates set to False, skip_hidden may not have any effects."
591 )
592
535 593 def do_skip_hidden(self, arg):
536 594 """
537 595 Change whether or not we should skip frames with the
538 596 __tracebackhide__ attribute.
539 597 """
540 if arg.strip().lower() in ("true", "yes"):
598 if not arg.strip():
599 print(
600 f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
601 )
602 elif arg.strip().lower() in ("true", "yes"):
541 603 self.skip_hidden = True
542 604 elif arg.strip().lower() in ("false", "no"):
543 605 self.skip_hidden = False
606 if not any(self._predicates.values()):
607 print(
608 "Warning, all predicates set to False, skip_hidden may not have any effects."
609 )
544 610
545 611 def do_list(self, arg):
546 612 """Print lines of code from the current stack frame
@@ -704,7 +770,7 b' class Pdb(OldPdb):'
704 770 def stop_here(self, frame):
705 771 hidden = False
706 772 if self.skip_hidden:
707 hidden = frame.f_locals.get("__tracebackhide__", False)
773 hidden = self._hidden_predicate(frame)
708 774 if hidden:
709 775 Colors = self.color_scheme_table.active_colors
710 776 ColorsNormal = Colors.Normal
@@ -720,7 +786,7 b' class Pdb(OldPdb):'
720 786 Will skip hidden frames.
721 787 """
722 788 # modified version of upstream that skips
723 # frames with __tracebackide__
789 # frames with __tracebackhide__
724 790 if self.curindex == 0:
725 791 self.error("Oldest frame")
726 792 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