forked from Kyria/EsiPy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcache.py
171 lines (126 loc) · 5.08 KB
/
cache.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# -*- encoding: utf-8 -*-
""" Cache objects for EsiPy """
import hashlib
import logging
import time
try:
import pickle
except ImportError: # pragma: no cover
import cPickle as pickle
LOGGER = logging.getLogger(__name__)
def _hash(data):
""" generate a hash from data object to be used as cache key """
hash_algo = hashlib.new('md5')
hash_algo.update(pickle.dumps(data))
# prefix allows possibility of multiple applications
# sharing same keyspace
return 'esi_' + hash_algo.hexdigest()
class BaseCache(object):
""" Base cache 'abstract' object that defined
the cache methods used in esipy
"""
def set(self, key, value, timeout=300):
""" Set a value in the cache. If timeout=(None): never expires """
raise NotImplementedError
def get(self, key, default=None):
""" Get a value in the cache, return default if not exist """
raise NotImplementedError
def invalidate(self, key):
""" Invalidate a cache key """
raise NotImplementedError
class FileCache(BaseCache):
""" BaseCache implementation using files to store the data.
This implementation uses diskcache.Cache
see http://www.grantjenks.com/docs/diskcache/api.html#cache for more
informations
This cache requires you to install diskcache using `pip install diskcache`
"""
def __init__(self, path, **settings):
""" Constructor
Arguments:
path {String} -- The path on the disk to save the data
settings {dict} -- The settings values for diskcache
"""
from diskcache import Cache
self._cache = Cache(path, **settings)
def __del__(self):
""" Close the connection as the cache instance is deleted.
Safe to use as there are no circular ref.
"""
self._cache.close()
def set(self, key, value, timeout=300):
expire_time = None if timeout == 0 else timeout
self._cache.set(_hash(key), value, expire=expire_time)
def get(self, key, default=None):
return self._cache.get(_hash(key), default)
def invalidate(self, key):
self._cache.delete(_hash(key))
class DictCache(BaseCache):
""" BaseCache implementation using Dict to store the cached data. """
def __init__(self):
self._dict = {}
def get(self, key, default=None):
cache_val = self._dict.get(key, (None, 0))
if cache_val[1] is not None and cache_val[1] < time.time():
self.invalidate(key)
return default
return cache_val[0]
def set(self, key, value, timeout=300):
if timeout is None or timeout == 0:
expire_time = None
else:
expire_time = timeout + time.time()
self._dict[key] = (value, expire_time)
def invalidate(self, key):
self._dict.pop(key, None)
class DummyCache(BaseCache):
""" Base cache implementation that provide a fake cache that
allows a "no cache" use without breaking everything """
def __init__(self):
self._dict = {}
def get(self, key, default=None):
return None
def set(self, key, value, timeout=300):
pass
def invalidate(self, key):
pass
class MemcachedCache(BaseCache):
""" Base cache implementation for memcached.
This cache requires you to install memcached using
`pip install python-memcached`
"""
def __init__(self, memcache_client):
""" memcache_client must be an instance of memcache.Client().
"""
import memcache
if not isinstance(memcache_client, memcache.Client):
raise TypeError('cache must be an instance of memcache.Client')
self._mc = memcache_client
def get(self, key, default=None):
value = self._mc.get(_hash(key))
return value if value is not None else default
def set(self, key, value, timeout=300):
expire_time = 0 if timeout is None else timeout
return self._mc.set(_hash(key), value, expire_time)
def invalidate(self, key):
return self._mc.delete(_hash(key))
class RedisCache(BaseCache):
""" BaseCache implementation for Redis cache.
This cache handler requires the redis package to be installed
`pip install redis`
"""
def __init__(self, redis_client):
""" redis_client must be an instance of redis.Redis"""
from redis import Redis
if not isinstance(redis_client, Redis):
raise TypeError('cache must be an instance of redis.Redis')
self._r = redis_client
def get(self, key, default=None):
value = self._r.get(_hash(key))
return pickle.loads(value) if value is not None else default
def set(self, key, value, timeout=300):
if timeout is None or timeout == 0:
return self._r.set(_hash(key), pickle.dumps(value))
return self._r.setex(_hash(key), pickle.dumps(value), timeout)
def invalidate(self, key):
return self._r.delete(_hash(key))