PK42EGG-INFO/dependency_links.txt PK47SBEGG-INFO/namespace_packages.txtpeak peak.util PK4)&&EGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: ProxyTypes Version: 0.9 Summary: General purpose proxy and wrapper types Home-page: http://cheeseshop.python.org/pypi/ProxyTypes Author: Phillip J. Eby Author-email: peak@eby-sarna.com License: PSF or ZPL Description: Simple Proxy Types ================== The ``peak.util.proxies`` module provides some useful base classes for creating proxies and wrappers for ordinary Python objects. Proxy objects automatically delegate all attribute access and operations to the proxied object. Wrappers are similar, but can be subclassed to allow additional attributes and operations to be added to the wrapped object. Note that these proxy types are not intended to be tamper-proof; the unproxied form of an object can be readily accessed using a proxy's ``__subject__`` attribute, and some proxy types even allow this attribute to be set. (This can be handy for algorithms that lazily create circular structures and thus need to be able to hand out "forward reference" proxies.) .. contents:: **Table of Contents** Proxy Basics ------------ Here's a quick demo of the ``ObjectProxy`` type:: >>> from peak.util.proxies import ObjectProxy >>> p = ObjectProxy(42) >>> p 42 >>> isinstance(p, int) True >>> p.__class__ >>> p*2 84 >>> 'X' * p 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' >>> hex(p) '0x2a' >>> chr(p) '*' >>> p ^ 1 43 >>> p ** 2 1764 As you can see, a proxy is virtually indistinguishable from the object it proxies, except via its ``__subject__`` attribute, and its ``type()``:: >>> p.__subject__ 42 >>> type(p) You can change the ``__subject__`` of an ``ObjectProxy``, and it will then refer to something else:: >>> p.__subject__ = 99 >>> p 99 >>> p-33 66 >>> p.__subject__ = "foo" >>> p 'foo' All operations are delegated to the subject, including setattr and delattr:: >>> class Dummy: pass >>> d = Dummy() >>> p = ObjectProxy(d) >>> p.foo = "bar" >>> d.foo 'bar' >>> del p.foo >>> hasattr(d,'foo') False Callback Proxies ---------------- Sometimes, you may want a proxy's subject to be determined dynamically whenever the proxy is used. For this purpose, you can use the ``CallbackProxy`` type, which accepts a callback function and creates a proxy that will invoke the callback in order to get the target. Here's a quick example of a counter that gets incremented each time it's used, from zero to three:: >>> from peak.util.proxies import CallbackProxy >>> callback = iter(range(4)).next >>> counter = CallbackProxy(callback) >>> counter 0 >>> counter 1 >>> str(counter) '2' >>> hex(counter) '0x3' >>> counter Traceback (most recent call last): ... StopIteration As you can see, the callback is automatically invoked on any attempt to use the proxy. This is a somewhat silly example; a better one would be something like a ``thread_id`` proxy that is always equal to the ID # of the thread it's running in. A callback proxy's callback can be obtained or changed via the ``get_callback`` and ``set_callback`` functions:: >>> from peak.util.proxies import get_callback, set_callback >>> set_callback(counter, lambda: 42) >>> counter 42 >>> get_callback(counter) at ...> Lazy Proxies ------------ A ``LazyProxy`` is similar to a ``DynamicProxy``, but its callback is called at most once, and then cached:: >>> from peak.util.proxies import LazyProxy >>> def callback(): ... print "called!" ... return 42 >>> lazy = LazyProxy(callback) >>> lazy called! 42 >>> lazy 42 You can use the ``get_callback`` and ``set_callback`` functions on lazy proxies, but it has no effect if the callback was already called:: >>> set_callback(lazy, lambda: 99) >>> lazy 42 But you can use the ``get_cache`` and ``set_cache`` functions to tamper with the cached value:: >>> from peak.util.proxies import get_cache, set_cache >>> get_cache(lazy) 42 >>> set_cache(lazy, 99) >>> lazy 99 Wrappers -------- The ``ObjectWrapper``, ``CallbackWrapper`` and ``LazyWrapper`` classes are similar to their proxy counterparts, except that they are intended to be subclassed in order to add custom extra attributes or methods. Any attribute that exists in a subclass of these classes will be read or written from the wrapper instance, instead of the wrapped object. For example:: >>> from peak.util.proxies import ObjectWrapper >>> class NameWrapper(ObjectWrapper): ... name = None ... def __init__(self, ob, name): ... ObjectWrapper.__init__(self, ob) ... self.name = name ... def __str__(self): ... return self.name >>> w = NameWrapper(42, "The Ultimate Answer") >>> w 42 >>> print w The Ultimate Answer >>> w * 2 84 >>> w.name 'The Ultimate Answer' Notice that any attributes you add must be defined *in the class*. You can't add arbitary attributes at runtime, because they'll be set on the wrapped object instead of the wrapper:: >>> w.foo = 'bar' Traceback (most recent call last): ... AttributeError: 'int' object has no attribute 'foo' Note that this means that all instance attributes must be implemented as either slots, properties, or have a default value defined in the class body (like the ``name = None`` shown in the example above. The ``CallbackWrapper`` and ``LazyWrapper`` base classes are basically the same as ``ObjectWrapper``, except that they use a callback or cached lazy callback instead of expecting an object as their subject. Creating Custom Subclasses and Mixins ------------------------------------- In addition to all the concrete classes described above, there are also two abstract base classes: ``AbstractProxy`` and ``AbstractWrapper``. If you want to create a mixin type that can be used with any of the concrete types, you should subclass the abstract version and set ``__slots__`` to an empty list:: >>> from peak.util.proxies import AbstractWrapper >>> class NamedMixin(AbstractWrapper): ... __slots__ = [] ... name = None ... def __init__(self, ob, name): ... super(NamedMixin, self).__init__(ob) ... self.name = name ... def __str__(self): ... return self.name Then, when you mix it in with the respective base class, you can add back in any necessary slots, or leave off ``__slots__`` to give the subclass instances a dictionary of their own:: >>> from peak.util.proxies import CallbackWrapper, LazyWrapper >>> class NamedObject(NamedMixin, ObjectWrapper): pass >>> class NamedCallback(NamedMixin, CallbackWrapper): pass >>> class NamedLazy(NamedMixin, LazyWrapper): pass >>> print NamedObject(42, "The Answer") The Answer >>> n = NamedCallback(callback, "Test") >>> n called! 42 >>> n called! 42 >>> n = NamedLazy(callback, "Once") >>> n called! 42 >>> n 42 Both the ``AbstractProxy`` and ``AbstractWrapper`` base classes work by assuming that ``self.__subject__`` will be the wrapped or proxied object. If you don't want to use any of the standard three ways of defining ``__subject__`` (i.e., as an object, callback, or lazy callback), you will need to subclass ``AbstractProxy`` or ``AbstractWrapper`` and provide your own way of defining ``__subject__``. Mailing List ------------ Please direct questions regarding this package to the PEAK mailing list; see http://www.eby-sarna.com/mailman/listinfo/PEAK/ for details. Platform: UNKNOWN PK4(m00EGG-INFO/SOURCES.txtREADME.txt quirky-tests.txt setup.py test_proxies.py ProxyTypes.egg-info/PKG-INFO ProxyTypes.egg-info/SOURCES.txt ProxyTypes.egg-info/dependency_links.txt ProxyTypes.egg-info/namespace_packages.txt ProxyTypes.egg-info/top_level.txt peak/__init__.py peak/util/__init__.py peak/util/proxies.py PK4EGG-INFO/top_level.txtpeak PK 42EGG-INFO/zip-safe PK\4i77peak/__init__.py__import__('pkg_resources').declare_namespace(__name__)PK 4+\-peak/__init__.pyc; Dc@sediedS(s pkg_resourcesN(s __import__sdeclare_namespaces__name__(((s&build\bdist.win32\egg\peak\__init__.pys?sPK4q2Dpeak/util/proxies.pyclass 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 __nonzero__(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 oct hex'.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 __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__ = () PK 4`}((peak/util/proxies.pyc; 5ܾDc@s&defdYZdefdYZdefdYZeiiZeiiZe ede_ defdYZ e i iZ e i iZe ed Z e e ee _ [ d efd YZd eefd YZdeefdYZde efdYZdS(s AbstractProxyc BsFtZdZfZdZeidZeidZeidZdZ dZ dZ dZ d Z d Zd Zd Zx&d iD]ZdeefdUqWx)dddfD]ZdeefdUqWx\ddfddfddfddfddfddfgD]\ZZd eefdUq"WxAd!d"fd#d$fd%d&fgD]\ZZd'eefdUqfWxd(d)fd*d+fd,d-fd.d/fd0d1fd2d$fd3d"fd4d5fd6d7fd8d9fd:d7fd;d<fg D]\ZZd=edUqW[[d>Zd?Zd@ZdAZRS(BsDDelegates all operations (except ``.__subject__``) to another objectcOs|i||SdS(N(sselfs __subject__sargsskw(sselfsargsskw((s*build\bdist.win32\egg\peak\util\proxies.pys__call__scCs5||d}|djo|Snt||SdS(Ns __subject__(sogasselfssubjectsattrsgetattr(sselfsattrsogassubject((s*build\bdist.win32\egg\peak\util\proxies.pys__getattribute__s cCs8|djo||||nt|i||dS(Ns __subject__(sattrsosasselfsvalssetattrs __subject__(sselfsattrsvalsosa((s*build\bdist.win32\egg\peak\util\proxies.pys __setattr__s cCs2|djo|||nt|i|dS(Ns __subject__(sattrsodasselfsdelattrs __subject__(sselfsattrsoda((s*build\bdist.win32\egg\peak\util\proxies.pys __delattr__s cCst|iSdS(N(sboolsselfs __subject__(sself((s*build\bdist.win32\egg\peak\util\proxies.pys __nonzero__scCs|i|SdS(N(sselfs __subject__sarg(sselfsarg((s*build\bdist.win32\egg\peak\util\proxies.pys __getitem__scCs||i|sles<=sges>=seqs==snes!=s2def __%s__(self,ob): return self.__subject__ %s obsnegs-sposs+sinverts~s,def __%s__(self): return %s self.__subject__sors|sands&sxors^slshifts<>saddssubsmuls*sdivs/smods%struedivsfloordivs//sdef __%(name)s__(self,ob): return self.__subject__ %(op)s ob def __r%(name)s__(self,ob): return ob %(op)s self.__subject__ def __i%(name)s__(self,ob): self.__subject__ %(op)s=ob return self cCst||iSdS(N(sdivmodsobsselfs __subject__(sselfsob((s*build\bdist.win32\egg\peak\util\proxies.pys __rdivmod__WscGst|i|SdS(N(spowsselfs __subject__sargs(sselfsargs((s*build\bdist.win32\egg\peak\util\proxies.pys__pow__ZscCs|i|C_|SdS(N(sselfs __subject__sob(sselfsob((s*build\bdist.win32\egg\peak\util\proxies.pys__ipow__]scCst||iSdS(N(spowsobsselfs __subject__(sselfsob((s*build\bdist.win32\egg\peak\util\proxies.pys__rpow__as(s__name__s __module__s__doc__s __slots__s__call__sobjects__getattribute__s __setattr__s __delattr__s __nonzero__s __getitem__s __setitem__s __delitem__s __getslice__s __setslice__s __delslice__s __contains__ssplitsnamesopslocalss __rdivmod__s__pow__s__ipow__s__rpow__(((s*build\bdist.win32\egg\peak\util\proxies.pys AbstractProxysD           = " s     s ObjectProxycBstZdZdZdZRS(sProxy for a specific objects __subject__cCs ||_dS(N(ssubjectsselfs __subject__(sselfssubject((s*build\bdist.win32\egg\peak\util\proxies.pys__init__js(s__name__s __module__s__doc__s __slots__s__init__(((s*build\bdist.win32\egg\peak\util\proxies.pys ObjectProxyes s CallbackProxycBstZdZdZdZRS(s%Proxy for a dynamically-chosen objects __callback__cCst||dS(N(s set_callbacksselfsfunc(sselfsfunc((s*build\bdist.win32\egg\peak\util\proxies.pys__init__ss(s__name__s __module__s__doc__s __slots__s__init__(((s*build\bdist.win32\egg\peak\util\proxies.pys CallbackProxyns cCs ||S(N(sgcsself(sselfsgc((s*build\bdist.win32\egg\peak\util\proxies.pysxss LazyProxycBstZdZdZRS(s?Proxy for a lazily-obtained object, that is cached on first uses __cache__(s__name__s __module__s__doc__s __slots__(((s*build\bdist.win32\egg\peak\util\proxies.pys LazyProxy|s cCsHy||SWn3tj o'||t|||SnXdS(N(s get_cachesselfsAttributeErrors set_caches get_callback(sselfs get_caches set_cache((s*build\bdist.win32\egg\peak\util\proxies.pys __subject__s sAbstractWrappercBsPtZdZfZeidZeidZeidZeidZRS(s?Mixin to allow extra behaviors and attributes on proxy instancecCsV|ido5||d}|djo|Snt||Sn|||SdS(Ns__s __subject__(sattrs startswithsogasselfssubjectsgetattr(sselfsattrsogassubject((s*build\bdist.win32\egg\peak\util\proxies.pys__getattribute__s  cCst||d|SdS(Ns __subject__(sgetattrsogasselfsattr(sselfsattrsoga((s*build\bdist.win32\egg\peak\util\proxies.pys __getattr__scCs_|djp$tt||o|id o||||nt|i||dS(Ns __subject__s__( sattrshasattrstypesselfs startswithsosasvalssetattrs __subject__(sselfsattrsvalsosa((s*build\bdist.win32\egg\peak\util\proxies.pys __setattr__s4cCsY|djp$tt||o|id o|||nt|i|dS(Ns __subject__s__(sattrshasattrstypesselfs startswithsodasdelattrs __subject__(sselfsattrsoda((s*build\bdist.win32\egg\peak\util\proxies.pys __delattr__s4( s__name__s __module__s__doc__s __slots__sobjects__getattribute__s __getattr__s __setattr__s __delattr__(((s*build\bdist.win32\egg\peak\util\proxies.pysAbstractWrappers  s ObjectWrappercBstZfZRS(N(s__name__s __module__s __slots__(((s*build\bdist.win32\egg\peak\util\proxies.pys ObjectWrapperssCallbackWrappercBstZfZRS(N(s__name__s __module__s __slots__(((s*build\bdist.win32\egg\peak\util\proxies.pysCallbackWrapperss LazyWrappercBstZfZRS(N(s__name__s __module__s __slots__(((s*build\bdist.win32\egg\peak\util\proxies.pys LazyWrappersN(sobjects AbstractProxys ObjectProxys CallbackProxys __callback__s__set__s set_callbacks__get__s get_callbackspropertys __subject__s LazyProxys __cache__s get_caches set_cachesAbstractWrappers ObjectWrappersCallbackWrappers LazyWrapper( s ObjectProxysAbstractWrappers set_callbacks CallbackProxysCallbackWrappers get_callbacks LazyProxys set_caches ObjectWrappers AbstractProxys LazyWrappers get_caches __subject__((s*build\bdist.win32\egg\peak\util\proxies.pys?sd     !PKa4i77peak/util/__init__.py__import__('pkg_resources').declare_namespace(__name__)PK 4³Fpeak/util/__init__.pyc; Dc@sediedS(s pkg_resourcesN(s __import__sdeclare_namespaces__name__(((s+build\bdist.win32\egg\peak\util\__init__.pys?sPK42EGG-INFO/dependency_links.txtPK47SB<EGG-INFO/namespace_packages.txtPK4)&&EGG-INFO/PKG-INFOPK4(m00G'EGG-INFO/SOURCES.txtPK4(EGG-INFO/top_level.txtPK 42(EGG-INFO/zip-safePK\4i77)peak/__init__.pyPK 4+\-w)peak/__init__.pycPK4q2Ds*peak/util/proxies.pyPK 4`}((2?peak/util/proxies.pycPKa4i77@hpeak/util/__init__.pyPK 4³Fhpeak/util/__init__.pycPK %i