Source code for toolbox.functools.timeout
import asyncio
import datetime
import functools
import inspect
import signal
from typing import Awaitable, Callable, Union
[docs]
def timeout(
days: int = 0,
hours: int = 0,
minutes: int = 0,
seconds: int = 0,
error: bool = False,
) -> Union[Callable, Awaitable]:
"""
Wait for *time* before quitting *func* run and returning None.
This decorator works with both asynchronous and synchronous functions. Note,
however, that with synchronous function the *signal* module is used and
therefore will not work with non-Unix based systems.
Args:
days: Days to wait before timeout.
hours: Hours to wait before timeout.
minutes: Minutes to wait before timeout.
seconds: Seconds to wait before timeout.
error: Indicates whether or not to throw ``TimeoutError`` error once function timeouts.
Example:
.. code-block:: python
from toolbox.functools.timeout import timeout
@timeout(seconds=5)
def func():
time.wait(15)
func()
"""
td = datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
total_seconds = int(td.total_seconds())
def wrapper(func: Union[Callable, Awaitable]):
"""
Wraps async or sync function with timeout functionality.
"""
@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
"""
Leverages the asyncio.wait_for() function to wait for a given amount of time.
"""
try:
return await asyncio.wait_for(func(*args, **kwargs), total_seconds)
except asyncio.TimeoutError as err:
if error:
raise TimeoutError(
"Function {} timed out.".format(func.__name__)
) from err
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
"""
Leverages the signal.alarm() function to wait for a given amount of time.
"""
def _handle_timeout(signum, frame):
raise TimeoutError
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(total_seconds)
try:
return func(*args, **kwargs)
except TimeoutError as err:
if error:
raise TimeoutError(
"Function {} timed out.".format(func.__name__)
) from err
if inspect.iscoroutinefunction(func):
return async_wrapper
else:
return sync_wrapper
return wrapper