diff options
author | Rémi Lapeyre <remi.lapeyre@lenstra.fr> | 2024-03-01 19:39:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-01 19:39:16 (GMT) |
commit | b5949eac6220ee8002971b5e7026432ac7990c74 (patch) | |
tree | 31ce0e7194306baa3afdfba3b3fcc2584aeb7aef | |
parent | e6e35327d87e5456ba2178915e4f523a42051d4b (diff) | |
download | cpython-b5949eac6220ee8002971b5e7026432ac7990c74.zip cpython-b5949eac6220ee8002971b5e7026432ac7990c74.tar.gz cpython-b5949eac6220ee8002971b5e7026432ac7990c74.tar.bz2 |
gh-84995: Run sys.__interactivehook__() on asyncio REPL startup (#20517)
This makes the asyncio REPL (`python -m asyncio`) more usable
and similar to the regular REPL.
This exposes register_readline() as a top-level function in site.py,
but it's intentionally undocumented.
Co-authored-by: Carol Willing <carolcode@willingconsulting.com>
Co-authored-by: Itamar Oren <itamarost@gmail.com>
-rw-r--r-- | Lib/asyncio/__main__.py | 16 | ||||
-rw-r--r-- | Lib/site.py | 82 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst | 3 |
3 files changed, 62 insertions, 39 deletions
diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 18bb87a..cbc1d7c 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -3,6 +3,7 @@ import asyncio import code import concurrent.futures import inspect +import site import sys import threading import types @@ -109,6 +110,21 @@ if __name__ == '__main__': except ImportError: pass + interactive_hook = getattr(sys, "__interactivehook__", None) + + 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 0631f3f..2aee63e 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -460,60 +460,64 @@ def gethistoryfile(): def enablerlcompleter(): """Enable default readline configuration on interactive prompts, by registering a sys.__interactivehook__. + """ + sys.__interactivehook__ = register_readline + + +def register_readline(): + """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. 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. - if readline.backend == 'editline': - 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. + if readline.backend == 'editline': + 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, + # 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_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, - # 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() + 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 OSError: - # bpo-19891, bpo-41193: Home directory does not exist - # or is not writable, or the filesystem is read-only. - pass + atexit.register(write_history) - atexit.register(write_history) - - sys.__interactivehook__ = register_readline def venv(known_paths): global PREFIXES, ENABLE_USER_SITE 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 0000000..27f6a6d --- /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 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. |