Timeout decorator for Python functions with signal-based and multiprocessing timeout strategies
npx @tessl/cli install tessl/pypi-timeout-decorator@0.5.0A Python decorator that enables developers to set execution timeouts for functions, preventing them from running indefinitely. It offers two timeout strategies: signal-based timeouts for main thread execution and multiprocessing-based timeouts for worker threads or web application contexts where signals are not available.
pip install timeout-decoratorfrom timeout_decorator import timeout, TimeoutErrorAlternative import pattern:
import timeout_decorator
# Use as timeout_decorator.timeout(5)import time
from timeout_decorator import timeout, TimeoutError
# Basic timeout with default settings (signal-based)
@timeout(5)
def slow_function():
print("Start")
for i in range(1, 10):
time.sleep(1)
print(f"{i} seconds have passed")
# This will raise TimeoutError after 5 seconds
try:
slow_function()
except TimeoutError:
print("Function timed out!")
# Multiprocessing-based timeout for thread-safe contexts
@timeout(3, use_signals=False)
def worker_function():
time.sleep(5) # This will timeout
try:
worker_function()
except TimeoutError:
print("Worker function timed out!")The timeout decorator provides two distinct timeout strategies to accommodate different execution contexts:
signal.SIGALRM to interrupt function executionThe decorator automatically handles strategy selection based on the use_signals parameter, allowing developers to choose the appropriate timeout mechanism for their specific execution context.
The main decorator function that adds timeout functionality to any function. Supports both signal-based and multiprocessing-based timeout strategies with configurable exception handling.
def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exception_message=None):
"""
Add a timeout parameter to a function and return it.
Parameters:
- seconds (float, optional): Time limit in seconds or fractions of a second.
If None is passed, no timeout is applied. This adds flexibility to usage:
you can disable timing out depending on settings.
- use_signals (bool, default=True): Flag indicating whether signals should be
used for timing function out or multiprocessing. When using multiprocessing,
timeout granularity is limited to 10ths of a second.
- timeout_exception (Exception, default=TimeoutError): Custom exception type
to raise on timeout.
- exception_message (str, optional): Custom message for the timeout exception.
Returns:
Decorated function with timeout capability
Raises:
TimeoutError (or custom exception) if time limit is reached
"""Basic timeout with seconds:
@timeout(5)
def my_function():
# Function implementation
passFractional seconds:
@timeout(0.5)
def quick_function():
# Must complete within half a second
passCustom exception type:
@timeout(5, timeout_exception=RuntimeError)
def my_function():
# Will raise RuntimeError instead of TimeoutError
passCustom exception message:
@timeout(5, exception_message="Operation took too long")
def my_function():
# Will raise TimeoutError with custom message
passMultiprocessing strategy (thread-safe):
@timeout(5, use_signals=False)
def thread_worker():
# Safe to use in threads or web applications
passRuntime timeout override:
@timeout(10)
def flexible_function():
pass
# Override timeout at runtime
flexible_function(timeout=5) # Will timeout after 5 seconds instead of 10Disabled timeout:
@timeout() # or @timeout(None)
def conditional_function():
# No timeout applied
passCustom exception raised when timeout occurs, extending Python's AssertionError.
class TimeoutError(AssertionError):
"""
Thrown when a timeout occurs in the timeout decorator.
Parameters:
- value (str, default="Timed Out"): Error message
"""
def __init__(self, value="Timed Out"):
"""Initialize TimeoutError with custom message."""
def __str__(self):
"""Return string representation of the exception."""The decorator works with class methods and instance methods:
class MyClass:
@timeout(5)
def instance_method(self):
# Will timeout after 5 seconds
pass
@classmethod
@timeout(3)
def class_method(cls):
# Will timeout after 3 seconds
passThe decorator preserves original function metadata:
@timeout(5)
def documented_function():
"""This function has documentation."""
pass
# Original function name and documentation are preserved
print(documented_function.__name__) # "documented_function"
print(documented_function.__doc__) # "This function has documentation."from timeout_decorator import timeout, TimeoutError
@timeout(2)
def risky_operation():
# Some operation that might take too long
import requests
return requests.get("https://httpbin.org/delay/5")
try:
result = risky_operation()
print("Operation completed successfully")
except TimeoutError:
print("Operation timed out - implementing fallback")
# Implement fallback logic
except Exception as e:
print(f"Operation failed with error: {e}")
# Handle other exceptionssignal.SIGALRM for timeout implementationuse_signals=False, function arguments and return values must be pickle-serializable