Skip to content

Commit 014c38e

Browse files
ichard26tomviner
andcommitted
gh-72327: Suggest using system terminal for pip install in REPL
Users new to Python packaging often try to use pip from the REPL only to be met with a confusing SyntaxError. If this happens, guide the user to use a system terminal instead to invoke pip. Co-authored-by: Tom Viner <tom@viner.tv>
1 parent 5dac137 commit 014c38e

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

Lib/site.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,46 @@ def enablerlcompleter():
488488
"""Enable default readline configuration on interactive prompts, by
489489
registering a sys.__interactivehook__.
490490
"""
491+
# NOTE: This function is only kept for backwards compatibility.
491492
sys.__interactivehook__ = register_readline
492493

493494

495+
def _set_interactive_hook():
496+
"""Register a sys.__interactivehook__:
497+
- Enable default readline configuration on interactive prompts.
498+
- Register an excepthook to detect pip usage in the REPL.
499+
"""
500+
def interactivehook():
501+
enablerlcompleter()
502+
_register_detect_pip_usage_in_repl()
503+
504+
sys.__interactivehook__ = interactivehook
505+
506+
507+
def _register_detect_pip_usage_in_repl():
508+
"""Register an exception hook that adds a helpful hint to use the
509+
system command prompt if pip install is invoked in the REPL, often
510+
done by newbies.
511+
"""
512+
old_excepthook = sys.excepthook
513+
514+
def detect_pip_usage_in_repl(typ, value, traceback):
515+
if typ is SyntaxError and (
516+
"pip install" in value.text or "pip3 install" in value.text
517+
):
518+
value.add_note(
519+
"The Python package manager (pip) can only be"
520+
" used outside of the Python REPL.\n"
521+
"Please try the 'pip' command in a separate terminal"
522+
" or command prompt."
523+
)
524+
525+
old_excepthook(typ, value, traceback)
526+
527+
detect_pip_usage_in_repl.__wrapped__ = old_excepthook
528+
sys.excepthook = detect_pip_usage_in_repl
529+
530+
494531
def register_readline():
495532
"""Configure readline completion on interactive prompts.
496533
@@ -711,7 +748,7 @@ def main():
711748
setcopyright()
712749
sethelper()
713750
if not sys.flags.isolated:
714-
enablerlcompleter()
751+
_set_interactive_hook()
715752
execsitecustomize()
716753
if ENABLE_USER_SITE:
717754
execusercustomize()

Lib/test/test_site.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,8 @@ def test_startup_interactivehook_isolated(self):
655655
def test_startup_interactivehook_isolated_explicit(self):
656656
# issue28192 readline can be explicitly enabled in isolated mode
657657
r = subprocess.Popen([sys.executable, '-I', '-c',
658-
'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
659-
self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()")
658+
'import site, sys; site._set_interactive_hook(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
659+
self.assertTrue(r, "'__interactivehook__' not added by _set_interactive_hook()")
660660

661661
class _pthFileTests(unittest.TestCase):
662662

@@ -803,5 +803,29 @@ def test_underpth_dll_file(self):
803803
self.assertTrue(rc, "sys.path is incorrect")
804804

805805

806+
class DetectPipUsageInReplTests(unittest.TestCase):
807+
def setUp(self):
808+
self.old_excepthook = sys.excepthook
809+
site._register_detect_pip_usage_in_repl()
810+
811+
def tearDown(self):
812+
sys.excepthook = self.old_excepthook
813+
814+
def test_detect_pip_usage_in_repl(self):
815+
for pip_cmd in [
816+
'pip install a', 'pip3 install b', 'python -m pip install c'
817+
]:
818+
with self.subTest(pip_cmd=pip_cmd):
819+
try:
820+
exec(pip_cmd, {}, {})
821+
except SyntaxError as exc:
822+
with captured_stderr() as err_out:
823+
sys.excepthook(SyntaxError, exc, exc.__traceback__)
824+
825+
self.assertIn("The Python package manager (pip) can only be"
826+
" used outside of the Python REPL",
827+
err_out.getvalue())
828+
829+
806830
if __name__ == "__main__":
807831
unittest.main()

Misc/ACKS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,7 @@ Joel Shprentz
17421742
Yue Shuaijie
17431743
Jaysinh Shukla
17441744
Terrel Shumway
1745+
Richard Si
17451746
Eric Siegerman
17461747
Reilly Tucker Siemens
17471748
Paul Sijben
@@ -1986,6 +1987,7 @@ Olivier Vielpeau
19861987
Kannan Vijayan
19871988
Kurt Vile
19881989
Norman Vine
1990+
Tom Viner
19891991
Pauli Virtanen
19901992
Frank Visser
19911993
Long Vo
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Suggest using the system command prompt when ``pip install`` is typed into
2+
the REPL. Patch by Tom Viner and Richard Si.

0 commit comments

Comments
 (0)