Skip to content

Commit b847597

Browse files
committed
[3.13] pythongh-82378 fix sys.tracebacklimit in pyrepl, approach 2 (pythonGH-123062)
Make sure that pyrepl uses the same logic for sys.tracebacklimit as both the basic repl and the standard sys.excepthook (cherry picked from commit 63603bc) Co-authored-by: CF Bolz-Tereick <cfbolz@gmx.de>
1 parent fda8aec commit b847597

File tree

4 files changed

+53
-12
lines changed

4 files changed

+53
-12
lines changed

Lib/_pyrepl/console.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,13 @@ def __init__(
164164
def showsyntaxerror(self, filename=None, **kwargs):
165165
super().showsyntaxerror(filename=filename, **kwargs)
166166

167-
def showtraceback(self):
168-
super().showtraceback(colorize=self.can_colorize)
167+
def _excepthook(self, typ, value, tb):
168+
import traceback
169+
lines = traceback.format_exception(
170+
typ, value, tb,
171+
colorize=self.can_colorize,
172+
limit=traceback.BUILTIN_EXCEPTION_LIMIT)
173+
self.write(''.join(lines))
169174

170175
def runsource(self, source, filename="<input>", symbol="single"):
171176
try:

Lib/code.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -107,32 +107,30 @@ def showsyntaxerror(self, filename=None, **kwargs):
107107
The output is written by self.write(), below.
108108
109109
"""
110-
colorize = kwargs.pop('colorize', False)
111110
try:
112111
typ, value, tb = sys.exc_info()
113112
if filename and issubclass(typ, SyntaxError):
114113
value.filename = filename
115114
source = kwargs.pop('source', "")
116-
self._showtraceback(typ, value, None, colorize, source)
115+
self._showtraceback(typ, value, None, source)
117116
finally:
118117
typ = value = tb = None
119118

120-
def showtraceback(self, **kwargs):
119+
def showtraceback(self):
121120
"""Display the exception that just occurred.
122121
123122
We remove the first stack item because it is our own code.
124123
125124
The output is written by self.write(), below.
126125
127126
"""
128-
colorize = kwargs.pop('colorize', False)
129127
try:
130128
typ, value, tb = sys.exc_info()
131-
self._showtraceback(typ, value, tb.tb_next, colorize, '')
129+
self._showtraceback(typ, value, tb.tb_next, '')
132130
finally:
133131
typ = value = tb = None
134132

135-
def _showtraceback(self, typ, value, tb, colorize, source):
133+
def _showtraceback(self, typ, value, tb, source):
136134
sys.last_type = typ
137135
sys.last_traceback = tb
138136
value = value.with_traceback(tb)
@@ -143,9 +141,7 @@ def _showtraceback(self, typ, value, tb, colorize, source):
143141
value.text = lines[value.lineno - 1]
144142
sys.last_exc = sys.last_value = value = value.with_traceback(tb)
145143
if sys.excepthook is sys.__excepthook__:
146-
lines = traceback.format_exception(typ, value, tb,
147-
colorize=colorize)
148-
self.write(''.join(lines))
144+
self._excepthook(typ, value, tb)
149145
else:
150146
# If someone has set sys.excepthook, we let that take precedence
151147
# over self.write
@@ -162,6 +158,12 @@ def _showtraceback(self, typ, value, tb, colorize, source):
162158
print('Original exception was:', file=sys.stderr)
163159
sys.__excepthook__(typ, value, tb)
164160

161+
def _excepthook(self, typ, value, tb):
162+
# This method is being overwritten in
163+
# _pyrepl.console.InteractiveColoredConsole
164+
lines = traceback.format_exception(typ, value, tb)
165+
self.write(''.join(lines))
166+
165167
def write(self, data):
166168
"""Write a string.
167169

Lib/test/test_pyrepl/test_pyrepl.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ def test_dumb_terminal_exits_cleanly(self):
10201020
env.update({"TERM": "dumb"})
10211021
output, exit_code = self.run_repl("exit()\n", env=env)
10221022
self.assertEqual(exit_code, 0)
1023-
self.assertIn("warning: can\'t use pyrepl", output)
1023+
self.assertIn("warning: can't use pyrepl", output)
10241024
self.assertNotIn("Exception", output)
10251025
self.assertNotIn("Traceback", output)
10261026

@@ -1114,6 +1114,38 @@ def test_correct_filename_in_syntaxerrors(self):
11141114
self.assertIn("IndentationError: unexpected indent", output)
11151115
self.assertIn("<python-input-0>", output)
11161116

1117+
@force_not_colorized
1118+
def test_proper_tracebacklimit(self):
1119+
env = os.environ.copy()
1120+
for set_tracebacklimit in [True, False]:
1121+
commands = ("import sys\n" +
1122+
("sys.tracebacklimit = 1\n" if set_tracebacklimit else "") +
1123+
"def x1(): 1/0\n\n"
1124+
"def x2(): x1()\n\n"
1125+
"def x3(): x2()\n\n"
1126+
"x3()\n"
1127+
"exit()\n")
1128+
1129+
for basic_repl in [True, False]:
1130+
if basic_repl:
1131+
env["PYTHON_BASIC_REPL"] = "1"
1132+
else:
1133+
env.pop("PYTHON_BASIC_REPL", None)
1134+
with self.subTest(set_tracebacklimit=set_tracebacklimit,
1135+
basic_repl=basic_repl):
1136+
output, exit_code = self.run_repl(commands, env=env)
1137+
if "can't use pyrepl" in output:
1138+
self.skipTest("pyrepl not available")
1139+
self.assertIn("in x1", output)
1140+
if set_tracebacklimit:
1141+
self.assertNotIn("in x2", output)
1142+
self.assertNotIn("in x3", output)
1143+
self.assertNotIn("in <module>", output)
1144+
else:
1145+
self.assertIn("in x2", output)
1146+
self.assertIn("in x3", output)
1147+
self.assertIn("in <module>", output)
1148+
11171149
def run_repl(
11181150
self,
11191151
repl_input: str | list[str],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Make sure that the new :term:`REPL` interprets :data:`sys.tracebacklimit` in
2+
the same way that the classic REPL did.

0 commit comments

Comments
 (0)