[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