]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-140287: Handle `PYTHONSTARTUP` script exceptions in the asyncio REPL (#140288)
authorBartosz Sławecki <bartosz@ilikepython.com>
Sat, 25 Apr 2026 14:24:40 +0000 (16:24 +0200)
committerGitHub <noreply@github.com>
Sat, 25 Apr 2026 14:24:40 +0000 (15:24 +0100)
Lib/asyncio/__main__.py
Lib/test/test_repl.py
Misc/NEWS.d/next/Library/2025-10-18-12-13-39.gh-issue-140287.49iU-4.rst [new file with mode: 0644]

index 8ee09b38469d4ccea52425d6f40ffb35bcf74379..37eba9657ac5a884e0c16e55ab55c61d5cf8a4f2 100644 (file)
@@ -101,11 +101,15 @@ class REPLThread(threading.Thread):
 
             if not sys.flags.isolated and (startup_path := os.getenv("PYTHONSTARTUP")):
                 sys.audit("cpython.run_startup", startup_path)
-
-                import tokenize
-                with tokenize.open(startup_path) as f:
-                    startup_code = compile(f.read(), startup_path, "exec")
+                try:
+                    import tokenize
+                    with tokenize.open(startup_path) as f:
+                        startup_code = compile(f.read(), startup_path, "exec")
                     exec(startup_code, console.locals)
+                except SystemExit:
+                    raise
+                except BaseException:
+                    console.showtraceback()
 
             ps1 = getattr(sys, "ps1", ">>> ")
             if CAN_USE_PYREPL:
index 27cd125078ea69c7acdcec2e311888d99f5b9392..850cb66a89ba84a0528602a30b8f05b0b88578b9 100644 (file)
@@ -5,6 +5,7 @@ import select
 import subprocess
 import sys
 import unittest
+from contextlib import contextmanager
 from functools import partial
 from textwrap import dedent
 from test import support
@@ -67,6 +68,19 @@ def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, custom=F
 spawn_asyncio_repl = partial(spawn_repl, "-m", "asyncio", custom=True)
 
 
+@contextmanager
+def temp_pythonstartup(*, source: str, histfile: str = ".pythonhist"):
+    """Create environment variables for a PYTHONSTARTUP script in a temporary directory."""
+    with os_helper.temp_dir() as tmpdir:
+        filename = os.path.join(tmpdir, "pythonstartup.py")
+        with open(filename, "w") as f:
+            f.write(source)
+        yield {
+            "PYTHONSTARTUP": filename,
+            "PYTHON_HISTORY": os.path.join(tmpdir, histfile)
+        }
+
+
 def run_on_interactive_mode(source):
     """Spawn a new Python interpreter, pass the given
     input source code from the stdin and return the
@@ -276,8 +290,6 @@ class TestInteractiveInterpreter(unittest.TestCase):
         """) % script
         self.assertIn(expected, output)
 
-
-
     def test_runsource_show_syntax_error_location(self):
         user_input = dedent("""def f(x, x): ...
                             """)
@@ -449,6 +461,33 @@ class TestAsyncioREPL(unittest.TestCase):
         self.assertEqual(p.returncode, 0)
         self.assertEqual(output[:3], ">>>")
 
+    @support.force_not_colorized
+    @support.subTests(
+        ("startup_code", "expected_error"),
+        [
+            ("some invalid syntax\n", "SyntaxError: invalid syntax"),
+            ("1/0\n", "ZeroDivisionError: division by zero"),
+        ],
+    )
+    def test_pythonstartup_failure(self, startup_code, expected_error):
+        startup_env = self.enterContext(
+            temp_pythonstartup(source=startup_code, histfile=".asyncio_history"))
+
+        p = spawn_repl(
+            "-qm", "asyncio",
+            env=os.environ | startup_env,
+            isolated=False,
+            custom=True)
+        p.stdin.write("print('user code', 'executed')\n")
+        output = kill_python(p)
+        self.assertEqual(p.returncode, 0)
+
+        tb_hint = f'File "{startup_env["PYTHONSTARTUP"]}", line 1'
+        self.assertIn(tb_hint, output)
+        self.assertIn(expected_error, output)
+
+        self.assertIn("user code executed", output)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2025-10-18-12-13-39.gh-issue-140287.49iU-4.rst b/Misc/NEWS.d/next/Library/2025-10-18-12-13-39.gh-issue-140287.49iU-4.rst
new file mode 100644 (file)
index 0000000..0964395
--- /dev/null
@@ -0,0 +1,2 @@
+The :mod:`asyncio` REPL now handles exceptions when executing :envvar:`PYTHONSTARTUP` scripts.
+Patch by Bartosz Sławecki.