[Zope3-checkins] SVN: Zope3/branches/jim-adapter/src/zope/ Merged
new design from jim-adapter-alt1 branch.
Jim Fulton
jim at zope.com
Tue Jan 31 06:08:36 EST 2006
Log message for revision 41506:
Merged new design from jim-adapter-alt1 branch.
Changed:
U Zope3/branches/jim-adapter/src/zope/interface/adapter.py
U Zope3/branches/jim-adapter/src/zope/security/checker.py
-=-
Modified: Zope3/branches/jim-adapter/src/zope/interface/adapter.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/interface/adapter.py 2006-01-30 19:04:42 UTC (rev 41505)
+++ Zope3/branches/jim-adapter/src/zope/interface/adapter.py 2006-01-31 11:08:35 UTC (rev 41506)
@@ -16,84 +16,320 @@
$Id$
"""
+import weakref
from zope.interface import providedBy, Interface, ro
+class readproperty(object):
+
+ def __init__(self, func):
+ self.func = func
+
+ def __get__(self, inst, class_):
+ if inst is None:
+ return self
+
+ func = self.func
+ return func(inst)
+
+
+_delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter',
+ 'adapter_hook', 'lookupAll', 'names',
+ 'subscriptions', 'subscribers')
+
_marker = object
class AdapterRegistry(object):
def __init__(self, bases=()):
- self._unnamed_adapters = [] # [{ provided -> components }]
- self._named_adapters = {} # { name -> [{ provided -> components }] }
- self._unnamed_subscriptions = [] # ditto
- self._named_subscriptions = {} # ditto
+ self._adapters = []
+ self._subscribers = []
+ self._provided = {}
+ self._init_non_persistent()
self.__bases__ = bases
+ def _init_non_persistent(self):
+ self._v_subregistries = weakref.WeakKeyDictionary()
+ self._v_lookup = lookup = AdapterLookup(self)
+ for name in _delegated:
+ self.__dict__[name] = getattr(lookup, name)
+
+ def __getstate__(self):
+ state = super(AdapterRegistry, self).__getstate__().copy()
+ for name in _delegated:
+ state.pop(name, 0)
+ return state
+
+ def __setstate__(self, state):
+ super(AdapterRegistry, self).__setstate__(state)
+ self._init_non_persistent()
+
+ @apply
def __bases__():
+
def get(self):
return self.__dict__['__bases__']
+
def set(self, v):
+ old = self.__dict__.get('__bases__', ())
+ for r in old:
+ if r not in v:
+ r._removeSubregistry(self)
+ for r in v:
+ if r not in old:
+ r._addSubregistry(self)
+
self.__dict__['__bases__'] = v
self.ro = ro.ro(self)
+ self.changed()
return property(get, set)
- __bases__ = __bases__()
-
+
+ def _addSubregistry(self, r):
+ self._v_subregistries[r] = 1
+
+ def _removeSubregistry(self, r):
+ if r in self._v_subregistries:
+ del self._v_subregistries[r]
+
+ def changed(self):
+ try:
+ lookup = self._v_lookup
+ except AttributeError:
+ pass
+ else:
+ lookup.changed()
+
+ for sub in self._v_subregistries.keys():
+ sub.changed()
+
+ @readproperty
+ def _v_extendors(self):
+ _v_extendors = {}
+ for provided in self._provided:
+ for i in provided.__iro__:
+ extendors = _v_extendors.get(i, ())
+ if provided not in extendors:
+ _v_extendors[i] = (
+ [e for e in extendors if provided.isOrExtends(e)]
+ +
+ [provided]
+ +
+ [e for e in extendors if not provided.isOrExtends(e)]
+ )
+ self._v_extendors = _v_extendors
+ return self._v_extendors
+
def register(self, required, provided, name, value):
if value is None:
self.unregister(required, provided, name, value)
return
- if name:
- name = _normalize_name(name)
- byorder = self._named_adapters.get(name)
- if byorder is None:
- self._named_adapters[name] = byorder = []
- else:
- byorder = self._unnamed_adapters
-
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = _normalize_name(name)
order = len(required)
+ byorder = self._adapters
while len(byorder) <= order:
- byorder.append(Adapters())
+ byorder.append({})
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = {}
+ components[k] = d
+ components = d
+ if components.get(name) == value:
+ return
+
+ components[name] = value
+
+ n = self._provided.get(provided, 0) + 1
+ self._provided[provided] = n
+ if n == 1 and '_v_extendors' in self.__dict__:
+ del self.__dict__['_v_extendors']
+
+ self.changed()
+
+ def unregister(self, required, provided, name, value=None):
+ required = tuple(map(_convert_None_to_Interface, required))
+ order = len(required)
+ byorder = self._adapters
+ if order >= len(byorder):
+ return False
components = byorder[order]
- components.register(required, provided, value)
+ key = required + (provided,)
- def unregister(self, required, provided, name, value=None):
- if name:
- name = _normalize_name(name)
- byorder = self._named_adapters.get(name)
- if byorder is None:
+ for k in key:
+ d = components.get(k)
+ if d is None:
return
- else:
- byorder = self._unnamed_adapters
+ components = d
+ old = components.get(name)
+ if old is None:
+ return
+ if value is not None and old != value:
+ return
+
+ del components[name]
+ n = self._provided[provided] - 1
+ if n == 0:
+ del self._provided[provided]
+ if '_v_extendors' in self.__dict__:
+ del self.__dict__['_v_extendors']
+
+ self.changed()
+
+ return
+
+
+ def subscribe(self, required, provided, value):
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = u''
order = len(required)
+ byorder = self._subscribers
+ while len(byorder) <= order:
+ byorder.append({})
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = {}
+ components[k] = d
+ components = d
+
+ components[name] = components.get(name, ()) + (value, )
+
+ if provided is not None:
+ n = self._provided.get(provided, 0) + 1
+ self._provided[provided] = n
+ if n == 1 and '_v_extendors' in self.__dict__:
+ del self.__dict__['_v_extendors']
+
+ self.changed()
+
+ def unsubscribe(self, required, provided, value):
+ required = tuple(map(_convert_None_to_Interface, required))
+ order = len(required)
+ byorder = self._subscribers
if order >= len(byorder):
- return
+ return False
components = byorder[order]
- components.unregister(required, provided, value)
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return
+ components = d
+ components[u''] = tuple([
+ v for v in components.get(u'', ())
+ if v != value
+ ])
+ if provided is not None:
+ n = self._provided[provided] - 1
+ if n == 0:
+ del self._provided[provided]
+ if '_v_extendors' in self.__dict__:
+ del self.__dict__['_v_extendors']
+
+ self.changed()
+
+ return
+
+ # XXX hack to fake out twisted's use of a private api. We'll need
+ # to add a public api to mean twisted's needs and get them to use
+ # it.
+ def get(self, _):
+ class XXXTwistedFakeOut:
+ selfImplied = {}
+ return XXXTwistedFakeOut
+
+
+
+
+_not_in_mapping = object()
+class AdapterLookup(object):
+
+ def __init__(self, registry):
+ self._registry = registry
+ self._cache = {}
+ self._mcache = {}
+ self._scache = {}
+ self._required = {}
+
+ def changed(self):
+ self._cache.clear()
+ self._mcache.clear()
+ self._scache.clear()
+ for r in self._required.keys():
+ r = r()
+ if r is not None:
+ r.unsubscribe(self)
+ self._required.clear()
+
+ def _getcache(self, provided, name):
+ cache = self._cache.get(provided)
+ if cache is None:
+ cache = {}
+ self._cache[provided] = cache
+ if name:
+ c = cache.get(name)
+ if c is None:
+ c = {}
+ cache[name] = c
+ cache = c
+ return cache
+
+ def _subscribe(self, *required):
+ _refs = self._required
+ for r in required:
+ ref = r.weakref()
+ if ref not in _refs:
+ r.subscribe(self)
+ _refs[ref] = 1
+
def lookup(self, required, provided, name=u'', default=None):
- for self in self.ro:
- if name:
- byorder = self._named_adapters.get(name)
- if byorder is None:
+ cache = self._getcache(provided, name)
+ if len(required) == 1:
+ result = cache.get(required[0], _not_in_mapping)
+ else:
+ result = cache.get(tuple(required), _not_in_mapping)
+
+ if result is _not_in_mapping:
+ result = None
+ order = len(required)
+ for registry in self._registry.ro:
+ byorder = registry._adapters
+ if order >= len(byorder):
continue
+
+ extendors = registry._v_extendors.get(provided)
+ if not extendors:
+ continue
+
+ components = byorder[order]
+ result = _lookup(components, required, extendors, name, 0,
+ order)
+ if result is not None:
+ break
+
+ self._subscribe(*required)
+ if len(required) == 1:
+ cache[required[0]] = result
else:
- byorder = self._unnamed_adapters
+ cache[tuple(required)] = result
- order = len(required)
- if order >= len(byorder):
- continue
+ if result is None:
+ return default
- components = byorder[order]
- result = lookup(components.components, required, provided)
- if result is not None:
- return result
+ return result
- return default
-
def queryMultiAdapter(self, objects, provided, name=u'', default=None):
factory = self.lookup(map(providedBy, objects), provided, name)
if factory is None:
@@ -104,31 +340,29 @@
return default
return result
-
+
def lookup1(self, required, provided, name=u'', default=None):
- for self in self.ro:
- if name:
- byorder = self._named_adapters.get(name)
- if byorder is None:
- continue
- else:
- byorder = self._unnamed_adapters
+ cache = self._getcache(provided, name)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ return self.lookup((required, ), provided, name, default)
- if 1 >= len(byorder):
- continue
+ if result is None:
+ return default
- components = byorder[1]
- result = lookup1(components.components, required, provided)
- if result is not None:
- return result
+ return result
- return default
-
+
def queryAdapter(self, object, provided, name=u'', default=None):
return self.adapter_hook(provided, object, name, default)
def adapter_hook(self, provided, object, name=u'', default=None):
- factory = self.lookup1(providedBy(object), provided, name)
+ required = providedBy(object)
+ cache = self._getcache(provided, name)
+ factory = cache.get(required, _not_in_mapping)
+ if factory is _not_in_mapping:
+ factory = self.lookup((required, ), provided, name)
+
if factory is not None:
result = factory(object)
if result is not None:
@@ -137,303 +371,131 @@
return default
def lookupAll(self, required, provided):
- for self in self.ro:
+ cache = self._mcache.get(provided)
+ if cache is None:
+ cache = {}
+ self._mcache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
order = len(required)
- if order < len(self._unnamed_adapters):
- result = lookup(self._unnamed_adapters[order].components,
- required, provided)
- if result is not None:
- yield (u'', result)
+ result = {}
+ for registry in reversed(self._registry.ro):
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
+ extendors = registry._v_extendors.get(provided)
+ if not extendors:
+ continue
+ components = byorder[order]
+ _lookupAll(components, required, extendors, result, 0, order)
- for name, byorder in self._named_adapters.iteritems():
- if order < len(byorder):
- result = lookup(byorder[order].components,
- required, provided)
- if result is not None:
- yield (name, result)
+ self._subscribe(*required)
+ cache[required] = result
+ return result.iteritems()
+
def names(self, required, provided):
return [c[0] for c in self.lookupAll(required, provided)]
- def subscribe(self, required, provided, value):
+ def subscriptions(self, required, provided):
+ cache = self._scache.get(provided)
+ if cache is None:
+ cache = {}
+ self._scache[provided] = cache
-# XXX when we are ready to support named subscribers, we'll add a name
-# argument and uncomment the following.
-## if name:
-## name = _normalize_name(name)
-## byorder = self._named_subscriptions.get(name)
-## if byorder is None:
-## self._named_subscriptions[name] = byorder = []
-## else:
-## byorder = self._unnamed_subscriptions
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ order = len(required)
+ result = []
+ for registry in reversed(self._registry.ro):
+ byorder = registry._subscribers
+ if order >= len(byorder):
+ continue
- byorder = self._unnamed_subscriptions
+ if provided is None:
+ extendors = (provided, )
+ else:
+ extendors = registry._v_extendors.get(provided)
+ if extendors is None:
+ continue
- order = len(required)
- while len(byorder) <= order:
- byorder.append(Subscriptions())
+ _subscriptions(byorder[order], required, extendors, u'',
+ result, 0, order)
- components = byorder[order]
- components.register(required, provided, value)
+ self._subscribe(*required)
+ cache[required] = result
- def unsubscribe(self, required, provided, value):
-
-# XXX when we are ready to support named subscribers, we'll add a name
-# argument and uncomment the following.
-## if name:
-## name = _normalize_name(name)
-## byorder = self._named_subscriptions.get(name)
-## if byorder is None:
-## self._named_subscriptions[name] = byorder = []
-## else:
-## byorder = self._unnamed_subscriptions
-
- byorder = self._unnamed_subscriptions
-
- order = len(required)
- if len(byorder) <= order:
- return
-
- components = byorder[order]
- components.unregister(required, provided, value)
-
- def subscriptions(self, required, provided, name=u''):
- result = []
- # XXX should we traverse ro in reverse?
- for self in self.ro:
- if name:
- byorder = self._named_subscriptions.get(name)
- if byorder is None:
- continue
- else:
- byorder = self._unnamed_subscriptions
-
- order = len(required)
- if order >= len(byorder):
- continue
-
- subscriptions(byorder[order].components, required, provided,
- result)
-
return result
- def subscribers(self, objects, provided, name=u''):
+ def subscribers(self, objects, provided):
+ subscriptions = self.subscriptions(map(providedBy, objects), provided)
if provided is None:
result = ()
+ for subscription in subscriptions:
+ subscription(*objects)
else:
result = []
-
- for self in self.ro:
- if name:
- byorder = self._named_subscriptions.get(name)
- if byorder is None:
- continue
- else:
- byorder = self._unnamed_subscriptions
-
- order = len(objects)
- if order >= len(byorder):
- continue
-
- subscribers(byorder[order].components, objects, provided, result)
-
+ for subscription in subscriptions:
+ subscriber = subscription(*objects)
+ if subscriber is not None:
+ result.append(subscriber)
return result
-
- # XXX hack to fake out twisted's use of a private api. We'll need
- # to add a public api to mean twisted's needs and get them to use
- # it.
- def get(self, _):
- class XXXTwistedFakeOut:
- selfImplied = {}
- return XXXTwistedFakeOut
+def _convert_None_to_Interface(x):
+ if x is None:
+ return Interface
+ else:
+ return x
-
def _normalize_name(name):
if isinstance(name, basestring):
return unicode(name)
raise TypeError("name must be a regular or unicode string")
-
-class Next:
-
- def __init__(self, spec, basis):
- sro = spec.__sro__
- self.__sro__ = sro[sro.index(basis)+1:]
-
-
-class Adapters(object):
-
- def __init__(self):
- self.components = {}
- self.provided = {} # {iface -> (iro, [(required, value)])}
-
- def register(self, required, provided, value):
- if (provided is None) or (provided is Interface):
- self._register(required, provided, provided, value)
- else:
- registered = self.provided.get(provided)
- if registered is None:
- self.provided[provided] = registered = provided.__iro__, []
- provided.subscribe(self)
- registered[1].append((required, value))
-
- for p in provided.__iro__:
- self._register(required, provided, p, value)
-
- def _register(self, required, provided, p, value):
- d = self.components
- k = p
- for r in required:
- if r is None:
- r = Interface
- v = d.get(k)
- if v is None:
- d[k] = v = {}
- d = v
- k = r
-
- components = d.get(k, ())
- d[k] = self._add(components, provided, value)
-
- def _add(self, components, provided, value):
- if provided is None:
- return components + ((value, provided), )
-
- return (
- tuple([c for c in components if provided.extends(c[1])])
- +
- ((value, provided), )
- +
- tuple([c for c in components if not provided.extends(c[1])])
- )
-
- def unregister(self, required, provided, value):
- if (provided is None) or (provided is Interface):
- self._unregister(required, provided, provided, value)
- else:
- registered = self.provided.get(provided)
- if registered is None:
- return
- if value is None:
- rv = [r for r in registered[1] if r[0] != required]
- else:
- rv = [r for r in registered[1] if r != (required, value)]
-
- if rv:
- self.provided[provided] = registered[0], rv
- else:
- del self.provided[provided]
-
- for p in provided.__iro__:
- self._unregister(required, provided, p, value)
-
- def _unregister(self, required, provided, p, value):
- items = []
- d = self.components
- k = p
- for r in required:
- if r is None:
- r = Interface
- v = d.get(k)
- if v is None:
- return
- items.append((d, k))
- d = v
- k = r
-
- components = d.get(k, None)
- if components is None:
- return
-
- if value is None:
- # unregister all
- components = [c for c in components
- if c[1] != provided]
- else:
- # unregister just this one
- components = [c for c in components
- if c != (value, provided)]
-
- if components:
- d[k] = tuple(components)
- else:
- del d[k]
-
- items.reverse()
- for d, k in items:
- if not d[k]:
- del d[k]
-
-class Subscriptions(Adapters):
-
- def _add(self, components, provided, value):
- return components + ((value, provided), )
-
-def _lookup(components, specs, i, l):
+def _lookup(components, specs, provided, name, i, l):
if i < l:
for spec in specs[i].__sro__:
comps = components.get(spec)
- if comps is not None:
- r = _lookup(comps, specs, i+1, l)
+ if comps:
+ r = _lookup(comps, specs, provided, name, i+1, l)
if r is not None:
return r
- return None
-
- return components
-
-def lookup(components, required, provided):
- components = components.get(provided)
- if components:
-
- if required:
- components = _lookup(components, required, 0, len(required))
- if not components:
- return None
-
- return components[0][0]
-
+ else:
+ for iface in provided:
+ comps = components.get(iface)
+ if comps:
+ r = comps.get(name)
+ if r is not None:
+ return r
+
return None
-def lookup1(components, required, provided):
- components = components.get(provided)
- if components:
- for s in required.__sro__:
- comps = components.get(s)
+def _lookupAll(components, specs, provided, result, i, l):
+ if i < l:
+ for spec in reversed(specs[i].__sro__):
+ comps = components.get(spec)
if comps:
- return comps[0][0]
+ _lookupAll(comps, specs, provided, result, i+1, l)
+ else:
+ for iface in reversed(provided):
+ comps = components.get(iface)
+ if comps:
+ result.update(comps)
- return None
-
-def _subscribers(components, specs, i, l, objects, result):
+def _subscriptions(components, specs, provided, name, result, i, l):
if i < l:
- sro = list(specs[i].__sro__)
- sro.reverse()
- for spec in sro:
+ for spec in reversed(specs[i].__sro__):
comps = components.get(spec)
- if comps is not None:
- _subscribers(comps, specs, i+1, l, objects, result)
+ if comps:
+ _subscriptions(comps, specs, provided, name, result, i+1, l)
else:
- if objects is None:
- result.extend([c[0] for c in components])
- else:
- for c in components:
- c = c[0](*objects)
- if c is not None and result is not None:
- result.append(c)
-
-def subscriptions(components, required, provided, result):
- components = components.get(provided)
- if components:
- _subscribers(components, required, 0, len(required), None, result)
-
-def subscribers(components, objects, provided, result):
- components = components.get(provided)
- if components:
- required = map(providedBy, objects)
-
- if provided is None:
- result == None
-
- _subscribers(components, required, 0, len(required), objects, result)
+ for iface in reversed(provided):
+ comps = components.get(iface)
+ if comps:
+ comps = comps.get(name)
+ if comps:
+ result.extend(comps)
Modified: Zope3/branches/jim-adapter/src/zope/security/checker.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/security/checker.py 2006-01-30 19:04:42 UTC (rev 41505)
+++ Zope3/branches/jim-adapter/src/zope/security/checker.py 2006-01-31 11:08:35 UTC (rev 41506)
@@ -658,7 +658,9 @@
_Declaration_checker = InterfaceChecker(
IDeclaration,
_implied=CheckerPublic,
- subscribe=CheckerPublic)
+ subscribe=CheckerPublic,
+ unsubscribe=CheckerPublic,
+ )
def f():
yield f
More information about the Zope3-Checkins
mailing list