]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-84995: Run sys.__interactivehook__() on asyncio REPL startup (#20517)
authorRémi Lapeyre <remi.lapeyre@lenstra.fr>
Fri, 1 Mar 2024 19:39:16 +0000 (20:39 +0100)
committerGitHub <noreply@github.com>
Fri, 1 Mar 2024 19:39:16 +0000 (11:39 -0800)
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>
Lib/asyncio/__main__.py
Lib/site.py
Misc/NEWS.d/next/Library/2020-05-29-18-08-54.bpo-40818.Ij8ffq.rst [new file with mode: 0644]

index 18bb87a5bc4ffd89fb24ef193ee88af64ee5dcbc..cbc1d7c93ef76f5b01e5019bc300a218f79b1717 100644 (file)
@@ -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()
index 0631f3f6115ec0ccf98875e56ff11325f35ab165..2aee63e24ca52be35b13fc3ed9604ebeb83f3bb1 100644 (file)
@@ -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 (file)
index 0000000..27f6a6d
--- /dev/null
@@ -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.