Show More
@@ -89,20 +89,22 b' Inheritance diagram:' | |||
|
89 | 89 | #***************************************************************************** |
|
90 | 90 | |
|
91 | 91 | |
|
92 | import functools | |
|
92 | 93 | import inspect |
|
93 | 94 | import linecache |
|
94 | 95 | import pydoc |
|
95 | 96 | import sys |
|
96 | 97 | import time |
|
97 | 98 | import traceback |
|
99 | import types | |
|
98 | 100 | from types import TracebackType |
|
99 |
from typing import |
|
|
101 | from typing import Any, List, Optional, Tuple | |
|
100 | 102 | |
|
101 | 103 | import stack_data |
|
102 | from stack_data import FrameInfo as SDFrameInfo | |
|
103 | 104 | from pygments.formatters.terminal256 import Terminal256Formatter |
|
104 | 105 | from pygments.styles import get_style_by_name |
|
105 | 106 | |
|
107 | import IPython.utils.colorable as colorable | |
|
106 | 108 | # IPython's own modules |
|
107 | 109 | from IPython import get_ipython |
|
108 | 110 | from IPython.core import debugger |
@@ -113,8 +115,6 b' from IPython.utils import path as util_path' | |||
|
113 | 115 | from IPython.utils import py3compat |
|
114 | 116 | from IPython.utils.terminal import get_terminal_size |
|
115 | 117 | |
|
116 | import IPython.utils.colorable as colorable | |
|
117 | ||
|
118 | 118 | # Globals |
|
119 | 119 | # amount of space to put line numbers before verbose tracebacks |
|
120 | 120 | INDENT_SIZE = 8 |
@@ -135,6 +135,54 b' FAST_THRESHOLD = 10_000' | |||
|
135 | 135 | # (SyntaxErrors have to be treated specially because they have no traceback) |
|
136 | 136 | |
|
137 | 137 | |
|
138 | @functools.lru_cache() | |
|
139 | def count_lines_in_py_file(filename: str) -> int: | |
|
140 | """ | |
|
141 | Given a filename, returns the number of lines in the file | |
|
142 | if it ends with the extension ".py". Otherwise, returns 0. | |
|
143 | """ | |
|
144 | if not filename.endswith(".py"): | |
|
145 | return 0 | |
|
146 | else: | |
|
147 | try: | |
|
148 | with open(filename, "r") as file: | |
|
149 | s = sum(1 for line in file) | |
|
150 | except UnicodeError: | |
|
151 | return 0 | |
|
152 | return s | |
|
153 | ||
|
154 | """ | |
|
155 | Given a frame object, returns the total number of lines in the file | |
|
156 | if the filename ends with the extension ".py". Otherwise, returns 0. | |
|
157 | """ | |
|
158 | ||
|
159 | ||
|
160 | def get_line_number_of_frame(frame: types.FrameType) -> int: | |
|
161 | """ | |
|
162 | Given a frame object, returns the total number of lines in the file | |
|
163 | containing the frame's code object, or the number of lines in the | |
|
164 | frame's source code if the file is not available. | |
|
165 | ||
|
166 | Parameters | |
|
167 | ---------- | |
|
168 | frame : FrameType | |
|
169 | The frame object whose line number is to be determined. | |
|
170 | ||
|
171 | Returns | |
|
172 | ------- | |
|
173 | int | |
|
174 | The total number of lines in the file containing the frame's | |
|
175 | code object, or the number of lines in the frame's source code | |
|
176 | if the file is not available. | |
|
177 | """ | |
|
178 | filename = frame.f_code.co_filename | |
|
179 | if filename is None: | |
|
180 | print("No file....") | |
|
181 | lines, first = inspect.getsourcelines(frame) | |
|
182 | return first + len(lines) | |
|
183 | return count_lines_in_py_file(filename) | |
|
184 | ||
|
185 | ||
|
138 | 186 | def _format_traceback_lines(lines, Colors, has_colors: bool, lvals): |
|
139 | 187 | """ |
|
140 | 188 | Format tracebacks lines with pointing arrow, leading numbers... |
@@ -194,8 +242,8 b' def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_form' | |||
|
194 | 242 | """ |
|
195 | 243 | numbers_width = INDENT_SIZE - 1 |
|
196 | 244 | res = [] |
|
197 | ||
|
198 | 245 | for i, line in enumerate(lines, lnum - index): |
|
246 | # assert isinstance(line, str) | |
|
199 | 247 | line = py3compat.cast_unicode(line) |
|
200 | 248 | |
|
201 | 249 | new_line, err = _line_format(line, "str") |
@@ -396,7 +444,7 b' class TBTools(colorable.Colorable):' | |||
|
396 | 444 | evalue: Optional[BaseException], |
|
397 | 445 | etb: Optional[TracebackType] = None, |
|
398 | 446 | tb_offset: Optional[int] = None, |
|
399 | context=5, | |
|
447 | number_of_lines_of_context: int = 5, | |
|
400 | 448 | ): |
|
401 | 449 | """Return a list of traceback frames. |
|
402 | 450 | |
@@ -497,7 +545,7 b' class ListTB(TBTools):' | |||
|
497 | 545 | |
|
498 | 546 | exception = self.get_parts_of_chained_exception(evalue) |
|
499 | 547 | |
|
500 |
if exception and |
|
|
548 | if exception and (id(exception[1]) not in chained_exc_ids): | |
|
501 | 549 | chained_exception_message = ( |
|
502 | 550 | self.prepare_chained_exception_message(evalue.__cause__)[0] |
|
503 | 551 | if evalue is not None |
@@ -509,8 +557,12 b' class ListTB(TBTools):' | |||
|
509 | 557 | chained_exceptions_tb_offset = 0 |
|
510 | 558 | out_list = ( |
|
511 | 559 | self.structured_traceback( |
|
512 |
etype, |
|
|
513 | chained_exceptions_tb_offset, context) | |
|
560 | etype, | |
|
561 | evalue, | |
|
562 | (etb, chained_exc_ids), # type: ignore | |
|
563 | chained_exceptions_tb_offset, | |
|
564 | context, | |
|
565 | ) | |
|
514 | 566 | + chained_exception_message |
|
515 | 567 | + out_list) |
|
516 | 568 | |
@@ -673,27 +725,41 b' class FrameInfo:' | |||
|
673 | 725 | """ |
|
674 | 726 | |
|
675 | 727 | description: Optional[str] |
|
676 | filename: str | |
|
677 | lineno: int | |
|
728 | filename: Optional[str] | |
|
729 | lineno: Tuple[int] | |
|
730 | # number of context lines to use | |
|
731 | context: Optional[int] | |
|
678 | 732 | |
|
679 | 733 | @classmethod |
|
680 | 734 | def _from_stack_data_FrameInfo(cls, frame_info): |
|
681 | 735 | return cls( |
|
682 | 736 | getattr(frame_info, "description", None), |
|
683 | getattr(frame_info, "filename", None), | |
|
684 | getattr(frame_info, "lineno", None), | |
|
737 | getattr(frame_info, "filename", None), # type: ignore[arg-type] | |
|
738 | getattr(frame_info, "lineno", None), # type: ignore[arg-type] | |
|
685 | 739 | getattr(frame_info, "frame", None), |
|
686 | 740 | getattr(frame_info, "code", None), |
|
687 | 741 | sd=frame_info, |
|
742 | context=None, | |
|
688 | 743 | ) |
|
689 | 744 | |
|
690 | def __init__(self, description, filename, lineno, frame, code, sd=None): | |
|
745 | def __init__( | |
|
746 | self, | |
|
747 | description: Optional[str], | |
|
748 | filename: str, | |
|
749 | lineno: Tuple[int], | |
|
750 | frame, | |
|
751 | code, | |
|
752 | *, | |
|
753 | sd=None, | |
|
754 | context=None, | |
|
755 | ): | |
|
691 | 756 | self.description = description |
|
692 | 757 | self.filename = filename |
|
693 | 758 | self.lineno = lineno |
|
694 | 759 | self.frame = frame |
|
695 | 760 | self.code = code |
|
696 | 761 | self._sd = sd |
|
762 | self.context = context | |
|
697 | 763 | |
|
698 | 764 | # self.lines = [] |
|
699 | 765 | if sd is None: |
@@ -848,7 +914,6 b' class VerboseTB(TBTools):' | |||
|
848 | 914 | |
|
849 | 915 | result = f'{link}{", " if call else ""}{call}\n' |
|
850 | 916 | if frame_info._sd is None: |
|
851 | assert False | |
|
852 | 917 | # fast fallback if file is too long |
|
853 | 918 | tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal) |
|
854 | 919 | link = tpl_link % util_path.compress_user(frame_info.filename) |
@@ -858,13 +923,25 b' class VerboseTB(TBTools):' | |||
|
858 | 923 | ).format2 |
|
859 | 924 | first_line = frame_info.code.co_firstlineno |
|
860 | 925 | current_line = frame_info.lineno[0] |
|
926 | raw_lines = frame_info.raw_lines | |
|
927 | index = current_line - first_line | |
|
928 | ||
|
929 | if index >= frame_info.context: | |
|
930 | start = max(index - frame_info.context, 0) | |
|
931 | stop = index + frame_info.context | |
|
932 | index = frame_info.context | |
|
933 | else: | |
|
934 | start = 0 | |
|
935 | stop = index + frame_info.context | |
|
936 | raw_lines = raw_lines[start:stop] | |
|
937 | ||
|
861 | 938 | return "%s%s" % ( |
|
862 | 939 | level, |
|
863 | 940 | "".join( |
|
864 | 941 | _simple_format_traceback_lines( |
|
865 | 942 | current_line, |
|
866 |
|
|
|
867 |
|
|
|
943 | index, | |
|
944 | raw_lines, | |
|
868 | 945 | Colors, |
|
869 | 946 | lvals, |
|
870 | 947 | _line_format, |
@@ -942,13 +1019,13 b' class VerboseTB(TBTools):' | |||
|
942 | 1019 | # some locals |
|
943 | 1020 | orig_etype = etype |
|
944 | 1021 | try: |
|
945 | etype = etype.__name__ | |
|
1022 | etype = etype.__name__ # type: ignore | |
|
946 | 1023 | except AttributeError: |
|
947 | 1024 | pass |
|
948 | 1025 | |
|
949 | 1026 | tb_offset = self.tb_offset if tb_offset is None else tb_offset |
|
950 | 1027 | assert isinstance(tb_offset, int) |
|
951 | head = self.prepare_header(etype, self.long_header) | |
|
1028 | head = self.prepare_header(str(etype), self.long_header) | |
|
952 | 1029 | records = ( |
|
953 | 1030 | self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else [] |
|
954 | 1031 | ) |
@@ -1018,23 +1095,34 b' class VerboseTB(TBTools):' | |||
|
1018 | 1095 | tbs = [] |
|
1019 | 1096 | while cf is not None: |
|
1020 | 1097 | try: |
|
1021 |
|
|
|
1022 | lines, first = inspect.getsourcelines(etb.tb_frame) | |
|
1098 | mod = inspect.getmodule(cf.tb_frame) | |
|
1099 | if mod is not None: | |
|
1100 | mod_name = mod.__name__ | |
|
1101 | root_name, *_ = mod_name.split(".") | |
|
1102 | if root_name == "IPython": | |
|
1103 | cf = cf.tb_next | |
|
1104 | continue | |
|
1105 | max_len = get_line_number_of_frame(cf.tb_frame) | |
|
1106 | ||
|
1023 | 1107 | except OSError: |
|
1024 |
max_len = |
|
|
1025 | break | |
|
1026 | max_len = max(max_len, first + len(lines)) | |
|
1108 | max_len = 0 | |
|
1109 | max_len = max(max_len, max_len) | |
|
1027 | 1110 | tbs.append(cf) |
|
1028 |
cf = cf |
|
|
1111 | cf = getattr(cf, "tb_next", None) | |
|
1029 | 1112 | |
|
1030 | 1113 | if max_len > FAST_THRESHOLD: |
|
1031 | 1114 | FIs = [] |
|
1032 | 1115 | for tb in tbs: |
|
1033 | frame = tb.tb_frame | |
|
1116 | frame = tb.tb_frame # type: ignore | |
|
1034 | 1117 | lineno = (frame.f_lineno,) |
|
1035 | 1118 | code = frame.f_code |
|
1036 | 1119 | filename = code.co_filename |
|
1037 | FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code)) | |
|
1120 | # TODO: Here we need to use before/after/ | |
|
1121 | FIs.append( | |
|
1122 | FrameInfo( | |
|
1123 | "Raw frame", filename, lineno, frame, code, context=context | |
|
1124 | ) | |
|
1125 | ) | |
|
1038 | 1126 | return FIs |
|
1039 | 1127 | res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:] |
|
1040 | 1128 | res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res] |
@@ -1044,7 +1132,7 b' class VerboseTB(TBTools):' | |||
|
1044 | 1132 | self, |
|
1045 | 1133 | etype: type, |
|
1046 | 1134 | evalue: Optional[BaseException], |
|
1047 | etb: Optional[TracebackType], | |
|
1135 | etb: Optional[TracebackType] = None, | |
|
1048 | 1136 | tb_offset: Optional[int] = None, |
|
1049 | 1137 | number_of_lines_of_context: int = 5, |
|
1050 | 1138 | ): |
@@ -1115,8 +1203,8 b' class VerboseTB(TBTools):' | |||
|
1115 | 1203 | with display_trap: |
|
1116 | 1204 | self.pdb.reset() |
|
1117 | 1205 | # Find the right frame so we don't pop up inside ipython itself |
|
1118 |
if hasattr(self, |
|
|
1119 | etb = self.tb | |
|
1206 | if hasattr(self, "tb") and self.tb is not None: # type: ignore[has-type] | |
|
1207 | etb = self.tb # type: ignore[has-type] | |
|
1120 | 1208 | else: |
|
1121 | 1209 | etb = self.tb = sys.last_traceback |
|
1122 | 1210 | while self.tb is not None and self.tb.tb_next is not None: |
@@ -1291,24 +1379,23 b' class AutoFormattedTB(FormattedTB):' | |||
|
1291 | 1379 | |
|
1292 | 1380 | def structured_traceback( |
|
1293 | 1381 | self, |
|
1294 |
etype |
|
|
1295 | value=None, | |
|
1296 | tb=None, | |
|
1297 | tb_offset=None, | |
|
1298 | number_of_lines_of_context=5, | |
|
1382 | etype: type, | |
|
1383 | evalue: Optional[BaseException], | |
|
1384 | etb: Optional[TracebackType] = None, | |
|
1385 | tb_offset: Optional[int] = None, | |
|
1386 | number_of_lines_of_context: int = 5, | |
|
1299 | 1387 | ): |
|
1300 | etype: type | |
|
1301 | value: BaseException | |
|
1302 | 1388 | # tb: TracebackType or tupleof tb types ? |
|
1303 | 1389 | if etype is None: |
|
1304 | etype, value, tb = sys.exc_info() | |
|
1305 | if isinstance(tb, tuple): | |
|
1390 | etype, evalue, etb = sys.exc_info() | |
|
1391 | if isinstance(etb, tuple): | |
|
1306 | 1392 | # tb is a tuple if this is a chained exception. |
|
1307 | self.tb = tb[0] | |
|
1393 | self.tb = etb[0] | |
|
1308 | 1394 | else: |
|
1309 | self.tb = tb | |
|
1395 | self.tb = etb | |
|
1310 | 1396 | return FormattedTB.structured_traceback( |
|
1311 |
self, etype, value, tb, tb_offset, number_of_lines_of_context |
|
|
1397 | self, etype, evalue, etb, tb_offset, number_of_lines_of_context | |
|
1398 | ) | |
|
1312 | 1399 | |
|
1313 | 1400 | |
|
1314 | 1401 | #--------------------------------------------------------------------------- |
@@ -1366,7 +1453,7 b' def text_repr(value):' | |||
|
1366 | 1453 | """Hopefully pretty robust repr equivalent.""" |
|
1367 | 1454 | # this is pretty horrible but should always return *something* |
|
1368 | 1455 | try: |
|
1369 | return pydoc.text.repr(value) | |
|
1456 | return pydoc.text.repr(value) # type: ignore[call-arg] | |
|
1370 | 1457 | except KeyboardInterrupt: |
|
1371 | 1458 | raise |
|
1372 | 1459 | except: |
@@ -19,7 +19,7 b' exclude = [' | |||
|
19 | 19 | #'IPython/core/interactiveshell.py', |
|
20 | 20 | 'IPython/core/magic.py', |
|
21 | 21 | 'IPython/core/profileapp.py', |
|
22 | 'IPython/core/ultratb.py', | |
|
22 | # 'IPython/core/ultratb.py', | |
|
23 | 23 | 'IPython/lib/deepreload.py', |
|
24 | 24 | 'IPython/lib/pretty.py', |
|
25 | 25 | 'IPython/sphinxext/ipython_directive.py', |
General Comments 0
You need to be logged in to leave comments.
Login now