You can use signals and a context manager to acheive this. The idea is to register a function that will raise an exeption when the alarm signal is received and schedule the alarm signal for the timeout.
import signal from contextlib import contextmanager @contextmanager def timeout(time): # Register a function to raise a TimeoutError on the signal. signal.signal(signal.SIGALRM, raise_timeout). # Schedule the signal to be sent after ``time``. signal.alarm(time) try: yield except TimeoutError: pass finally: # Unregister the signal so it won't be triggered # if the timeout is not reached. signal.signal(signal.SIGALRM, signal.SIG_IGN) def raise_timeout(signum, frame): raise TimeoutError def my_func(): # Add a timeout block. with timeout(1): print('entering block') import time time.sleep(10) print('This should never get printed because the line before timed out')
Even if this solution works well, you can't nest timeout which can be a problem. Perhaps a solution relying on concurrent.futures may work but during my tests, I never managed to correctly stop a function once a timeout has been reached.