*** empty log message ***
[pli.git] / pli / pattern / proxy / generic.py
bloba716d64fb46fd32a5cf50360af70e6fce7557773
1 #=======================================================================
3 __version__ = '''0.0.11'''
4 __sub_version__ = '''20040911205351'''
5 __copyright__ = '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 __doc__ = '''\
11 this module will define a set of utilities and classes to be used to build
12 various proxies...
14 NOTE: currently most proxy object do not use weak refs to reference the
15 objcet, thus deleting the object alone will not cause its total
16 removal...
17 '''
20 #-----------------------------------------------------------------------
22 import sys
23 import new
24 import types
25 import weakref
29 #-----------------------------------------------------------------------
30 # Q: does this section belong here, in this module???
31 #---------------------------------------------------------proxymethod---
32 def proxymethod(method_name, depth=1):
33 '''
34 this will create a proxy to the method name in the containing namespace.
36 NOTE: this will add the method_name to the containing namespace.
37 '''
38 # text of the new function....
39 txt = '''\
40 def %(method_name)s(self, *p, **n):
41 """
42 this is the proxy to %(method_name)s method.
43 """
44 return getattr(self, self.__proxy_target_attr_name__).%(method_name)s(*p, **n)
45 proxy = %(method_name)s'''
46 # execute the above code...
47 exec (txt % {'method_name': method_name})
48 # update the NS...
49 sys._getframe(depth).f_locals[method_name] = proxy
52 #--------------------------------------------------------proxymethods---
53 def proxymethods(names, source_attr):
54 '''
55 this will generate a direct proxy for each name in names.
56 '''
57 for name in names:
58 proxymethod(name, source_attr, depth=2)
62 #-----------------------------------------------------------------------
63 #-------------------------------------------------------------isproxy---
64 def isproxy(obj):
65 '''
66 this will return True if obj is a proxy object (relative to AbstractProxy).
68 NOTE: this will work only for the pli framework proxies that inherit
69 from AbstractProxy.
70 '''
71 return isinstance(obj, AbstractProxy)
75 #-----------------------------------------------------------------------
76 # TODO add weakref to target option!!!
77 #-------------------------------------------------------AbstractProxy---
78 class AbstractProxy(object):
79 '''
80 this is a base class for all proxies...
81 '''
82 __proxy_target_attr_name__ = 'proxy_target'
85 #----------------------------------------------------------BasicProxy---
86 class BasicProxy(AbstractProxy):
87 ##!! check !!##
88 def __repr__(self):
89 '''
90 '''
91 return '<%s proxy at %s to %s>' % (object.__getattribute__(self, '__class__').__name__,
92 hex(id(self)),
93 repr(getattr(self, self.__proxy_target_attr_name__)))
97 #-----------------------------------------------------------------------
98 # this section defines component mix-ins...
99 #-----------------------------------------------------ComparibleProxy---
100 class ComparibleProxy(BasicProxy):
102 proxy mixin. this will transfer the rich comparison calls directly
103 to the target...
105 __proxy_target_attr_name__ = 'proxy_target'
107 # these cant be avoided without eval...
108 def __eq__(self, other):
111 return getattr(self, self.__proxy_target_attr_name__) == other
112 def __ne__(self, other):
115 return self.proxy_target != other
116 def __gt__(self, other):
119 return getattr(self, self.__proxy_target_attr_name__) > other
120 def __lt__(self, other):
123 return getattr(self, self.__proxy_target_attr_name__) < other
124 def __ge__(self, other):
127 return getattr(self, self.__proxy_target_attr_name__) >= other
128 def __le__(self, other):
131 return getattr(self, self.__proxy_target_attr_name__) <= other
134 #---------------------------------------------------------CachedProxy---
135 # TODO write a more elaborate cache manager... (wee need to take into
136 # consideration, input args... etc.)
137 # might be good to make an "iscached" predicate...
139 class CachedProxy(BasicProxy):
142 # this may either be None or a dict-like (usualy a weakref.WeakKeyDictionary)
143 # if None the proxy caching will be disabled
144 __proxy_cache__ = None
146 def __new__(cls, source, *p, **n):
149 if hasattr(cls, '__proxy_cache__') and cls.__proxy_cache__ != None:
150 if source in cls.__proxy_cache__:
151 return cls.__proxy_cache__[source]
152 else:
153 res = cls.__proxy_cache__[source] = super(CachedProxy, cls).__new__(cls, source, *p, **n)
154 return res
155 return super(CachedProxy, cls).__new__(cls, source, *p, **n)
159 #-----------------------------------------------------------------------
160 # this section defines ready to use base proxies...
161 #---------------------------------------------InheritAndOverrideProxy---
162 # this is the Proxy cache...
163 _InheritAndOverrideProxy_cache = weakref.WeakKeyDictionary()
165 # NOTE: the problem that might accur here is when we assign to
166 # self.__class__.something
167 # TODO test module support (e.g. proxieng a module)...
168 # TODO make this a child of CachedProxy...
170 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171 # this works as follows:
172 # 1) create a class that inherits from InheritAndOverrideProxy and the
173 # proxiead objects class...
174 # reference code:
175 # class local_proxy(InheritAndOverrideProxy, proxied.__class__):
176 # pass
177 # 2) creates an object from the above class, and sets its __dict__ to
178 # reference the target objects __dict__. thus enabling setting and
179 # referencing data to the proxied object....
181 ##class InheritAndOverrideProxy(CachedProxy):
182 class InheritAndOverrideProxy(BasicProxy):
184 this is a general (semi-transparent) proxy.
186 # this defines the attribute name where the proxy target is
187 # stored...
188 __proxy_target_attr_name__ = 'proxy_target'
189 # this is used to generate unique proxy class names...
190 __proxy_count__ = 0
191 # this may either be None or a dict-like (usualy a weakref.WeakKeyDictionary)
192 # if None the proxy caching will be disabled
193 ## __proxy_cache__ = None
194 __proxy_cache__ = _InheritAndOverrideProxy_cache
196 def __new__(cls, source, *p, **n):
199 osetattr = object.__setattr__
200 cls_name = cls.__name__
201 try:
202 # process proxy cache...
203 if hasattr(cls, '__proxy_cache__') and cls.__proxy_cache__ != None:
204 if source in cls.__proxy_cache__:
205 return cls.__proxy_cache__[source]
206 # create an object of a class (also just created) inherited
207 # from cls and source.__class__
208 _obj = object.__new__(new.classobj('',(cls, source.__class__), {}))
209 # get the new class....
210 cls = object.__getattribute__(_obj, '__class__')
211 # name the new class...
212 # NOTE: the name may not be unique!
213 cls.__name__ = cls_name + '_' + str(cls.__proxy_count__)
214 cls.__proxy_count__ += 1
215 # considering that the class we just created is unique we
216 # can use it as a data store... (and we do not want to
217 # polute the targets dict :) )
218 setattr(cls, cls.__proxy_target_attr_name__, source)
219 # replace the dict so that the proxy behaves exactly like
220 # the target...
221 osetattr(_obj, '__dict__', source.__dict__)
222 # we fall here in case we either are a class constructor, function or a callable....
223 # WARNING: this is Python implementation specific!!
224 except (TypeError, AttributeError):
225 # function or callable
226 if type(source) in (types.FunctionType, types.LambdaType, types.MethodType, weakref.CallableProxyType):
227 # callable wrapper hook...
228 if hasattr(cls, '__proxy_call__') and cls.__proxy_call__ != None:
229 return cls.__proxy_call__(source)
230 return source
231 # class (nested class constructors...)
232 elif callable(source):
233 # class wrapper hook...
234 if hasattr(cls, '__proxy_class__') and cls.__proxy_class__ != None:
235 return cls.__proxy_class__(source)
236 return source
237 # process proxy cache...
238 if hasattr(cls, '__proxy_cache__') and cls.__proxy_cache__ != None:
239 cls.__proxy_cache__[source] = _obj
240 return _obj
241 # this is here to define the minimal __init__ format...
242 def __init__(self, source, *p, **n):
245 super(InheritAndOverrideProxy, self).__init__(source, *p, **n)
246 ## def __proxy_call__(self, target):
247 ## '''
248 ## '''
249 ## return target
250 ## def __proxy_class__(self, target):
251 ## '''
252 ## '''
253 ## return target
256 #-----------------------------------TranparentInheritAndOverrideProxy---
257 # this is the Proxy cache...
258 _TranparentInheritAndOverrideProxy_cache = weakref.WeakKeyDictionary()
259 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
260 # Q: do we need any other magic methods???
261 class TranparentInheritAndOverrideProxy(InheritAndOverrideProxy, ComparibleProxy):
263 this is a tranparent variant of InheritAndOverrideProxy. its' behavior
264 is in no way diferent from the proxied object.
266 NOTE: due to the fact that this explicitly proxies the __getattribute__
267 and __setattr__ calls, it is slower then the semi-transparent
268 variant.
270 __proxy_target_attr_name__ = 'proxy_target'
271 __proxy_count__ = 0
272 __proxy_cache__ = _TranparentInheritAndOverrideProxy_cache
273 # this defines the attributes that are resolved to the proxy itself
274 # (not the target object)...
275 __proxy_public_attrs__ = (
276 'proxy_target',
277 '__proxy_call__',
278 '__proxy_class__',
279 '__proxy_target_attr_name__',
282 def __getattribute__(self, name):
285 if name in object.__getattribute__(self, '__proxy_public_attrs__'):
286 return super(TranparentInheritAndOverrideProxy, self).__getattribute__(name)
287 return self.proxy_target.__getattribute__(name)
288 # directly proxy __setattr__ to the target...
289 proxymethod('__setattr__')
292 #--------------------------------------RecursiveInheritNOverrideProxy---
293 ##!! test...
294 class RecursiveInheritNOverrideProxy(InheritAndOverrideProxy):
297 __wrapper__ = None
300 def __getattribute__(self, name):
303 ogetattribute = object.__getattribute__
304 try:
305 wrapper = ogetattribute(self, '__wrapper__')
306 return wrapper(super(TranparentInheritAndOverrideProxy, self).__getattribute__(name))
307 except:
308 return ogetattribute(self, '__class__')(super(TranparentInheritAndOverrideProxy, self).__getattribute__(name))
312 #=======================================================================
313 if __name__ == '__main__':
315 class O(object):
318 def __call__(self):
321 print 'O object! (', self.__class__, ')',
323 o = O()
325 class Proxy(TranparentInheritAndOverrideProxy):
328 def __call__(self, *p, **n):
331 print 'Proxy:',
332 self.proxy_target(*p, **n)
333 print '.'
335 p = Proxy(o)
338 print '.'
342 p.xxx = 0
343 print o.xxx
345 print o.__class__
346 print p.__class__
348 print o == p
350 print isproxy(p), isproxy(o)
352 print o
353 print p
355 p0 = Proxy(o)
356 p1 = Proxy(o)
358 print p is p0, p0 is p1
361 #=======================================================================
362 # vim:set ts=4 sw=4 nowrap :