mirror of https://github.com/python/cpython
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>
This commit is contained in:
parent
e6e35327d8
commit
b5949eac62
|
@ -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()
|
||||
|
|
80
Lib/site.py
80
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
|
||||
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')
|
||||
# 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
|
||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue