diff --git a/Lib/_pyrepl/completing_reader.py b/Lib/_pyrepl/completing_reader.py index 9d2d43be5144e8..8d7ddd64f1e66a 100644 --- a/Lib/_pyrepl/completing_reader.py +++ b/Lib/_pyrepl/completing_reader.py @@ -41,11 +41,11 @@ def prefix(wordlist: list[str], j: int = 0) -> str: for word in wordlist: d[word[i]] = 1 if len(d) > 1: - return wordlist[0][j:i] + return wordlist[0][:i] i += 1 d = {} except IndexError: - return wordlist[0][j:i] + return wordlist[0][:i] return "" @@ -181,10 +181,16 @@ def do(self) -> None: if completions_unchangable and len(completions[0]) == len(stem): r.msg = "[ sole completion ]" r.dirty = True - r.insert(completions[0][len(stem):]) + stem_len = len(stem) + del r.buffer[r.pos - stem_len:r.pos] + r.pos -= stem_len + r.insert(completions[0]) else: p = prefix(completions, len(stem)) if p: + stem_len = len(stem) + del r.buffer[r.pos - stem_len:r.pos] + r.pos -= stem_len r.insert(p) if last_is_completer: r.cmpltn_menu_visible = True diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 35a1733787e7a2..428ab879ceafb1 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -936,6 +936,25 @@ def test_func(self): self.assertEqual(output, "dummy.test_func.__") self.assertEqual(mock_stderr.getvalue(), "") + def test_completion_replaces_input(self): + matches = [] + def case_insensitive_completer(text, state): + nonlocal matches + candidates = ["PYTHON", "PYREPL"] + if state == 0: + matches = [c for c in candidates if c.lower().startswith(text.lower())] + if state < len(matches): + return matches[state] + return None + + events = code_to_events("s='pyt\t'\ns='py\t\tr\t'\n") + reader = self.prepare_reader(events, {}) + reader.config.readline_completer = case_insensitive_completer + output = multiline_input(reader) + self.assertEqual(output, "s='PYTHON'") + + output = multiline_input(reader) + self.assertEqual(output, "s='PYREPL'") class TestPyReplModuleCompleter(TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2026-03-01-23-27-19.gh-issue-145392.uiNk5Y.rst b/Misc/NEWS.d/next/Library/2026-03-01-23-27-19.gh-issue-145392.uiNk5Y.rst new file mode 100644 index 00000000000000..4b533e277fffe2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-01-23-27-19.gh-issue-145392.uiNk5Y.rst @@ -0,0 +1 @@ +Fix :mod:`!_pyrepl` completion to replace input stem instead of appending.