Skip to content

Commit 8fa9c19

Browse files
yihong0618picnixz
andauthored
fix: apply suggestions from code review
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent ffc77f2 commit 8fa9c19

File tree

3 files changed

+11
-20
lines changed

3 files changed

+11
-20
lines changed

Lib/_pyrepl/unix_console.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,9 @@ def prepare(self):
329329
Prepare the console for input/output operations.
330330
"""
331331
# gh-130168: prevents signal handlers from overwriting the original state
332-
if not hasattr(self, '_UnixConsole__svtermstate'):
332+
if self.__svtermstate is None:
333333
self.__svtermstate = tcgetattr(self.input_fd)
334-
335-
raw = tcgetattr(self.input_fd).copy()
334+
raw = self.__svtermstate.copy()
336335
raw.iflag &= ~(termios.INPCK | termios.ISTRIP | termios.IXON)
337336
raw.oflag &= ~(termios.OPOST)
338337
raw.cflag &= ~(termios.CSIZE | termios.PARENB)
@@ -374,11 +373,10 @@ def restore(self):
374373
self.__disable_bracketed_paste()
375374
self.__maybe_write_code(self._rmkx)
376375
self.flushoutput()
377-
378-
if hasattr(self, '_UnixConsole__svtermstate'):
376+
if self.__svtermstate is not None:
379377
tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate)
380-
# Clear the saved state so prepare() can save a fresh one next time
381-
del self.__svtermstate
378+
# Reset the state for the next prepare() call.
379+
self.__svtermstate = None
382380

383381
if platform.system() == "Darwin" and os.getenv("TERM_PROGRAM") == "Apple_Terminal":
384382
os.write(self.output_fd, b"\033[?7h")
@@ -429,17 +427,12 @@ def wait(self, timeout: float | None = None) -> bool:
429427
"""
430428
if not self.event_queue.empty():
431429
return True
432-
433430
current_thread = threading.current_thread()
434-
435431
if self._polling_thread is current_thread:
436-
# This is a re-entrant call from the same thread
437-
# like old repl runtime error
432+
# Forbid re-entrant calls and use the old REPL error message.
438433
raise RuntimeError("can't re-enter readline")
439-
440434
if not self._poll_lock.acquire(blocking=False):
441435
return False
442-
443436
try:
444437
self._polling_thread = current_thread
445438
return bool(self.pollob.poll(timeout))

Lib/test/test_pyrepl/test_unix_console.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,9 @@ def test_wait_reentry_protection(self, _os_write):
309309
# gh-130168: Test signal handler re-entry protection
310310
console = UnixConsole(term="xterm")
311311
console.prepare()
312+
self.addCleanup(console.restore)
313+
self.addCleanup(setattr, console, '_polling_thread', None)
312314

313315
console._polling_thread = threading.current_thread()
314-
315-
with self.assertRaises(RuntimeError) as cm:
316+
with self.assertRaisesRegex(RuntimeError, "can't re-enter readline"):
316317
console.wait(timeout=0)
317-
self.assertEqual(str(cm.exception), "can't re-enter readline")
318-
319-
console._polling_thread = None
320-
console.restore()
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
Fix: pyrepl messed up terminal if a signal handler expects stdin.
1+
Make sure that the new REPL does not get scrambled when a signal handler
2+
uses interactive input.

0 commit comments

Comments
 (0)