gh-140287: Handle PYTHONSTARTUP script exceptions in the asyncio REPL (#140288)

This commit is contained in:
Bartosz Sławecki 2026-04-25 16:24:40 +02:00 committed by GitHub
parent 9dab866f9c
commit 5ea3ae7c97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 6 deletions

View file

@ -101,11 +101,15 @@ def run(self):
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:

View file

@ -5,6 +5,7 @@
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 @@ def make_repl(env):
""") % script
self.assertIn(expected, output)
def test_runsource_show_syntax_error_location(self):
user_input = dedent("""def f(x, x): ...
""")
@ -449,6 +461,33 @@ def test_quiet_mode(self):
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()

View file

@ -0,0 +1,2 @@
The :mod:`asyncio` REPL now handles exceptions when executing :envvar:`PYTHONSTARTUP` scripts.
Patch by Bartosz Sławecki.