diff --git a/Lib/_pyrepl/__main__.py b/Lib/_pyrepl/__main__.py index c598019e7cd4ad..86673a74af7dbf 100644 --- a/Lib/_pyrepl/__main__.py +++ b/Lib/_pyrepl/__main__.py @@ -1,12 +1,10 @@ import os import sys -CAN_USE_PYREPL = sys.platform != "win32" - def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): - global CAN_USE_PYREPL - if not CAN_USE_PYREPL: + from . import env + if not env.IS_PYREPL_SUPPORTED_PLATFORM: return sys._baserepl() startup_path = os.getenv("PYTHONSTARTUP") @@ -23,7 +21,6 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): if not hasattr(sys, "ps2"): sys.ps2 = "... " - run_interactive = None try: import errno if not os.isatty(sys.stdin.fileno()): @@ -32,16 +29,15 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): if err := check(): raise RuntimeError(err) from .simple_interact import run_multiline_interactive_console - run_interactive = run_multiline_interactive_console + return run_multiline_interactive_console(mainmodule) except Exception as e: from .trace import trace msg = f"warning: can't use pyrepl: {e}" trace(msg) print(msg, file=sys.stderr) - CAN_USE_PYREPL = False - if run_interactive is None: + env.CAN_USE_PYREPL = False return sys._baserepl() - return run_interactive(mainmodule) + if __name__ == "__main__": interactive_console() diff --git a/Lib/_pyrepl/env.py b/Lib/_pyrepl/env.py new file mode 100644 index 00000000000000..a61477e8e701ce --- /dev/null +++ b/Lib/_pyrepl/env.py @@ -0,0 +1,6 @@ +import sys + +IS_PYREPL_SUPPORTED_PLATFORM = sys.platform != "win32" + +# Note: This will be updated on REPL startup based on additional checks. +CAN_USE_PYREPL = IS_PYREPL_SUPPORTED_PLATFORM diff --git a/Lib/site.py b/Lib/site.py index 4ba078388a37b8..40861ac598300a 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -523,7 +523,7 @@ def register_readline(): pass def write_history(): - from _pyrepl.__main__ import CAN_USE_PYREPL + from _pyrepl.env import CAN_USE_PYREPL try: if os.getenv("PYTHON_BASIC_REPL") or not CAN_USE_PYREPL: readline.write_history_file(history) diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 340178366fc13a..c2e26183d35eea 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -34,8 +34,9 @@ def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): # Set TERM=vt100, for the rationale see the comments in spawn_python() of # test.support.script_helper. - env = kw.setdefault('env', dict(os.environ)) - env['TERM'] = 'vt100' + if "env" not in kw: + env = kw.setdefault('env', dict(os.environ)) + env['TERM'] = 'vt100' return subprocess.Popen(cmd_line, executable=sys.executable, text=True, @@ -198,6 +199,15 @@ def bar(x): def test_asyncio_repl_is_ok(self): assert_python_ok("-m", "asyncio") + def test_repl_with_dumb_term_exits_cleanly(self): + env = dict(os.environ) + env.update({"TERM": "dumb"}) + p = spawn_repl(env=env) + p.stdin.write("quit()\n") + output = kill_python(p) + self.assertEqual(p.returncode, 0) + self.assertNotIn("Exception", output) + self.assertNotIn("Traceback", output) class TestInteractiveModeSyntaxErrors(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2024-05-21-13-06-27.gh-issue-119102.E1k90T.rst b/Misc/NEWS.d/next/Library/2024-05-21-13-06-27.gh-issue-119102.E1k90T.rst new file mode 100644 index 00000000000000..83885ecaf6f67b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-21-13-06-27.gh-issue-119102.E1k90T.rst @@ -0,0 +1 @@ +Fix error being thrown on quit() in REPL when TERM is set to dumb