From 1328b5e7da3f908be350ff101a0ec95140a74bca Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 6 Jul 2024 06:46:38 +0300 Subject: [PATCH 1/3] gh-121245: Refactor site.register_readline() also initialize CAN_USE_PYREPL at import from _pyrepl.main --- Lib/_pyrepl/main.py | 39 +++++++++---------- Lib/site.py | 23 +++++------ ...-07-13-06-23-24.gh-issue-121245.RfOgf4.rst | 3 ++ 3 files changed, 32 insertions(+), 33 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst diff --git a/Lib/_pyrepl/main.py b/Lib/_pyrepl/main.py index 041a4009f42ed8..aaa0763cc03b0b 100644 --- a/Lib/_pyrepl/main.py +++ b/Lib/_pyrepl/main.py @@ -7,10 +7,26 @@ else: CAN_USE_PYREPL = sys.getwindowsversion().build >= 10586 # Windows 10 TH2 +FAIL_MSG = "" +try: + import errno + if not os.isatty(sys.stdin.fileno()): + raise OSError(errno.ENOTTY, "tty required", "stdin") + from .simple_interact import check + if err := check(): + raise RuntimeError(err) +except Exception as e: + FAIL_MSG = f"warning: can't use pyrepl: {e}" + CAN_USE_PYREPL = False + def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): - global CAN_USE_PYREPL + global CAN_USE_PYREPL, FAIL_MSG if not CAN_USE_PYREPL: + if not os.environ.get('PYTHON_BASIC_REPL', None): + from .trace import trace + trace(FAIL_MSG) + print(FAIL_MSG, file=sys.stderr) return sys._baserepl() if mainmodule: @@ -34,22 +50,5 @@ 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()): - raise OSError(errno.ENOTTY, "tty required", "stdin") - from .simple_interact import check - if err := check(): - raise RuntimeError(err) - from .simple_interact import run_multiline_interactive_console - run_interactive = run_multiline_interactive_console - 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: - return sys._baserepl() - run_interactive(namespace) + from .simple_interact import run_multiline_interactive_console + run_multiline_interactive_console(namespace) diff --git a/Lib/site.py b/Lib/site.py index daa56e158949db..b54e9f22f5cad8 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -509,6 +509,10 @@ def register_readline(): pass if readline.get_current_history_length() == 0: + try: + from _pyrepl.main import CAN_USE_PYREPL + except ImportError: + CAN_USE_PYREPL = False # If no history was loaded, default to .python_history, # or PYTHON_HISTORY. # The guard is necessary to avoid doubling history size at @@ -516,25 +520,18 @@ def register_readline(): # through a PYTHONSTARTUP hook, see: # http://bugs.python.org/issue5845#msg198636 history = gethistoryfile() + if os.getenv("PYTHON_BASIC_REPL") or not CAN_USE_PYREPL: + my_readline = readline + else: + my_readline = _pyrepl.readline try: - if os.getenv("PYTHON_BASIC_REPL"): - readline.read_history_file(history) - else: - _pyrepl.readline.read_history_file(history) + my_readline.read_history_file(history) except (OSError,* _pyrepl.unix_console._error): pass def write_history(): try: - from _pyrepl.main import CAN_USE_PYREPL - except ImportError: - CAN_USE_PYREPL = False - - try: - if os.getenv("PYTHON_BASIC_REPL") or not CAN_USE_PYREPL: - readline.write_history_file(history) - else: - _pyrepl.readline.write_history_file(history) + my_readline.write_history_file(history) except (FileNotFoundError, PermissionError): # home directory does not exist or is not writable # https://bugs.python.org/issue19891 diff --git a/Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst b/Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst new file mode 100644 index 00000000000000..1758f587157f36 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst @@ -0,0 +1,3 @@ +Simplify handling of the history file in ``site.register_readline()`` +helper. The ``CAN_USE_PYREPL`` variable now will be initialized, when +imported. Patch by Sergey B Kirpichev. From aadf263fa6c81d1a0c44923a4a26053c587f45d6 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 13 Jul 2024 17:42:34 +0300 Subject: [PATCH 2/3] address review: apply suggestions --- Lib/_pyrepl/main.py | 1 - Lib/site.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/_pyrepl/main.py b/Lib/_pyrepl/main.py index aaa0763cc03b0b..0bb9ed0045df92 100644 --- a/Lib/_pyrepl/main.py +++ b/Lib/_pyrepl/main.py @@ -21,7 +21,6 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): - global CAN_USE_PYREPL, FAIL_MSG if not CAN_USE_PYREPL: if not os.environ.get('PYTHON_BASIC_REPL', None): from .trace import trace diff --git a/Lib/site.py b/Lib/site.py index b54e9f22f5cad8..796f8c8f1c1439 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -521,17 +521,17 @@ def register_readline(): # http://bugs.python.org/issue5845#msg198636 history = gethistoryfile() if os.getenv("PYTHON_BASIC_REPL") or not CAN_USE_PYREPL: - my_readline = readline + readline_module = readline else: - my_readline = _pyrepl.readline + readline_module = _pyrepl.readline try: - my_readline.read_history_file(history) + readline_module.read_history_file(history) except (OSError,* _pyrepl.unix_console._error): pass def write_history(): try: - my_readline.write_history_file(history) + readline_module.write_history_file(history) except (FileNotFoundError, PermissionError): # home directory does not exist or is not writable # https://bugs.python.org/issue19891 From a623107acc51297691aae52936935eb77a34a0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 15 Jul 2024 21:31:21 +0200 Subject: [PATCH 3/3] nitpicks and clarifications --- Lib/_pyrepl/main.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Lib/_pyrepl/main.py b/Lib/_pyrepl/main.py index 0bb9ed0045df92..946bf339220865 100644 --- a/Lib/_pyrepl/main.py +++ b/Lib/_pyrepl/main.py @@ -1,31 +1,32 @@ +import errno import os import sys -CAN_USE_PYREPL: bool -if sys.platform != "win32": - CAN_USE_PYREPL = True -else: - CAN_USE_PYREPL = sys.getwindowsversion().build >= 10586 # Windows 10 TH2 -FAIL_MSG = "" +CAN_USE_PYREPL: bool +FAIL_REASON: str try: - import errno + if sys.platform == "win32" and sys.getwindowsversion().build < 10586: + raise RuntimeError("Windows 10 TH2 or later required") if not os.isatty(sys.stdin.fileno()): raise OSError(errno.ENOTTY, "tty required", "stdin") from .simple_interact import check if err := check(): raise RuntimeError(err) except Exception as e: - FAIL_MSG = f"warning: can't use pyrepl: {e}" CAN_USE_PYREPL = False + FAIL_REASON = f"warning: can't use pyrepl: {e}" +else: + CAN_USE_PYREPL = True + FAIL_REASON = "" def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): if not CAN_USE_PYREPL: - if not os.environ.get('PYTHON_BASIC_REPL', None): + if not os.environ.get('PYTHON_BASIC_REPL', None) and FAIL_REASON: from .trace import trace - trace(FAIL_MSG) - print(FAIL_MSG, file=sys.stderr) + trace(FAIL_REASON) + print(FAIL_REASON, file=sys.stderr) return sys._baserepl() if mainmodule: @@ -35,6 +36,7 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): namespace = __main__.__dict__ namespace.pop("__pyrepl_interactive_console", None) + # sys._baserepl() above does this internally, we do it here startup_path = os.getenv("PYTHONSTARTUP") if pythonstartup and startup_path: import tokenize