Delayed iteration for polling and retries.
Does Python need yet another retry / poll library? It needs at least one that isn't coupled to decorators and functions. Decorators prevent the caller from customizing delay options, and organizing the code around functions hinders any custom handling of failures.
Waiter is built around iteration instead, because the foundation of retrying / polling is a slowly executing loop. The resulting interface is both easier to use and more flexible, decoupling the delay algorithms from the application logic.
Supply a number of seconds to repeat endlessly, or any iterable of seconds.
from waiter import wait wait(1) # 1, 1, 1, 1, ... wait( * 3) # 1, 1, 1 wait([0.5, 0.5, 60]) # circuit breaker
Iterable delays can express any waiting strategy, and constructors for common algorithms are also provided.
wait.count(1) # incremental backoff 1, 2, 3, 4, 5, ... wait(1) + 1 # alternate syntax 1, 2, 3, 4, 5, ... wait.fibonacci(1) # 1, 1, 2, 3, 5, ... wait.polynomial(2) # 0, 1, 4, 9, 16, ... wait.exponential(2) # exponential backoff 1, 2, 4, 8, ... backoff = wait(1) * 2 # alternate syntax 1, 2, 4, 8, ... backoff[:3] # limit attempt count 1, 2, 4 backoff <= 5 # set maximum delay 1, 2, 4, 5, 5, 5, ... backoff.random(-1, 1) # add random jitter
Then simply use the
wait object like any iterable, yielding the amount of elapsed time.
Timeouts also supported of course.
from waiter import wait, suppress, first for elapsed in wait(delays): # first iteration is immediate with suppress(exception): # then each subsequent iteration sleeps as necessary ... break for _ in wait(delays, timeout): # standard convention for ignoring a loop variable ... # won't sleep past the timeout if ...: break results = (... for _ in wait(delays)) # expressions are even easier first(predicate, results[, default]) # filter for first true item assert any(results) # perfect for tests too
Yes, functional versions are provided, as well as being trivial to implement.
wait(...).throttle(iterable) # generate items from iterable wait(...).repeat(func, *args, **kwargs) # generate successive results wait(...).retry(exception, func, *args, **kwargs) # return first success or re-raise exception wait(...).poll(predicate, func, *args, **kwargs) # return first success or raise StopIteration
The decorator variants are simply partial applications of the corresponding methods. Note decorator syntax doesn't support arbitrary expressions.
backoff = wait(0.1) * 2 @backoff.repeating @backoff.retrying(exception) @backoff.polling(predicate)
But in the real world:
- the function may not exist or be succinctly written as a lambda
- the predicate may not exist or be succinctly written as a lambda
- logging may be required
- there may be complex handling of different exceptions or results
So consider the block form, just as decorators don't render
with blocks superfluous.
wait objects are re-iterable provided their original delays were.
In Python >=3.6, waiters also support async iteration.
throttle optionally accepts an async iterable.
poll optionally accept coroutine functions.
Waiter objects have a
stats attribute for aggregating statistics about the calls made.
The base implementation provides
The interface of the
stats object itself is considered provisional for now,
but can be extended by overriding the
Stats class attribute.
This also allows customization of the iterable values; elapsed time is the default.
$ pip install waiter
- multimethod (if Python >=3.6)
100% branch coverage.
$ pytest [--cov]
- Stream from sized groups
- Map a function across an iterable in batches
- Extensible iterable values and statistics
- Additional constructors: fibonacci, polynomial, accumulate
- Asynchronous iteration
- Decorators support methods
- Iterables can be throttled
- Waiters behave as iterables instead of iterators
- Support for function decorators
suppresscontext manager for exception handling
repeatmethod for decoupled iteration
firstfunction for convenient filtering
|Filename, size||File type||Python version||Upload date||Hashes|
|Filename, size waiter-1.1-py2.py3-none-any.whl (7.3 kB)||File type Wheel||Python version py2.py3||Upload date||Hashes View hashes|
|Filename, size waiter-1.1.tar.gz (12.2 kB)||File type Source||Python version None||Upload date||Hashes View hashes|