[Zope3-checkins] SVN: Zope3/branches/jim-adapter/src/zope/component/ Added new component-management api

Jim Fulton jim at zope.com
Mon Feb 20 16:54:18 EST 2006


Log message for revision 41719:
  Added new component-management api
  

Changed:
  A   Zope3/branches/jim-adapter/src/zope/component/components.py
  A   Zope3/branches/jim-adapter/src/zope/component/components.txt
  U   Zope3/branches/jim-adapter/src/zope/component/interfaces.py
  U   Zope3/branches/jim-adapter/src/zope/component/tests.py

-=-
Added: Zope3/branches/jim-adapter/src/zope/component/components.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/component/components.py	2006-02-20 21:54:16 UTC (rev 41718)
+++ Zope3/branches/jim-adapter/src/zope/component/components.py	2006-02-20 21:54:18 UTC (rev 41719)
@@ -0,0 +1,337 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Basic components support
+
+$Id$
+"""
+
+import zope.interface.adapter
+from zope import interface
+from zope.component import interfaces
+import zope.interface.interfaces
+
+class Components(object):
+
+    def __init__(self, bases=()):
+        self._init_registries()
+        self._init_registrations()
+        self.__bases__ = tuple(bases)
+
+    def _init_registries(self):
+        self.adapters = zope.interface.adapter.AdapterRegistry()
+        self.utilities = zope.interface.adapter.AdapterRegistry()
+
+    def _init_registrations(self):
+        self._utility_registrations = {}
+        self._adapter_registrations = {}
+        self._subscription_registrations = []
+        self._handler_registrations = []
+
+
+    @apply
+    def __bases__():
+
+        def get_bases(self):
+            return self.__dict__['__bases__']
+        def set_bases(self, bases):
+            self.adapters.__bases__ = tuple([
+                base.adapters for base in bases])
+            self.utilities.__bases__ = tuple([
+                base.utilities for base in bases])
+            self.__dict__['__bases__'] = bases
+
+        return property(get_bases, set_bases)
+
+    def registerUtility(self, component, provided=None, name=u'', info=u''):
+        if provided is None:
+            provided = _getUtilityProvided(component)
+        self._utility_registrations[(provided, name)] = component, info
+        self.utilities.register((), provided, name, component)
+
+    def unregisterUtility(self, component=None, provided=None, name=u''):
+        if provided is None:
+            if component is None:
+                raise TypeError("Must specify one of component and provided")
+            provided = _getUtilityProvided(component)
+
+        old = self._utility_registrations.get((provided, name))
+        if (old is None) or ((component is not None) and
+                             (component != old[0])):
+            return False
+        
+        del self._utility_registrations[(provided, name)]
+        self.utilities.unregister((), provided, name)
+        return True
+
+    def registeredUtilities(self):
+        for ((provided, name), (component, info)
+             ) in self._utility_registrations.iteritems():
+            yield UtilityRegistration(provided, name, component, info)
+
+    def queryUtility(self, provided, name=u'', default=None):
+        return self.utilities.lookup((), provided, name, default)
+
+    def getUtility(self, provided, name=u''):
+        utility = self.utilities.lookup((), provided, name)
+        if utility is None:
+            raise interfaces.ComponentLookupError(provided, name)
+        return utility
+
+    def registerAdapter(self, factory, required=None, provided=None, name=u'',
+                        info=u''):
+        if provided is None:
+            provided = _getAdapterProvided(factory)
+        required = _getAdapterRequired(factory, required)
+        self._adapter_registrations[(required, provided, name)
+                                    ] = factory, info
+        self.adapters.register(required, provided, name, factory)
+
+    def unregisterAdapter(self, factory=None,
+                          required=None, provided=None, name=u'',
+                          ):
+        if provided is None:
+            if factory is None:
+                raise TypeError("Must specify one of factory and provided")
+            provided = _getAdapterProvided(factory)
+
+        if (required is None) and (factory is None):
+            raise TypeError("Must specify one of factory and required")
+        
+        required = _getAdapterRequired(factory, required)
+        old = self._adapter_registrations.get((required, provided, name))
+        if (old is None) or ((factory is not None) and
+                             (factory != old[0])):
+            return False
+        
+        del self._adapter_registrations[(required, provided, name)]
+        self.adapters.unregister(required, provided, name)
+        return True
+        
+    def registeredAdapters(self):
+        for ((required, provided, name), (component, info)
+             ) in self._adapter_registrations.iteritems():
+            yield AdapterRegistration(required, provided, name,
+                                      component, info)
+
+    def queryAdapter(self, object, interface, name=u'', default=None):
+        return self.adapters.queryAdapter(object, interface, name, default)
+
+    def getAdapter(self, object, interface, name=u''):
+        adapter = self.adapters.queryAdapter(object, interface, name)
+        if adapter is None:
+            raise interfaces.ComponentLookupError(object, interface, name)
+        return adapter
+
+    def queryMultiAdapter(self, objects, interface, name=u'', default=None):
+        return self.adapters.queryMultiAdapter(
+            objects, interface, name, default)
+
+    def getMultiAdapter(self, objects, interface, name=u''):
+        adapter = self.adapters.queryMultiAdapter(objects, interface, name)
+        if adapter is None:
+            raise interfaces.ComponentLookupError(objects, interface, name)
+        return adapter
+
+    def getAdapters(self, objects, provided):
+        for name, factory in self.adapters.lookupAll(
+            map(interface.providedBy, objects),
+            provided):
+            adapter = factory(*objects)
+            if adapter is not None:
+                yield name, adapter
+
+    def registerSubscriptionAdapter(self,
+                                    factory, required=None, provided=None,
+                                    name=u'', info=u''):
+        if name:
+            raise TypeError("Named subscribers are not yet supported")
+        if provided is None:
+            provided = _getAdapterProvided(factory)
+        required = _getAdapterRequired(factory, required)
+        self._subscription_registrations.append(
+            (required, provided, name, factory, info)
+            )
+        self.adapters.subscribe(required, provided, factory)
+
+    def registeredSubscriptionAdapters(self):
+        for data in self._subscription_registrations:
+            yield SubscriptionRegistration(*data)
+
+    def unregisterSubscriptionAdapter(self, factory=None,
+                          required=None, provided=None, name=u'',
+                          ):
+        if name:
+            raise TypeError("Named subscribers are not yet supported")
+        if provided is None:
+            if factory is None:
+                raise TypeError("Must specify one of factory and provided")
+            provided = _getAdapterProvided(factory)
+
+        if (required is None) and (factory is None):
+            raise TypeError("Must specify one of factory and required")
+        
+        required = _getAdapterRequired(factory, required)
+
+        if factory is None:
+            new = [(r, p, n, f, i)
+                   for (r, p, n, f, i)
+                   in self._subscription_registrations
+                   if not (r == required and p == provided)
+                   ]
+        else:
+            new = [(r, p, n, f, i)
+                   for (r, p, n, f, i)
+                   in self._subscription_registrations
+                   if not (r == required and p == provided and f == factory)
+                   ]
+
+        if len(new) == len(self._subscription_registrations):
+            return False
+        
+
+        self._subscription_registrations = new
+        self.adapters.unsubscribe(required, provided)
+        return True
+
+    def subscribers(self, objects, provided):
+        return self.adapters.subscribers(objects, provided)
+
+
+
+
+    def registerHandler(self,
+                        factory, required=None,
+                        name=u'', info=u''):
+        if name:
+            raise TypeError("Named handlers are not yet supported")
+        required = _getAdapterRequired(factory, required)
+        self._handler_registrations.append(
+            (required, name, factory, info)
+            )
+        self.adapters.subscribe(required, None, factory)
+
+    def registeredHandlers(self):
+        for data in self._handler_registrations:
+            yield HandlerRegistration(*data)
+
+    def unregisterHandler(self, factory=None, required=None, name=u''):
+        if name:
+            raise TypeError("Named subscribers are not yet supported")
+
+        if (required is None) and (factory is None):
+            raise TypeError("Must specify one of factory and required")
+        
+        required = _getAdapterRequired(factory, required)
+
+        if factory is None:
+            new = [(r, n, f, i)
+                   for (r, n, f, i)
+                   in self._handler_registrations
+                   if r != required
+                   ]
+        else:
+            new = [(r, n, f, i)
+                   for (r, n, f, i)
+                   in self._handler_registrations
+                   if not (r == required and f == factory)
+                   ]
+
+        if len(new) == len(self._handler_registrations):
+            return False
+        
+        self._handler_registrations = new
+        self.adapters.unsubscribe(required, None)
+        return True
+
+    def handle(self, *objects):
+        self.adapters.subscribers(objects, None)
+
+
+def _getUtilityProvided(component):
+    provided = list(interface.providedBy(component))
+    if len(provided) == 1:
+        return provided[0]
+    raise TypeError(
+        "The utility doesn't provide a single interface "
+        "and no provided interface was specified.")
+
+def _getAdapterProvided(factory):
+    provided = list(interface.implementedBy(factory))
+    if len(provided) == 1:
+        return provided[0]
+    raise TypeError(
+        "The adapter factory doesn't implement a single interface "
+        "and no provided interface was specified.")
+
+def _getAdapterRequired(factory, required):
+    if required is None:
+        try:
+            required = factory.__component_adapts__
+        except AttributeError:
+            raise TypeError(
+                "The adapter factory doesn't have a __component_adapts__ "
+                "attribute and no required specifications were specified"
+                )
+
+    result = []
+    for r in required:
+        if not zope.interface.interfaces.ISpecification.providedBy(r):
+            r = interface.implementedBy(r)
+        result.append(r)
+    return tuple(result)
+        
+        
+class UtilityRegistration(object):
+
+    def __init__(self, provided, name, component, doc):
+        (self.provided, self.name, self.component, self.info
+         ) = provided, name, component, doc
+
+    def __repr__(self):
+        return '%s(%r, %r, %r, %r)' % (
+            self.__class__.__name__,
+            getattr(self.provided, '__name__', None), self.name,
+            getattr(self.component, '__name__', self.component), self.info,
+            )
+
+    def __cmp__(self, other):
+        return cmp(self.__repr__(), other.__repr__())
+        
+class AdapterRegistration(object):
+
+    def __init__(self, required, provided, name, component, doc):
+        (self.required, self.provided, self.name, self.factory, self.info
+         ) = required, provided, name, component, doc
+
+    def __repr__(self):
+        return '%s(%r, %r, %r, %r, %r)' % (
+            self.__class__.__name__,
+            tuple([r.__name__ for r in self.required]), 
+            getattr(self.provided, '__name__', None), self.name,
+            getattr(self.factory, '__name__', self.factory), self.info,
+            )
+
+    def __cmp__(self, other):
+        return cmp(self.__repr__(), other.__repr__())
+
+class SubscriptionRegistration(AdapterRegistration):
+    pass
+
+class HandlerRegistration(object):
+
+    def __init__(self, required, name, handler, doc):
+        (self.required, self.name, self.handler, self.info
+         ) = required, name, handler, doc
+
+    


Property changes on: Zope3/branches/jim-adapter/src/zope/component/components.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: Zope3/branches/jim-adapter/src/zope/component/components.txt
===================================================================
--- Zope3/branches/jim-adapter/src/zope/component/components.txt	2006-02-20 21:54:16 UTC (rev 41718)
+++ Zope3/branches/jim-adapter/src/zope/component/components.txt	2006-02-20 21:54:18 UTC (rev 41719)
@@ -0,0 +1,799 @@
+Component-Management objects
+============================
+
+Component-management objects provide a higher-level
+component-management API over the basic adapter-registration API
+provided by the zope.interface package.  In particular, it provides:
+
+- utilities
+
+- support for computing adapters, rather than just looking up adapter
+  factories.
+
+- management of registration comments
+
+The zope.component.components.Components class provides an
+implementation of zope.component.interfaces.IComponents that provides
+these features.
+
+    >>> from zope.component.components import Components
+    >>> from zope.component import tests
+    >>> components = Components()
+    
+Utilities
+---------
+
+You can register Utilities using registerUtility:
+
+    >>> components.registerUtility(tests.U1(1))
+
+Here we didn't specify an interface or name.  An unnamed utility was
+registered for interface I1, since that is only interface implemented
+by the U1 class:
+
+    >>> components.getUtility(tests.I1)
+    U1(1)
+
+If a component implements other than one interface or no interface,
+then an error will be raised:
+
+    >>> components.registerUtility(tests.U12(2))
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The utility doesn't provide a single interface and
+    no provided interface was specified.
+
+    >>> components.registerUtility(tests.A)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The utility doesn't provide a single interface and
+    no provided interface was specified.
+ 
+    
+We can provide an interface if desired:
+
+    >>> components.registerUtility(tests.U12(2), tests.I2)
+
+and we can specify a name:
+
+    >>> components.registerUtility(tests.U12(3), tests.I2, u'three')
+
+    >>> components.getUtility(tests.I2)
+    U12(2)
+
+    >>> components.getUtility(tests.I2, 'three')
+    U12(3)
+
+If you try to get a utility that doesn't exist, you'll get a component
+lookup error:
+
+    >>> components.getUtility(tests.I3)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: 
+    (<InterfaceClass zope.component.tests.I3>, u'')
+
+Unless you use queryUtility:
+
+    >>> components.queryUtility(tests.I3)
+    >>> components.queryUtility(tests.I3, default=42)
+    42
+
+You can get information about registered utilities with the
+registeredUtilities method:
+
+    >>> for regsitration in sorted(components.registeredUtilities()):
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.component, regsitration.info
+    <InterfaceClass zope.component.tests.I1> 
+    U1(1) 
+    <InterfaceClass zope.component.tests.I2> 
+    U12(2) 
+    <InterfaceClass zope.component.tests.I2> three
+    U12(3) 
+
+Duplicate registrations replace existing ones:
+
+    >>> components.registerUtility(tests.U1(4), info=u'use 4 now')
+    >>> components.getUtility(tests.I1)
+    U1(4)
+
+    >>> for regsitration in sorted(components.registeredUtilities()):
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.component, regsitration.info
+    <InterfaceClass zope.component.tests.I1> 
+    U1(4) use 4 now
+    <InterfaceClass zope.component.tests.I2> 
+    U12(2) 
+    <InterfaceClass zope.component.tests.I2> three
+    U12(3) 
+
+As shown in the this example, you can provide an "info" argumemnt when
+registering utilities.  This provides extra documentation about the
+registration itself that is shown when listing registrations.
+
+You can also unregister utilities:
+
+    >>> components.unregisterUtility(provided=tests.I1)
+    True
+
+A boolean is returned indicating whether anything changed:
+
+    >>> components.queryUtility(tests.I1)
+    >>> for regsitration in sorted(components.registeredUtilities()):
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.component, regsitration.info
+    <InterfaceClass zope.component.tests.I2> 
+    U12(2) 
+    <InterfaceClass zope.component.tests.I2> three
+    U12(3) 
+
+When you unregister, you can specify a component.  If the component
+doesn't match the one registered, then nothing happens:
+
+    >>> u5 = tests.U1(5)
+    >>> components.registerUtility(u5)
+    >>> components.unregisterUtility(tests.U1(6))
+    False
+    >>> components.queryUtility(tests.I1)
+    U1(5)
+    >>> components.unregisterUtility(u5)
+    True
+    >>> components.queryUtility(tests.I1)
+
+Adapters
+--------
+
+You can register adapters with registerAdapter:
+
+    >>> components.registerAdapter(tests.A12_1)
+
+Here, we didn't specify required interfaces, a provided interface, or
+a name.  The required interfaces were determined from the factory
+s __component_adapts__ attribute and the provided interface was
+determined by introspecting what the factory implements.
+
+    >>> components.getMultiAdapter((tests.U1(6), tests.U12(7)), tests.IA1)
+    A12_1(U1(6), U12(7))
+
+If a factory implements more than one interface, an exception will be
+raised:
+
+    >>> components.registerAdapter(tests.A1_12)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single
+    interface and no provided interface was specified.
+
+Unless the provided interface is specified:
+
+    >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
+
+If a factory doesn't declare an implemented interface, an exception will be
+raised:
+
+    >>> components.registerAdapter(tests.A12_)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single
+    interface and no provided interface was specified. 
+
+Unless the provided interface is specified:
+
+    >>> components.registerAdapter(tests.A12_, provided=tests.IA2)
+
+If the required interface needs to be specified in the
+registration if the factory doesn't have a __component_adapts__
+attribute: 
+
+    >>> components.registerAdapter(tests.A_2)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't have a __component_adapts__
+    attribute and no required specifications were specified 
+
+Unless the required specifications specified:
+
+    >>> components.registerAdapter(tests.A_2, required=[tests.I3])
+
+Classes can be specified in place of specifications, in which case the
+implementedBy specification for the class is used:
+
+    >>> components.registerAdapter(tests.A_3, required=[tests.U],
+    ...                            info="Really class specific")
+
+We can see the adapters that have been registered using the
+registeredAdapters method:
+
+    >>> for regsitration in sorted(components.registeredAdapters()):
+    ...     print regsitration.required
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.factory, regsitration.info
+    ... # doctest: +NORMALIZE_WHITESPACE
+    (<InterfaceClass zope.component.tests.I1>, 
+     <InterfaceClass zope.component.tests.I2>)
+    <InterfaceClass zope.component.tests.IA1> 
+    zope.component.tests.A12_1 
+    (<InterfaceClass zope.component.tests.I1>, 
+     <InterfaceClass zope.component.tests.I2>)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A12_ 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A1_12 
+    (<InterfaceClass zope.component.tests.I3>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A_2 
+    (<implementedBy zope.component.tests.U>,)
+    <InterfaceClass zope.component.tests.IA3> 
+    zope.component.tests.A_3 Really class specific
+
+As with utilities, we can provide registration information when
+registering adapters.
+
+If you try to fetch an adapter that isn't registered, you'll get a
+component-lookup error:
+
+    >>> components.getMultiAdapter((tests.U(8), ), tests.IA1)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: ((U(8),), 
+                          <InterfaceClass zope.component.tests.IA1>, u'')
+
+unless you use queryAdapter:
+
+    >>> components.queryMultiAdapter((tests.U(8), ), tests.IA1)
+    >>> components.queryMultiAdapter((tests.U(8), ), tests.IA1, default=42)
+    42
+
+When looking up an adapter for a single object, you can use the
+slightly simpler getAdapter and queryAdapter calls:
+
+    >>> components.getAdapter(tests.U1(9), tests.IA2)
+    A1_12(U1(9))
+
+    >>> components.queryAdapter(tests.U1(9), tests.IA2)
+    A1_12(U1(9))
+
+    >>> components.getAdapter(tests.U(8), tests.IA1)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: (U(8), 
+                           <InterfaceClass zope.component.tests.IA1>, u'')
+
+    >>> components.queryAdapter(tests.U(8), tests.IA2)
+    >>> components.queryAdapter(tests.U(8), tests.IA2, default=42)
+    42
+
+You can unregister an adapter.  If a factory is provided and if the
+rewuired and provided interfaces, can be infered, then they need not
+be provided:
+
+    >>> components.unregisterAdapter(tests.A12_1)
+    True
+    >>> for regsitration in sorted(components.registeredAdapters()):
+    ...     print regsitration.required
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.factory, regsitration.info
+    ... # doctest: +NORMALIZE_WHITESPACE
+    (<InterfaceClass zope.component.tests.I1>, 
+     <InterfaceClass zope.component.tests.I2>)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A12_ 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A1_12 
+    (<InterfaceClass zope.component.tests.I3>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A_2 
+    (<implementedBy zope.component.tests.U>,)
+    <InterfaceClass zope.component.tests.IA3> 
+    zope.component.tests.A_3 Really class specific
+
+A boolean is returned indicating whether a change was made.
+
+If a factory implements more than one interface, an exception will be
+raised:
+
+    >>> components.unregisterAdapter(tests.A1_12)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single
+    interface and no provided interface was specified.
+
+Unless the provided interface is specified:
+
+    >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2)
+    True
+
+If a factory doesn't declare an implemented interface, an exception will be
+raised:
+
+    >>> components.unregisterAdapter(tests.A12_)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single
+    interface and no provided interface was specified. 
+
+Unless the provided interface is specified:
+
+    >>> components.unregisterAdapter(tests.A12_, provided=tests.IA2)
+    True
+
+The required interface needs to be specified if the factory doesn't
+have a __component_adapts__ attribute:
+
+    >>> components.unregisterAdapter(tests.A_2)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't have a __component_adapts__
+    attribute and no required specifications were specified 
+
+    >>> components.unregisterAdapter(tests.A_2, required=[tests.I3])
+    True
+
+    >>> for regsitration in sorted(components.registeredAdapters()):
+    ...     print regsitration.required
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.factory, regsitration.info
+    ... # doctest: +NORMALIZE_WHITESPACE
+    (<implementedBy zope.component.tests.U>,)
+    <InterfaceClass zope.component.tests.IA3> 
+    zope.component.tests.A_3 Really class specific
+
+If a factory is unregistered that is not registered, False is
+returned:
+
+
+    >>> components.unregisterAdapter(tests.A_2, required=[tests.I3])
+    False
+    >>> components.unregisterAdapter(tests.A12_1, required=[tests.U])
+    False
+
+The factory can be omitted, to unregister *any* factory that matches
+specified required and provided interfaces:
+
+    >>> components.unregisterAdapter(required=[tests.U], provided=tests.IA3)
+    True
+
+    >>> for regsitration in sorted(components.registeredAdapters()):
+    ...     print regsitration
+
+Adapters can be named:
+
+    >>> components.registerAdapter(tests.A1_12, provided=tests.IA2, 
+    ...                            name=u'test')
+
+    >>> components.queryMultiAdapter((tests.U1(9), ), tests.IA2)
+    >>> components.queryMultiAdapter((tests.U1(9), ), tests.IA2, name=u'test')
+    A1_12(U1(9))
+
+    >>> components.queryAdapter(tests.U1(9), tests.IA2)
+    >>> components.queryAdapter(tests.U1(9), tests.IA2, name=u'test')
+    A1_12(U1(9))
+    >>> components.getAdapter(tests.U1(9), tests.IA2, name=u'test')
+    A1_12(U1(9))
+
+It is possible to look up all of the adapters that provide an
+interface:
+
+    >>> components.registerAdapter(tests.A1_23, provided=tests.IA2, 
+    ...                            name=u'test 2')
+
+    >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
+    >>> for name, adapter in sorted(components.getAdapters((tests.U1(9), ), 
+    ...                                                    tests.IA2)):
+    ...     print name, adapter
+     A1_12(U1(9))
+    test A1_12(U1(9))
+    test 2 A1_23(U1(9))
+
+
+getAdapters is most commonly used as the basis of menu systems.
+
+If an adapter factory returns None, it is equivalent to there being no
+factory:
+
+    >>> components.registerAdapter(tests.noop, 
+    ...                            required=[tests.IA1], provided=tests.IA2, 
+    ...                            name=u'test noop')
+    >>> components.queryAdapter(tests.U1(9), tests.IA2, name=u'test noop')
+
+    >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
+    >>> for name, adapter in sorted(components.getAdapters((tests.U1(9), ), 
+    ...                                                    tests.IA2)):
+    ...     print name, adapter
+     A1_12(U1(9))
+    test A1_12(U1(9))
+    test 2 A1_23(U1(9))
+
+
+    >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2, 
+    ...                            name=u'test')
+    True
+    >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2)
+    True
+    >>> for regsitration in sorted(components.registeredAdapters()):
+    ...     print regsitration.required
+    ...     print regsitration.provided, regsitration.name
+    ...     print regsitration.factory, regsitration.info
+    ... # doctest: +NORMALIZE_WHITESPACE
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> test 2
+    zope.component.tests.A1_23 
+    (<InterfaceClass zope.component.tests.IA1>,)
+    <InterfaceClass zope.component.tests.IA2> test noop
+    <function noop at 0xb79a1064> 
+
+
+Subscribers
+-----------
+
+Subscribers provide a way to get multiple adapters of a given type.
+In this regard, subscribers are like named adapters, except that there
+isn't any concept of the most specific adapter for a given name.
+
+Subscribers are registered by calling registerSubscriptionAdapter:
+
+     >>> components.registerSubscriptionAdapter(tests.A1_2)
+
+     >>> components.registerSubscriptionAdapter(
+     ...     tests.A1_12, provided=tests.IA2)
+
+     >>> components.registerSubscriptionAdapter(
+     ...     tests.A, [tests.I1], tests.IA2,
+     ...     info='a sample comment')
+
+The same rules, with regard to when required and provided interfaces
+have to be specified apply as with adapters:
+
+    >>> components.registerSubscriptionAdapter(tests.A1_12)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single 
+    interface and no provided interface was specified.
+
+    >>> components.registerSubscriptionAdapter(tests.A)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single interface and
+     no provided interface was specified.
+
+    >>> components.registerSubscriptionAdapter(tests.A, required=[tests.IA1])
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single interface
+    and no provided interface was specified.
+
+Note that we provided the info argument as a keyword argument above.
+That's because there is a name argument that's reserved for future
+use. We can give a name, as long as it is an empty string:
+
+    >>> components.registerSubscriptionAdapter(
+    ...     tests.A, [tests.I1], tests.IA2, u'', 'a sample comment')
+
+    >>> components.registerSubscriptionAdapter(
+    ...     tests.A, [tests.I1], tests.IA2, u'oops', 'a sample comment')
+    Traceback (most recent call last):
+    ...
+    TypeError: Named subscribers are not yet supported
+
+Subscribers are looked up using the subscribers method:
+
+    >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+    ...    print s
+    A1_2(U1(1))
+    A1_12(U1(1))
+    A(U1(1),)
+    A(U1(1),)
+
+Note that, because we created multiple subscriptions for A, we got multiple
+subscriber instances.
+
+As with normal adapters, if a factory returns None, the result is skipped:
+
+     >>> components.registerSubscriptionAdapter(
+     ...     tests.noop, [tests.I1], tests.IA2)
+
+    >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+    ...    print s
+    A1_2(U1(1))
+    A1_12(U1(1))
+    A(U1(1),)
+    A(U1(1),)
+
+We can get registration information for subscriptions:
+
+    >>> for registration in sorted(
+    ...     components.registeredSubscriptionAdapters()):
+    ...     print registration.required
+    ...     print registration.provided, registration.name
+    ...     print registration.factory, registration.info
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A a sample comment
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A a sample comment
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A1_12 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A1_2 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    <function noop at 0xb796ff7c> 
+
+We can also unregister subscriptions in much the same way we can for adapters:
+
+    >>> components.unregisterSubscriptionAdapter(tests.A1_2)
+    True
+
+    >>> for registration in sorted(
+    ...     components.registeredSubscriptionAdapters()):
+    ...     print registration.required
+    ...     print registration.provided, registration.name
+    ...     print registration.factory, registration.info
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A a sample comment
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A a sample comment
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A1_12 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    <function noop at 0xb796ff7c> 
+
+    >>> components.unregisterSubscriptionAdapter(
+    ...     tests.A, [tests.I1], tests.IA2)
+    True
+
+    >>> for registration in sorted(
+    ...     components.registeredSubscriptionAdapters()):
+    ...     print registration.required
+    ...     print registration.provided, registration.name
+    ...     print registration.factory, registration.info
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    zope.component.tests.A1_12 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <InterfaceClass zope.component.tests.IA2> 
+    <function noop at 0xb796ff7c> 
+
+Note here that both registrations for A were removed.
+
+If we omit the factory, we must specify the required and provided interfaces:
+
+    >>> components.unregisterSubscriptionAdapter(required=[tests.I1])
+    Traceback (most recent call last):
+    ...
+    TypeError: Must specify one of factory and provided
+
+    >>> components.unregisterSubscriptionAdapter(provided=tests.IA2)
+    Traceback (most recent call last):
+    ...
+    TypeError: Must specify one of factory and required
+
+    >>> components.unregisterSubscriptionAdapter(
+    ...     required=[tests.I1], provided=tests.IA2)
+    True
+
+    >>> for registration in sorted(
+    ...     components.registeredSubscriptionAdapters()):
+    ...     print registration.factory
+
+As when registering, an error is raised if the registration
+information can't be determined from the factory and isn't specified:
+
+    >>> components.unregisterSubscriptionAdapter(tests.A1_12)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single 
+    interface and no provided interface was specified.
+
+    >>> components.unregisterSubscriptionAdapter(tests.A)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single interface and
+     no provided interface was specified.
+
+    >>> components.unregisterSubscriptionAdapter(tests.A, required=[tests.IA1])
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't implement a single interface
+    and no provided interface was specified.
+
+If you unregister something that's not registered, nothing will be changed and False will be returned:
+
+
+    >>> components.unregisterSubscriptionAdapter(
+    ...     required=[tests.I1], provided=tests.IA2)
+    False
+
+Handlers
+--------
+
+Handlers are used when you want to perform some function in response
+to an event.  Handlers aren't expected to return anything when called
+and are not registered to provide any interface.
+
+    >>> from zope import component
+    >>> @component.adapter(tests.I1)
+    ... def handle1(x):
+    ...     print 'handle1', x
+
+    >>> components.registerHandler(handle1, info="First handler")
+    >>> components.handle(tests.U1(1))
+    handle1 U1(1)
+
+    >>> @component.adapter(tests.I1, tests.I2)
+    ... def handle12(x, y):
+    ...     print 'handle12', x, y
+
+    >>> components.registerHandler(handle12)
+    >>> components.handle(tests.U1(1), tests.U12(2))
+    handle12 U1(1) U12(2)
+
+If a handler doesn't document interfaces it handles, then 
+the required interfaces must be specified:
+
+    >>> def handle(*objects):
+    ...     print 'handle', objects
+
+    >>> components.registerHandler(handle)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't have a __component_adapts__ 
+    attribute and no required specifications were specified
+
+    >>> components.registerHandler(handle, required=[tests.I1], 
+    ...                            info="a comment")
+
+Handlers can also be registered for classes:
+
+    >>> components.registerHandler(handle, required=[tests.U], 
+    ...                            info="handle a class")
+
+
+    >>> components.handle(tests.U1(1))
+    handle (U1(1),)
+    handle1 U1(1)
+    handle (U1(1),)
+
+We can list the handler registrations:
+
+    >>> for registration in components.registeredHandlers():
+    ...     print registration.required
+    ...     print registration.handler, registration.info
+    ... # doctest: +NORMALIZE_WHITESPACE
+    (<InterfaceClass zope.component.tests.I1>,)
+    <function handle1 at 0xb78f5bfc> First handler
+    (<InterfaceClass zope.component.tests.I1>,
+     <InterfaceClass zope.component.tests.I2>)
+    <function handle12 at 0xb78f5c34> 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <function handle at 0xb78f5ca4> a comment
+    (<implementedBy zope.component.tests.U>,)
+    <function handle at 0xb78f5ca4> handle a class
+
+and we can unregister handlers:
+
+    >>> components.unregisterHandler(required=[tests.U])
+    True
+
+    >>> for registration in components.registeredHandlers():
+    ...     print registration.required
+    ...     print registration.handler, registration.info
+    ... # doctest: +NORMALIZE_WHITESPACE
+    (<InterfaceClass zope.component.tests.I1>,)
+    <function handle1 at 0xb78f5bfc> First handler
+    (<InterfaceClass zope.component.tests.I1>,
+     <InterfaceClass zope.component.tests.I2>)
+    <function handle12 at 0xb78f5c34> 
+    (<InterfaceClass zope.component.tests.I1>,)
+    <function handle at 0xb78f5ca4> a comment
+
+    >>> components.unregisterHandler(handle12)
+    True
+
+    >>> for registration in components.registeredHandlers():
+    ...     print registration.required
+    ...     print registration.handler, registration.info
+    (<InterfaceClass zope.component.tests.I1>,)
+    <function handle1 at 0xb78f5bfc> First handler
+    (<InterfaceClass zope.component.tests.I1>,)
+    <function handle at 0xb78f5ca4> a comment
+
+    >>> components.unregisterHandler(handle12)
+    False
+
+    >>> components.unregisterHandler()
+    Traceback (most recent call last):
+    ...
+    TypeError: Must specify one of factory and required
+
+    >>> components.registerHandler(handle)
+    ... # doctest: +NORMALIZE_WHITESPACE
+    Traceback (most recent call last):
+    ...
+    TypeError: The adapter factory doesn't have a __component_adapts__ 
+    attribute and no required specifications were specified
+
+Extending
+---------
+
+Component-management objects can extend other component-management
+objects. 
+
+    >>> c1 = Components()
+    >>> c1.__bases__
+    ()
+
+    >>> c2 = Components((c1, ))
+    >>> c2.__bases__ == (c1, )
+    True
+
+    >>> c1.registerUtility(tests.U1(1))
+    >>> c1.queryUtility(tests.I1)
+    U1(1)
+    >>> c2.queryUtility(tests.I1)
+    U1(1)
+    >>> c1.registerUtility(tests.U1(2))
+    >>> c2.queryUtility(tests.I1)
+    U1(2)
+
+We can use multiple inheritence:
+
+    >>> c3 = Components((c1, ))
+    >>> c4 = Components((c2, c3))
+    >>> c4.queryUtility(tests.I1)
+    U1(2)
+
+    >>> c1.registerUtility(tests.U12(1), tests.I2)
+    >>> c4.queryUtility(tests.I2)
+    U12(1)
+
+    >>> c3.registerUtility(tests.U12(3), tests.I2)
+    >>> c4.queryUtility(tests.I2)
+    U12(3)
+
+    >>> c1.registerHandler(handle1, info="First handler")
+    >>> c2.registerHandler(handle, required=[tests.U])
+    
+    >>> @component.adapter(tests.I1)
+    ... def handle3(x):
+    ...     print 'handle3', x
+    >>> c3.registerHandler(handle3)
+    
+    >>> @component.adapter(tests.I1)
+    ... def handle4(x):
+    ...     print 'handle4', x
+    >>> c4.registerHandler(handle4)
+
+    >>> c4.handle(tests.U1(1))
+    handle1 U1(1)
+    handle3 U1(1)
+    handle (U1(1),)
+    handle4 U1(1)


Property changes on: Zope3/branches/jim-adapter/src/zope/component/components.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: Zope3/branches/jim-adapter/src/zope/component/interfaces.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/component/interfaces.py	2006-02-20 21:54:16 UTC (rev 41718)
+++ Zope3/branches/jim-adapter/src/zope/component/interfaces.py	2006-02-20 21:54:18 UTC (rev 41719)
@@ -15,18 +15,19 @@
 
 $Id$
 """
-import zope.deprecation
 
+import zope.deferredimport
 from zope.interface import Interface, Attribute
 
+
+# BBB: Backward-compatibility; 12/05/2004
+from bbb.interfaces import *
+
 # BBB: Can be removed in 3.3
 zope.deprecation.__show__.off()
 from zope.exceptions import NotFoundError
 zope.deprecation.__show__.on()
 
-# BBB: Backward-compatibility; 12/05/2004
-from bbb.interfaces import *
-
 class ComponentLookupError(NotFoundError):
     """A component could not be found."""
 
@@ -36,7 +37,7 @@
 class Misused(Exception):
     """A component is being used (registered) for the wrong interface."""
 
-class IComponentArchitecture(Interface, IBBBComponentArchitecture):
+class IComponentArchitecture(Interface):
     """The Component Architecture is defined by two key components: Adapters
     and Utiltities. Both are managed by site managers. All other components
     build on top of them.
@@ -275,8 +276,7 @@
         create objects which implement the given interface.
         """
 
-
-class ISiteManager(Interface):
+class IComponentLookup(Interface):
     """Component Manager for a Site
 
     This object manages the components registered at a particular site. The
@@ -289,34 +289,40 @@
     utilities = Attribute("Adapter Registry to manage all registered "
                           "utilities.")
 
-    def queryAdapter(object, interface, name, default=None):
+    def queryAdapter(object, interface, name=u'', default=None):
         """Look for a named adapter to an interface for an object
 
         If a matching adapter cannot be found, returns the default.
+        """
 
-        The name consisting of an empty string is reserved for unnamed
-        adapters. The unnamed adapter methods will often call the
-        named adapter methods with an empty string for a name.
+    def getAdapter(object, interface, name=u''):
+        """Look for a named adapter to an interface for an object
+
+        If a matching adapter cannot be found, a ComponentLookupError
+        is raised.
         """
 
-    def queryMultiAdapter(objects, interface, name, default=None):
-        """Look for a multi-adapter to an interface for an object
+    def queryMultiAdapter(objects, interface, name=u'', default=None):
+        """Look for a multi-adapter to an interface for multiple objects
 
         If a matching adapter cannot be found, returns the default.
+        """
 
-        The name consisting of an empty string is reserved for unnamed
-        adapters. The unnamed adapter methods will often call the
-        named adapter methods with an empty string for a name.
+    def queryMultiAdapter(objects, interface, name=u''):
+        """Look for a multi-adapter to an interface for multiple objects
+
+        If a matching adapter cannot be found, a ComponentLookupError
+        is raised.
         """
 
     def getAdapters(objects, provided):
         """Look for all matching adapters to a provided interface for objects
 
-        Return a list of adapters that match. If an adapter is named, only the
-        most specific adapter of a given name is returned.
+        Return an iterable of name-adapter pairs for adapters that
+        provide the given interface.
         """
 
-    def subscribers(required, provided):
+    def subscribers(objects, provided):
         """Get subscribers
 
         Subscribers are returned that provide the provided interface
@@ -324,6 +330,12 @@
         required objects.
         """
 
+    def handle(*objects):
+        """Call handlers for the given objects
+
+        Handlers registered for the given objects are called.
+        """
+
     def queryUtility(interface, name='', default=None):
         """Look up a utility that provides an interface.
 
@@ -345,6 +357,10 @@
         returned.
         """
 
+zope.deferredimport.deprecated(
+    "Use IComponentLookup instead.  ISiteManager will be removed in 2007.",
+    ISiteManager = "zope.component.interfaces:IComponentLookup",
+    )
         
 class IComponentRegistrationConvenience(Interface):
     """API for registering components.
@@ -454,3 +470,363 @@
         created by this factory will implement. If the callable's Implements
         instance cannot be created, an empty Implements instance is returned.
         """
+
+
+class IComponentRegistry(Interface):
+    """Register components
+    """
+
+    def registerUtility(component, provided=None, name=u'', comment=u''):
+        """Register a utility
+
+        component
+           The registered component
+
+        provided
+           This is the interface provided by the utility.  If the
+           component provides a single interface, then this
+           argument is optional and the component-implemented
+           interface will be used.
+
+        name
+           The utility name.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+    def unregisterUtility(component=None, provided=None, name=u''):
+        """Unregister a utility
+
+        A boolean is returned indicating whether the registry was
+        changed.  If the given component is None and there is no
+        component registered, or if the given component is not
+        None and is not registered, then the function returns
+        False, otherwise it returns True.
+
+        component
+           The registered component The given component can be
+           None, in which case any component registered to provide
+           the given provided interface with the given name is
+           unregistered.
+
+        provided
+           This is the interface provided by the utility.  If the
+           component is not None and provides a single interface,
+           then this argument is optional and the
+           component-implemented interface will be used.
+
+        name
+           The utility name.
+        """
+
+    def registeredUtilities():
+        """Return an iterable of utility-information objects
+
+        The information objects will have attributes:
+
+        provided
+           The provided interface
+
+        name
+           The name
+
+        component
+           The registered component
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+    def registerAdapter(factory, required=None, provided=None, name=u'',
+                       info=u''):
+        """Register an adapter factory
+
+        Parameters:
+
+        factory
+            The object used to compute the adapter
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required. 
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory
+            implements a single interface, then this argument is
+            optional and the factory-implemented interface will be
+            used. 
+
+        name
+            The adapter name.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+    def unregisterAdapter(factory=None, required=None,
+                          provided=None, name=u''):
+        """Register an adapter factory
+
+        A boolean is returned indicating whether the registry was
+        changed.  If the given component is None and there is no
+        component registered, or if the given component is not
+        None and is not registered, then the function returns
+        False, otherwise it returns True.
+
+        Parameters:
+
+        factory
+            This is the object used to compute the adapter. The
+            factory can be None, in which case any factory
+            registered to implement the given provided interface
+            for the given required specifications with the given
+            name is unregistered.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If the factory is not None and the required
+            arguments is omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute attribute is normally
+            set in class definitions using adapts function, or for
+            callables using the adapter decorator.  If the factory
+            is None or doesn't have a __component_adapts__ adapts
+            attribute, then this argument is required.
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory is not
+            None and implements a single interface, then this
+            argument is optional and the factory-implemented
+            interface will be used.
+
+        name
+            The adapter name.
+        """
+
+    def registeredAdapters():
+        """Return an iterable of adapter-information objects
+
+        The adapter information objects will have attributes:
+
+        required
+           An iterable of required interfaces
+
+        provided
+           The provided interface
+
+        name
+           The name
+
+        factory
+           The registered factory
+
+        info
+           Provide some info about this particular adapter registration.
+        """
+
+    def registerSubscriptionAdapter(factory, required=None, provides=None,
+                                    name=u'', info=''):
+        """Register a subscriber factory
+
+        Parameters:
+
+        factory
+            The object used to compute the adapter
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required. 
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory implements
+            a single interface, then this argument is optional and
+            the factory-implemented interface will be used.
+
+        name
+            The adapter name.
+
+            Currently, only the empty string is accepted.  Other
+            strings will be accepted in the future when support for
+            named subscribers is added.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+    def unregisterSubscriptionAdapter(factory=None, required=None, 
+                                      provides=None, name=u''):
+        """Register a subscriber factory
+
+        A boolean is returned indicating whether the registry was
+        changed.  If the given component is None and there is no
+        component registered, or if the given component is not
+        None and is not registered, then the function returns
+        False, otherwise it returns True.
+
+        Parameters:
+
+        factory
+            This is the object used to compute the adapter. The
+            factory can be None, in which case any factories
+            registered to implement the given provided interface
+            for the given required specifications with the given
+            name are unregistered.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If the factory is not None and the required
+            arguments is omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute attribute is normally
+            set in class definitions using adapts function, or for
+            callables using the adapter decorator.  If the factory
+            is None or doesn't have a __component_adapts__ adapts
+            attribute, then this argument is required.
+
+        provided
+            This is the interface provided by the adapter and
+            implemented by the factory.  If the factory is not
+            None implements a single interface, then this argument
+            is optional and the factory-implemented interface will
+            be used.
+
+        name
+            The adapter name.
+
+            Note that this parameter is ignored and is reserved
+            for future use when named subscribers are implemented.
+        """
+
+    def registeredSubscriptionAdapters():
+        """Return an iterable of subscriber-information objects
+
+        The subscriber information objects will have attributes:
+
+        required
+           An iterable of required interfaces
+
+        provided
+           The provided interface
+
+        name
+           The name
+
+        factory
+           The registered factory
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+    def registerHandler(handler, adapts=None, name=u'', info=''):
+        """Register a handler.
+
+        A handler is a subscriber that doesn't compute an adapter
+        but performs some function when called.
+
+        Parameters:
+
+        handler
+            The object used to handle some event represented by
+            the objects passed to it.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required. 
+
+        name
+            The handler name.
+
+            Note that this parameter is ignored and is reserved
+            for future use when named handlers are implemented.
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+    def unregisterHandler(handler=None, adapts=None, name=u''):
+        """Register a handler.
+
+        A handler is a subscriber that doesn't compute an adapter
+        but performs some function when called.
+
+        Parameters:
+
+        handler
+            This is the object used to handle some event
+            represented by the objects passed to it. The handler
+            can be None, in which case any handlers registered for
+            the given required specifications with the given are
+            unregistered.
+
+        required
+            This is a sequence of specifications for objects to be
+            adapted.  If omitted, then the value of the factory's
+            __component_adapts__ attribute will be used.  The
+            __component_adapts__ attribute is usually attribute is
+            normally set in class definitions using adapts
+            function, or for callables using the adapter
+            decorator.  If the factory doesn't have a
+            __component_adapts__ adapts attribute, then this
+            argument is required. 
+
+        name
+            The handler name.
+
+            Note that this parameter is ignored and is reserved
+            for future use when named handlers are implemented.
+        """
+
+    def registeredHandlers():
+        """Return an iterable of handler-information objects
+
+        The subscriber information objects will have attributes:
+
+        required
+           An iterable of required interfaces
+
+        name
+           The name
+
+        handler
+           The registered handler
+
+        info
+           An object that can be converted to a string to provide
+           information about the registration.
+        """
+
+class IComponents(IComponentLookup, IComponentRegistry):
+    """Component registration and access
+    """

Modified: Zope3/branches/jim-adapter/src/zope/component/tests.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/component/tests.py	2006-02-20 21:54:16 UTC (rev 41718)
+++ Zope3/branches/jim-adapter/src/zope/component/tests.py	2006-02-20 21:54:18 UTC (rev 41719)
@@ -15,27 +15,86 @@
 
 $Id: test_api.py 28632 2004-12-16 17:42:59Z srichter $
 """
+import re
 import unittest
-
-from zope.interface import Interface, implements
+from zope import interface, component
 from zope.interface.verify import verifyObject
-from zope.testing import doctest
+from zope.testing import doctest, renormalizing
 
-import zope.component
 from zope.component.interfaces import ComponentLookupError
 from zope.component.interfaces import IComponentArchitecture
 from zope.component.interfaces import ISiteManager
 from zope.component.testing import setUp, tearDown
 
-class I1(Interface):
+class I1(interface.Interface):
     pass
-class I2(Interface):
+class I2(interface.Interface):
     pass
-class I3(Interface):
+class I3(interface.Interface):
     pass
 
+
+class U:
+
+    def __init__(self, name):
+        self.__name__ = name
+
+    def __repr__(self):
+        return "%s(%s)" % (self.__class__.__name__, self.__name__)
+
+class U1(U):
+    interface.implements(I1)
+
+class U12(U):
+    interface.implements(I1, I2)
+
+class IA1(interface.Interface):
+    pass
+
+class IA2(interface.Interface):
+    pass
+
+class IA3(interface.Interface):
+    pass
+
+class A:
+
+    def __init__(self, *context):
+        self.context = context
+
+    def __repr__(self):
+        return "%s%r" % (self.__class__.__name__, self.context)
+    
+class A12_1(A):
+    component.adapts(I1, I2)
+    interface.implements(IA1)
+    
+class A12_(A):
+    component.adapts(I1, I2)
+
+class A_2(A):
+    interface.implements(IA2)
+
+class A_3(A):
+    interface.implements(IA3)
+
+class A1_12(U):
+    component.adapts(I1)
+    interface.implements(IA1, IA2)
+
+class A1_2(U):
+    component.adapts(I1)
+    interface.implements(IA2)
+
+class A1_23(U):
+    component.adapts(I1)
+    interface.implements(IA1, IA3)
+
+def noop(*args):
+    pass
+
 class Ob(object):
-    implements(I1)
+    interface.implements(I1)
     def __repr__(self):
         return '<instance Ob>'
 
@@ -43,19 +102,19 @@
 ob = Ob()
 
 class Ob2(object):
-    implements(I2)
+    interface.implements(I2)
     def __repr__(self):
         return '<instance Ob2>'
 
 class Comp(object):
-    implements(I2)
+    interface.implements(I2)
     def __init__(self, context):
         self.context = context
 
 comp = Comp(1)
 
 class Comp2(object):
-    implements(I3)
+    interface.implements(I3)
     def __init__(self, context):
         self.context = context
 
@@ -77,8 +136,7 @@
     """Ensure that the component architecture API is provided by
     `zope.component`.
 
-    >>> import zope.component
-    >>> verifyObject(IComponentArchitecture, zope.component)
+    >>> verifyObject(IComponentArchitecture, component)
     True
     """
 
@@ -89,7 +147,7 @@
 
     Get the global site manager via the CA API function:
 
-      >>> gsm = zope.component.getGlobalSiteManager()
+      >>> gsm = component.getGlobalSiteManager()
 
     Make sure that the global site manager implements the correct interface
     and is the global site manager instance we expect to get.
@@ -102,7 +160,7 @@
     Finally, ensure that we always get the same global site manager, otherwise
     our component registry will always be reset.
 
-      >>> zope.component.getGlobalSiteManager() is gsm
+      >>> component.getGlobalSiteManager() is gsm
       True
     """
 
@@ -113,13 +171,13 @@
     We don't know anything about the default service manager, except that it
     is an `ISiteManager`.
 
-      >>> ISiteManager.providedBy(zope.component.getSiteManager())
+      >>> ISiteManager.providedBy(component.getSiteManager())
       True
 
     Calling `getSiteManager()` with no args is equivalent to calling it with a
     context of `None`.
 
-      >>> zope.component.getSiteManager() is zope.component.getSiteManager(None)
+      >>> component.getSiteManager() is component.getSiteManager(None)
       True
 
     If the context passed to `getSiteManager()` is not `None`, it is adapted
@@ -138,16 +196,16 @@
     Now make sure that the `getSiteManager()` API call returns the correct
     site manager.
 
-      >>> zope.component.getSiteManager(context) is sitemanager
+      >>> component.getSiteManager(context) is sitemanager
       True
 
     Using a context that is not adaptable to `ISiteManager` should fail.
 
-      >>> zope.component.getSiteManager(ob) #doctest: +NORMALIZE_WHITESPACE
+      >>> component.getSiteManager(ob) #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
       ComponentLookupError: ('Could not adapt', <instance Ob>,
-      <InterfaceClass zope.component.interfaces.ISiteManager>)
+      <InterfaceClass zope.component.interfaces.IComponentLookup>)
     """
 
 def testAdapterInContext(self):
@@ -160,7 +218,7 @@
     `__conform__()` method:
 
       >>> class Component(object):
-      ...     implements(I1)
+      ...     interface.implements(I1)
       ...     def __conform__(self, iface, default=None):
       ...         if iface == I2:
       ...             return 42
@@ -190,26 +248,26 @@
     If an object implements the interface you want to adapt to,
     `getAdapterInContext()` should simply return the object.
 
-      >>> zope.component.getAdapterInContext(ob, I1, context)
+      >>> component.getAdapterInContext(ob, I1, context)
       <Component implementing 'I1'>
-      >>> zope.component.queryAdapterInContext(ob, I1, context)
+      >>> component.queryAdapterInContext(ob, I1, context)
       <Component implementing 'I1'>
 
     If an object conforms to the interface you want to adapt to,
     `getAdapterInContext()` should simply return the conformed object.
 
-      >>> zope.component.getAdapterInContext(ob, I2, context)
+      >>> component.getAdapterInContext(ob, I2, context)
       42
-      >>> zope.component.queryAdapterInContext(ob, I2, context)
+      >>> component.queryAdapterInContext(ob, I2, context)
       42
 
     If an adapter isn't registered for the given object and interface, and you
     provide no default, raise ComponentLookupError...
 
-      >>> class I4(Interface):
+      >>> class I4(interface.Interface):
       ...     pass
 
-      >>> zope.component.getAdapterInContext(ob, I4, context) \\
+      >>> component.getAdapterInContext(ob, I4, context) \\
       ... #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
@@ -218,15 +276,15 @@
 
     ...otherwise, you get the default:
 
-      >>> zope.component.queryAdapterInContext(ob, I4, context, 44)
+      >>> component.queryAdapterInContext(ob, I4, context, 44)
       44
 
     If you ask for an adapter for which something's registered you get the
     registered adapter
 
-      >>> zope.component.getAdapterInContext(ob, I3, context)
+      >>> component.getAdapterInContext(ob, I3, context)
       43
-      >>> zope.component.queryAdapterInContext(ob, I3, context)
+      >>> component.queryAdapterInContext(ob, I3, context)
       43
     """
 
@@ -239,7 +297,7 @@
     If an adapter isn't registered for the given object and interface, and you
     provide no default, raise `ComponentLookupError`...
 
-      >>> zope.component.getAdapter(ob, I2, '') #doctest: +NORMALIZE_WHITESPACE
+      >>> component.getAdapter(ob, I2, '') #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
       ComponentLookupError: (<instance Ob>,
@@ -248,19 +306,19 @@
 
     ...otherwise, you get the default
 
-      >>> zope.component.queryAdapter(ob, I2, '', '<default>')
+      >>> component.queryAdapter(ob, I2, '', '<default>')
       '<default>'
 
     Now get the global site manager and register an adapter from `I1` to `I2`
     without a name:
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     (I1,), I2, '', Comp)
 
     You should get a sensible error message if you forget that the 'requires'
     argument is supposed to be a sequence
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     I1, I2, '', Comp)
       Traceback (most recent call last):
         ...
@@ -269,7 +327,7 @@
     You can now simply access the adapter using the `getAdapter()` API
     function:
 
-      >>> adapter = zope.component.getAdapter(ob, I2, '')
+      >>> adapter = component.getAdapter(ob, I2, '')
       >>> adapter.__class__ is Comp
       True
       >>> adapter.context is ob
@@ -283,7 +341,7 @@
 
     First, we need to register an adapter:
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     [I1], I2, '', Comp)
 
     Then we try to adapt `ob` to provide an `I2` interface by calling the `I2`
@@ -316,13 +374,13 @@
 
     First we register some named adapter:
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     [I1], I2, 'foo', lambda x: 0)
 
     If an adapter isn't registered for the given object and interface,
     and you provide no default, raise `ComponentLookupError`...
 
-      >>> zope.component.getAdapter(ob, I2, 'bar') \\
+      >>> component.getAdapter(ob, I2, 'bar') \\
       ... #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
@@ -331,17 +389,17 @@
 
     ...otherwise, you get the default
 
-      >>> zope.component.queryAdapter(ob, I2, 'bar', '<default>')
+      >>> component.queryAdapter(ob, I2, 'bar', '<default>')
       '<default>'
 
     But now we register an adapter for the object having the correct name
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     [I1], I2, 'bar', Comp)
 
     so that the lookup succeeds:
 
-      >>> adapter = zope.component.getAdapter(ob, I2, 'bar')
+      >>> adapter = component.getAdapter(ob, I2, 'bar')
       >>> adapter.__class__ is Comp
       True
       >>> adapter.context is ob
@@ -361,7 +419,7 @@
     objects and interface, and you provide no default, raise
     `ComponentLookupError`...
 
-      >>> zope.component.getMultiAdapter((ob, ob2), I3) \\
+      >>> component.getMultiAdapter((ob, ob2), I3) \\
       ... #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
@@ -372,7 +430,7 @@
 
     ...otherwise, you get the default
 
-      >>> zope.component.queryMultiAdapter((ob, ob2), I3, default='<default>')
+      >>> component.queryMultiAdapter((ob, ob2), I3, default='<default>')
       '<default>'
 
     Note that the name is not a required attribute here.
@@ -381,20 +439,20 @@
     handles to context objects:
 
       >>> class DoubleAdapter(object):
-      ...     implements(I3)
+      ...     interface.implements(I3)
       ...     def __init__(self, first, second):
       ...         self.first = first
       ...         self.second = second
 
     Now we can register the multi-adapter using
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     (I1, I2), I3, '', DoubleAdapter)
 
     Notice how the required interfaces are simply provided by a tuple. Now we
     can get the adapter:
 
-      >>> adapter = zope.component.getMultiAdapter((ob, ob2), I3)
+      >>> adapter = component.getMultiAdapter((ob, ob2), I3)
       >>> adapter.__class__ is DoubleAdapter
       True
       >>> adapter.first is ob
@@ -407,7 +465,7 @@
     """Providing an adapter for None says that your adapter can adapt anything
     to `I2`.
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     (None,), I2, '', Comp)
 
       >>> adapter = I2(ob)
@@ -433,15 +491,15 @@
 
     Let's register some adapters first:
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     [I1], I2, '', Comp)
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     [None], I2, 'foo', Comp)
 
     Now we get all the adapters that are registered for `ob` that provide
     `I2`:
 
-      >>> adapters = zope.component.getAdapters((ob,), I2)
+      >>> adapters = component.getAdapters((ob,), I2)
       >>> adapters.sort()
       >>> [(name, adapter.__class__.__name__) for name, adapter in adapters]
       [(u'', 'Comp'), (u'foo', 'Comp')]
@@ -449,9 +507,9 @@
     Note that the output doesn't include None values. If an adapter
     factory returns None, it is as if it wasn't present.
 
-      >>> zope.component.getGlobalSiteManager().provideAdapter(
+      >>> component.getGlobalSiteManager().provideAdapter(
       ...     [I1], I2, 'nah', lambda context: None)
-      >>> adapters = zope.component.getAdapters((ob,), I2)
+      >>> adapters = component.getAdapters((ob,), I2)
       >>> adapters.sort()
       >>> [(name, adapter.__class__.__name__) for name, adapter in adapters]
       [(u'', 'Comp'), (u'foo', 'Comp')]
@@ -467,7 +525,7 @@
     course. The pure instatiation of an object does not make it a utility. If
     you do not specify a default, you get a `ComponentLookupError`...
 
-      >>> zope.component.getUtility(I1) #doctest: +NORMALIZE_WHITESPACE
+      >>> component.getUtility(I1) #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
       ComponentLookupError: \
@@ -475,18 +533,18 @@
 
     ...otherwise, you get the default
 
-      >>> zope.component.queryUtility(I1, default='<default>')
+      >>> component.queryUtility(I1, default='<default>')
       '<default>'
-      >>> zope.component.queryUtility(I2, default='<default>')
+      >>> component.queryUtility(I2, default='<default>')
       '<default>'
 
     Now we declare `ob` to be the utility providing `I1`
 
-      >>> zope.component.getGlobalSiteManager().provideUtility(I1, ob)
+      >>> component.getGlobalSiteManager().provideUtility(I1, ob)
 
     so that the component is now available:
 
-      >>> zope.component.getUtility(I1) is ob
+      >>> component.getUtility(I1) is ob
       True
     """
 
@@ -495,11 +553,11 @@
 
     Just because you register an utility having no name
 
-      >>> zope.component.getGlobalSiteManager().provideUtility(I1, ob)
+      >>> component.getGlobalSiteManager().provideUtility(I1, ob)
 
     does not mean that they are available when you specify a name:
 
-      >>> zope.component.getUtility(I1, name='foo') \\
+      >>> component.getUtility(I1, name='foo') \\
       ... #doctest: +NORMALIZE_WHITESPACE
       Traceback (most recent call last):
       ...
@@ -509,17 +567,17 @@
 
     ...otherwise, you get the default
 
-      >>> zope.component.queryUtility(I1, name='foo', default='<default>')
+      >>> component.queryUtility(I1, name='foo', default='<default>')
       '<default>'
 
     Registering the utility under the correct name
 
-      >>> zope.component.getGlobalSiteManager().provideUtility(
+      >>> component.getGlobalSiteManager().provideUtility(
       ...     I1, ob, name='foo')
 
     really helps:
 
-      >>> zope.component.getUtility(I1, 'foo') is ob
+      >>> component.getUtility(I1, 'foo') is ob
       True
     """
 
@@ -534,14 +592,14 @@
       ...     pass
 
       >>> class Ob11(Ob):
-      ...     implements(I11)
+      ...     interface.implements(I11)
 
       >>> ob11 = Ob11()
       >>> ob_bob = Ob()
 
     Now we register the new utilities:
 
-      >>> gsm = zope.component.getGlobalSiteManager()
+      >>> gsm = component.getGlobalSiteManager()
       >>> gsm.provideUtility(I1, ob)
       >>> gsm.provideUtility(I11, ob11)
       >>> gsm.provideUtility(I1, ob_bob, name='bob')
@@ -549,7 +607,7 @@
 
     We can now get all the utilities that provide interface `I1`:
 
-      >>> uts = list(zope.component.getAllUtilitiesRegisteredFor(I1))
+      >>> uts = list(component.getAllUtilitiesRegisteredFor(I1))
       >>> uts = [util.__class__.__name__ for util in uts]
       >>> uts.sort()
       >>> uts
@@ -583,9 +641,8 @@
     We want to make sure that an `adapts()` call in a class definition
     doesn't affect instances.
 
-      >>> import zope.component
       >>> class C:
-      ...     zope.component.adapts()
+      ...     component.adapts()
 
       >>> C.__component_adapts__
       ()
@@ -616,6 +673,11 @@
     """
 
 def test_suite():
+    checker = renormalizing.RENormalizing([
+        (re.compile('at 0x[0-9a-f]+'), 'at <SOME ADDRESS>'),
+        ])
+
+
     return unittest.TestSuite((
         doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
         doctest.DocTestSuite('zope.component.site'),
@@ -625,10 +687,8 @@
                              setUp=setUp, tearDown=tearDown),
         doctest.DocFileSuite('factory.txt',
                              setUp=setUp, tearDown=tearDown),
+        doctest.DocFileSuite('components.txt', checker=checker),
         ))
 
 if __name__ == "__main__":
     unittest.main(defaultTest='test_suite')
-
-# BBB: Import some backward-compatibility; 12/10/2004
-from zope.component.bbb.tests import placelesssetup



More information about the Zope3-Checkins mailing list