From 21bdbc434e309d43df01769a97ded5c5392c4e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 29 May 2020 18:09:13 +0200 Subject: [PATCH 1/5] Run sys.__interactivehook__() on asyncio REPL startup --- Lib/asyncio/__main__.py | 19 ++++ Lib/site.py | 86 +++++++++---------- .../2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst | 3 + 3 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 18bb87a5bc4ffd..516839c66d923a 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -3,6 +3,7 @@ import code import concurrent.futures import inspect +import site import sys import threading import types @@ -109,6 +110,24 @@ def run(self): except ImportError: pass + try: + interactive_hook = sys.__interactivehook__ + except AttributeError(): + pass + else: + if interactive_hook is not None: + interactive_hook() + + if interactive_hook is site.register_readline: + # Fix the completer function to use the interactive console locals + try: + import rlcompleter + except: + pass + else: + completer = rlcompleter.Completer(console.locals) + readline.set_completer(completer.complete) + repl_thread = REPLThread() repl_thread.daemon = True repl_thread.start() diff --git a/Lib/site.py b/Lib/site.py index e981a142088fdf..cff6ae66a541a5 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -403,64 +403,60 @@ def setcopyright(): def sethelper(): builtins.help = _sitebuiltins._Helper() -def enablerlcompleter(): - """Enable default readline configuration on interactive prompts, by - registering a sys.__interactivehook__. +def register_readline(): + """Enable default readline configuration on interactive prompts. If the readline module can be imported, the hook will set the Tab key as completion key and register ~/.python_history as history file. This can be overridden in the sitecustomize or usercustomize module, or in a PYTHONSTARTUP file. """ - def register_readline(): - import atexit - try: - import readline - import rlcompleter - 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. - readline_doc = getattr(readline, '__doc__', '') - if readline_doc is not None and 'libedit' in readline_doc: - readline.parse_and_bind('bind ^I rl_complete') - else: - readline.parse_and_bind('tab: complete') + import atexit + try: + import readline + import rlcompleter + 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. + readline_doc = getattr(readline, '__doc__', '') + if readline_doc is not None and 'libedit' in readline_doc: + readline.parse_and_bind('bind ^I rl_complete') + else: + readline.parse_and_bind('tab: complete') + try: + 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 + # Mac OS X + libedit) in the expected location. In that case, we + # want to ignore the exception. + pass + + if readline.get_current_history_length() == 0: + # If no history was loaded, default to .python_history. + # The guard is necessary to avoid doubling history size at + # each interpreter exit when readline was already configured + # through a PYTHONSTARTUP hook, see: + # http://bugs.python.org/issue5845#msg198636 + history = os.path.join(os.path.expanduser('~'), + '.python_history') try: - readline.read_init_file() + readline.read_history_file(history) 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 - # Mac OS X + libedit) in the expected location. In that case, we - # want to ignore the exception. pass - if readline.get_current_history_length() == 0: - # If no history was loaded, default to .python_history. - # The guard is necessary to avoid doubling history size at - # each interpreter exit when readline was already configured - # through a PYTHONSTARTUP hook, see: - # http://bugs.python.org/issue5845#msg198636 - history = os.path.join(os.path.expanduser('~'), - '.python_history') + def write_history(): try: - readline.read_history_file(history) - except OSError: + readline.write_history_file(history) + except (FileNotFoundError, PermissionError): + # home directory does not exist or is not writable + # https://bugs.python.org/issue19891 pass - def write_history(): - try: - readline.write_history_file(history) - except (FileNotFoundError, PermissionError): - # home directory does not exist or is not writable - # https://bugs.python.org/issue19891 - pass - - atexit.register(write_history) - - sys.__interactivehook__ = register_readline + atexit.register(write_history) def venv(known_paths): global PREFIXES, ENABLE_USER_SITE @@ -578,7 +574,7 @@ def main(): setcopyright() sethelper() if not sys.flags.isolated: - enablerlcompleter() + sys.__interactivehook__ = register_readline execsitecustomize() if ENABLE_USER_SITE: execusercustomize() diff --git a/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst b/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst new file mode 100644 index 00000000000000..9c1da2d34c8184 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst @@ -0,0 +1,3 @@ +The asyncio REPL now run :func:`sys.__interactivehook__` on startup. The +default implementation of :func:`sys.__interactivehook__` gives +auto-completion to the asyncio REPL. Patch contributed by Rémi Lapeyre. From 988f2151d66c552b921f25af84f6d43d72c0c399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Sun, 31 May 2020 20:55:29 +0200 Subject: [PATCH 2/5] Address review comments --- Lib/asyncio/__main__.py | 2 +- .../next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 516839c66d923a..edb54e7570ae46 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -112,7 +112,7 @@ def run(self): try: interactive_hook = sys.__interactivehook__ - except AttributeError(): + except AttributeError: pass else: if interactive_hook is not None: diff --git a/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst b/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst index 9c1da2d34c8184..a8eebf15d83ce3 100644 --- a/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst +++ b/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst @@ -1,3 +1,3 @@ -The asyncio REPL now run :func:`sys.__interactivehook__` on startup. The -default implementation of :func:`sys.__interactivehook__` gives +The asyncio REPL now run :data:`sys.__interactivehook__` on startup. The +default implementation of :data:`sys.__interactivehook__` gives auto-completion to the asyncio REPL. Patch contributed by Rémi Lapeyre. From 5f60485f241b8dfb6dfe2dc73033073f14c8aab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 1 Mar 2024 09:50:38 +0100 Subject: [PATCH 3/5] Improve wording in News Co-authored-by: Itamar Oren --- .../next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst b/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst index a8eebf15d83ce3..27f6a6daa52f53 100644 --- a/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst +++ b/Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst @@ -1,3 +1,3 @@ -The asyncio REPL now run :data:`sys.__interactivehook__` on startup. The -default implementation of :data:`sys.__interactivehook__` gives +The asyncio REPL now runs :data:`sys.__interactivehook__` on startup. The +default implementation of :data:`sys.__interactivehook__` provides auto-completion to the asyncio REPL. Patch contributed by Rémi Lapeyre. From caaa7c705897775a54af8f69359e831f9b3cfd78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 1 Mar 2024 10:10:25 +0100 Subject: [PATCH 4/5] Address code review comments --- Lib/asyncio/__main__.py | 29 +++++++++++++---------------- Lib/site.py | 19 ++++++++++++++----- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index edb54e7570ae46..cbc1d7c93ef76f 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -110,23 +110,20 @@ def run(self): except ImportError: pass - try: - interactive_hook = sys.__interactivehook__ - except AttributeError: - pass - else: - if interactive_hook is not None: - interactive_hook() + interactive_hook = getattr(sys, "__interactivehook__", None) - if interactive_hook is site.register_readline: - # Fix the completer function to use the interactive console locals - try: - import rlcompleter - except: - pass - else: - completer = rlcompleter.Completer(console.locals) - readline.set_completer(completer.complete) + if interactive_hook is not None: + interactive_hook() + + if interactive_hook is site.register_readline: + # Fix the completer function to use the interactive console locals + try: + import rlcompleter + except: + pass + else: + completer = rlcompleter.Completer(console.locals) + readline.set_completer(completer.complete) repl_thread = REPLThread() repl_thread.daemon = True diff --git a/Lib/site.py b/Lib/site.py index 7889784b4bc485..61e1d97cb84c6b 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -457,8 +457,15 @@ def gethistoryfile(): '.python_history') +def enablerlcompleter(): + """Enable default readline configuration on interactive prompts, by + registering a sys.__interactivehook__. + """ + sys.__interactivehook__ = register_readline + + def register_readline(): - """Enable default readline configuration on interactive prompts. + """Configure readline completion on interactive prompts. If the readline module can be imported, the hook will set the Tab key as completion key and register ~/.python_history as history file. @@ -489,20 +496,21 @@ def register_readline(): pass if readline.get_current_history_length() == 0: - # If no history was loaded, default to .python_history, or - # PYTHON_HISTORY. + # If no history was loaded, default to .python_history, + # or PYTHON_HISTORY. # The guard is necessary to avoid doubling history size at # each interpreter exit when readline was already configured # through a PYTHONSTARTUP hook, see: # http://bugs.python.org/issue5845#msg198636 + history = gethistoryfile() try: - readline.read_history_file(gethistoryfile()) + readline.read_history_file(history) except OSError: pass def write_history(): try: - readline.write_history_file(gethistoryfile()) + readline.write_history_file(history) except (FileNotFoundError, PermissionError): # home directory does not exist or is not writable # https://bugs.python.org/issue19891 @@ -510,6 +518,7 @@ def write_history(): atexit.register(write_history) + def venv(known_paths): global PREFIXES, ENABLE_USER_SITE From bd6098823ebfb924a3171d26494e2f846bfa143b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 1 Mar 2024 10:39:37 +0100 Subject: [PATCH 5/5] Use enablerlcompleter() --- Lib/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/site.py b/Lib/site.py index 61e1d97cb84c6b..2aee63e24ca52b 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -638,7 +638,7 @@ def main(): setcopyright() sethelper() if not sys.flags.isolated: - sys.__interactivehook__ = register_readline + enablerlcompleter() execsitecustomize() if ENABLE_USER_SITE: execusercustomize()