blob: f5b7c0aa4f85c32cd56382a87cbd8823d77cebe8 [file] [log] [blame]
"""Simulates the REPL that Python spawns when invoking the binary with no arguments.
The code module is responsible for the default shell.
The import and `ocde.interact()` call here his is equivalent to doing:
$ python3 -m code
Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
The logic for PYTHONSTARTUP is handled in python/private/repl_template.py.
"""
# Capture the globals from PYTHONSTARTUP so we can pass them on to the console.
console_locals = globals().copy()
import code
import rlcompleter
import sys
class DynamicCompleter(rlcompleter.Completer):
"""
A custom completer that dynamically updates its namespace to include new
imports made within the interactive session.
"""
def __init__(self, namespace):
# Store a reference to the namespace, not a copy, so that changes to the namespace are
# reflected.
self.namespace = namespace
def complete(self, text, state):
# Update the completer's internal namespace with the current interactive session's locals
# and globals. This is the key to making new imports discoverable.
rlcompleter.Completer.__init__(self, self.namespace)
return super().complete(text, state)
if sys.stdin.isatty():
# Use the default options.
exitmsg = None
else:
# On a non-interactive console, we want to suppress the >>> and the exit message.
exitmsg = ""
sys.ps1 = ""
sys.ps2 = ""
# Set up tab completion.
try:
import readline
completer = DynamicCompleter(console_locals)
readline.set_completer(completer.complete)
# TODO(jpwoodbu): Use readline.backend instead of readline.__doc__ once we can depend on having
# Python >=3.13.
if "libedit" in readline.__doc__: # type: ignore
readline.parse_and_bind("bind ^I rl_complete")
elif "GNU readline" in readline.__doc__: # type: ignore
readline.parse_and_bind("tab: complete")
else:
print(
"Could not enable tab completion: "
"unable to determine readline backend"
)
except ImportError:
print(
"Could not enable tab completion: "
"readline module not available on this platform"
)
# We set the banner to an empty string because the repl_template.py file already prints the banner.
code.interact(local=console_locals, banner="", exitmsg=exitmsg)