diff options
| author | CF Bolz-Tereick <cfbolz@gmx.de> | 2024-08-23 11:59:08 (GMT) |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-23 11:59:08 (GMT) |
| commit | 0955db1bd80edf8e20788b95dcfe8580aa0ade19 (patch) | |
| tree | 485812e0a0656f1b9d7998e46f052761c0e75147 | |
| parent | 95b4f9c9ad3d7a13442a6874bbcf3683d17723dc (diff) | |
| download | cpython-0955db1bd80edf8e20788b95dcfe8580aa0ade19.zip cpython-0955db1bd80edf8e20788b95dcfe8580aa0ade19.tar.gz cpython-0955db1bd80edf8e20788b95dcfe8580aa0ade19.tar.bz2 | |
[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 63603bca35798c166e1b8e0be76aef69217f8b1b)
| -rw-r--r-- | Lib/_pyrepl/console.py | 9 | ||||
| -rw-r--r-- | Lib/code.py | 20 | ||||
| -rw-r--r-- | Lib/test/test_pyrepl/test_pyrepl.py | 34 | ||||
| -rw-r--r-- | Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst | 2 |
4 files changed, 53 insertions, 12 deletions
diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py index f04a1ba..3e72a56 100644 --- a/Lib/_pyrepl/console.py +++ b/Lib/_pyrepl/console.py @@ -164,8 +164,13 @@ class InteractiveColoredConsole(code.InteractiveConsole): def showsyntaxerror(self, filename=None, **kwargs): super().showsyntaxerror(filename=filename, **kwargs) - def showtraceback(self): - super().showtraceback(colorize=self.can_colorize) + def _excepthook(self, typ, value, tb): + 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"): try: diff --git a/Lib/code.py b/Lib/code.py index 25f5b6a..a70d8cc 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -107,17 +107,16 @@ class InteractiveInterpreter: 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. @@ -125,14 +124,13 @@ class InteractiveInterpreter: 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) @@ -143,9 +141,7 @@ class InteractiveInterpreter: 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 @@ -162,6 +158,12 @@ class InteractiveInterpreter: 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. diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 9944cd0..b03cf13 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -1020,7 +1020,7 @@ class TestMain(TestCase): 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) @@ -1114,6 +1114,38 @@ class TestMain(TestCase): 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], diff --git a/Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst b/Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst new file mode 100644 index 0000000..8af016e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst @@ -0,0 +1,2 @@ +Make sure that the new :term:`REPL` interprets :data:`sys.tracebacklimit` in +the same way that the classic REPL did. |
