]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-69605: Disable PyREPL module autocomplete fallback on regular completion (gh-134181)
authorLoïc Simon <loic.pano@gmail.com>
Sun, 25 May 2025 23:05:08 +0000 (01:05 +0200)
committerGitHub <noreply@github.com>
Sun, 25 May 2025 23:05:08 +0000 (01:05 +0200)
Co-authored-by: Loïc Simon <loic.simon@napta.io>
Lib/_pyrepl/_module_completer.py
Lib/_pyrepl/readline.py
Lib/test/test_pyrepl/test_pyrepl.py
Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-14-33-23.gh-issue-69605.ZMO49F.rst [new file with mode: 0644]

index 494a501101a9b296dc8077480cbd9c91f6a5ea53..1e9462a42156d45431270385f917ed8763f2ce67 100644 (file)
@@ -42,11 +42,11 @@ class ModuleCompleter:
         self._global_cache: list[pkgutil.ModuleInfo] = []
         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'."""
         result = ImportParser(line).parse()
         if not result:
-            return []
+            return None
         try:
             return self.complete(*result)
         except Exception:
index 572eee520e53f3ba27238bb6d189f6c1e050eeb1..9560ae779abfea24894f79f8177c01311fb1966f 100644 (file)
@@ -134,7 +134,8 @@ class ReadlineAlikeReader(historical_reader.HistoricalReader, CompletingReader):
         return "".join(b[p + 1 : self.pos])
 
     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
         if len(stem) == 0 and self.more_lines is not None:
             b = self.buffer
@@ -165,7 +166,7 @@ class ReadlineAlikeReader(historical_reader.HistoricalReader, CompletingReader):
             result.sort()
         return result
 
-    def get_module_completions(self) -> list[str]:
+    def get_module_completions(self) -> list[str] | None:
         line = self.get_line()
         return self.config.module_completer.get_completions(line)
 
index abb4bd1bc25fb11b381a829541009087a328b73d..aa3a592766d6d150df35f7c95fad659d075cb8f1 100644 (file)
@@ -918,7 +918,14 @@ class TestPyReplCompleter(TestCase):
 
 class TestPyReplModuleCompleter(TestCase):
     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
+        sys.path = [lib_path]
 
     def tearDown(self):
         sys.path = self._saved_sys_path
@@ -932,14 +939,6 @@ class TestPyReplModuleCompleter(TestCase):
         return reader
 
     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 = (
             ("import path\t\n", "import pathlib"),
             ("import importlib.\t\tres\t\n", "import importlib.resources"),
@@ -1052,6 +1051,19 @@ class TestPyReplModuleCompleter(TestCase):
                 output = reader.readline()
                 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):
         cases = (
             ('', ('', '')),
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-14-33-23.gh-issue-69605.ZMO49F.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-14-33-23.gh-issue-69605.ZMO49F.rst
new file mode 100644 (file)
index 0000000..7b7275f
--- /dev/null
@@ -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.