[Zope3-checkins] SVN: Zope3/trunk/src/zope/ Factored lookup and adaptation code from adapter registries and

Jim Fulton jim at zope.com
Fri Jun 25 15:56:50 EDT 2004


Log message for revision 25985:
Factored lookup and adaptation code from adapter registries and
services into a separate class in preparation for creating a C
implementation. 

This has the nice side effect that adapter registries now actually can
do adaptation.



-=-
Modified: Zope3/trunk/src/zope/app/adapter/adapter.py
===================================================================
--- Zope3/trunk/src/zope/app/adapter/adapter.py	2004-06-25 16:26:30 UTC (rev 25984)
+++ Zope3/trunk/src/zope/app/adapter/adapter.py	2004-06-25 19:56:49 UTC (rev 25985)
@@ -104,10 +104,12 @@
 
     def __getstate__(self):
         state = Persistent.__getstate__(self).copy()
-        del state['_surrogates']
-        del state['_default']
-        del state['_null']
-        del state['_remove']
+        
+        for name in ('_default', '_null',
+                     'lookup', 'lookup1', 'queryAdapter', 'get',
+                     'subscriptions', 'queryMultiAdapter', 'subscribers'
+                     ):
+            del state[name]
         return state
 
     def __setstate__(self, state):

Modified: Zope3/trunk/src/zope/app/presentation/presentation.py
===================================================================
--- Zope3/trunk/src/zope/app/presentation/presentation.py	2004-06-25 16:26:30 UTC (rev 25984)
+++ Zope3/trunk/src/zope/app/presentation/presentation.py	2004-06-25 19:56:49 UTC (rev 25985)
@@ -274,7 +274,6 @@
 
 class LocalLayer(
     zope.app.adapter.LocalAdapterRegistry,
-    zope.component.presentation.Layer,
     zope.app.container.contained.Contained,
     ):
 

Modified: Zope3/trunk/src/zope/component/adapter.py
===================================================================
--- Zope3/trunk/src/zope/component/adapter.py	2004-06-25 16:26:30 UTC (rev 25984)
+++ Zope3/trunk/src/zope/component/adapter.py	2004-06-25 19:56:49 UTC (rev 25985)
@@ -58,24 +58,6 @@
 
     implements(IAdapterService)
 
-    def queryAdapter(self, object, interface, name='', default=None):
-        factory = self.lookup1(providedBy(object), interface, name)
-        if factory is not None:
-            return factory(object)
-
-        return default
-
-    def queryMultiAdapter(self, objects, interface, name='', default=None):
-        factory = self.lookup(map(providedBy, objects), interface, name)
-        if factory is not None:
-            return factory(*objects)
-
-        return default
-
-    def subscribers(self, objects, interface):
-        subscriptions = self.subscriptions(map(providedBy, objects), interface)
-        return [subscription(*objects) for subscription in subscriptions]
-
 class GlobalAdapterService(AdapterService, GlobalService):
     """Global Adapter Service implementation."""
 

Modified: Zope3/trunk/src/zope/component/presentation.py
===================================================================
--- Zope3/trunk/src/zope/component/presentation.py	2004-06-25 16:26:30 UTC (rev 25984)
+++ Zope3/trunk/src/zope/component/presentation.py	2004-06-25 19:56:49 UTC (rev 25985)
@@ -469,23 +469,8 @@
     return presentation_service.queryLayer(layer_name)
 
 
-class Layer(zope.interface.adapter.AdapterRegistry):
+class GlobalLayer(zope.interface.adapter.AdapterRegistry):
 
-    def queryAdapter(self, obj, interface, name='', default=None):
-        factory = self.lookup1(providedBy(obj), interface, name)
-        if factory is not None:
-            return factory(obj)
-        return default
-
-    def queryMultiAdapter(self, objects, interface, name='', default=None):
-        factory = self.lookup(map(providedBy, objects), interface, name)
-        if factory is not None:
-            return factory(*objects)
-        return default
-
-
-class GlobalLayer(Layer):
-
     def __init__(self, parent, name):
         super(GlobalLayer, self).__init__()
         self.__parent__ = parent

Modified: Zope3/trunk/src/zope/interface/adapter.py
===================================================================
--- Zope3/trunk/src/zope/interface/adapter.py	2004-06-25 16:26:30 UTC (rev 25984)
+++ Zope3/trunk/src/zope/interface/adapter.py	2004-06-25 19:56:49 UTC (rev 25985)
@@ -291,23 +291,24 @@
             break
     return False
 
-class AdapterRegistry(object):
-    """Adapter registry
-    """
 
-    # Implementation note:
-    # We are like a weakref dict ourselves. We can't use a weakref
-    # dict because we have to use spec.weakref() rather than
-    # weakref.ref(spec) to get weak refs to specs.
+class AdapterLookup(object):
+    # Adapter lookup support
+    # We have a class here because we want to provide very
+    # fast lookup support in C and making this part of the adapter
+    # registry itself would provide problems if someone wanted to
+    # persistent adapter registries, because we want C slots for fast
+    # lookup that would clash with persistence-suppplied slots.
+    # so this class acts a little bit like a lookup adapter for the adapter
+    # registry.
 
-    _surrogateClass = Surrogate
-
-    def __init__(self):
-        default = self._surrogateClass(Default, self)
-        self._default = default
-        null = self._surrogateClass(Null, self)
-        self._null = null
-        surrogates = {Default.weakref(): default, Null.weakref(): null}
+    def __init__(self, registry):
+        self._registry = registry
+        self._surrogateClass = registry._surrogateClass
+        surrogates = {Default.weakref(): registry._default,
+                      Null.weakref(): registry._null}
+        self._default = registry._default
+        self._null = registry._null
         self._surrogates = surrogates
 
         def _remove(k):
@@ -318,37 +319,6 @@
 
         self._remove = _remove
 
-    def get(self, declaration):
-        if declaration is None:
-            return self._default
-
-        ref = declaration.weakref(self._remove)
-        surrogate = self._surrogates.get(ref)
-        if surrogate is None:
-            surrogate = self._surrogateClass(declaration, self)
-            self._surrogates[ref] = surrogate
-
-        return surrogate
-
-    def register(self, required, provided, name, value):
-        if required:
-            with = []
-            for iface in required[1:]:
-                if iface is None:
-                    iface = Interface
-                with.append(iface)
-            with = tuple(with)
-            required = self.get(required[0])
-        else:
-            with = ()
-            required = self._null
-        
-        if not isinstance(name, basestring):
-            raise TypeError("The name provided to provideAdapter "
-                            "must be a string or unicode")
-
-        required._adaptTo(provided, value, unicode(name), with)
-
     def lookup(self, required, provided, name='', default=None):
         order = len(required)
         if order == 1:
@@ -417,6 +387,129 @@
 
         return value
 
+    def queryAdapter(self, object, interface, name='', default=None):
+        factory = self.lookup1(providedBy(object), interface, name)
+        if factory is not None:
+            return factory(object)
+
+        return default
+
+    def subscriptions(self, required, provided):
+        if provided is None:
+            provided = Null
+
+        order = len(required)
+        if order == 1:
+            # Simple subscriptions:
+            s = self.get(required[0])
+            result = s.get(('s', provided))
+            if result:
+                result = list(result)
+            else:
+                result = []
+
+            default = self._default.get(('s', provided))
+            if default:
+                result.extend(default)
+                
+            return result
+
+        elif order == 0:
+            result = self._null.get(('s', provided))
+            if result:
+                return list(result)
+            else:
+                return []
+        
+        # Multi
+        key = 's', provided, order
+        with = required[1:]
+        result = []
+        
+        for surrogate in self.get(required[0]), self._default:
+            bywith = surrogate.get(key)
+            if not bywith:
+                continue
+
+            for rwith, values in bywith:
+                for rspec, spec in zip(rwith, with):
+                    if not spec.isOrExtends(rspec):
+                        break # This one is no good
+                else:
+                    # we didn't break, so we have a match
+                    result.extend(values)
+
+        return result
+
+        
+
+    def queryMultiAdapter(self, objects, interface, name='', default=None):
+        factory = self.lookup(map(providedBy, objects), interface, name)
+        if factory is not None:
+            return factory(*objects)
+
+        return default
+
+    def subscribers(self, objects, interface):
+        subscriptions = self.subscriptions(map(providedBy, objects), interface)
+        return [subscription(*objects) for subscription in subscriptions]
+
+    def get(self, declaration):
+        if declaration is None:
+            return self._default
+
+        ref = declaration.weakref(self._remove)
+        surrogate = self._surrogates.get(ref)
+        if surrogate is None:
+            surrogate = self._surrogateClass(declaration, self._registry)
+            self._surrogates[ref] = surrogate
+
+        return surrogate
+
+
+class AdapterRegistry(object):
+    """Adapter registry
+    """
+
+    # Implementation note:
+    # We are like a weakref dict ourselves. We can't use a weakref
+    # dict because we have to use spec.weakref() rather than
+    # weakref.ref(spec) to get weak refs to specs.
+
+    _surrogateClass = Surrogate
+
+    def __init__(self):
+        default = self._surrogateClass(Default, self)
+        self._default = default
+        null = self._surrogateClass(Null, self)
+        self._null = null
+
+        # Create separate lookup object and copy it's methods
+        lookup = AdapterLookup(self)
+        for name in ('lookup', 'lookup1', 'queryAdapter', 'get',
+                     'subscriptions', 'queryMultiAdapter', 'subscribers'
+                     ):
+            setattr(self, name, getattr(lookup, name))
+
+    def register(self, required, provided, name, value):
+        if required:
+            with = []
+            for iface in required[1:]:
+                if iface is None:
+                    iface = Interface
+                with.append(iface)
+            with = tuple(with)
+            required = self.get(required[0])
+        else:
+            with = ()
+            required = self._null
+        
+        if not isinstance(name, basestring):
+            raise TypeError("The name provided to provideAdapter "
+                            "must be a string or unicode")
+
+        required._adaptTo(provided, value, unicode(name), with)
+
     def lookupAll(self, required, provided):
         order = len(required)
         if order == 1:
@@ -472,7 +565,6 @@
 
             first = byname
 
-
     def subscribe(self, required, provided, value):
         if required:
             required, with = self.get(required[0]), tuple(required[1:])
@@ -485,56 +577,6 @@
             
         required._subscriptionAdaptTo(provided, value, with)
 
-
-    def subscriptions(self, required, provided):
-        if provided is None:
-            provided = Null
-
-        order = len(required)
-        if order == 1:
-            # Simple subscriptions:
-            s = self.get(required[0])
-            result = s.get(('s', provided))
-            if result:
-                result = list(result)
-            else:
-                result = []
-
-            default = self._default.get(('s', provided))
-            if default:
-                result.extend(default)
-                
-            return result
-
-        elif order == 0:
-            result = self._null.get(('s', provided))
-            if result:
-                return list(result)
-            else:
-                return []
-        
-        # Multi
-        key = 's', provided, order
-        with = required[1:]
-        result = []
-        
-        for surrogate in self.get(required[0]), self._default:
-            bywith = surrogate.get(key)
-            if not bywith:
-                continue
-
-            for rwith, values in bywith:
-                for rspec, spec in zip(rwith, with):
-                    if not spec.isOrExtends(rspec):
-                        break # This one is no good
-                else:
-                    # we didn't break, so we have a match
-                    result.extend(values)
-
-        return result
-
-        
-
 def mextends(with, rwith):
     if len(with) == len(rwith):
         for w, r in zip(with, rwith):

Modified: Zope3/trunk/src/zope/interface/adapter.txt
===================================================================
--- Zope3/trunk/src/zope/interface/adapter.txt	2004-06-25 16:26:30 UTC (rev 25984)
+++ Zope3/trunk/src/zope/interface/adapter.txt	2004-06-25 19:56:49 UTC (rev 25985)
@@ -126,7 +126,52 @@
   >>> registry.lookup1(IR2, IP1)
   21
 
+Actual Adaptation
+-----------------
 
+The adapter registry is intended to support adaptation, where one
+object that implements an interface is adapted to another object that
+supports a different interface.  The adapter registry supports the
+computation of adapters. In this case, we have to register adapter
+factories: 
+
+   >>> class IR(zope.interface.Interface):
+   ...     pass
+
+   >>> class X:
+   ...     zope.interface.implements(IR)
+           
+   >>> class Y:
+   ...     zope.interface.implements(IP1)
+   ...     def __init__(self, context):
+   ...         self.context = context
+
+  >>> registry.register([IR], IP1, '', Y)
+
+In this case, we registered a class as the factory. Now we can call
+`queryAdapter` to get the adapted object:
+
+  >>> x = X()
+  >>> y = registry.queryAdapter(x, IP1)
+  >>> y.__class__.__name__
+  'Y'
+  >>> y.context is x
+  True
+
+We can register and lookup by name too:
+
+  >>> class Y2(Y):
+  ...     pass
+
+  >>> registry.register([IR], IP1, 'bob', Y2)
+  >>> y = registry.queryAdapter(x, IP1, 'bob')
+  >>> y.__class__.__name__
+  'Y2'
+  >>> y.context is x
+  True
+
+
+
 Default Adapters
 ----------------
   
@@ -196,6 +241,43 @@
   >>> registry.lookup([IR2, IQ2], IP1, '')
   '1q22'
 
+Multi-adaptation
+----------------
+
+You can adapt multiple objects:
+
+  >>> class Q:
+  ...     zope.interface.implements(IQ)
+
+As with single adapters, we register a factory, which is often a class:
+
+  >>> class IM(zope.interface.Interface):
+  ...     pass
+  >>> class M:
+  ...     zope.interface.implements(IM)
+  ...     def __init__(self, x, q):
+  ...         self.x, self.q = x, q
+  >>> registry.register([IR, IQ], IM, '', M)
+
+And then we can call `queryMultiAdapter` to compute an adapter:
+
+  >>> q = Q()
+  >>> m = registry.queryMultiAdapter((x, q), IM)
+  >>> m.__class__.__name__
+  'M'
+  >>> m.x is x and m.q is q
+  True
+
+and, of course, we can use names:
+
+  >>> class M2(M):
+  ...     pass
+  >>> registry.register([IR, IQ], IM, 'bob', M2)
+  >>> m = registry.queryMultiAdapter((x, q), IM, 'bob')
+  >>> m.__class__.__name__
+  'M2'
+  >>> m.x is x and m.q is q
+  True
   
 Default Adapters
 ----------------
@@ -332,6 +414,28 @@
   >>> registry.subscriptions([], IP2)
   ['sub2']
 
+
+Subscription adapters
+---------------------
+
+We normally register adapter factories, which then allow us to compute
+adapters, but with subscriptions, we get multiple adapters.  Here's an
+example of multiple-object subscribers:
+
+  >>> registry.subscribe([IR, IQ], IM, M)
+  >>> registry.subscribe([IR, IQ], IM, M2)
+
+  >>> subscribers = registry.subscribers((x, q), IM)
+  >>> len(subscribers)
+  2
+  >>> class_names = [s.__class__.__name__ for s in subscribers]
+  >>> class_names.sort()
+  >>> class_names
+  ['M', 'M2']
+  >>> [(s.x is x and s.q is q) for s in subscribers]
+  [True, True]
+
+
 Handlers
 --------
 



More information about the Zope3-Checkins mailing list