https://github.com/python/cpython/commit/63603bca35798c166e1b8e0be76aef69217f8b1b
commit: 63603bca35798c166e1b8e0be76aef69217f8b1b
branch: main
author: CF Bolz-Tereick <cfb...@gmx.de>
committer: pablogsal <pablog...@gmail.com>
date: 2024-08-18T13:28:23+02:00
summary:

gh-82378 fix sys.tracebacklimit in pyrepl, approach 2 (#123062)

Make sure that pyrepl uses the same logic for sys.tracebacklimit as both
the basic repl and the standard sys.excepthook

files:
A Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst
M Lib/_pyrepl/console.py
M Lib/code.py
M Lib/test/test_pyrepl/test_pyrepl.py

diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py
index a8d3f520340dcf..2b6c6beab7b304 100644
--- a/Lib/_pyrepl/console.py
+++ b/Lib/_pyrepl/console.py
@@ -161,11 +161,13 @@ def __init__(
         super().__init__(locals=locals, filename=filename, 
local_exit=local_exit)  # type: ignore[call-arg]
         self.can_colorize = _colorize.can_colorize()
 
-    def showsyntaxerror(self, filename=None):
-        super().showsyntaxerror(colorize=self.can_colorize)
-
-    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 a1fd389b5a1015..6860b61a48df3f 100644
--- a/Lib/code.py
+++ b/Lib/code.py
@@ -94,7 +94,7 @@ def runcode(self, code):
         except:
             self.showtraceback()
 
-    def showsyntaxerror(self, filename=None, **kwargs):
+    def showsyntaxerror(self, filename=None):
         """Display the syntax error that just occurred.
 
         This doesn't display a stack trace because there isn't one.
@@ -106,7 +106,6 @@ 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 typ is SyntaxError:
@@ -119,11 +118,11 @@ def showsyntaxerror(self, filename=None, **kwargs):
                 else:
                     # Stuff in the right filename
                     value = SyntaxError(msg, (filename, lineno, offset, line))
-            self._showtraceback(typ, value, None, colorize)
+            self._showtraceback(typ, value, None)
         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.
@@ -131,21 +130,18 @@ def showtraceback(self, **kwargs):
         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):
+    def _showtraceback(self, typ, value, tb):
         sys.last_type = typ
         sys.last_traceback = tb
         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 @@ def _showtraceback(self, typ, value, tb, colorize):
                 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 d5eafc5eb58cac..e11ec74aa14058 100644
--- a/Lib/test/test_pyrepl/test_pyrepl.py
+++ b/Lib/test/test_pyrepl/test_pyrepl.py
@@ -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)
 
@@ -1100,6 +1100,38 @@ def test_not_wiping_history_file(self):
         self.assertIn("spam", output)
         self.assertNotEqual(pathlib.Path(hfile.name).stat().st_size, 0)
 
+    @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 00000000000000..8af016e7c82fcb
--- /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.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to