Wrapt Timeout Decorator
wrapt-timeout-decorator is a Python library providing a robust timeout decorator. It emphasizes correctness when used with various types of methods (e.g., class, static) and preserves traceback information for debugging. It supports dynamic timeout adjustment and offers two strategies: 'Signals' (for POSIX systems and main thread) and 'Subprocess' (the default, compatible with Windows and multithreaded environments, utilizing `multiprocess` and `dill` for extended pickling capabilities). The library is actively maintained, with version 1.5.1 released in February 2024.
Warnings
- gotcha When using the default 'Subprocess' strategy (especially on Windows), functions decorated in the `__main__` context (i.e., directly in the script being run) might encounter pickling errors. To avoid this, it's highly recommended to define decorated functions within a separate module and import them.
- gotcha The 'Signals' timeout strategy (`use_signals=True`) is only available on POSIX systems (Linux, macOS) and exclusively works in the main thread. It will be automatically disabled if used in a subthread or on Windows.
- breaking Enabling the `allow_eval=True` parameter can introduce severe security vulnerabilities if the timeout string is derived from untrusted input, as it allows arbitrary code execution within the decorator's context.
- gotcha Using `dec_hard_timeout=True` to enforce a strict timeout can lead to immediate timeouts if the specified duration is too short for the subprocess to even spawn and initialize, particularly on Windows where process spawning can take significant time (e.g., 0.5 seconds).
- gotcha Nested `@timeout` decorators are problematic if more than one attempts to use `use_signals=True`, as there is only one ALARM signal per process on Unix. Only the outermost decorator should use signals, while inner ones must use `use_signals=False` (the default).
Install
-
pip install wrapt-timeout-decorator
Imports
- timeout
from wrapt_timeout_decorator import timeout
Quickstart
import time
from wrapt_timeout_decorator import timeout, TimeoutError
@timeout(5)
def long_running_function():
print("Starting long_running_function...")
for i in range(1, 10):
time.sleep(1)
print(f'{i} seconds passed inside function.')
print("long_running_function finished.")
if __name__ == '__main__':
try:
long_running_function()
print("Function completed without timeout.")
except TimeoutError:
print("Function timed out after 5 seconds.")
except Exception as e:
print(f"An unexpected error occurred: {e}")