Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b0c288a

Browse filesBrowse files
committed
gh-133400: Fixed Ctrl+D (^D) behavior in :mod:_pyrepl module
1 parent 13cb8ca commit b0c288a
Copy full SHA for b0c288a

File tree

3 files changed

+46
-0
lines changed
Filter options

3 files changed

+46
-0
lines changed

‎Lib/_pyrepl/commands.py

Copy file name to clipboardExpand all lines: Lib/_pyrepl/commands.py
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,9 @@ def do(self) -> None:
421421
r.update_screen()
422422
r.console.finish()
423423
raise EOFError
424+
elif "\n" in b and self.event[-1] == "\004":
425+
self.finish = True
426+
424427
for i in range(r.get_arg()):
425428
if r.pos != len(b):
426429
del b[r.pos]

‎Lib/test/test_pyrepl/test_pyrepl.py

Copy file name to clipboardExpand all lines: Lib/test/test_pyrepl/test_pyrepl.py
+40Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,3 +1610,43 @@ def test_prompt_after_help(self):
16101610
# Extra stuff (newline and `exit` rewrites) are necessary
16111611
# because of how run_repl works.
16121612
self.assertNotIn(">>> \n>>> >>>", cleaned_output)
1613+
1614+
class TestPyReplCtrlD(TestCase):
1615+
def prepare_reader(self, events):
1616+
console = FakeConsole(events)
1617+
config = ReadlineConfig(readline_completer=None)
1618+
reader = ReadlineAlikeReader(console=console, config=config)
1619+
return reader
1620+
1621+
def test_ctrl_d_empty_buffer(self):
1622+
"""Test that pressing Ctrl+D on empty buffer exits the program"""
1623+
events = [
1624+
Event(evt="key", data="\x04", raw=bytearray(b"\x04")), # Ctrl+D
1625+
]
1626+
reader = self.prepare_reader(events)
1627+
with self.assertRaises(EOFError):
1628+
multiline_input(reader)
1629+
1630+
def test_ctrl_d_multiline_mode(self):
1631+
"""Test that pressing Ctrl+D in multiline mode exits multiline mode"""
1632+
events = itertools.chain(
1633+
code_to_events("def f():\n"), # Enter multiline mode
1634+
[
1635+
Event(evt="key", data="\x04", raw=bytearray(b"\x04")), # Ctrl+D
1636+
],
1637+
)
1638+
reader = self.prepare_reader(events)
1639+
output = multiline_input(reader)
1640+
self.assertEqual(output, "def f():\n ") # Should return current input
1641+
1642+
def test_ctrl_d_single_line(self):
1643+
"""Test that pressing Ctrl+D in single line mode deletes current character"""
1644+
events = itertools.chain(
1645+
code_to_events("hello"),
1646+
[Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))], # move left
1647+
[Event(evt="key", data="\x04", raw=bytearray(b"\x04"))], # Ctrl+D
1648+
code_to_events("\n"),
1649+
)
1650+
reader = self.prepare_reader(events)
1651+
output = multiline_input(reader)
1652+
self.assertEqual(output, "hell") # Should delete the last character
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed Ctrl+D (^D) behavior in _pyrepl module: Now properly exits multiline
2+
mode when pressed in multiline section. Added test cases to verify the
3+
behavior in both multiline and single line modes.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.