Skip to content

Commit 074d743

Browse files
Fix pyrepl overriding printed output without newlines
1 parent 5edfe55 commit 074d743

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

Lib/_pyrepl/unix_console.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,9 @@ def refresh(self, screen, c_xy):
235235
if not self.__gone_tall:
236236
while len(self.screen) < min(len(screen), self.height):
237237
self.__hide_cursor()
238-
self.__move(0, len(self.screen) - 1)
239-
self.__write("\n")
238+
if self.screen:
239+
self.__move(0, len(self.screen) - 1)
240+
self.__write("\n")
240241
self.posxy = 0, len(self.screen)
241242
self.screen.append("")
242243
else:
@@ -785,7 +786,7 @@ def __tputs(self, fmt, prog=delayprog):
785786
will never do anyone any good."""
786787
# using .get() means that things will blow up
787788
# only if the bps is actually needed (which I'm
788-
# betting is pretty unlkely)
789+
# betting is pretty unlikely)
789790
bps = ratedict.get(self.__svtermstate.ospeed)
790791
while True:
791792
m = prog.search(fmt)

Lib/_pyrepl/windows_console.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,9 @@ def refresh(self, screen: list[str], c_xy: tuple[int, int]) -> None:
183183

184184
while len(self.screen) < min(len(screen), self.height):
185185
self._hide_cursor()
186-
self._move_relative(0, len(self.screen) - 1)
187-
self.__write("\n")
186+
if self.screen:
187+
self._move_relative(0, len(self.screen) - 1)
188+
self.__write("\n")
188189
self.posxy = 0, len(self.screen)
189190
self.screen.append("")
190191

Lib/test/test_pyrepl/test_pyrepl.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,3 +1787,33 @@ def test_detect_pip_usage_in_repl(self):
17871787
" outside of the Python REPL"
17881788
)
17891789
self.assertIn(hint, output)
1790+
1791+
@force_not_colorized
1792+
def test_no_newline(self):
1793+
env = os.environ.copy()
1794+
env.pop("PYTHON_BASIC_REPL", "")
1795+
env["PYTHON_BASIC_REPL"] = "1"
1796+
expected_output_sequence = "Something pretty long>>> exit()"
1797+
basic_output, basic_exit_code = self.run_repl("print('Something pretty long', end='')\nexit()\n", env=env)
1798+
self.assertEqual(basic_exit_code, 0)
1799+
self.assertIn(expected_output_sequence, basic_output)
1800+
1801+
output, exit_code = self.run_repl("print('Something pretty long', end='')\nexit()\n")
1802+
self.assertEqual(exit_code, 0)
1803+
1804+
# Define escape sequences that don't affect cursor position or visual output
1805+
bracketed_paste_mode = r'\x1b\[\?2004[hl]' # Enable/disable bracketed paste
1806+
application_cursor_keys = r'\x1b\[\?1[hl]' # Enable/disable application cursor keys
1807+
application_keypad_mode = r'\x1b[=>]' # Enable/disable application keypad
1808+
insert_character = r'\x1b\[\d+@' # Insert character sequences
1809+
cursor_visibility = r'\x1b\[\?25[hl]' # Show/hide cursor
1810+
cursor_blinking = r'\x1b\[\?12[hl]' # Start/stop cursor blinking
1811+
1812+
# Remove only non-visual terminal control sequences (NOT cursor movement)
1813+
cleaned_output = re.sub(
1814+
f'{bracketed_paste_mode}|{application_cursor_keys}|{application_keypad_mode}|{insert_character}|{cursor_visibility}|{cursor_blinking}',
1815+
'',
1816+
output
1817+
)
1818+
1819+
self.assertIn(expected_output_sequence, cleaned_output)

0 commit comments

Comments
 (0)