Skip to content

Commit 53a30d1

Browse files
committed
Update _run_cmdfinalization_hooks to use termios instead of suprocess('stty sane')
1 parent 03520b1 commit 53a30d1

File tree

2 files changed

+17
-17
lines changed

2 files changed

+17
-17
lines changed

cmd2/cmd2.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -513,12 +513,13 @@ def __init__(
513513
self._initial_termios_settings = None
514514
if not sys.platform.startswith('win') and self.stdin.isatty():
515515
try:
516+
import io
516517
import termios
517518

518519
self._initial_termios_settings = termios.tcgetattr(self.stdin.fileno())
519-
except (ImportError, termios.error):
520+
except (ImportError, io.UnsupportedOperation, termios.error):
520521
# This can happen if termios isn't available or stdin is a pseudo-TTY
521-
pass
522+
self._initial_termios_settings = None
522523

523524
# If a startup script is provided and exists, then execute it in the startup commands
524525
if startup_script:
@@ -2834,14 +2835,15 @@ def onecmd_plus_hooks(
28342835

28352836
def _run_cmdfinalization_hooks(self, stop: bool, statement: Statement | None) -> bool:
28362837
"""Run the command finalization hooks."""
2837-
with self.sigint_protection:
2838-
if not sys.platform.startswith('win') and self.stdin.isatty():
2839-
# Before the next command runs, fix any terminal problems like those
2840-
# caused by certain binary characters having been printed to it.
2841-
import subprocess
2842-
2843-
proc = subprocess.Popen(['stty', 'sane']) # noqa: S607
2844-
proc.communicate()
2838+
if self._initial_termios_settings is not None and self.stdin.isatty():
2839+
import io
2840+
import termios
2841+
2842+
# Before the next command runs, fix any terminal problems like those
2843+
# caused by certain binary characters having been printed to it.
2844+
with self.sigint_protection, contextlib.suppress(io.UnsupportedOperation, termios.error):
2845+
# This can fail if stdin is a pseudo-TTY, in which case we just ignore it
2846+
termios.tcsetattr(self.stdin.fileno(), termios.TCSANOW, self._initial_termios_settings)
28452847

28462848
data = plugin.CommandFinalizationData(stop, statement)
28472849
for func in self._cmdfinalization_hooks:

tests/test_cmd2.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,16 +1068,14 @@ def test_cmdloop_without_rawinput() -> None:
10681068
assert out == expected
10691069

10701070

1071-
@pytest.mark.skipif(sys.platform.startswith('win'), reason="stty sane only run on Linux/Mac")
1072-
def test_stty_sane(base_app, monkeypatch) -> None:
1073-
"""Make sure stty sane is run on Linux/Mac after each command if stdin is a terminal"""
1071+
def test_cmdfinalizations_runs(base_app, monkeypatch) -> None:
1072+
"""Make sure _run_cmdfinalization_hooks is run on after each command."""
10741073
with mock.patch('sys.stdin.isatty', mock.MagicMock(name='isatty', return_value=True)):
1075-
# Mock out the subprocess.Popen call so we don't actually run stty sane
1076-
m = mock.MagicMock(name='Popen')
1077-
monkeypatch.setattr("subprocess.Popen", m)
1074+
m = mock.MagicMock(name='cmdfinalization')
1075+
monkeypatch.setattr("cmd2.Cmd._run_cmdfinalization_hooks", m)
10781076

10791077
base_app.onecmd_plus_hooks('help')
1080-
m.assert_called_once_with(['stty', 'sane'])
1078+
m.assert_called_once()
10811079

10821080

10831081
def test_sigint_handler(base_app) -> None:

0 commit comments

Comments
 (0)