From cd2d7fbcbc8b39a03e798353b4cfeee8aa50af2a Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:26:36 -0300 Subject: [PATCH 01/10] Support PyREPL history in Windows. --- Lib/_pyrepl/readline.py | 2 +- Lib/site.py | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/_pyrepl/readline.py b/Lib/_pyrepl/readline.py index 3d94f91753587e..3908fdc32f2664 100644 --- a/Lib/_pyrepl/readline.py +++ b/Lib/_pyrepl/readline.py @@ -423,7 +423,7 @@ def read_history_file(self, filename: str = gethistoryfile()) -> None: history = self.get_reader().history with open(os.path.expanduser(filename), 'rb') as f: - lines = [line.decode('utf-8', errors='replace') for line in f.read().split(b'\n')] + lines = [line.decode('utf-8', errors='replace') for line in f.read().splitlines()] buffer = [] for line in lines: # Ignore readline history file header diff --git a/Lib/site.py b/Lib/site.py index cafd3ab70b2cac..c092d7d660e8a7 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -493,16 +493,22 @@ def register_readline(): """ import atexit try: - import readline + try: + import readline + import _pyrepl.unix_console + console_error = _pyrepl.unix_console._error + except ImportError: + import _pyrepl.readline as readline + import _pyrepl.windows_console + console_error = [_pyrepl.windows_console._error] import rlcompleter # noqa: F401 import _pyrepl.readline - import _pyrepl.unix_console except ImportError: return # Reading the initialization (config) file may not be enough to set a # completion key, so we set one first and then read the file. - if readline.backend == 'editline': + if hasattr(readline, "backend") and readline.backend == 'editline': readline.parse_and_bind('bind ^I rl_complete') else: readline.parse_and_bind('tab: complete') @@ -531,7 +537,7 @@ def register_readline(): readline_module = _pyrepl.readline try: readline_module.read_history_file(history) - except (OSError,* _pyrepl.unix_console._error): + except (OSError, * console_error): pass def write_history(): From aa3b826e59c341b87d39cf0a65c3bae857d1ae92 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:45:12 -0300 Subject: [PATCH 02/10] Support multi-line history items in Windows. --- Lib/_pyrepl/readline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/_pyrepl/readline.py b/Lib/_pyrepl/readline.py index 3908fdc32f2664..a77e20dd596665 100644 --- a/Lib/_pyrepl/readline.py +++ b/Lib/_pyrepl/readline.py @@ -423,7 +423,7 @@ def read_history_file(self, filename: str = gethistoryfile()) -> None: history = self.get_reader().history with open(os.path.expanduser(filename), 'rb') as f: - lines = [line.decode('utf-8', errors='replace') for line in f.read().splitlines()] + lines = [line.decode('utf-8', errors='replace') for line in f.read().split(b'\n')] buffer = [] for line in lines: # Ignore readline history file header @@ -442,7 +442,7 @@ def read_history_file(self, filename: str = gethistoryfile()) -> None: def write_history_file(self, filename: str = gethistoryfile()) -> None: maxlength = self.saved_history_length history = self.get_reader().get_trimmed_history(maxlength) - with open(os.path.expanduser(filename), "w", encoding="utf-8") as f: + with open(os.path.expanduser(filename), "w", encoding="utf-8", newline="\n") as f: for entry in history: entry = entry.replace("\n", "\r\n") # multiline history support f.write(entry + "\n") From bb9904b9a33cfc80890e7e05ecf44d1d4f03a2b2 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:58:41 -0300 Subject: [PATCH 03/10] Silence a warning for readline.read_init_file() in Windows. --- Lib/site.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/site.py b/Lib/site.py index c092d7d660e8a7..d99cb2d8e0accd 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -497,10 +497,12 @@ def register_readline(): import readline import _pyrepl.unix_console console_error = _pyrepl.unix_console._error + real_readline = True except ImportError: import _pyrepl.readline as readline import _pyrepl.windows_console console_error = [_pyrepl.windows_console._error] + real_readline = False import rlcompleter # noqa: F401 import _pyrepl.readline except ImportError: @@ -514,7 +516,8 @@ def register_readline(): readline.parse_and_bind('tab: complete') try: - readline.read_init_file() + if real_readline: + readline.read_init_file() except OSError: # An OSError here could have many causes, but the most likely one # is that there's no .inputrc file (or .editrc file in the case of From a1d2336222b7303c4fddda5a13439c98b4575c51 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:04:33 +0000 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-07-25-20-04-31.gh-issue-122273.ud9Vsi.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-20-04-31.gh-issue-122273.ud9Vsi.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-20-04-31.gh-issue-122273.ud9Vsi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-20-04-31.gh-issue-122273.ud9Vsi.rst new file mode 100644 index 00000000000000..f5d7f81aa6e5b3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-20-04-31.gh-issue-122273.ud9Vsi.rst @@ -0,0 +1 @@ +Add support for command history in the new REPL running on Windows. From 1c7589687fdf149652860dde67d6e23d1ba0fa91 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Wed, 9 Oct 2024 09:26:29 -0300 Subject: [PATCH 05/10] Remove duplicated imports. --- Lib/site.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/site.py b/Lib/site.py index 8df1bed4d277aa..fbbe30232ace7e 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -512,8 +512,6 @@ def register_readline(): if PYTHON_BASIC_REPL: CAN_USE_PYREPL = False else: - import _pyrepl.readline - import _pyrepl.unix_console from _pyrepl.main import CAN_USE_PYREPL except ImportError: return From bef3c7cbe4b8a36da8857f6402edf0ac71530558 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Wed, 9 Oct 2024 09:56:40 -0300 Subject: [PATCH 06/10] Fix importing of _pyrepl in non-Windows when CAN_USE_PYREPL is False. --- Lib/site.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Lib/site.py b/Lib/site.py index fbbe30232ace7e..3a6a793019813f 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -497,24 +497,25 @@ def register_readline(): PYTHON_BASIC_REPL = False import atexit - try: + if PYTHON_BASIC_REPL: + CAN_USE_PYREPL = False + else: + from _pyrepl.main import CAN_USE_PYREPL try: - import readline - import _pyrepl.unix_console - console_error = _pyrepl.unix_console._error - real_readline = True + try: + import readline + import _pyrepl.unix_console + console_error = _pyrepl.unix_console._error + real_readline = True + except ImportError: + import _pyrepl.readline as readline + import _pyrepl.windows_console + console_error = [_pyrepl.windows_console._error] + real_readline = False + import rlcompleter # noqa: F401 + except ImportError: - import _pyrepl.readline as readline - import _pyrepl.windows_console - console_error = [_pyrepl.windows_console._error] - real_readline = False - import rlcompleter # noqa: F401 - if PYTHON_BASIC_REPL: - CAN_USE_PYREPL = False - else: - from _pyrepl.main import CAN_USE_PYREPL - except ImportError: - return + return # Reading the initialization (config) file may not be enough to set a # completion key, so we set one first and then read the file. From 0a5699d6a2a163a4b7c5a9fdb035052df0001d21 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:23:41 -0300 Subject: [PATCH 07/10] Refactor import of _pyrepl.readline so test_python_basic_repl passes. --- Lib/site.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Lib/site.py b/Lib/site.py index 3a6a793019813f..eada726f624ba0 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -497,25 +497,27 @@ def register_readline(): PYTHON_BASIC_REPL = False import atexit - if PYTHON_BASIC_REPL: - CAN_USE_PYREPL = False - else: - from _pyrepl.main import CAN_USE_PYREPL + try: try: - try: - import readline + import readline + real_readline = True + except ImportError: + import _pyrepl.readline as readline + real_readline = False + import rlcompleter # noqa: F401 + if PYTHON_BASIC_REPL: + CAN_USE_PYREPL = False + else: + from _pyrepl.main import CAN_USE_PYREPL + if real_readline: import _pyrepl.unix_console console_error = _pyrepl.unix_console._error - real_readline = True - except ImportError: - import _pyrepl.readline as readline + else: import _pyrepl.windows_console console_error = [_pyrepl.windows_console._error] - real_readline = False - import rlcompleter # noqa: F401 - except ImportError: - return + except ImportError: + return # Reading the initialization (config) file may not be enough to set a # completion key, so we set one first and then read the file. From 3ea8c79c04627a27011cea2f2f1477c22ad6d39a Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:39:46 -0300 Subject: [PATCH 08/10] Refactor a test for readline.backend == 'editline', thanks @vstinner Co-authored-by: Victor Stinner --- Lib/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/site.py b/Lib/site.py index eada726f624ba0..9d3352c70e3d06 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -521,7 +521,7 @@ def register_readline(): # Reading the initialization (config) file may not be enough to set a # completion key, so we set one first and then read the file. - if hasattr(readline, "backend") and readline.backend == 'editline': + if getattr(readline, "backend", None) == 'editline': readline.parse_and_bind('bind ^I rl_complete') else: readline.parse_and_bind('tab: complete') From 9ad8e721373bf7b53d2fb9141fd3fc4863a80e3d Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Sat, 12 Oct 2024 11:06:05 -0300 Subject: [PATCH 09/10] Only import _pyrepl if PYTHON_BASIC_REPL isn't set. --- Lib/site.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/site.py b/Lib/site.py index 9d3352c70e3d06..a27373000fa5f2 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -502,12 +502,13 @@ def register_readline(): import readline real_readline = True except ImportError: - import _pyrepl.readline as readline + readline = None real_readline = False import rlcompleter # noqa: F401 if PYTHON_BASIC_REPL: CAN_USE_PYREPL = False else: + import _pyrepl.readline as readline from _pyrepl.main import CAN_USE_PYREPL if real_readline: import _pyrepl.unix_console @@ -521,9 +522,10 @@ def register_readline(): # Reading the initialization (config) file may not be enough to set a # completion key, so we set one first and then read the file. - if getattr(readline, "backend", None) == 'editline': + backend = getattr(readline, "backend", None) + if backend == 'editline': readline.parse_and_bind('bind ^I rl_complete') - else: + elif backend: readline.parse_and_bind('tab: complete') try: @@ -536,7 +538,7 @@ def register_readline(): # want to ignore the exception. pass - if readline.get_current_history_length() == 0: + if readline and readline.get_current_history_length() == 0: # If no history was loaded, default to .python_history, # or PYTHON_HISTORY. # The guard is necessary to avoid doubling history size at @@ -553,13 +555,15 @@ def register_readline(): exceptions = OSError try: - readline_module.read_history_file(history) + if readline: + readline_module.read_history_file(history) except exceptions: pass def write_history(): try: - readline_module.write_history_file(history) + if readline: + readline_module.write_history_file(history) except (FileNotFoundError, PermissionError): # home directory does not exist or is not writable # https://bugs.python.org/issue19891 From 746099ba9215f9aafd9ec5b5c4b4c5906b047497 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Sat, 12 Oct 2024 13:23:48 -0300 Subject: [PATCH 10/10] Only import _pyrepl.readline as readline if real readline wasn't imported. --- Lib/site.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/site.py b/Lib/site.py index d2addf20fbb364..b789fa67d3d937 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -511,7 +511,8 @@ def register_readline(): original_path = sys.path sys.path = [p for p in original_path if p != ''] try: - import _pyrepl.readline as readline + if not readline: + import _pyrepl.readline as readline from _pyrepl.main import CAN_USE_PYREPL if real_readline: import _pyrepl.unix_console