"""Basic binding tools""" |
"""Basic binding tools""" |
|
|
from once import Once, New |
from once import Once, New, WeakBinding |
import meta, modules |
import meta, modules |
|
|
from weakref import ref, WeakValueDictionary |
from weakref import ref, WeakValueDictionary |
|
|
from peak.naming.names import toName, Syntax, CompoundName |
from peak.naming.names import toName, Syntax, CompoundName |
from peak.naming.interfaces import NameNotFoundException |
from peak.naming.interfaces import NameNotFoundException |
from peak.util.EigenData import EigenRegistry |
from peak.util.EigenData import EigenRegistry |
|
|
from Interface import Interface |
from Interface import Interface |
from peak.api import config |
from peak.api import config, NOT_FOUND |
|
|
|
|
__all__ = [ |
__all__ = [ |
'acquireComponent', 'globalLookup' |
'acquireComponent', 'globalLookup' |
] |
] |
|
|
_ACQUIRED = object() |
|
|
|
InterfaceClass = Interface.__class__ |
InterfaceClass = Interface.__class__ |
|
|
|
|
|
|
|
|
|
|
def Provider(callable): |
def Provider(callable): |
return lambda foundIn, forObj: callable(forObj) |
return lambda foundIn, forObj: callable(forObj) |
|
|
|
|
def globalLookup(name, component=None): |
def globalLookup(name, component=None): |
|
|
"""Lookup 'name' in global 'InitialContext', w/'component' in environ""" |
"""Lookup 'name' in global 'InitialContext', relative to 'component'""" |
|
|
from peak.naming.api import InitialContext |
from peak.naming.api import InitialContext |
|
|
return InitialContext(RELATIVE_TO_COMPONENT=component).lookup(name) |
return InitialContext(component).lookup(name) |
|
|
|
|
|
|
|
|
while target is not None: |
while target is not None: |
|
|
ob = getattr(target, name, _ACQUIRED) |
ob = getattr(target, name, NOT_FOUND) |
|
|
if ob is not _ACQUIRED: |
if ob is not NOT_FOUND: |
return ob |
return ob |
|
|
target = getParentComponent(target) |
target = getParentComponent(target) |
|
|
singleValue = True |
singleValue = True |
|
|
def __init__(self,targetName,weak=False): |
def __init__(self,targetName,weak=False,provides=None): |
|
|
self.targetNames = (targetName,) |
self.targetNames = (targetName,) |
self.weak = weak |
self.weak = weak |
|
self._provides=provides |
|
|
|
|
|
|
|
|
def computeValue(self, obj, instanceDict, attrName): |
def computeValue(self, obj, instanceDict, attrName): |
|
|
instanceDict[attrName] = _ACQUIRED # recursion guard |
|
|
|
names = self.targetNames |
names = self.targetNames |
obs = map(obj.lookupComponent, names) |
obs = map(obj.lookupComponent, names) |
|
|
for name,newOb in zip(names, obs): |
for name,newOb in zip(names, obs): |
|
|
if newOb is _ACQUIRED: |
if newOb is NOT_FOUND: |
|
|
del instanceDict[attrName] |
del instanceDict[attrName] |
raise NameNotFoundError(attrName, resolvedName = name) |
raise NameNotFoundError(attrName, resolvedName = name) |
|
|
|
|
|
|
|
|
|
|
class bindToNames(bindTo): |
class bindToNames(bindTo): |
|
|
"""Automatically look up and cache a sequence of services by name |
"""Automatically look up and cache a sequence of services by name |
def __init__(self, *targetNames, **kw): |
def __init__(self, *targetNames, **kw): |
self.targetNames = targetNames |
self.targetNames = targetNames |
self.weak = kw.get('weak') |
self.weak = kw.get('weak') |
|
self._provides = kw.get('provides') |
|
|
|
|
|
|
|
|
|
|
|
|
|
class bindToParent(WeakBinding): |
|
|
class bindToParent(Once): |
"""Look up and cache a weak ref to the nth-level parent component |
|
|
"""Look up and cache a reference to the nth-level parent service |
|
|
|
Usage:: |
Usage:: |
|
|
|
|
'someClass' can then refer to 'self.grandPa' instead of calling |
'someClass' can then refer to 'self.grandPa' instead of calling |
'self.getParentComponent().getParentComponent()'. |
'self.getParentComponent().getParentComponent()'. |
|
|
This binding descriptor saves a weak reference to its target in |
|
the object's instance dictionary, and dereferences it on each access. |
|
It therefore supports '__set__' and '__delete__' as well as '__get__' |
|
methods, and retrieval is slower than for other 'Once' attributes. But |
|
it avoids creating circular reference garbage. |
|
""" |
""" |
|
|
def __init__(self,level=1): |
def __init__(self,level=1,provides=None): |
self.level = level |
self.level = level |
|
self._provides = provides |
def __get__(self, obj, typ=None): |
|
|
|
if obj is None: return self |
|
|
|
d = obj.__dict__ |
|
n = self.attrName |
|
|
|
if not n or getattr(obj.__class__,n) is not self: |
|
self.usageError() |
|
|
|
ref = d.get(n) |
|
|
|
if ref is None: |
|
d[n] = ref = self.computeValue(obj, d, n) |
|
|
|
return ref() |
|
|
|
|
|
def __set__(self, obj, val): |
|
|
|
n = self.attrName |
|
|
|
if not n or getattr(obj.__class__,n) is not self: |
|
self.usageError() |
|
|
|
from weakref import ref |
|
obj.__dict__[n] = ref(val) |
|
|
|
|
|
def __delete__(self, obj): |
|
|
|
n = self.attrName |
|
|
|
if not n or getattr(obj.__class__,n) is not self: |
|
self.usageError() |
|
|
|
del obj.__dict__[n] |
|
|
|
|
|
def computeValue(self, obj, instDict, attrName): |
def computeValue(self, obj, instDict, attrName): |
|
|
if newObj is None: break |
if newObj is None: break |
obj = newObj |
obj = newObj |
|
|
from weakref import ref |
return obj |
return ref(obj) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bindToSelf(provides=None): |
|
|
|
|
|
|
|
|
def bindToSelf(): |
|
|
|
"""Weak reference to the 'self' object |
"""Weak reference to the 'self' object |
|
|
you'd expect. It's handy for objects that provide default support for |
you'd expect. It's handy for objects that provide default support for |
various interfaces in the absence of an object to delegate to. The object |
various interfaces in the absence of an object to delegate to. The object |
can refer to 'self.delegateForInterfaceX.someMethod()', and have |
can refer to 'self.delegateForInterfaceX.someMethod()', and have |
'delegateForInterfaceX' be a 'bindToSelf()' by default. |
'delegateForInterfaceX' be a 'bindToSelf()' by default.""" |
""" |
|
|
|
return bindToParent(0) |
return bindToParent(0,provides) |
|
|
|
|
class requireBinding(Once): |
class requireBinding(Once): |
|
|
"""Placeholder for a binding that should be (re)defined by a subclass""" |
"""Placeholder for a binding that should be (re)defined by a subclass""" |
|
|
def __init__(self,description=""): |
def __init__(self,description="",provides=None): |
self.description = description |
self.description = description |
|
self._provides = provides |
|
|
def computeValue(self, obj, instanceDict, attrName): |
def computeValue(self, obj, instanceDict, attrName): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Component(object): |
class Component(object): |
|
|
"""Thing that can be composed into a component tree, w/binding & lookups""" |
"""Thing that can be composed into a component tree, w/binding & lookups""" |
|
|
utility = getattr(self,attr) |
utility = getattr(self,attr) |
|
|
if utility is not _ACQUIRED: |
if utility is not NOT_FOUND: |
return utility |
return utility |
|
|
parent = self.getParentComponent() |
parent = self.getParentComponent() |