Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Lib/asyncio/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,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:
Expand Down
43 changes: 41 additions & 2 deletions Lib/test/test_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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): ...
""")
Expand Down Expand Up @@ -442,6 +454,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()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The :mod:`asyncio` REPL now handles exceptions when executing :envvar:`PYTHONSTARTUP` scripts.
Patch by Bartosz Sławecki.
Loading