A FutureCollection is an object to store and interact with :class:`concurrent.futures.Future` objects. It provides access to all attributes and methods of a Future by proxying attribute calls to the stored Future object. To access the methods of a Future from a FutureCollection inst
| 5 | |
| 6 | |
| 7 | class FutureCollection: |
| 8 | """A FutureCollection is an object to store and interact with |
| 9 | :class:`concurrent.futures.Future` objects. It provides access to all |
| 10 | attributes and methods of a Future by proxying attribute calls to the |
| 11 | stored Future object. |
| 12 | |
| 13 | To access the methods of a Future from a FutureCollection instance, include |
| 14 | a valid ``future_key`` value as the first argument of the method call. To |
| 15 | access attributes, call them as though they were a method with |
| 16 | ``future_key`` as the sole argument. If ``future_key`` does not exist, the |
| 17 | call will always return None. If ``future_key`` does exist but the |
| 18 | referenced Future does not contain the requested attribute an |
| 19 | :exc:`AttributeError` will be raised. |
| 20 | |
| 21 | To prevent memory exhaustion a FutureCollection instance can be bounded by |
| 22 | number of items using the ``max_length`` parameter. As a best practice, |
| 23 | Futures should be popped once they are ready for use, with the proxied |
| 24 | attribute form used to determine whether a Future is ready to be used or |
| 25 | discarded. |
| 26 | |
| 27 | :param max_length: Maximum number of Futures to store. Oldest Futures are |
| 28 | discarded first. |
| 29 | |
| 30 | """ |
| 31 | |
| 32 | def __init__(self, max_length=50): |
| 33 | self.max_length = max_length |
| 34 | self._futures = OrderedDict() |
| 35 | |
| 36 | def __contains__(self, future): |
| 37 | return future in self._futures.values() |
| 38 | |
| 39 | def __len__(self): |
| 40 | return len(self._futures) |
| 41 | |
| 42 | def __getattr__(self, attr): |
| 43 | # Call any valid Future method or attribute |
| 44 | def _future_attr(future_key, *args, **kwargs): |
| 45 | if future_key not in self._futures: |
| 46 | return None |
| 47 | future_attr = getattr(self._futures[future_key], attr) |
| 48 | if callable(future_attr): |
| 49 | return future_attr(*args, **kwargs) |
| 50 | return future_attr |
| 51 | |
| 52 | return _future_attr |
| 53 | |
| 54 | def _check_limits(self): |
| 55 | if self.max_length is not None: |
| 56 | while len(self._futures) > self.max_length: |
| 57 | self._futures.popitem(last=False) |
| 58 | |
| 59 | def add(self, future_key, future): |
| 60 | """Add a new Future. If ``max_length`` limit was defined for the |
| 61 | FutureCollection, old Futures may be dropped to respect this limit. |
| 62 | |
| 63 | :param future_key: Key for the Future to be added. |
| 64 | :param future: Future to be added. |
no outgoing calls