[3.13] gh-82378 fix sys.tracebacklimit in pyrepl (GH-123062) by cfbolz · Pull Request #123252 · python/cpython · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Lib/_pyrepl/console.py
20 changes: 11 additions & 9 deletions Lib/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,32 +107,30 @@ def showsyntaxerror(self, filename=None, **kwargs):
The output is written by self.write(), below.

"""
colorize = kwargs.pop('colorize', False)
try:
typ, value, tb = sys.exc_info()
if filename and issubclass(typ, SyntaxError):
value.filename = filename
source = kwargs.pop('source', "")
self._showtraceback(typ, value, None, colorize, source)
self._showtraceback(typ, value, None, source)
finally:
typ = value = tb = None

def showtraceback(self, **kwargs):
def showtraceback(self):
"""Display the exception that just occurred.

We remove the first stack item because it is our own code.

The output is written by self.write(), below.

"""
colorize = kwargs.pop('colorize', False)
try:
typ, value, tb = sys.exc_info()
self._showtraceback(typ, value, tb.tb_next, colorize, '')
self._showtraceback(typ, value, tb.tb_next, '')
finally:
typ = value = tb = None

def _showtraceback(self, typ, value, tb, colorize, source):
def _showtraceback(self, typ, value, tb, source):
sys.last_type = typ
sys.last_traceback = tb
value = value.with_traceback(tb)
Expand All @@ -143,9 +141,7 @@ def _showtraceback(self, typ, value, tb, colorize, source):
value.text = lines[value.lineno - 1]
sys.last_exc = sys.last_value = value = value.with_traceback(tb)
if sys.excepthook is sys.__excepthook__:
lines = traceback.format_exception(typ, value, tb,
colorize=colorize)
self.write(''.join(lines))
self._excepthook(typ, value, tb)
else:
# If someone has set sys.excepthook, we let that take precedence
# over self.write
Expand All @@ -162,6 +158,12 @@ def _showtraceback(self, typ, value, tb, colorize, source):
print('Original exception was:', file=sys.stderr)
sys.__excepthook__(typ, value, tb)

def _excepthook(self, typ, value, tb):
# This method is being overwritten in
# _pyrepl.console.InteractiveColoredConsole
lines = traceback.format_exception(typ, value, tb)
self.write(''.join(lines))

def write(self, data):
"""Write a string.

Expand Down
34 changes: 33 additions & 1 deletion Lib/test/test_pyrepl/test_pyrepl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ def test_dumb_terminal_exits_cleanly(self):
env.update({"TERM": "dumb"})
output, exit_code = self.run_repl("exit()\n", env=env)
self.assertEqual(exit_code, 0)
self.assertIn("warning: can\'t use pyrepl", output)
self.assertIn("warning: can't use pyrepl", output)
self.assertNotIn("Exception", output)
self.assertNotIn("Traceback", output)

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

@force_not_colorized
def test_proper_tracebacklimit(self):
env = os.environ.copy()
for set_tracebacklimit in [True, False]:
commands = ("import sys\n" +
("sys.tracebacklimit = 1\n" if set_tracebacklimit else "") +
"def x1(): 1/0\n\n"
"def x2(): x1()\n\n"
"def x3(): x2()\n\n"
"x3()\n"
"exit()\n")

for basic_repl in [True, False]:
if basic_repl:
env["PYTHON_BASIC_REPL"] = "1"
else:
env.pop("PYTHON_BASIC_REPL", None)
with self.subTest(set_tracebacklimit=set_tracebacklimit,
basic_repl=basic_repl):
output, exit_code = self.run_repl(commands, env=env)
if "can't use pyrepl" in output:
self.skipTest("pyrepl not available")
self.assertIn("in x1", output)
if set_tracebacklimit:
self.assertNotIn("in x2", output)
self.assertNotIn("in x3", output)
self.assertNotIn("in <module>", output)
else:
self.assertIn("in x2", output)
self.assertIn("in x3", output)
self.assertIn("in <module>", output)

def run_repl(
self,
repl_input: str | list[str],
Expand Down