Timerutil is a collection of timer-related utilities for Python. Chances are, you've used tools like these yourself at one point. This library was born out of a desire to avoid needing to reimplement various time-related functionality throughout various Python code bases. Maybe you'll find it similarly useful as well!
Specifically, this library provides the following:
TimeoutManager
: A context manager/decorator for enforcing timeouts around operationsWaiter
: A context manager/decorator which enforces a minimum time restriction on wrapped operations
This class acts as a simple context manager or decorator for enforcing timeouts around operations.
from timerutil import TimeoutManager
with TimeoutManager(10):
something_that_should_not_exceed_ten_seconds()
from timerutil import TimeoutManager
@TimeoutManager(10)
def something_that_should_not_exceed_ten_seconds():
print("If you can't read this, you're under some heavy load.")
By default, TimeoutError
are raised by TimeoutManager
with the platform-specific message
corresponding to the ETIME
error number. If you want something more specific for your use-case,
you can provide one during initialization.
with TimeoutManager(10, timeout_message='Houston, we have a timeout'):
something_that_should_not_exceed_ten_seconds()
Sometimes you don't care if when timeouts occur- maybe it's not important enough to interrupt your application.
In these cases, you can configure TimeoutManager
to suppress timeout errors so that wrapped operations
will fail silently if they exceed your configured duration.
with TimeoutManager(10, suppress_timeout_errors=True):
something_that_should_not_exceed_ten_seconds()
print('Maybe exceeded 10 seconds, but no longer executing either way')
Another context manager/decorator class for enforcing a minimum execution time on wrapped code. This is useful if you're fairly confident that your function should finish in a certain amount of time, but you want to make the return time constant (e.g. to prevent constant-time attacks).
from timerutil import Waiter
@Waiter(10)
def take_ten():
print('Starting to wait')
take_ten()
# Ten seconds later...
print('Done waiting!')
with Waiter(10):
print('Starting to wait')
# Ten seconds later...
print('Done waiting!')
The timerutil.waits
module provides a few additional implementations of the Waiter
class that may be useful
in certain particular scenarios.
This Waiter
subclass which behaves exactly the same as its parent, except that it records usage statistics
for inspection. This also be used as a context manager or a decorator.
with ObservableWaiter(10) as ten_second_waiter:
print('Starting to wait')
print(
'Done waiting after',
ten_second_waiter.last_elapsed,
'seconds'
)
A subclass of ObservableWaiter
, this implementation doesn't actually enforce any minimum execution time. Therefore,
it is especially useful as a way to time wrapped code execution without impacting its behavior or extending its
execution time. Use this for easily logging execution time in Production when solutions like timeit
are impractical.
with StopWatch() as stop_watch:
watch_this()
logging.log(logging.INFO, 'Watched watch_this() do some things for %r seconds', timer.last_runtime)
When subclassed, you can override the StopWatch.__exit__
method to add behaviors for automatically capturing
execution time for your wrapped code- just be sure to call super()
!
class LoggingStopWatch(StopWatch):
def __exit__(self, exc_type, exc_val, exc_tb):
rv = super(LoggingStopWatch, self).__exit__()
my_logger.info('Finished executing after %r seconds' % self.last_runtime)
return rv
- This package has been tested compatible with Python versions 2.7 to 3.7
- As
TimeoutManager
makes use of signals, this utility will not work on Windows platforms - Systems running versions of Python < 3.3 do not have a builtin
TimeoutError
exception class. In these cases, a customTimeoutError
exception will be used instead. - The
contextlib
package in versions of Python < 3.2 does not provide theContextDecorator
class. In these cases, thetimerutil
library will substitute a version of this class (backported from Python 3.4) when defining context manager/decorator utilities.