Skip to content

Commit 96005d3

Browse files
[3.15] gh-69605: fix PyREPL completions inserted for import statements with spaces (GH-148629) (#159989)
Fix `from math .<tab>` inserting `from math .ath.integer` instead of `from math.integer` (cherry picked from commit 488ce0f) Co-authored-by: Loïc Simon <loic.simon@napta.io>
1 parent 605d16a commit 96005d3

3 files changed

Lines changed: 38 additions & 1 deletion

File tree

‎Lib/_pyrepl/_module_completer.py‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ def get_completions(
8888
if not result:
8989
return None
9090
try:
91-
return self.complete(*result, include_values=include_values)
91+
names, values, action = self.complete(
92+
*result, include_values=include_values
93+
)
94+
names = [self._remove_separated_words(line, c) for c in names]
95+
return names, values, action
9296
except Exception:
9397
# Some unexpected error occurred, make it look like
9498
# no completions are available
@@ -341,6 +345,26 @@ def _do_import() -> str | None:
341345

342346
return (prompt, _do_import)
343347

348+
def _remove_separated_words(self, line: str, completion: str) -> str:
349+
"""Remove completion parts imputed as separate words.
350+
351+
Needed because the completer insert any completion provided
352+
by replacing the stem (eg. word) currently imputed, if any.
353+
354+
Examples:
355+
- 'import foo.', 'foo.bar' -> 'foo.bar'
356+
- 'import foo .', 'foo.bar' -> '.bar'
357+
- 'from foo import ', 'bar' -> 'bar'
358+
- 'import x.x .x.', 'x.x.x.x' -> '.x.x'
359+
"""
360+
last_word = line.split(" ")[-1]
361+
if not last_word:
362+
return completion
363+
index = completion.rfind(last_word)
364+
if index > 0:
365+
return completion[index:]
366+
return completion
367+
344368

345369
class ImportParser:
346370
"""

‎Lib/test/test_pyrepl/test_pyrepl.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,12 @@ def test_completions(self):
12381238
("from importlib import res\t\n", "from importlib import resources"),
12391239
("from importlib.res\t import a\t\n", "from importlib.resources import abc"),
12401240
("from __phello__ import s\t\n", "from __phello__ import spam"), # frozen module
1241+
("import importlib .res\t\n", "import importlib .resources"),
1242+
("import importlib. res\t\n", "import importlib. resources"),
1243+
("import importlib . res\t\n", "import importlib . resources"),
1244+
("import importlib .metadata.\t\n", "import importlib .metadata.diagnose"),
1245+
("import importlib .metadata .\t\n", "import importlib .metadata .diagnose"),
1246+
("from importlib .resources .a\t\n", "from importlib .resources .abc"),
12411247
)
12421248
for code, expected in cases:
12431249
with self.subTest(code=code):
@@ -1629,8 +1635,13 @@ def test_parse(self):
16291635
('import a.b.c, foo.bar, ', (None, '')),
16301636
('from foo', ('foo', None)),
16311637
('from a.', ('a.', None)),
1638+
('from a .', ('a.', None)),
1639+
('from a .', ('a.', None)),
1640+
('from a .', ('a.', None)),
16321641
('from a.b', ('a.b', None)),
16331642
('from a.b.', ('a.b.', None)),
1643+
('from a. b.', ('a.b.', None)),
1644+
('from a . b .', ('a.b.', None)),
16341645
('from a.b.c', ('a.b.c', None)),
16351646
('from foo import ', ('foo', '')),
16361647
('from foo import a', ('foo', 'a')),
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :term:`REPL` completions inserted incorrectly when there was spaces in
2+
import statements.

0 commit comments

Comments
 (0)