mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-69605: Disable PyREPL module autocomplete fallback on regular completion (gh-134181)
Co-authored-by: Loïc Simon <loic.simon@napta.io>
This commit is contained in:
parent
a32ea45699
commit
0e3bc962c6
4 changed files with 27 additions and 12 deletions
|
@ -42,11 +42,11 @@ class ModuleCompleter:
|
||||||
self._global_cache: list[pkgutil.ModuleInfo] = []
|
self._global_cache: list[pkgutil.ModuleInfo] = []
|
||||||
self._curr_sys_path: list[str] = sys.path[:]
|
self._curr_sys_path: list[str] = sys.path[:]
|
||||||
|
|
||||||
def get_completions(self, line: str) -> list[str]:
|
def get_completions(self, line: str) -> list[str] | None:
|
||||||
"""Return the next possible import completions for 'line'."""
|
"""Return the next possible import completions for 'line'."""
|
||||||
result = ImportParser(line).parse()
|
result = ImportParser(line).parse()
|
||||||
if not result:
|
if not result:
|
||||||
return []
|
return None
|
||||||
try:
|
try:
|
||||||
return self.complete(*result)
|
return self.complete(*result)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -134,7 +134,8 @@ class ReadlineAlikeReader(historical_reader.HistoricalReader, CompletingReader):
|
||||||
return "".join(b[p + 1 : self.pos])
|
return "".join(b[p + 1 : self.pos])
|
||||||
|
|
||||||
def get_completions(self, stem: str) -> list[str]:
|
def get_completions(self, stem: str) -> list[str]:
|
||||||
if module_completions := self.get_module_completions():
|
module_completions = self.get_module_completions()
|
||||||
|
if module_completions is not None:
|
||||||
return module_completions
|
return module_completions
|
||||||
if len(stem) == 0 and self.more_lines is not None:
|
if len(stem) == 0 and self.more_lines is not None:
|
||||||
b = self.buffer
|
b = self.buffer
|
||||||
|
@ -165,7 +166,7 @@ class ReadlineAlikeReader(historical_reader.HistoricalReader, CompletingReader):
|
||||||
result.sort()
|
result.sort()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_module_completions(self) -> list[str]:
|
def get_module_completions(self) -> list[str] | None:
|
||||||
line = self.get_line()
|
line = self.get_line()
|
||||||
return self.config.module_completer.get_completions(line)
|
return self.config.module_completer.get_completions(line)
|
||||||
|
|
||||||
|
|
|
@ -918,7 +918,14 @@ class TestPyReplCompleter(TestCase):
|
||||||
|
|
||||||
class TestPyReplModuleCompleter(TestCase):
|
class TestPyReplModuleCompleter(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
import importlib
|
||||||
|
# Make iter_modules() search only the standard library.
|
||||||
|
# This makes the test more reliable in case there are
|
||||||
|
# other user packages/scripts on PYTHONPATH which can
|
||||||
|
# interfere with the completions.
|
||||||
|
lib_path = os.path.dirname(importlib.__path__[0])
|
||||||
self._saved_sys_path = sys.path
|
self._saved_sys_path = sys.path
|
||||||
|
sys.path = [lib_path]
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
sys.path = self._saved_sys_path
|
sys.path = self._saved_sys_path
|
||||||
|
@ -932,14 +939,6 @@ class TestPyReplModuleCompleter(TestCase):
|
||||||
return reader
|
return reader
|
||||||
|
|
||||||
def test_import_completions(self):
|
def test_import_completions(self):
|
||||||
import importlib
|
|
||||||
# Make iter_modules() search only the standard library.
|
|
||||||
# This makes the test more reliable in case there are
|
|
||||||
# other user packages/scripts on PYTHONPATH which can
|
|
||||||
# intefere with the completions.
|
|
||||||
lib_path = os.path.dirname(importlib.__path__[0])
|
|
||||||
sys.path = [lib_path]
|
|
||||||
|
|
||||||
cases = (
|
cases = (
|
||||||
("import path\t\n", "import pathlib"),
|
("import path\t\n", "import pathlib"),
|
||||||
("import importlib.\t\tres\t\n", "import importlib.resources"),
|
("import importlib.\t\tres\t\n", "import importlib.resources"),
|
||||||
|
@ -1052,6 +1051,19 @@ class TestPyReplModuleCompleter(TestCase):
|
||||||
output = reader.readline()
|
output = reader.readline()
|
||||||
self.assertEqual(output, expected)
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_no_fallback_on_regular_completion(self):
|
||||||
|
cases = (
|
||||||
|
("import pri\t\n", "import pri"),
|
||||||
|
("from pri\t\n", "from pri"),
|
||||||
|
("from typing import Na\t\n", "from typing import Na"),
|
||||||
|
)
|
||||||
|
for code, expected in cases:
|
||||||
|
with self.subTest(code=code):
|
||||||
|
events = code_to_events(code)
|
||||||
|
reader = self.prepare_reader(events, namespace={})
|
||||||
|
output = reader.readline()
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
def test_get_path_and_prefix(self):
|
def test_get_path_and_prefix(self):
|
||||||
cases = (
|
cases = (
|
||||||
('', ('', '')),
|
('', ('', '')),
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
When auto-completing an import in the :term:`REPL`, finding no candidates
|
||||||
|
now issues no suggestion, rather than suggestions from the current namespace.
|
Loading…
Add table
Add a link
Reference in a new issue