1 #=======================================================================
3 __version__
= '''0.0.11'''
4 __sub_version__
= '''20040911205351'''
5 __copyright__
= '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
11 this module will define a set of utilities and classes to be used to build
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
20 #-----------------------------------------------------------------------
29 #-----------------------------------------------------------------------
30 # Q: does this section belong here, in this module???
31 #---------------------------------------------------------proxymethod---
32 def proxymethod(method_name
, depth
=1):
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.
38 # text of the new function....
40 def %(method_name)s(self, *p, **n):
42 this is the proxy to %(method_name)s method.
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
})
49 sys
._getframe
(depth
).f_locals
[method_name
] = proxy
52 #--------------------------------------------------------proxymethods---
53 def proxymethods(names
, source_attr
):
55 this will generate a direct proxy for each name in names.
58 proxymethod(name
, source_attr
, depth
=2)
62 #-----------------------------------------------------------------------
63 #-------------------------------------------------------------isproxy---
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
71 return isinstance(obj
, AbstractProxy
)
75 #-----------------------------------------------------------------------
76 # TODO add weakref to target option!!!
77 #-------------------------------------------------------AbstractProxy---
78 class AbstractProxy(object):
80 this is a base class for all proxies...
82 __proxy_target_attr_name__
= 'proxy_target'
85 #----------------------------------------------------------BasicProxy---
86 class BasicProxy(AbstractProxy
):
91 return '<%s proxy at %s to %s>' % (object.__getattribute
__(self
, '__class__').__name
__,
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
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
]
153 res
= cls
.__proxy
_cache
__[source
] = super(CachedProxy
, cls
).__new
__(cls
, source
, *p
, **n
)
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...
175 # class local_proxy(InheritAndOverrideProxy, proxied.__class__):
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
188 __proxy_target_attr_name__
= 'proxy_target'
189 # this is used to generate unique proxy class names...
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
__
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
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
)
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
)
237 # process proxy cache...
238 if hasattr(cls
, '__proxy_cache__') and cls
.__proxy
_cache
__ != None:
239 cls
.__proxy
_cache
__[source
] = _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):
250 ## def __proxy_class__(self, 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
270 __proxy_target_attr_name__
= 'proxy_target'
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__
= (
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---
294 class RecursiveInheritNOverrideProxy(InheritAndOverrideProxy
):
300 def __getattribute__(self
, name
):
303 ogetattribute
= object.__getattribute
__
305 wrapper
= ogetattribute(self
, '__wrapper__')
306 return wrapper(super(TranparentInheritAndOverrideProxy
, self
).__getattribute
__(name
))
308 return ogetattribute(self
, '__class__')(super(TranparentInheritAndOverrideProxy
, self
).__getattribute
__(name
))
312 #=======================================================================
313 if __name__
== '__main__':
321 print 'O object! (', self
.__class
__, ')',
325 class Proxy(TranparentInheritAndOverrideProxy
):
328 def __call__(self
, *p
, **n
):
332 self
.proxy_target(*p
, **n
)
350 print isproxy(p
), isproxy(o
)
358 print p
is p0
, p0
is p1
361 #=======================================================================
362 # vim:set ts=4 sw=4 nowrap :