Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
faa22f4
Handle `PYTHONSTARTUP` script exceptions
johnslavik Oct 18, 2025
5b3ad2c
Add blurb
johnslavik Oct 18, 2025
00edac4
Use `console.showtraceback()` instead of `sys.excepthook()`
johnslavik Oct 18, 2025
e396622
Properly run asyncio REPL in REPL tests
johnslavik Oct 18, 2025
4079074
Move comment to a better place
johnslavik Oct 18, 2025
0440d0e
Add tests
johnslavik Oct 23, 2025
af6f657
Merge branch 'properly-run-asyncio-repl-in-repl-tests' into asyncio-r…
johnslavik Oct 23, 2025
848638d
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Oct 24, 2025
d158dbf
Improve test structure
johnslavik Oct 27, 2025
9355da7
Use `SHORT_TIMEOUT`
johnslavik Oct 27, 2025
3dc4cac
Revert "Use `SHORT_TIMEOUT`"
johnslavik Oct 27, 2025
c786584
Force no colorization
johnslavik Oct 27, 2025
b76db67
Linecache doesn't matter and shouldn't break tests
johnslavik Oct 28, 2025
cad1748
Don't rely on line numbering on Windows...
johnslavik Oct 29, 2025
d114ed5
Different names
johnslavik Oct 29, 2025
e6e10ad
Idiomatize and simplify
johnslavik Oct 29, 2025
ac6cd83
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Oct 30, 2025
149740a
Purifying `sys.path` is implied by `-P`
johnslavik Oct 30, 2025
bffac1c
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Nov 7, 2025
a4c307e
Separate tests for regular and asyncio REPL
johnslavik Nov 8, 2025
a774da5
Remove duplicate assertion
johnslavik Nov 8, 2025
b3ed3d4
Document `new_startup_env`
johnslavik Nov 8, 2025
df6dfd8
Fix `new_startup_env` docs
johnslavik Nov 8, 2025
b004839
More meaningful line breaks
johnslavik Nov 8, 2025
ce03cce
Better variables
johnslavik Nov 8, 2025
9e92510
Use default histfile
johnslavik Nov 8, 2025
0a50a50
Fix newline
johnslavik Nov 8, 2025
f8b8d53
Use `TestCase.enterContext`
johnslavik Nov 8, 2025
5701fef
Remove lines with ps1
johnslavik Nov 8, 2025
393aaad
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Dec 16, 2025
875fd2a
Employ `asyncio.Runner` in the asyncio REPL
johnslavik Dec 16, 2025
4377d82
Revert "Employ `asyncio.Runner` in the asyncio REPL"
johnslavik Dec 16, 2025
c4e488e
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Dec 18, 2025
b9ffea7
Add a todo for future
johnslavik Dec 20, 2025
ab799e6
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Jan 3, 2026
2f8f99b
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Jan 4, 2026
6020996
Rename the decorator
johnslavik Jan 4, 2026
125efa6
Colorize the news entry
johnslavik Jan 4, 2026
cc624d1
Simplify `new_pythonstartup_env`
johnslavik Jan 4, 2026
812d22f
Simplify tests by a gazillion procent 🚀🚀🚀
johnslavik Jan 4, 2026
6749b83
Simplify the tests further 🚀
johnslavik Jan 4, 2026
e76426d
And even further
johnslavik Jan 4, 2026
376c7a4
Rephrase the news entry
johnslavik Jan 4, 2026
8888083
Merge branch 'main' into asyncio-repl-handle-python-startup
johnslavik Apr 1, 2026
a5e4ff0
Simplify test
johnslavik Apr 1, 2026
0d246a5
Formatting
johnslavik Apr 1, 2026
e19437b
Remove coverage for regular REPL
johnslavik Apr 1, 2026
57af54d
Shorten news entry
johnslavik Apr 1, 2026
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
8 changes: 7 additions & 1 deletion Lib/asyncio/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ def run(self):
import tokenize
with tokenize.open(startup_path) as f:
startup_code = compile(f.read(), startup_path, "exec")
exec(startup_code, console.locals)
try:
exec(startup_code, console.locals)
# TODO: Revisit in GH-143023
except SystemExit:
raise
except BaseException:
console.showtraceback()

ps1 = getattr(sys, "ps1", ">>> ")
if CAN_USE_PYREPL:
Expand Down
38 changes: 36 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 new_pythonstartup_env(*, code: 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(code)
yield {
"PYTHONSTARTUP": filename,
"PYTHON_HISTORY": os.path.join(tmpdir, histfile)
}
Comment on lines +71 to +81
Copy link
Copy Markdown
Member Author

@johnslavik johnslavik Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be useful in #143023. I can inline it in test_pythonstartup_failure until then if we want to increase locality and not overdo idioms prematurely.



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 @@ -392,6 +404,7 @@ def f():
self.assertEqual(traceback_lines, expected_lines)


@support.force_not_colorized_test_class
Copy link
Copy Markdown
Member Author

@johnslavik johnslavik Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is needed, but I think it's OK to keep it as is.

class TestAsyncioREPL(unittest.TestCase):
def test_multiple_statements_fail_early(self):
user_input = "1 / 0; print(f'afterwards: {1+1}')"
Expand Down Expand Up @@ -449,6 +462,27 @@ def test_quiet_mode(self):
self.assertEqual(p.returncode, 0)
self.assertEqual(output[:3], ">>>")

def test_pythonstartup_failure(self):
startup_code = "1/0\n"
startup_env = self.enterContext(
new_pythonstartup_env(code=startup_code, histfile=".asyncio_history"))

p = spawn_repl(
"-qm", "asyncio",
env=os.environ | startup_env,
isolated=False,
custom=True)
p.stdin.write("print('executed user code anyway')")
output = kill_python(p)
expected = dedent(f"""\
File "{startup_env['PYTHONSTARTUP']}", line 1, in <module>
1/0
~^~
ZeroDivisionError: division by zero
""")
self.assertIn(expected, output)
self.assertIn("executed user code anyway", 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