mirror of https://github.com/python/cpython
[3.13] gh-82378 fix sys.tracebacklimit in pyrepl, approach 2 (GH-123062) (#123252)
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 63603bca35
)
This commit is contained in:
parent
95b4f9c9ad
commit
0955db1bd8
|
@ -164,8 +164,13 @@ class InteractiveColoredConsole(code.InteractiveConsole):
|
||||||
def showsyntaxerror(self, filename=None, **kwargs):
|
def showsyntaxerror(self, filename=None, **kwargs):
|
||||||
super().showsyntaxerror(filename=filename, **kwargs)
|
super().showsyntaxerror(filename=filename, **kwargs)
|
||||||
|
|
||||||
def showtraceback(self):
|
def _excepthook(self, typ, value, tb):
|
||||||
super().showtraceback(colorize=self.can_colorize)
|
import traceback
|
||||||
|
lines = traceback.format_exception(
|
||||||
|
typ, value, tb,
|
||||||
|
colorize=self.can_colorize,
|
||||||
|
limit=traceback.BUILTIN_EXCEPTION_LIMIT)
|
||||||
|
self.write(''.join(lines))
|
||||||
|
|
||||||
def runsource(self, source, filename="<input>", symbol="single"):
|
def runsource(self, source, filename="<input>", symbol="single"):
|
||||||
try:
|
try:
|
||||||
|
|
20
Lib/code.py
20
Lib/code.py
|
@ -107,17 +107,16 @@ class InteractiveInterpreter:
|
||||||
The output is written by self.write(), below.
|
The output is written by self.write(), below.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
colorize = kwargs.pop('colorize', False)
|
|
||||||
try:
|
try:
|
||||||
typ, value, tb = sys.exc_info()
|
typ, value, tb = sys.exc_info()
|
||||||
if filename and issubclass(typ, SyntaxError):
|
if filename and issubclass(typ, SyntaxError):
|
||||||
value.filename = filename
|
value.filename = filename
|
||||||
source = kwargs.pop('source', "")
|
source = kwargs.pop('source', "")
|
||||||
self._showtraceback(typ, value, None, colorize, source)
|
self._showtraceback(typ, value, None, source)
|
||||||
finally:
|
finally:
|
||||||
typ = value = tb = None
|
typ = value = tb = None
|
||||||
|
|
||||||
def showtraceback(self, **kwargs):
|
def showtraceback(self):
|
||||||
"""Display the exception that just occurred.
|
"""Display the exception that just occurred.
|
||||||
|
|
||||||
We remove the first stack item because it is our own code.
|
We remove the first stack item because it is our own code.
|
||||||
|
@ -125,14 +124,13 @@ class InteractiveInterpreter:
|
||||||
The output is written by self.write(), below.
|
The output is written by self.write(), below.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
colorize = kwargs.pop('colorize', False)
|
|
||||||
try:
|
try:
|
||||||
typ, value, tb = sys.exc_info()
|
typ, value, tb = sys.exc_info()
|
||||||
self._showtraceback(typ, value, tb.tb_next, colorize, '')
|
self._showtraceback(typ, value, tb.tb_next, '')
|
||||||
finally:
|
finally:
|
||||||
typ = value = tb = None
|
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_type = typ
|
||||||
sys.last_traceback = tb
|
sys.last_traceback = tb
|
||||||
value = value.with_traceback(tb)
|
value = value.with_traceback(tb)
|
||||||
|
@ -143,9 +141,7 @@ class InteractiveInterpreter:
|
||||||
value.text = lines[value.lineno - 1]
|
value.text = lines[value.lineno - 1]
|
||||||
sys.last_exc = sys.last_value = value = value.with_traceback(tb)
|
sys.last_exc = sys.last_value = value = value.with_traceback(tb)
|
||||||
if sys.excepthook is sys.__excepthook__:
|
if sys.excepthook is sys.__excepthook__:
|
||||||
lines = traceback.format_exception(typ, value, tb,
|
self._excepthook(typ, value, tb)
|
||||||
colorize=colorize)
|
|
||||||
self.write(''.join(lines))
|
|
||||||
else:
|
else:
|
||||||
# If someone has set sys.excepthook, we let that take precedence
|
# If someone has set sys.excepthook, we let that take precedence
|
||||||
# over self.write
|
# over self.write
|
||||||
|
@ -162,6 +158,12 @@ class InteractiveInterpreter:
|
||||||
print('Original exception was:', file=sys.stderr)
|
print('Original exception was:', file=sys.stderr)
|
||||||
sys.__excepthook__(typ, value, tb)
|
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):
|
def write(self, data):
|
||||||
"""Write a string.
|
"""Write a string.
|
||||||
|
|
||||||
|
|
|
@ -1020,7 +1020,7 @@ class TestMain(TestCase):
|
||||||
env.update({"TERM": "dumb"})
|
env.update({"TERM": "dumb"})
|
||||||
output, exit_code = self.run_repl("exit()\n", env=env)
|
output, exit_code = self.run_repl("exit()\n", env=env)
|
||||||
self.assertEqual(exit_code, 0)
|
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("Exception", output)
|
||||||
self.assertNotIn("Traceback", output)
|
self.assertNotIn("Traceback", output)
|
||||||
|
|
||||||
|
@ -1114,6 +1114,38 @@ class TestMain(TestCase):
|
||||||
self.assertIn("IndentationError: unexpected indent", output)
|
self.assertIn("IndentationError: unexpected indent", output)
|
||||||
self.assertIn("<python-input-0>", 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(
|
def run_repl(
|
||||||
self,
|
self,
|
||||||
repl_input: str | list[str],
|
repl_input: str | list[str],
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Make sure that the new :term:`REPL` interprets :data:`sys.tracebacklimit` in
|
||||||
|
the same way that the classic REPL did.
|
Loading…
Reference in New Issue