Files
catalyst/tests/utils/test_cache.py
T
Eddie Hebert 76e14eda2f ENH: Add expiring cache.
Add a cache interface which supports expirable entries with a changeable
backend for the cache into which they are entered.

The default cache is a `dict` but could swapped for
`cachetools.LRUCache` or any other cache which supports `__get__`,
`__set__`, and `__del__`.

So that consumers can change the use of `CachedObjects` stored in a
cache from:

```
self._cache = {}

...

try:
    obj = self._cache[key]
    try:
        return obj.unwrap(dt)
    except Expired:
        pass
except KeyError:
    pass

...

self._cache[key] = CachedObject(value, new_expiration)
```

to:

```
self._cache = ExpiringCache(LRUCache(maxsize=6))

...

try:
    return self._cache.get(key, dt)
except KeyError:
    # Get fresh value
    ...

    self._cache.set(key, value, new_expiration)
```
2016-04-14 16:10:32 -04:00

61 lines
1.9 KiB
Python

from unittest import TestCase
from pandas import Timestamp, Timedelta
from zipline.utils.cache import CachedObject, Expired, ExpiringCache
class CachedObjectTestCase(TestCase):
def test_cached_object(self):
expiry = Timestamp('2014')
before = expiry - Timedelta('1 minute')
after = expiry + Timedelta('1 minute')
obj = CachedObject(1, expiry)
self.assertEqual(obj.unwrap(before), 1)
self.assertEqual(obj.unwrap(expiry), 1) # Unwrap on expiry is allowed.
with self.assertRaises(Expired) as e:
obj.unwrap(after)
self.assertEqual(e.exception.args, (expiry,))
class ExpiringCacheTestCase(TestCase):
def test_expiring_cache(self):
expiry_1 = Timestamp('2014')
before_1 = expiry_1 - Timedelta('1 minute')
after_1 = expiry_1 + Timedelta('1 minute')
expiry_2 = Timestamp('2015')
after_2 = expiry_1 + Timedelta('1 minute')
expiry_3 = Timestamp('2016')
cache = ExpiringCache()
cache.set('foo', 1, expiry_1)
cache.set('bar', 2, expiry_2)
self.assertEqual(cache.get('foo', before_1), 1)
# Unwrap on expiry is allowed.
self.assertEqual(cache.get('foo', expiry_1), 1)
with self.assertRaises(KeyError) as e:
self.assertEqual(cache.get('foo', after_1))
self.assertEqual(e.exception.args, ('foo',))
# Should raise same KeyError after deletion.
with self.assertRaises(KeyError) as e:
self.assertEqual(cache.get('foo', before_1))
self.assertEqual(e.exception.args, ('foo',))
# Second value should still exist.
self.assertEqual(cache.get('bar', after_2), 2)
# Should raise similar KeyError on non-existent key.
with self.assertRaises(KeyError) as e:
self.assertEqual(cache.get('baz', expiry_3))
self.assertEqual(e.exception.args, ('baz',))