Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion Lib/_pyrepl/_module_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ def get_completions(self, line: str) -> tuple[list[str], CompletionAction | None
if not result:
return None
try:
return self.complete(*result)
names, action = self.complete(*result)
names = [self._remove_separated_words(line, c) for c in names]
return names, action
except Exception:
# Some unexpected error occurred, make it look like
# no completions are available
Expand Down Expand Up @@ -300,6 +302,26 @@ def _do_import() -> str | None:

return (prompt, _do_import)

def _remove_separated_words(self, line: str, completion: str) -> str:
"""Remove completion parts imputed as separate words.

Needed because the completer insert any completion provided
by replacing the stem (eg. word) currently imputed, if any.

Examples:
- 'import foo.', 'foo.bar' -> 'foo.bar'
- 'import foo .', 'foo.bar' -> '.bar'
- 'from foo import ', 'bar' -> 'bar'
- 'import x.x .x.', 'x.x.x.x' -> '.x.x'
"""
last_word = line.split(" ")[-1]
if not last_word:
return completion
index = completion.rfind(last_word)
if index > 0:
return completion[index:]
return completion


class ImportParser:
"""
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_pyrepl/test_pyrepl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,12 @@ def test_completions(self):
("from importlib import res\t\n", "from importlib import resources"),
("from importlib.res\t import a\t\n", "from importlib.resources import abc"),
("from __phello__ import s\t\n", "from __phello__ import spam"), # frozen module
("import importlib .res\t\n", "import importlib .resources"),
("import importlib. res\t\n", "import importlib. resources"),
("import importlib . res\t\n", "import importlib . resources"),
("import importlib .metadata.\t\n", "import importlib .metadata.diagnose"),
("import importlib .metadata .\t\n", "import importlib .metadata .diagnose"),
("from importlib .resources .a\t\n", "from importlib .resources .abc"),
)
for code, expected in cases:
with self.subTest(code=code):
Expand Down Expand Up @@ -1564,8 +1570,13 @@ def test_parse(self):
('import a.b.c, foo.bar, ', (None, '')),
('from foo', ('foo', None)),
('from a.', ('a.', None)),
('from a .', ('a.', None)),
('from a .', ('a.', None)),
('from a .', ('a.', None)),
('from a.b', ('a.b', None)),
('from a.b.', ('a.b.', None)),
('from a. b.', ('a.b.', None)),
('from a . b .', ('a.b.', None)),
('from a.b.c', ('a.b.c', None)),
('from foo import ', ('foo', '')),
('from foo import a', ('foo', 'a')),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :term:`REPL` completions inserted incorrectly when there was spaces in
import statements.
Loading