Skip to content

Commit 488ce0f

Browse files
authored
gh-69605: fix PyREPL completions inserted for import statements with spaces (#148629)
Fix `from math .<tab>` inserting `from math .ath.integer` instead of `from math.integer`
1 parent 13a807a commit 488ce0f

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
@@ -83,7 +83,11 @@ def get_completions(
8383
if not result:
8484
return None
8585
try:
86-
return self.complete(*result, include_values=include_values)
86+
names, values, action = self.complete(
87+
*result, include_values=include_values
88+
)
89+
names = [self._remove_separated_words(line, c) for c in names]
90+
return names, values, action
8791
except Exception:
8892
# Some unexpected error occurred, make it look like
8993
# no completions are available
@@ -336,6 +340,26 @@ def _do_import() -> str | None:
336340

337341
return (prompt, _do_import)
338342

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

340364
class ImportParser:
341365
"""

‎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)