Skip to content

gh-72327: Add help message for pip in REPL #8536

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Replace REPL checks with interactivehook
  • Loading branch information
tomviner committed Aug 1, 2018
commit 2bb1e385cce831adb2b3d4b62dd8dc6748b3d919
112 changes: 58 additions & 54 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,55 @@ def setcopyright():
files, dirs)


def sethelper():
builtins.help = _sitebuiltins._Helper()

def _register_readline():
"""
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.
"""
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_history_file(history)
except OSError:
pass
atexit.register(readline.write_history_file, history)


def _register_detect_pip_usage_in_repl():
old_excepthook = sys.excepthook

Expand All @@ -408,58 +457,17 @@ def detect_pip_usage_in_repl(typ, value, traceback):
sys.excepthook = detect_pip_usage_in_repl


def sethelper():
builtins.help = _sitebuiltins._Helper()

def enablerlcompleter():
"""Enable default readline configuration on interactive prompts, by
registering a sys.__interactivehook__.

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 _set_interactive_hook():
"""Register a sys.__interactivehook__ to:
- Enable default readline configuration on interactive prompts.
- Register an excepthook to detect pip usage in the REPL.
"""
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')

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
def interactivehook():
_register_readline()
_register_detect_pip_usage_in_repl()

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_history_file(history)
except OSError:
pass
atexit.register(readline.write_history_file, history)
sys.__interactivehook__ = interactivehook

sys.__interactivehook__ = register_readline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change to the way enablerlcompleter works is still concerning.

Reviewing 0e6d9e2 I think the public API to preserve would be:

  1. New top level function that actually does the registration is called _register_readline (as @tomviner originally had it)
  2. Reduced enablerlcompleter implementation just does sys.__interactive_hook__ = _register_readline
  3. _set_interactive_hook call _register_readline directly, bypassing enablerlcompleter (since it is setting its own hook)

enablerlcompleter would never be called by the standard library (outside the test suite), it would purely be a backwards compatibility API accounting for the fact that it was never marked as private in the interactive help.


def venv(known_paths):
global PREFIXES, ENABLE_USER_SITE
Expand Down Expand Up @@ -576,12 +584,8 @@ def main():
setquit()
setcopyright()
sethelper()
# Detect REPL by prompt, -i flag or PYTHONINSPECT env var being set.
if (hasattr(sys, 'ps1') or sys.flags.interactive or
os.environ.get('PYTHONINSPECT')):
_register_detect_pip_usage_in_repl()
if not sys.flags.isolated:
enablerlcompleter()
_set_interactive_hook()
execsitecustomize()
if ENABLE_USER_SITE:
execusercustomize()
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,8 @@ def test_startup_interactivehook_isolated(self):
def test_startup_interactivehook_isolated_explicit(self):
# issue28192 readline can be explicitly enabled in isolated mode
r = subprocess.Popen([sys.executable, '-I', '-c',
'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()")
'import site, sys; site._set_interactive_hook(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
self.assertTrue(r, "'__interactivehook__' not added by _set_interactive_hook()")


@unittest.skipUnless(sys.platform == 'win32', "only supported on Windows")
Expand Down