[Zope3-checkins] SVN: Zope3/branches/ZopeX3-3.0/src/zope/ Merged
from trunk 25985:
Jim Fulton
jim at zope.com
Fri Jul 2 18:25:52 EDT 2004
Log message for revision 26080:
Merged from trunk 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/branches/ZopeX3-3.0/src/zope/app/adapter/adapter.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/adapter/adapter.py 2004-07-02 22:17:11 UTC (rev 26079)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/adapter/adapter.py 2004-07-02 22:25:52 UTC (rev 26080)
@@ -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/branches/ZopeX3-3.0/src/zope/app/presentation/presentation.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/presentation/presentation.py 2004-07-02 22:17:11 UTC (rev 26079)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/presentation/presentation.py 2004-07-02 22:25:52 UTC (rev 26080)
@@ -274,7 +274,6 @@
class LocalLayer(
zope.app.adapter.LocalAdapterRegistry,
- zope.component.presentation.Layer,
zope.app.container.contained.Contained,
):
Modified: Zope3/branches/ZopeX3-3.0/src/zope/component/adapter.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/component/adapter.py 2004-07-02 22:17:11 UTC (rev 26079)
+++ Zope3/branches/ZopeX3-3.0/src/zope/component/adapter.py 2004-07-02 22:25:52 UTC (rev 26080)
@@ -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/branches/ZopeX3-3.0/src/zope/component/presentation.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/component/presentation.py 2004-07-02 22:17:11 UTC (rev 26079)
+++ Zope3/branches/ZopeX3-3.0/src/zope/component/presentation.py 2004-07-02 22:25:52 UTC (rev 26080)
@@ -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/branches/ZopeX3-3.0/src/zope/interface/adapter.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.py 2004-07-02 22:17:11 UTC (rev 26079)
+++ Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.py 2004-07-02 22:25:52 UTC (rev 26080)
@@ -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/branches/ZopeX3-3.0/src/zope/interface/adapter.txt
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.txt 2004-07-02 22:17:11 UTC (rev 26079)
+++ Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.txt 2004-07-02 22:25:52 UTC (rev 26080)
@@ -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