Timeout decorator for synchronous and asynchronous functions.
Written in pure Python
and has no dependencies other than the base libraries.
From source code:
pip install .
From PyPI
:
pip install timeout-function-decorator
There are three ways to import the decorator:
- Import directly from the package
from timeout_function_decorator import timeout
- Import directly from the module
from timeout_function_decorator.timeout_decorator import timeout
- Import the module
from timeout_function_decorator import timeout_decorator
This last case is useful if a timeout
function is already present in your namespace.
Using the decorator is as simple as:
import time
from timeout_function_decorator import timeout
@timeout()
def i_will_never_time_out(value):
while True:
time.sleep(1)
@timeout(None)
def i_will_never_time_out(value):
while True:
time.sleep(1)
@timeout(1)
def i_will_not_time_out(value):
return value
@timeout(1)
def i_will_time_out(value):
time.sleep(2)
return value
@timeout(1, RuntimeError)
def i_will_raise_runtime_error(value):
time.sleep(2)
return value
As you may have noticed, the decorator requires the brackets even when no parameters are passed.
The same result could be obtained for asynchronous functions:
import asyncio
from timeout_function_decorator import timeout
@timeout()
async def i_will_never_time_out(value):
while True:
await asyncio.sleep(1)
@timeout(None)
async def i_will_never_time_out(value):
while True:
await asyncio.sleep(1)
@timeout(1)
async def i_will_not_time_out(value):
return value
@timeout(1)
async def i_will_time_out(value):
await asyncio.sleep(2)
return value
@timeout(1, RuntimeError)
async def i_will_raise_runtime_error(value):
await asyncio.sleep(2)
return value
If you already have a timeout
function in your namespace, you could as easily use the decorator with the module namespace:
import time
from timeout_function_decorator import timeout_decorator
@timeout_decorator.timeout(1)
def i_still_time_out(value):
time.sleep(2)
return value
⚠️ Warning: When a function times out, an exception is raised but cancellation is not guaranteed. This decorator only notifies the user when enough time has passed since a function call. Handling of the situation and ensuring cancellation is up to the user.
In general, the decorator accepts two parameters:
timeout_duration
: afloat
specifying the timeout time in seconds. IfNone
, the function will not time out. Defaults toNone
exception_to_raise
: theException
type to be raised. Defaults toTimeoutError
.
They can be passed as positional or keyword arguments.
The wrapper uses asyncio and threads to keep track of timeouts. This adds a non-trivial overhead on the wrapped functions, in particular on the synchronous ones as they need a thread to be created.
As such, common use cases would include test suites where control on what happens when they time out is important, as with
packages like pytest-timeout
you can not have tests fail with a specified exception.
Use cases in production code, on the other hand, would be limited to long functions with a low call rate as the overhead is linear with the number of calls but independent of the size of the function or its execution time.
A notebook outlining the impact of the overhead on sync and async functions can be found here.
Plots from the notebook are presented below for a quick performance evaluation.