[Zodb-checkins] CVS: Zope3/src/zope/interface - adapter.py:1.9
interface.py:1.24 interfaces.py:1.22 surrogate.py:NONE
Jim Fulton
jim at zope.com
Mon Mar 8 12:27:28 EST 2004
Update of /cvs-repository/Zope3/src/zope/interface
In directory cvs.zope.org:/tmp/cvs-serv4511/src/zope/interface
Modified Files:
adapter.py interface.py interfaces.py
Removed Files:
surrogate.py
Log Message:
Removed the old adapter registry code.
Renamed the surrogate registry to AdapterRegistry and moved the
surrogate code to zope.interface.adapter.
Removed the old surrogate module.
=== Zope3/src/zope/interface/adapter.py 1.8 => 1.9 ===
--- Zope3/src/zope/interface/adapter.py:1.8 Fri Mar 5 17:09:28 2004
+++ Zope3/src/zope/interface/adapter.py Mon Mar 8 12:26:56 2004
@@ -13,200 +13,1131 @@
##############################################################################
"""Adapter-style interface registry
-See Adapter class.
+This implementationb is based on a notion of "surrogate" interfaces.
$Id$
"""
-__metaclass__ = type # All classes are new style when run with Python 2.2+
-from zope.interface import Interface, implements, providedBy
-from zope.interface import Declaration
-from zope.interface.interfaces import IInterface
-from zope.interface.interfaces import IAdapterRegistry
-from _flatten import _flatten
-class AdapterRegistry:
- """Adapter-style interface registry
+# Implementation notes
+
+# We keep a collection of surrogates.
+
+# A surrogate is a surrogate for a specification (interface or
+# declaration). We use weak references in order to remove surrogates
+# if the corresponding specification goes away.
+
+# Each surrogate keeps track of:
+
+# - The adapters registered directly for that surrogate, and
+
+# - The "implied" adapters, which is the adapters that can be computed
+# from instances of that surrogate.
+
+# The later data structure takes into account adapters registered for
+# specifications that the registered surrogate extends.
+
+# The registrations are of the form:
+
+# {(subscription, with, name, specification) -> factories}
+
+# where:
+
+# 'subscription' is a flag indicating if this registration is for
+# subscription adapters.
+
+# 'with' is a tuple of specs that is non-empty only in the case
+# of multi-adapters.
+
+# 'name' is a unicode adapter name. Unnamed adapters have an empty
+# name.
+
+# 'specification' is the interface being adapted to.
+
+# 'factories' is normally a tuple of factories, but can be anything.
+# (See the "raw" option to the query-adapter calls.) For subscription
+# adapters, it is a tuple of tuples of factories.
+
+# The implied adapters are held in a single dictionary. The items in the
+# dictionary are of 3 forms:
+
+# (subscription, specification) -> factories
+
+# for simple unnamed adapters
+
+# (subscription, specification, name) -> factories
+
+# for named adapters
+
+# (subscription, specification, name, order) -> {with -> factories}
+
+# for multi-adapters.
+
+
+import weakref
+from sets import Set
+from zope.interface.ro import ro
+from zope.interface.declarations import providedBy
+from zope.interface.interface import InterfaceClass
+
+Default = InterfaceClass("Default", (), {})
+
+class ReadProperty(object):
+
+ def __init__(self, func):
+ self.func = func
+
+ def __get__(self, inst, class_):
+ if inst is None:
+ return self
+ return self.func(inst)
+
+class Surrogate(object):
+ """Specification surrogate
+
+ A specification surrogate is used to hold adapter registrations on
+ behalf of a specification.
"""
- implements(IAdapterRegistry)
+ def __init__(self, spec, registry):
+ self.spec = spec.weakref()
+ spec.subscribe(self)
+ self.adapters = {}
+ self.dependents = weakref.WeakKeyDictionary()
+
+ self.__bases__ = [registry.get(base) for base in spec.__bases__]
+ for base in self.__bases__:
+ base.subscribe(self)
+
+ def dirty(self):
+ if 'get' in self.__dict__:
+ # Not already dirty
+ del self.selfImplied
+ del self.multImplied
+ del self.get
+ for dependent in self.dependents.keys():
+ dependent.dirty()
+
+ def clean(self):
+ self.selfImplied, self.multImplied = adapterImplied(self.adapters)
+
+ implied = {}
+
+ ancestors = ro(self)
+
+ # Collect implied data in reverse order to have more specific data
+ # override less-specific data.
+ ancestors.reverse()
+ for ancestor in ancestors:
+ for key, adapters in ancestor.selfImplied.iteritems():
+ subscription = key[0]
+ if subscription:
+ adapters = tuple(map(tuple, adapters))
+ implied[key] = tuple(Set(implied.get(key, ()) + adapters))
+ else:
+ implied[key] = adapters
+ for k, ancestor_adapters in ancestor.multImplied.iteritems():
+ implied_adapters = implied.get(k)
+ if implied_adapters:
+ subscription = k[0]
+ if subscription:
+ for key, adapters in ancestor_adapters.iteritems():
+ # XXX: remove dupes?
+ implied_adapters[key] = implied_adapters.get(
+ key, []) + adapters
+ else:
+ implied_adapters.update(ancestor_adapters)
+ else:
+ implied[k] = ancestor_adapters.copy()
- # The implementation uses a mapping:
- #
- # { (required, provided) -> (registered_provided, component) }
- #
- # Where the registered provides is what was registered and
- # provided may be some base interface
-
- def __init__(self, data=None):
- if data is None:
- data = {}
- self._reg = data
-
- def _registerAllProvided(self, require, primary_provide, object, provide):
- # Registers a component using (require, provide) as a key.
- # Also registers superinterfaces of the provided interface,
- # stopping when the registry already has a component
- # that provides a more general interface or when the Base is Interface.
-
- reg = self._reg
- reg[(require, provide)] = (primary_provide, object)
- bases = getattr(provide, '__bases__', ())
- for base in bases:
- if base is Interface:
- # Never register the say-nothing Interface.
- continue
- existing = reg.get((require, base), None)
- if existing is not None:
- existing_provide = existing[0]
- if existing_provide is not primary_provide:
- if not existing_provide.extends(primary_provide):
- continue
- # else we are registering a general component
- # after a more specific component.
- self._registerAllProvided(require, primary_provide, object, base)
-
-
- def register(self, require, provide, object):
-
- if require is not None and not IInterface.providedBy(require):
- raise TypeError(
- "The require argument must be an interface (or None)")
- if not IInterface.providedBy(provide):
- raise TypeError(
- "The provide argument must be an interface")
-
- # Invalidate our cache
- self._v_cache = {}
-
- self._registerAllProvided(require, provide, object, provide)
-
- def get(self, ob_interface_provide, default=None, filter=None):
- """
- Finds a registered component that provides the given interface.
- Returns None if not found.
- """
-
- if filter is None:
- cache = getattr(self, '_v_cache', self)
- if cache is self:
- cache = self._v_cache = {}
-
- # get the cache key
- key = ob_interface_provide
-
- cached = cache.get(key, self)
- if cached is self:
- cached = self._uncached_get(ob_interface_provide,
- default, filter)
- cache[key] = cached
- return cached
- return self._uncached_get(ob_interface_provide,
- default, filter)
+ self.get = implied.get
- def _uncached_get(self, (ob_interface, provide), default, filter):
+ def get(self, key):
+ """Get an implied value
- try:
- flattened = ob_interface.flattened
- except AttributeError:
- # Somebodey (probably a test) passed us a bare interface
- if ob_interface is not None:
- flattened = Declaration(ob_interface).flattened()
- else:
- flattened = None,
- else:
- flattened = flattened()
-
-
- for interface in flattened:
- c = self._reg.get((interface, provide))
- if c:
- c = c[1]
- if filter is None:
- return c
- if filter(c):
- return c
-
- c = self._reg.get((None, provide))
- if c:
- c = c[1]
- if filter is None:
- return c
- if filter(c):
- return c
+ This is only called when the surrogate is dirty
+ """
+ self.clean()
+ return self.__dict__['get'](key)
+
+ def selfImplied(self):
+ """Return selfImplied when dirty
+ """
+ self.clean()
+ return self.__dict__['selfImplied']
+ selfImplied = ReadProperty(selfImplied)
+
+ def multiImplied(self):
+ """Return _multiImplied when dirty
+ """
+ self.clean()
+ return self.__dict__['multiImplied']
+ multiImplied = ReadProperty(multiImplied)
+
+ def subscribe(self, dependent):
+ self.dependents[dependent] = 1
+
+ def unsubscribe(self, dependent):
+ del self.dependents[dependent]
+
+ def _adaptTo(self, specification, factories, name='', with=()):
+ if factories is None:
+ try:
+ del self.adapters[False, tuple(with), name, specification]
+ except KeyError:
+ pass
+ else:
+ self.adapters[False, tuple(with), name, specification] = factories
+
+ self.dirty()
+
+ def _subscriptionAdaptTo(self, specification, factories, name='', with=()):
+ if factories is None:
+ raise TypeError, ("Unregistering subscription adapters"
+ " isn't implemented")
+
+ # Add factories to our list of factory lists.
+ key = (True, tuple(with), name, specification)
+ factoriesList = self.adapters.get(key, ())
+ factoriesList = factoriesList + (factories,)
+ self.adapters[key] = factoriesList
+
+ self.dirty()
+
+ def changed(self, which=None):
+ self.dirty()
+
+ def __repr__(self):
+ return '<%s(%s)>' % (self.__class__.__name__, self.spec())
+
+class AdapterRegistry(object):
+ """Surrogate registry
+ """
+
+ # Implementation node:
+ # 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
+ surrogates = {Default.weakref(): default}
+ self._surrogates = surrogates
+
+ def _remove(k):
+ try:
+ del surrogates[k]
+ except KeyError:
+ pass
+
+ 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 provideAdapter(self, required, provided, factories, name=u'', with=()):
+ """Register an adapter
+
+ Note that the given name must be convertable to unicode.
+ Use an empty string for unnamed adapters. It is impossible to
+ have a named adapter with an empty name.
+ """
+ required = self.get(required)
+ if with:
+ with = tuple(with)
+ else:
+ with = ()
+
+ if not isinstance(name, basestring):
+ raise TypeError("The name provided to provideAdapter "
+ "must be a string or unicode")
+ required._adaptTo(provided, factories, unicode(name), with)
+
+ def provideSubscriptionAdapter(self, required, provided, factories,
+ name=u'', with=()):
+ """Register a subscription adapter
+
+ Note that the given name must be convertable to unicode.
+ Use an empty string for unnamed subscription adapters. It is
+ impossible to have a named subscription adapter with an empty name.
+ """
+ required = self.get(required)
+ if with:
+ with = tuple(with)
+ else:
+ with = ()
+
+ if not isinstance(name, basestring):
+ raise TypeError("The name provided to provideAdapter "
+ "must be a string or unicode")
+ required._subscriptionAdaptTo(provided, factories, unicode(name), with)
+
+ def queryAdapter(self, ob, interface, default=None, raw=False):
+ """Query a simple adapter
+
+ >>> import zope.interface
+ >>> class F0(zope.interface.Interface):
+ ... pass
+ >>> class F1(F0):
+ ... pass
+
+ >>> class C:
+ ... zope.interface.implements(F1)
+ >>> c = C()
+
+ >>> registry = AdapterRegistry()
+
+ Adapting to some other interface for which there is no
+ adapter returns the default:
+
+ >>> class B0(zope.interface.Interface):
+ ... pass
+ >>> class B1(B0):
+ ... pass
+
+ >>> registry.queryAdapter(c, B0)
+ >>> registry.queryAdapter(c, B0, 42)
+ 42
+
+ Unless we define an adapter:
+
+ >>> def f1(ob):
+ ... return 1
+
+ >>> registry.provideAdapter(F0, B1, [f1])
+ >>> registry.queryAdapter(c, B0)
+ 1
+ If we define a more specific adapter (for F1), we'll get that:
+ >>> def f2(ob):
+ ... return 2
+
+ >>> registry.provideAdapter(F1, B1, [f2])
+ >>> registry.queryAdapter(c, B0)
+ 2
+
+ >>> def f3(ob):
+ ... return 3
+
+ >>> registry.provideAdapter(F1, B0, [f3])
+ >>> registry.queryAdapter(c, B0)
+ 3
+ """
+
+ declaration = providedBy(ob)
+ s = self.get(declaration)
+
+ factories = s.get((False, interface))
+ if factories is None:
+ factories = self._default.get((False, interface))
+
+ if factories is not None:
+ if raw:
+ return factories
+
+ for factory in factories:
+ ob = factory(ob)
+ return ob
+
+ return default
+
+
+ def queryFactory(self, declaration, interface, default=None):
+ """Query for factory that adapts type-declaration things to interface.
+
+ This enables you to get an adapter, and/or check for the existence
+ of one, given just the type (interface) of a thing.
+
+ >>> import zope.interface
+ >>> from zope.interface import implementedBy
+ >>> class F0(zope.interface.Interface):
+ ... pass
+ >>> class F1(F0):
+ ... pass
+
+ >>> class C:
+ ... zope.interface.implements(F1)
+ >>> c = C()
+
+ >>> registry = AdapterRegistry()
+
+ Adapting to some other interface for which there is no
+ adapter returns the default:
+
+ >>> class B0(zope.interface.Interface):
+ ... pass
+ >>> class B1(B0):
+ ... pass
+
+ >>> registry.queryFactory(F1, B0)
+ >>> registry.queryFactory(F1, B0, 42)
+ 42
+
+ Unless we define an adapter:
+
+ >>> def f1(ob):
+ ... return 1
+
+ >>> registry.provideAdapter(F0, B1, [f1])
+ >>> registry.queryFactory(F1, B0) == [f1]
+ True
+
+ If we define a more specific adapter (for F1), we'll get that:
+
+ >>> def f2(ob):
+ ... return 2
+
+ >>> registry.provideAdapter(F1, B1, [f2])
+ >>> registry.queryFactory(F1, B0) == [f2]
+ True
+
+ >>> def f3(ob):
+ ... return 3
+
+ >>> registry.provideAdapter(F1, B0, [f3])
+ >>> registry.queryFactory(F1, B0) == [f3]
+ True
+ """
+
+ s = self.get(declaration)
+
+ factories = s.get((False, interface))
+ if factories is None:
+ factories = self._default.get((False, interface))
+
+ if factories is not None:
+ return factories
+
+ return default
+
+
+ def querySubscriptionAdapter(self, ob, interface, name=u'', default=(),
+ raw=False):
+ """Query for subscription adapters
+
+ >>> import zope.interface
+ >>> class IAnimal(zope.interface.Interface):
+ ... pass
+ >>> class IPoultry(IAnimal):
+ ... pass
+ >>> class IChicken(IPoultry):
+ ... pass
+ >>> class ISeafood(IAnimal):
+ ... pass
+
+ >>> class Poultry:
+ ... zope.interface.implements(IPoultry)
+ >>> poultry = Poultry()
+
+ >>> registry = AdapterRegistry()
+
+ Adapting to some other interface for which there is no
+ subscription adapter returns the default:
+
+ >>> class IRecipe(zope.interface.Interface):
+ ... pass
+ >>> class ISausages(IRecipe):
+ ... pass
+ >>> class INoodles(IRecipe):
+ ... pass
+ >>> class IKFC(IRecipe):
+ ... pass
+
+ >>> list(registry.querySubscriptionAdapter(poultry, IRecipe))
+ []
+ >>> registry.querySubscriptionAdapter(poultry, IRecipe, default=42)
+ 42
+
+ Unless we define a subscription adapter:
+
+ >>> def sausages(ob):
+ ... return 'sausages'
+
+ >>> registry.provideSubscriptionAdapter(IAnimal, ISausages, [sausages])
+ >>> list(registry.querySubscriptionAdapter(poultry, ISausages))
+ ['sausages']
+
+ And define another subscription adapter:
+
+ >>> def noodles(ob):
+ ... return 'noodles'
+
+ >>> registry.provideSubscriptionAdapter(IPoultry, INoodles, [noodles])
+ >>> meals = list(registry.querySubscriptionAdapter(poultry, IRecipe))
+ >>> meals.sort()
+ >>> meals
+ ['noodles', 'sausages']
+
+ >>> class Chicken:
+ ... zope.interface.implements(IChicken)
+ >>> chicken = Chicken()
+
+ >>> def kfc(ob):
+ ... return 'kfc'
+
+ >>> registry.provideSubscriptionAdapter(IChicken, IKFC, [kfc])
+ >>> meals = list(registry.querySubscriptionAdapter(chicken, IRecipe))
+ >>> meals.sort()
+ >>> meals
+ ['kfc', 'noodles', 'sausages']
+
+ And the answer for poultry hasn't changed:
+
+ >>> registry.provideSubscriptionAdapter(IPoultry, INoodles, [noodles])
+ >>> meals = list(registry.querySubscriptionAdapter(poultry, IRecipe))
+ >>> meals.sort()
+ >>> meals
+ ['noodles', 'sausages']
+ """
+
+ declaration = providedBy(ob)
+ s = self.get(declaration)
+
+ if name:
+ key = (True, interface, name)
+ else:
+ key = (True, interface)
+
+ factoriesLists = s.get(key)
+ if factoriesLists is None:
+ factoriesLists = self._default.get(key)
+
+ if factoriesLists is not None:
+ if raw:
+ return factoriesLists
+
+ return [factory(ob)
+ for factories in factoriesLists
+ for factory in factories]
+
+ return default
+
+
+ def queryNamedAdapter(self, ob, interface, name, default=None, raw=False):
+ """Query a named simple adapter
+
+ >>> import zope.interface
+ >>> class F0(zope.interface.Interface):
+ ... pass
+ >>> class F1(F0):
+ ... pass
+
+ >>> class C:
+ ... zope.interface.implements(F1)
+ >>> c = C()
+
+ >>> registry = AdapterRegistry()
+
+ If we ask for a named adapter, we won't get a result unless there
+ is a named adapter, even if the object implements the interface:
+
+ >>> registry.queryNamedAdapter(c, F0, 'bob')
+
+ >>> class B0(zope.interface.Interface):
+ ... pass
+ >>> class B1(B0):
+ ... pass
+
+
+ >>> def f1(ob):
+ ... return 1
+
+ >>> registry.provideAdapter(F0, B1, [f1], name='bob')
+ >>> registry.queryNamedAdapter(c, B0, 'bob')
+ 1
+ >>> registry.queryNamedAdapter(c, B0, 'bruce')
+
+
+ >>> def f2(ob):
+ ... return 2
+
+ >>> registry.provideAdapter(F1, B1, [f2], name='bob')
+ >>> registry.queryNamedAdapter(c, B0, 'bob')
+ 2
+
+ >>> def f3(ob):
+ ... return 3
+
+ >>> registry.provideAdapter(F1, B0, [f3], name='bob')
+ >>> registry.queryNamedAdapter(c, B0, 'bob')
+ 3
+
+ """
+
+ declaration = providedBy(ob)
+ s = self.get(declaration)
+ if name:
+ key = (False, interface, name)
+ else:
+ key = (False, interface)
+ factories = s.get(key)
+ if factories is None:
+ factories = self._default.get(key)
+ if factories is not None:
+ if raw:
+ return factories
+ for factory in factories:
+ ob = factory(ob)
+ return ob
return default
- def getForObject(self, object, interface, filter=None):
- return self.get((providedBy(object), interface), filter=filter)
+ def queryMultiAdapter(self, objects, interface, name=u'',
+ default=None, raw=False, _subscription=False):
+ """
+
+ >>> import zope.interface
+ >>> class IF0(zope.interface.Interface):
+ ... pass
+ >>> class IF1(IF0):
+ ... pass
+
+ >>> class IR0(zope.interface.Interface):
+ ... pass
+ >>> class IR1(IR0):
+ ... pass
+
+ >>> class F1:
+ ... zope.interface.implements(IF1)
+ >>> c = F1()
+
+ >>> class R1:
+ ... zope.interface.implements(IR1)
+ >>> r = R1()
+
+ >>> registry = AdapterRegistry()
+
+ If we ask for a multi adapter, we won't get a result unless there
+ is a named adapter, even if the object implements the interface:
+
+ >>> registry.queryMultiAdapter((c, r), IF0, 'bob')
+
+ >>> class IB0(zope.interface.Interface):
+ ... pass
+ >>> class IB1(IB0):
+ ... pass
+
+
+ >>> class f1:
+ ... def __init__(self, x, y):
+ ... self.x, self.y = x, y
+
+
+ >>> registry.provideAdapter(IF0, IB1, [f1], name='bob', with=[IR0])
+ >>> a = registry.queryMultiAdapter((c, r), IB0, 'bob')
+ >>> a.__class__ is f1
+ True
+ >>> a.x is c
+ True
+ >>> a.y is r
+ True
+
+ >>> registry.queryMultiAdapter((c, r), IB0, 'bruce')
+
+ >>> class f2(f1):
+ ... pass
+
+ >>> registry.provideAdapter(IF1, IB1, [f2], name='bob', with=[IR1])
+ >>> a = registry.queryMultiAdapter((c, r), IB0, 'bob')
+ >>> a.__class__ is f2
+ True
+ >>> a.x is c
+ True
+ >>> a.y is r
+ True
+
+ """
+ ob = objects[0]
+ order = len(objects)
+ obs = objects[1:]
+
+ declaration = providedBy(ob)
+ if _subscription:
+ result = []
+
+ surrogates = (self.get(declaration), self._default)
+
+ for surrogate in surrogates:
+ adapters = surrogate.get((_subscription, interface, name, order))
+ if adapters:
+ if _subscription:
+ matched_factories = []
+ else:
+ matched = None
+ matched_factories = None
+ for interfaces, factories in adapters.iteritems():
+ for iface, ob in zip(interfaces, obs):
+ if not iface.providedBy(ob):
+ break # This one is no good
+ else:
+ if _subscription:
+ matched_factories.extend(factories)
+ else:
+ # we didn't break, so we have a match
+ if matched is None:
+ matched = interfaces
+ matched_factories = factories
+ else:
+ # see if the new match is better than the old
+ # one:
+ for iface, m in zip(interfaces, matched):
+ if iface.extends(m):
+ # new is better than old
+ matched = interfaces
+ matched_factories = factories
+ break
+ elif m.extends(iface):
+ # old is better than new
+ break
+
+
+ if matched_factories is not None:
+ if raw:
+ return matched_factories
+
+ if not _subscription:
+ assert len(matched_factories) == 1, \
+ "matched_factories has more than 1 element: " \
+ + repr(matched_factories)
+ return matched_factories[0](*objects)
+ else:
+ for factories in matched_factories:
+ assert len(factories) == 1
+ result.append(factories[0](*objects))
+
+ if _subscription and result:
+ return result
+ else:
+ return default
- def getRegistered(self, require, provide):
- data = self._reg.get((require, provide))
- if data:
- registered_provide, object = data
- if registered_provide == provide:
- return object
- return None
+ def querySubscriptionMultiAdapter(self, objects, interface, name=u'',
+ default=(), raw=False):
+ """
+ Subscription multiadaption works too:
+
+ >>> import zope.interface
+ >>> class IAnimal(zope.interface.Interface):
+ ... pass
+ >>> class IPoultry(IAnimal):
+ ... pass
+ >>> class IChicken(IPoultry):
+ ... pass
+ >>> class ISeafood(IAnimal):
+ ... pass
+
+ >>> class Animal:
+ ... zope.interface.implements(IAnimal)
+ >>> animal = Animal()
+
+ >>> class Poultry:
+ ... zope.interface.implements(IPoultry)
+ >>> poultry = Poultry()
+
+ >>> class Poultry:
+ ... zope.interface.implements(IPoultry)
+ >>> poultry = Poultry()
+
+ >>> class Chicken:
+ ... zope.interface.implements(IChicken)
+ >>> chicken = Chicken()
+
+
+ >>> class IRecipe(zope.interface.Interface):
+ ... pass
+ >>> class ISausages(IRecipe):
+ ... pass
+ >>> class INoodles(IRecipe):
+ ... pass
+ >>> class IKFC(IRecipe):
+ ... pass
+
+ >>> class IDrink(zope.interface.Interface):
+ ... pass
+
+ >>> class Drink:
+ ... zope.interface.implements(IDrink)
+ >>> drink = Drink()
+
+ >>> class Meal:
+ ... def __init__(self, animal, drink):
+ ... self.animal, self.drink = animal, drink
+ >>> class Lunch(Meal):
+ ... pass
+ >>> class Dinner(Meal):
+ ... pass
+
+ >>> registry = AdapterRegistry()
+ >>> query = registry.querySubscriptionMultiAdapter
+ >>> provide = registry.provideSubscriptionAdapter
+
+ Can't find adapters for insufficiently specific interfaces:
+
+ >>> provide(IPoultry, IRecipe, [Dinner], with=[IDrink])
+ >>> list(query((animal, drink), IRecipe))
+ []
+
+ But we can for equally specific:
+
+ >>> adapters = list(query((poultry, drink), IRecipe))
+ >>> len(adapters)
+ 1
+
+ And for more specific:
+
+ >>> adapters = list(query((chicken, drink), IRecipe))
+ >>> len(adapters)
+ 1
+
+ >>> provide(IAnimal, IRecipe, [Meal], with=[IDrink])
+ >>> provide(IAnimal, IRecipe, [Lunch], with=[IDrink])
+ >>> adapters = list(query((animal, drink), IRecipe))
+ >>> names = [a.__class__.__name__ for a in adapters]
+ >>> names.sort()
+ >>> names
+ ['Lunch', 'Meal']
+ >>> adapters[0].animal is animal
+ True
+ >>> adapters[0].drink is drink
+ True
+ >>> adapters[1].animal is animal
+ True
+ >>> adapters[1].drink is drink
+ True
+
+ Mixed specificities:
+
+ >>> registry = AdapterRegistry()
+ >>> query = registry.querySubscriptionMultiAdapter
+ >>> provide = registry.provideSubscriptionAdapter
+
+ >>> provide(IPoultry, IRecipe, [Meal], with=[IDrink])
+ >>> provide(IChicken, IRecipe, [Lunch], with=[IDrink])
+
+ We can only use IPoultry recipes on poultry -- we can't apply chicken
+ recipes because poultry isn't specific enough. So there's only one
+ choice for poultry:
+
+ >>> adapters = list(query((poultry, drink), IRecipe))
+ >>> len(adapters)
+ 1
+
+ But using chicken, we can use poultry *and* chicken recipes:
+
+ >>> adapters = list(query((chicken, drink), IRecipe))
+ >>> len(adapters)
+ 2
+
+ We should get the same results if we swap the order of the input types:
+
+ >>> registry = AdapterRegistry()
+ >>> query = registry.querySubscriptionMultiAdapter
+ >>> provide = registry.provideSubscriptionAdapter
+
+ >>> provide(IDrink, IRecipe, [Meal], with=[IPoultry])
+ >>> provide(IDrink, IRecipe, [Lunch], with=[IChicken])
+
+ >>> adapters = list(query((drink,poultry), IRecipe))
+ >>> len(adapters)
+ 1
+ >>> adapters = list(query((drink,chicken), IRecipe))
+ >>> len(adapters)
+ 2
+
+ And check that names work, too:
+
+ >>> adapters = list(query((drink,poultry), IRecipe, name='Joes Diner'))
+ >>> len(adapters)
+ 0
+
+ >>> provide(IDrink, IRecipe, [Meal], with=[IPoultry],name='Joes Diner')
+ >>> adapters = list(query((drink,poultry), IRecipe, name='Joes Diner'))
+ >>> len(adapters)
+ 1
+
+ """
+ return self.queryMultiAdapter(objects, interface, name, default, raw,
+ _subscription=True)
def getRegisteredMatching(self,
required=None,
- provided=None):
+ provided=None,
+ name=None,
+ with=None,
+ ):
+ """Search for registered adapters
+
+ Return a 5-tuple with:
+
+ - (first) required interface
+
+ - provided interface
+
+ - a tuple of additional required interfaces (for multi-adapters)
+
+ - name, and
+
+ - a sequence of factories. (Note that this could be arbitrary data).
+
+
+ Note, this is usually slow!
+
+ >>> from zope.interface import Interface
+
+ >>> class R1(Interface):
+ ... pass
+ >>> class R12(Interface):
+ ... pass
+ >>> class R2(R1):
+ ... pass
+ >>> class R3(R2):
+ ... pass
+ >>> class R4(R3):
+ ... pass
+
+ >>> class P1(Interface):
+ ... pass
+ >>> class P2(P1):
+ ... pass
+ >>> class P3(P2):
+ ... pass
+ >>> class P4(P3):
+ ... pass
+
+
+ >>> registry = AdapterRegistry()
+ >>> registry.provideAdapter(None, P3, 'default P3')
+ >>> registry.provideAdapter(Interface, P3, 'any P3')
+ >>> registry.provideAdapter(R2, P3, 'R2 P3')
+ >>> registry.provideAdapter(R2, P3, "bobs R2 P3", name='bob')
+
+ >>> from pprint import PrettyPrinter
+ >>> pprint = PrettyPrinter(width=60).pprint
+ >>> def sorted(x):
+ ... x = [(getattr(r, '__name__', None), p.__name__, w, n, f)
+ ... for (r, p, w, n, f) in x]
+ ... x.sort()
+ ... pprint(x)
+
+ >>> sorted(registry.getRegisteredMatching())
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(name=''))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(required=[R1]))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3')]
+
+ >>> sorted(registry.getRegisteredMatching(required=R1))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3')]
+
+ >>> sorted(registry.getRegisteredMatching(provided=[P1]))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(provided=P1))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(provided=P3))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(
+ ... required = (R4, R12),
+ ... provided = (P1, )))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(
+ ... required = (R4, R12),
+ ... provided = (P3, )))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(
+ ... required = (R2, ),
+ ... provided = (P3, )))
+ [(None, 'P3', (), u'', 'default P3'),
+ ('Interface', 'P3', (), u'', 'any P3'),
+ ('R2', 'P3', (), u'', 'R2 P3'),
+ ('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(
+ ... required = (R2, ),
+ ... provided = (P3, ),
+ ... name='bob'))
+ [('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ >>> sorted(registry.getRegisteredMatching(
+ ... required = (R3, ),
+ ... provided = (P1, ),
+ ... name='bob'))
+ [('R2', 'P3', (), u'bob', 'bobs R2 P3')]
+
+ """
+
+ if name is not None:
+ name = unicode(name)
+
+ if isinstance(required, InterfaceClass):
+ required = (required, )
+ elif required is None:
+ required = [ref() for ref in self._surrogates.keys()
+ if ref() is not None]
+
+ required = tuple(required)+(None,)
+
+ if isinstance(provided, InterfaceClass):
+ provided = (provided, )
+
+
+ seen = {}
+
+ for required in required:
+ s = self.get(required)
+ for ancestor in ro(s):
+ if ancestor in seen:
+ continue
+ seen[ancestor] = 1
+ adapters = ancestor.adapters
+ if adapters:
+ items = adapters.iteritems()
+ ancestor = ancestor.spec()
+ if ancestor is Default:
+ ancestor = None
+ for key, factories in items:
+ subscription, rwith, aname, target = key
+ if subscription:
+ raise NotImplementedError
+ if with is not None and not mextends(with, rwith):
+ continue
+ if name is not None and aname != name:
+ continue
+
+ if provided:
+ for p in provided:
+ if target.extends(p, False):
+ break
+ else:
+ # None matching
+ continue
+
+ yield (ancestor, target, rwith, aname, factories)
+
+
+
+def mextends(with, rwith):
+ if len(with) == len(rwith):
+ for w, r in zip(with, rwith):
+ if not w.isOrExtends(r):
+ break
+ else:
+ return True
+ return False
+
+
+def adapterImplied(adapters):
+ implied = {}
+ multi = {}
+ registered = {}
+ # Add adapters and interfaces directly implied by same:
+ for key, factories in adapters.iteritems():
+
+ # XXX Backward compatability
+ # Don't need to handle 3-tuples some day
+ try:
+ (subscription, with, name, target) = key
+ except ValueError:
+ (with, name, target) = key
+ subscription = False
+ if with:
+ _add_multi_adapter(with, name, target, target, multi,
+ registered, factories, subscription)
+ elif name:
+ _add_named_adapter(target, target, name, implied,
+ registered, factories, subscription)
+ else:
+ _add_adapter(target, target, implied, registered, factories,
+ subscription)
- required_interfaces = required
- provided_interfaces = provided
+ return implied, multi
- if IInterface.providedBy(required_interfaces):
- required_interfaces = (required_interfaces, )
+def _add_adapter(target, provided, implied, registered, factories,
+ subscription):
+ key = subscription, target
+ if (key not in implied
+ or
+ (key in registered and registered[key].extends(provided))
+ ):
+ registered[key] = provided
+ implied[key] = factories
+ for b in target.__bases__:
+ _add_adapter(b, provided, implied, registered, factories,
+ subscription)
+
+def _add_named_adapter(target, provided, name,
+ implied, registered, factories, subscription):
+ key = subscription, target, name
+ if (key not in implied
+ or
+ (key in registered and registered[key].extends(provided))
+ ):
+ registered[key] = provided
+ implied[key] = factories
+ for b in target.__bases__:
+ _add_named_adapter(b, provided, name,
+ implied, registered, factories, subscription)
+
+def _add_multi_adapter(interfaces, name, target, provided, implied,
+ registered, factories, subscription):
+ order = len(interfaces)+1
+ key = subscription, target, name, order
+ adapters = implied.get(key)
+ if adapters is None:
+ adapters = {}
+ implied[key] = adapters
+
+ key = key, interfaces # The full key has all 5
+ if key not in registered or registered[key].extends(provided):
+ # This is either a new entry or it is an entry for a more
+ # general interface that is closer provided than what we had
+ # before
+ registered[key] = provided
+ adapters[interfaces] = factories
+
+ for b in target.__bases__:
+ _add_multi_adapter(interfaces, name, b, provided, implied,
+ registered, factories, subscription)
- if provided_interfaces:
-
- if IInterface.providedBy(provided_interfaces):
- provided_interfaces = (provided_interfaces, )
-
- r = {}
-
- if required_interfaces:
- # Both specified
- for required in _flatten(required_interfaces, 1):
- for provided in provided_interfaces:
- v = self._reg.get((required, provided))
- if v:
- rprovided, o = v
- r[required, rprovided] = o
-
-
- else:
- # Only provided specified
- for (required, provided), (rprovided, o) in self._reg.items():
- for p in provided_interfaces:
- if provided.extends(p, 0):
- r[required, rprovided] = o
- break
-
- return [(required, provided, o)
- for ((required, provided), o) in r.items()]
-
-
- elif required_interfaces:
- # Just required specified
- required_interfaces = _flatten(required_interfaces, 1)
- return [(required, provided, o)
- for (required, provided), (rprovided, o)
- in self._reg.items()
- if ((required in required_interfaces)
- and
- provided == rprovided
- )
- ]
-
- else:
- # Nothing specified
- return [(required, provided, o)
- for (required, provided), (rprovided, o)
- in self._reg.items()
- if provided == rprovided
- ]
=== Zope3/src/zope/interface/interface.py 1.23 => 1.24 ===
--- Zope3/src/zope/interface/interface.py:1.23 Sat Mar 6 10:38:46 2004
+++ Zope3/src/zope/interface/interface.py Mon Mar 8 12:26:56 2004
@@ -204,7 +204,7 @@
def isImplementedByInstancesOf(self, cls):
warnings.warn(
"isImplementedByInstancesOf has been renamed to implementedBy",
- DeprecationWarning, stacklevel=1,
+ DeprecationWarning, stacklevel=2,
)
return self.implementedBy(cls)
=== Zope3/src/zope/interface/interfaces.py 1.21 => 1.22 ===
--- Zope3/src/zope/interface/interfaces.py:1.21 Fri Mar 5 17:09:28 2004
+++ Zope3/src/zope/interface/interfaces.py Mon Mar 8 12:26:56 2004
@@ -324,107 +324,6 @@
"""Returns the number of distinct interfaces registered.
"""
-
-class IAdapterRegistry(Interface):
- """Adapter-style registry
-
- This registry stores objects registered to convert (or participate
- in the conversion from) one interface to another. The interface
- converted is the "required" interface. We say that the interface
- converted to is the "provided" interface.
-
- The objects registered here don't need to be adapters. What's
- important is that they are registered according to a required and
- a provided interface.
-
- The provided interface may not be None.
-
- The required interface may be None. Adapters with a required
- interface of None adapt non-components. An adapter that adapts all
- components should specify a required interface of
- Interface.Interface.
-
- """
-
- def register(require, provide, object):
- """Register an object for a required and provided interface.
-
- There are no restrictions on what the object might be.
- Any restrictions (e.g. callability, or interface
- implementation) must be enforced by higher-level code.
-
- The require argument may be None.
-
- """
-
- def get((implements, provides), default=None, filter=None):
- """Return a registered object
-
- The registered object is one that was registered to require an
- interface that one of the interfaces in the 'implements'
- specification argument extends or equals and that provides an
- interface that extends or equals the 'provides' argument. An
- attempt will be made to find the component that most closely
- matches the input arguments.
-
- The object returned could have been registered to require None.
-
- Note that the implements may be None, it which case a
- component will be returned only if it was registered with a
- require of None.
-
- An optional filter may be provided. If provided, the returned
- object must pass the filter. Search will continue until a
- suitable match can be found. The filter should take a single
- argument and return a true value if the object passes the
- filter, or false otherwise.
-
- """
-
- def getForObject(object, interface, filter=None):
- """Get an adapter for object that implements the specified interface
-
- The filter option has the same meaning as in the get method.
- """
-
- def getRegistered(require, provide):
- """return data registered specifically for the given interfaces
-
- None is returned if nothing is registered.
- """
-
- def getRegisteredMatching(required=None,
- provided=None):
- """Return information about registered data
-
- Zero or more required and provided interfaces may be
- specified. Registration information matching any of the
- specified interfaces is returned.
-
- The arguments may be interfaces, or sequences of interfaces.
-
- The returned value is a sequence of three-element tuples:
-
- - required interface
-
- - provided interface
-
- - the object registered specifically for the required and
- provided interfaces.
-
- To understand how the matching works, imagine that we have
- interfaces R1, R2, P1, and P2. R2 extends R1. P2 extends P1.
- We've registered C to require R1 and provide P2. Given this,
- if we call getRegisteredMatching:
-
- registry.getRegisteredMatching([R2], [P1])
-
- the returned value will include:
-
- (R1, P2, C)
- """
-
-
class IImplementorRegistry(Interface):
"""Implementor registry
=== Removed File Zope3/src/zope/interface/surrogate.py ===
More information about the Zodb-checkins
mailing list