-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobjproxies.py
215 lines (159 loc) · 6.08 KB
/
objproxies.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import sys
if sys.version_info.major < 3:
raise ImportError(
'objproxies requires Python 3. For Python 2, refer to ProxyTypes '
'<http://cheeseshop.python.org/pypi/ProxyTypes>')
class AbstractProxy(object):
"""Delegates all operations (except ``.__subject__``) to another object"""
__slots__ = ()
def __call__(self, *args, **kw):
return self.__subject__(*args, **kw)
def __getattribute__(self, attr, oga=object.__getattribute__):
subject = oga(self, '__subject__')
if attr == '__subject__':
return subject
return getattr(subject, attr)
def __setattr__(self, attr, val, osa=object.__setattr__):
if attr == '__subject__':
osa(self, attr, val)
else:
setattr(self.__subject__, attr, val)
def __delattr__(self, attr, oda=object.__delattr__):
if attr == '__subject__':
oda(self, attr)
else:
delattr(self.__subject__, attr)
def __bool__(self):
return bool(self.__subject__)
def __getitem__(self, arg):
return self.__subject__[arg]
def __setitem__(self, arg, val):
self.__subject__[arg] = val
def __delitem__(self, arg):
del self.__subject__[arg]
def __getslice__(self, i, j):
return self.__subject__[i:j]
def __setslice__(self, i, j, val):
self.__subject__[i:j] = val
def __delslice__(self, i, j):
del self.__subject__[i:j]
def __contains__(self, ob):
return ob in self.__subject__
for name in 'repr str hash len abs complex int long float iter'.split():
exec("def __%s__(self): return %s(self.__subject__)" % (name, name))
for name in 'cmp', 'coerce', 'divmod':
exec("def __%s__(self, ob): return %s(self.__subject__, ob)" % (name, name))
for name, op in [
('lt', '<'), ('gt', '>'), ('le', '<='), ('ge', '>='),
('eq', ' == '), ('ne', '!=')
]:
exec("def __%s__(self, ob): return self.__subject__ %s ob" % (name, op))
for name, op in [('neg', '-'), ('pos', '+'), ('invert', '~')]:
exec("def __%s__(self): return %s self.__subject__" % (name, op))
for name, op in [
('or', '|'), ('and', '&'), ('xor', '^'), ('lshift', '<<'), ('rshift', '>>'),
('add', '+'), ('sub', '-'), ('mul', '*'), ('div', '/'), ('mod', '%'),
('truediv', '/'), ('floordiv', '//')
]:
exec((
"def __%(name)s__(self, ob):\n"
" return self.__subject__ %(op)s ob\n"
"\n"
"def __r%(name)s__(self, ob):\n"
" return ob %(op)s self.__subject__\n"
"\n"
"def __i%(name)s__(self, ob):\n"
" self.__subject__ %(op)s=ob\n"
" return self\n"
) % locals())
del name, op
# Oddball signatures
def __index__(self):
return self.__subject__.__index__()
def __rdivmod__(self, ob):
return divmod(ob, self.__subject__)
def __pow__(self, *args):
return pow(self.__subject__, *args)
def __ipow__(self, ob):
self.__subject__ **= ob
return self
def __rpow__(self, ob):
return pow(ob, self.__subject__)
class ObjectProxy(AbstractProxy):
"""Proxy for a specific object"""
__slots__ = "__subject__"
def __init__(self, subject):
self.__subject__ = subject
class CallbackProxy(AbstractProxy):
"""Proxy for a dynamically-chosen object"""
__slots__ = '__callback__'
def __init__(self, func):
set_callback(self, func)
set_callback = CallbackProxy.__callback__.__set__
get_callback = CallbackProxy.__callback__.__get__
CallbackProxy.__subject__ = property(lambda self, gc=get_callback: gc(self)())
class LazyProxy(CallbackProxy):
"""Proxy for a lazily-obtained object, that is cached on first use"""
__slots__ = "__cache__"
get_cache = LazyProxy.__cache__.__get__
set_cache = LazyProxy.__cache__.__set__
def __subject__(self, get_cache=get_cache, set_cache=set_cache):
try:
return get_cache(self)
except AttributeError:
set_cache(self, get_callback(self)())
return get_cache(self)
LazyProxy.__subject__ = property(__subject__, set_cache)
del __subject__
class AbstractWrapper(AbstractProxy):
"""Mixin to allow extra behaviors and attributes on proxy instance"""
__slots__ = ()
def __getattribute__(self, attr, oga=object.__getattribute__):
if attr.startswith('__'):
subject = oga(self, '__subject__')
if attr == '__subject__':
return subject
return getattr(subject, attr)
return oga(self, attr)
def __getattr__(self, attr, oga=object.__getattribute__):
return getattr(oga(self, '__subject__'), attr)
def __setattr__(self, attr, val, osa=object.__setattr__):
if (
attr == '__subject__' or
hasattr(type(self), attr) and not attr.startswith('__')
):
osa(self, attr, val)
else:
setattr(self.__subject__, attr, val)
def __delattr__(self, attr, oda=object.__delattr__):
if (
attr == '__subject__' or
hasattr(type(self), attr) and not attr.startswith('__')
):
oda(self, attr)
else:
delattr(self.__subject__, attr)
class ObjectWrapper(ObjectProxy, AbstractWrapper):
__slots__ = ()
class CallbackWrapper(CallbackProxy, AbstractWrapper):
__slots__ = ()
class LazyWrapper(LazyProxy, AbstractWrapper):
__slots__ = ()
def lazymethod(method):
"""
Decorator for overriding methods on LazyWrapper classes, that fill in until
lazy initialization.
"""
import functools
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
try:
get_cache(self)
except AttributeError:
return method(self, *args, **kwargs)
else:
if method.__name__.startswith('__'):
return getattr(LazyProxy, method.__name__)(self, *args, **kwargs)
else:
return getattr(self.__subject__, method.__name__)(*args, **kwargs)
return wrapper