##// END OF EJS Templates
Resurrect fast (non-highlighted) traceback code for long files. (#13947)
Matthias Bussonnier -
r28127:3edbe3bd merge
parent child Browse files
Show More
@@ -3036,7 +3036,6 b' class IPCompleter(Completer):'
3036 3036 skip_matchers: Set[str],
3037 3037 abort_if_offset_changes: bool,
3038 3038 ):
3039
3040 3039 sortable: List[AnyMatcherCompletion] = []
3041 3040 ordered: List[AnyMatcherCompletion] = []
3042 3041 most_recent_fragment = None
@@ -591,7 +591,7 b' class Pdb(OldPdb):'
591 591 """
592 592 if not args.strip():
593 593 print("current predicates:")
594 for (p, v) in self._predicates.items():
594 for p, v in self._predicates.items():
595 595 print(" ", p, ":", v)
596 596 return
597 597 type_value = args.strip().split(" ")
@@ -838,7 +838,6 b' class Pdb(OldPdb):'
838 838 return False
839 839
840 840 def stop_here(self, frame):
841
842 841 if self._is_in_decorator_internal_and_should_skip(frame) is True:
843 842 return False
844 843
@@ -471,7 +471,6 b' def test_decorator_skip_with_breakpoint():'
471 471
472 472 ### we need a filename, so we need to exec the full block with a filename
473 473 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
474
475 474 name = tf.name[:-3].split("/")[-1]
476 475 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
477 476 tf.flush()
@@ -1094,7 +1094,6 b' def test_script_err():'
1094 1094
1095 1095
1096 1096 def test_script_out_err():
1097
1098 1097 ip = get_ipython()
1099 1098 ip.run_cell_magic(
1100 1099 "script",
@@ -193,7 +193,6 b' class TestPylabSwitch(object):'
193 193 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
194 194
195 195 def test_qt(self):
196
197 196 s = self.Shell()
198 197 gui, backend = s.enable_matplotlib(None)
199 198 assert gui == "qt"
@@ -99,6 +99,7 b' from types import TracebackType'
99 99 from typing import Tuple, List, Any, Optional
100 100
101 101 import stack_data
102 from stack_data import FrameInfo as SDFrameInfo
102 103 from pygments.formatters.terminal256 import Terminal256Formatter
103 104 from pygments.styles import get_style_by_name
104 105
@@ -107,6 +108,7 b' from IPython import get_ipython'
107 108 from IPython.core import debugger
108 109 from IPython.core.display_trap import DisplayTrap
109 110 from IPython.core.excolors import exception_colors
111 from IPython.utils import PyColorize
110 112 from IPython.utils import path as util_path
111 113 from IPython.utils import py3compat
112 114 from IPython.utils.terminal import get_terminal_size
@@ -122,6 +124,7 b' INDENT_SIZE = 8'
122 124 # value is used, but having a module global makes this functionality available
123 125 # to users of ultratb who are NOT running inside ipython.
124 126 DEFAULT_SCHEME = 'NoColor'
127 FAST_THRESHOLD = 10_000
125 128
126 129 # ---------------------------------------------------------------------------
127 130 # Code begins
@@ -170,6 +173,55 b' def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):'
170 173 res.append(lvals + '\n')
171 174 return res
172 175
176 def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
177 """
178 Format tracebacks lines with pointing arrow, leading numbers...
179
180 Parameters
181 ==========
182
183 lnum: int
184 number of the target line of code.
185 index: int
186 which line in the list should be highlighted.
187 lines: list[string]
188 Colors:
189 ColorScheme used.
190 lvals: bytes
191 Values of local variables, already colored, to inject just after the error line.
192 _line_format: f (str) -> (str, bool)
193 return (colorized version of str, failure to do so)
194 """
195 numbers_width = INDENT_SIZE - 1
196 res = []
197
198 for i, line in enumerate(lines, lnum - index):
199 line = py3compat.cast_unicode(line)
200
201 new_line, err = _line_format(line, "str")
202 if not err:
203 line = new_line
204
205 if i == lnum:
206 # This is the line with the error
207 pad = numbers_width - len(str(i))
208 num = "%s%s" % (debugger.make_arrow(pad), str(lnum))
209 line = "%s%s%s %s%s" % (
210 Colors.linenoEm,
211 num,
212 Colors.line,
213 line,
214 Colors.Normal,
215 )
216 else:
217 num = "%*s" % (numbers_width, i)
218 line = "%s%s%s %s" % (Colors.lineno, num, Colors.Normal, line)
219
220 res.append(line)
221 if lvals and i == lnum:
222 res.append(lvals + "\n")
223 return res
224
173 225
174 226 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
175 227 """
@@ -283,7 +335,6 b' class TBTools(colorable.Colorable):'
283 335 def get_parts_of_chained_exception(
284 336 self, evalue
285 337 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
286
287 338 chained_evalue = self._get_chained_exception(evalue)
288 339
289 340 if chained_evalue:
@@ -607,6 +658,59 b' class ListTB(TBTools):'
607 658 return u'<unprintable %s object>' % type(value).__name__
608 659
609 660
661 class FrameInfo:
662 """
663 Mirror of stack data's FrameInfo, but so that we can bypass highlighting on
664 really long frames.
665 """
666
667 description: Optional[str]
668 filename: str
669 lineno: int
670
671 @classmethod
672 def _from_stack_data_FrameInfo(cls, frame_info):
673 return cls(
674 getattr(frame_info, "description", None),
675 getattr(frame_info, "filename", None),
676 getattr(frame_info, "lineno", None),
677 getattr(frame_info, "frame", None),
678 getattr(frame_info, "code", None),
679 sd=frame_info,
680 )
681
682 def __init__(self, description, filename, lineno, frame, code, sd=None):
683 self.description = description
684 self.filename = filename
685 self.lineno = lineno
686 self.frame = frame
687 self.code = code
688 self._sd = sd
689
690 # self.lines = []
691 if sd is None:
692 ix = inspect.getsourcelines(frame)
693 self.raw_lines = ix[0]
694
695 @property
696 def variables_in_executing_piece(self):
697 if self._sd:
698 return self._sd.variables_in_executing_piece
699 else:
700 return []
701
702 @property
703 def lines(self):
704 return self._sd.lines
705
706 @property
707 def executing(self):
708 if self._sd:
709 return self._sd.executing
710 else:
711 return None
712
713
610 714 #----------------------------------------------------------------------------
611 715 class VerboseTB(TBTools):
612 716 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
@@ -658,12 +762,13 b' class VerboseTB(TBTools):'
658 762
659 763 self.skip_hidden = True
660 764
661 def format_record(self, frame_info):
765 def format_record(self, frame_info: FrameInfo):
662 766 """Format a single stack frame"""
767 assert isinstance(frame_info, FrameInfo)
663 768 Colors = self.Colors # just a shorthand + quicker name lookup
664 769 ColorsNormal = Colors.Normal # used a lot
665 770
666 if isinstance(frame_info, stack_data.RepeatedFrames):
771 if isinstance(frame_info._sd, stack_data.RepeatedFrames):
667 772 return ' %s[... skipping similar frames: %s]%s\n' % (
668 773 Colors.excName, frame_info.description, ColorsNormal)
669 774
@@ -684,8 +789,10 b' class VerboseTB(TBTools):'
684 789 lineno=frame_info.lineno,
685 790 )
686 791 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
687
792 if frame_info.executing is not None:
688 793 func = frame_info.executing.code_qualname()
794 else:
795 func = "?"
689 796 if func == "<module>":
690 797 call = ""
691 798 else:
@@ -732,8 +839,37 b' class VerboseTB(TBTools):'
732 839 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
733 840
734 841 result = f'{link}{", " if call else ""}{call}\n'
735
736 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
842 if frame_info._sd is None:
843 assert False
844 # fast fallback if file is too long
845 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
846 link = tpl_link % util_path.compress_user(frame_info.filename)
847 level = "%s %s\n" % (link, call)
848 _line_format = PyColorize.Parser(
849 style=self.color_scheme_table.active_scheme_name, parent=self
850 ).format2
851 first_line = frame_info.code.co_firstlineno
852 current_line = frame_info.lineno[0]
853 return "%s%s" % (
854 level,
855 "".join(
856 _simple_format_traceback_lines(
857 current_line,
858 current_line - first_line,
859 frame_info.raw_lines,
860 Colors,
861 lvals,
862 _line_format,
863 )
864 ),
865 )
866 # result += "\n".join(frame_info.raw_lines)
867 else:
868 result += "".join(
869 _format_traceback_lines(
870 frame_info.lines, Colors, self.has_colors, lvals
871 )
872 )
737 873 return result
738 874
739 875 def prepare_header(self, etype, long_version=False):
@@ -802,9 +938,15 b' class VerboseTB(TBTools):'
802 938 frames = []
803 939 skipped = 0
804 940 lastrecord = len(records) - 1
805 for i, r in enumerate(records):
806 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
807 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
941 for i, record in enumerate(records):
942 if (
943 not isinstance(record._sd, stack_data.RepeatedFrames)
944 and self.skip_hidden
945 ):
946 if (
947 record.frame.f_locals.get("__tracebackhide__", 0)
948 and i != lastrecord
949 ):
808 950 skipped += 1
809 951 continue
810 952 if skipped:
@@ -815,7 +957,7 b' class VerboseTB(TBTools):'
815 957 % (Colors.excName, skipped, ColorsNormal)
816 958 )
817 959 skipped = 0
818 frames.append(self.format_record(r))
960 frames.append(self.format_record(record))
819 961 if skipped:
820 962 Colors = self.Colors # just a shorthand + quicker name lookup
821 963 ColorsNormal = Colors.Normal # used a lot
@@ -851,7 +993,30 b' class VerboseTB(TBTools):'
851 993 after=after,
852 994 pygments_formatter=formatter,
853 995 )
854 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
996
997 # let's estimate the amount of code we eill have to parse/highlight.
998 cf = etb
999 max_len = 0
1000 tbs = []
1001 while cf is not None:
1002 source_file = inspect.getsourcefile(etb.tb_frame)
1003 lines, first = inspect.getsourcelines(etb.tb_frame)
1004 max_len = max(max_len, first + len(lines))
1005 tbs.append(cf)
1006 cf = cf.tb_next
1007
1008 if max_len > FAST_THRESHOLD:
1009 FIs = []
1010 for tb in tbs:
1011 frame = tb.tb_frame
1012 lineno = (frame.f_lineno,)
1013 code = frame.f_code
1014 filename = code.co_filename
1015 FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code))
1016 return FIs
1017 res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1018 res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res]
1019 return res
855 1020
856 1021 def structured_traceback(
857 1022 self,
@@ -1102,9 +1267,14 b' class AutoFormattedTB(FormattedTB):'
1102 1267 except KeyboardInterrupt:
1103 1268 print("\nKeyboardInterrupt")
1104 1269
1105 def structured_traceback(self, etype=None, value=None, tb=None,
1106 tb_offset=None, number_of_lines_of_context=5):
1107
1270 def structured_traceback(
1271 self,
1272 etype=None,
1273 value=None,
1274 tb=None,
1275 tb_offset=None,
1276 number_of_lines_of_context=5,
1277 ):
1108 1278 etype: type
1109 1279 value: BaseException
1110 1280 # tb: TracebackType or tupleof tb types ?
@@ -66,7 +66,6 b' class TerminalPdb(Pdb):'
66 66 # setup history only when we start pdb
67 67 if self.shell.debugger_history is None:
68 68 if self.shell.debugger_history_file is not None:
69
70 69 p = Path(self.shell.debugger_history_file).expanduser()
71 70 if not p.exists():
72 71 p.touch()
@@ -626,7 +626,6 b' class IPDoctestModule(pytest.Module):'
626 626 if _is_mocked(obj):
627 627 return
628 628 with _patch_unwrap_mock_aware():
629
630 629 # Type ignored because this is a private function.
631 630 super()._find( # type:ignore[misc]
632 631 tests, obj, name, module, source_lines, globs, seen
General Comments 0
You need to be logged in to leave comments. Login now