-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache.py
More file actions
191 lines (140 loc) · 5.22 KB
/
Copy pathcache.py
File metadata and controls
191 lines (140 loc) · 5.22 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
from types import FunctionType
import backends
__storage = backends.default()
def set_storage(BackendInstance):
global __storage
__storage = BackendInstance
def make_cached(make_key, f):
def cached(*args, **kwargs):
cache_key = make_key(args=args, kwargs=kwargs)
if __storage.has(cache_key):
return __storage.get(cache_key)
value = f(*args, **kwargs)
__storage.set(cache_key, value)
return value
return cached
def cache_function(function_or_key):
key = 'function:'
if type(function_or_key) is FunctionType:
"""No args to decorator makes the first arg the
function to be decorated"""
f = function_or_key
key = key + f.__name__
def make_key(args=None, kwargs=None):
return key + f.__name__ + str(args) + str(kwargs)
return make_cached(make_key, f)
else:
"""Arguments have been passed to the decorator.
The user wants to override automatic key creation and always
use the same, so do that here"""
key += function_or_key
def make_decorator(f):
def make_key(args=None, kwargs=None):
return key + ':' + f.__name__
return make_cached(make_key, f)
return make_decorator
__register = []
__open_queue = False
__in_init = False
__cache = {}
__next_provider = None
__update = []
def __register_update(id_, values):
__update.append((id_, values))
def do_updates():
global __update
for id_, values in __update:
__storage.set(id_, values)
__update = []
def __do_queue():
global __register
global __cache
global __open_queue
__open_queue = False
for id_, self, provider in __register:
if not __storage.has(id_):
__storage.set(id_, provider(self))
self.__cached__ = __storage.get(id_)
__register = []
def __register_class(id_, self, provider):
global __open_queue
__register.append((id_, self, provider))
__open_queue = True
def __make_id(cls, self, id_attribute):
return 'class:' + cls.__name__ + str(self.__dict__[id_attribute])
def __should_do_queue(self):
if not __open_queue:
return False
if '__in_init' in self.__dict__:
if self.__dict__['__in_init']:
return False
else:
return False
return True
def cache_class(id_attribute):
"""Cachable attributes don't have to be specified since
self.__cached__.keys() will provide all attributes that were
retrieved from cache (and could subsequently be updated).
"""
def make_class(cls):
global __next_provider
if __next_provider is None:
raise LookupError("No provider function declared. Put"
+ " the 'cache_provider' decorator on the"
+ " function that returns data for the"
+ " instance")
provider_function = __next_provider
__next_provider = None
old_init = cls.__init__
def new_init(self, *args, **kwargs):
self.__in_init = True
old_init(self, *args, **kwargs)
self.__in_init = False
__register_class(__make_id(cls, self, id_attribute),
self, provider_function)
cls.__init__ = new_init
old_getattribute = cls.__getattribute__
def new_getattribute(self, key):
if key != '__dict__' and key != '__cached__':
if __should_do_queue(self):
__do_queue()
if hasattr(self, '__cached__') and key in self.__cached__:
return self.__cached__[key]
return old_getattribute(self, key)
cls.__getattribute__ = new_getattribute
old_setattr = cls.__setattr__
def new_setattr(self, key, value):
if key != '__cache__':
if __should_do_queue(self):
__do_queue()
if hasattr(self, '__cached__'):
"""Only check for updatable cache values
when a cache dict exists"""
if not hasattr(self, '__cachable_attrs'):
self.__dict__['__cachable_attrs'] = \
self.__dict__['__cached__'].keys()
if key in self.__dict__['__cachable_attrs']:
if key != self.__dict__['__cached__'][key]:
self.__dict__['__cached__'][key] = value
__register_update(
__make_id(cls, self, id_attribute),
self.__cached__)
return
old_setattr(self, key, value)
cls.__setattr__ = new_setattr
def hasattr(self, key):
if __should_do_queue(self):
__do_queue()
if '__cache__' in self.__dict__:
if key in self.__dict__['__cache__']:
return True
if key in self.__dict__:
return True
return False
cls.__hasattr__ = hasattr
return cls
return make_class
def cache_provider(f):
global __next_provider
__next_provider = f
return f