diff --git a/sh.py b/sh.py index 84ed294d..14ad13a0 100644 --- a/sh.py +++ b/sh.py @@ -2306,7 +2306,11 @@ def __init__( def timeout_fn(): self.timed_out = True - self.signal(ca["timeout_signal"]) + try: + self.signal(ca["timeout_signal"]) + except ProcessLookupError: + # Edge case: the process probably exited + pass self._timeout_event = None self._timeout_timer = None diff --git a/tests/sh_test.py b/tests/sh_test.py index 74e514e3..c3d19adf 100644 --- a/tests/sh_test.py +++ b/tests/sh_test.py @@ -3012,6 +3012,25 @@ def test_custom_timeout_signal(self): else: self.fail("we should have handled a TimeoutException") + def test_timeout_race_condition_process_exit(self): + import signal + + from sh import TimeoutException + + py = create_tmp_test( + """ +import time +time.sleep(0.05) +""" + ) + # Run multiple times to increase likelihood of hitting the race condition + for _ in range(50): + try: + python(py.name, _timeout=0.1, _timeout_signal=signal.SIGTERM) + except TimeoutException: + # TimeoutException is OK, but ProcessLookupError isn't + pass + def test_append_stdout(self): py = create_tmp_test( """