[Zope3-checkins]
SVN: Zope3/branches/jim-adapter-alt1/src/zope/interface/adapter.py
Updated to use a simpler registry structure for adapters.
Jim Fulton
jim at zope.com
Sun Jan 29 15:37:54 EST 2006
Log message for revision 41485:
Updated to use a simpler registry structure for adapters.
Implemented a caching implementation.
Changed:
U Zope3/branches/jim-adapter-alt1/src/zope/interface/adapter.py
-=-
Modified: Zope3/branches/jim-adapter-alt1/src/zope/interface/adapter.py
===================================================================
--- Zope3/branches/jim-adapter-alt1/src/zope/interface/adapter.py 2006-01-29 19:08:39 UTC (rev 41484)
+++ Zope3/branches/jim-adapter-alt1/src/zope/interface/adapter.py 2006-01-29 20:37:53 UTC (rev 41485)
@@ -16,6 +16,7 @@
$Id$
"""
+import weakref
from zope.interface import providedBy, Interface, ro
class readproperty(object):
@@ -31,6 +32,9 @@
return func(inst)
+_delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter',
+ 'adapter_hook', 'lookupAll', 'names')
+
_marker = object
class AdapterRegistry(object):
@@ -39,19 +43,64 @@
self._provided = {}
self._unnamed_subscriptions = []
self._named_subscriptions = {}
+ 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)
+ 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 = {}
@@ -99,6 +148,8 @@
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))
@@ -128,70 +179,11 @@
if '_v_extendors' in self.__dict__:
del self.__dict__['_v_extendors']
+ self.changed()
+
return
- def lookup(self, required, provided, name=u'', default=None):
- order = len(required)
- for self in self.ro:
- byorder = self._adapters
- if order >= len(byorder):
- continue
- extendors = self._v_extendors.get(provided)
- if not extendors:
- continue
-
- components = byorder[order]
- result = _lookup(components, required, extendors, name, 0, order)
- if result is not None:
- 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:
- return default
-
- result = factory(*objects)
- if result is None:
- return default
-
- return result
-
- def lookup1(self, required, provided, name=u'', default=None):
- return self.lookup((required, ), provided, name, 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)
- if factory is not None:
- result = factory(object)
- if result is not None:
- return result
-
- return default
-
- def lookupAll(self, required, provided):
- order = len(required)
- result = {}
- for self in reversed(self.ro):
- byorder = self._adapters
- if order >= len(byorder):
- continue
- extendors = self._v_extendors.get(provided)
- if not extendors:
- continue
- components = byorder[order]
- _lookupAll(components, required, extendors, result, 0, order)
-
- return result.iteritems()
-
- def names(self, required, provided):
- return [c[0] for c in self.lookupAll(required, provided)]
-
def subscribe(self, required, provided, value):
# XXX when we are ready to support named subscribers, we'll add a name
@@ -283,7 +275,147 @@
class XXXTwistedFakeOut:
selfImplied = {}
return XXXTwistedFakeOut
+
+
+
+
+_not_in_mapping = object()
+class AdapterLookup(object):
+
+ def __init__(self, registry):
+ self._registry = registry
+ self._cache = {}
+ self._mcache = {}
+ self._required = {}
+
+ def changed(self):
+ self._cache.clear()
+ self._mcache.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):
+ 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:
+ cache[tuple(required)] = result
+
+ if result is None:
+ return default
+
+ return result
+
+ def queryMultiAdapter(self, objects, provided, name=u'', default=None):
+ factory = self.lookup(map(providedBy, objects), provided, name)
+ if factory is None:
+ return default
+
+ result = factory(*objects)
+ if result is None:
+ return default
+
+ return result
+ def lookup1(self, required, provided, name=u'', default=None):
+ return self.lookup((required, ), provided, name, 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)
+ if factory is not None:
+ result = factory(object)
+ if result is not None:
+ return result
+
+ return default
+
+ def lookupAll(self, required, provided):
+ 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)
+ 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)
+
+ 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 _convert_None_to_Interface(x):
if x is None:
return Interface
More information about the Zope3-Checkins
mailing list