@@ -336,7 +336,17 @@ def prepare(self):
336336 raw .lflag |= termios .ISIG
337337 raw .cc [termios .VMIN ] = 1
338338 raw .cc [termios .VTIME ] = 0
339- tcsetattr (self .input_fd , termios .TCSADRAIN , raw )
339+ try :
340+ tcsetattr (self .input_fd , termios .TCSADRAIN , raw )
341+ except termios .error as e :
342+ if e .args [0 ] == errno .EIO :
343+ # gh-135329
344+ # When running under external programs (like strace),
345+ # tcsetattr may fail with EIO. We can safely ignore this
346+ # and continue with default terminal settings.
347+ pass
348+ else :
349+ raise
340350
341351 # In macOS terminal we need to deactivate line wrap via ANSI escape code
342352 if platform .system () == "Darwin" and os .getenv ("TERM_PROGRAM" ) == "Apple_Terminal" :
@@ -368,7 +378,17 @@ def restore(self):
368378 self .__disable_bracketed_paste ()
369379 self .__maybe_write_code (self ._rmkx )
370380 self .flushoutput ()
371- tcsetattr (self .input_fd , termios .TCSADRAIN , self .__svtermstate )
381+ try :
382+ tcsetattr (self .input_fd , termios .TCSADRAIN , self .__svtermstate )
383+ except termios .error as e :
384+ if e .args [0 ] == errno .EIO :
385+ # gh-135329
386+ # When running under external programs (like strace),
387+ # tcsetattr may fail with EIO. We can safely ignore this
388+ # as the terminal state will be restored by the external program.
389+ pass
390+ else :
391+ raise
372392
373393 if platform .system () == "Darwin" and os .getenv ("TERM_PROGRAM" ) == "Apple_Terminal" :
374394 os .write (self .output_fd , b"\033 [?7h" )
@@ -407,6 +427,13 @@ def get_event(self, block: bool = True) -> Event | None:
407427 return self .event_queue .get ()
408428 else :
409429 continue
430+ elif err .errno == errno .EIO :
431+ # gh-135329
432+ # When running under external programs (like strace),
433+ # os.read may fail with EIO. In this case, we should
434+ # exit gracefully to avoid infinite error loops.
435+ import sys
436+ sys .exit (errno .EIO )
410437 else :
411438 raise
412439 else :
0 commit comments