[Zope3-checkins] SVN: Zope3/branches/srichter-blow-services/src/zope/component/ Merged in Jim's changes and documentation.

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Dec 17 16:36:22 EST 2004


Log message for revision 28644:
  Merged in Jim's changes and documentation.
  
  Renamed register{Adapter|Utility} to provide{Adapter|Utility}, since Jim 
  seems to prefer that.
  

Changed:
  A   Zope3/branches/srichter-blow-services/src/zope/component/README.txt
  U   Zope3/branches/srichter-blow-services/src/zope/component/__init__.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/bbb/adapter.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/bbb/service.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/bbb/tests/test_api.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/bbb/utility.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/factory.txt
  U   Zope3/branches/srichter-blow-services/src/zope/component/interfaces.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/site.py
  U   Zope3/branches/srichter-blow-services/src/zope/component/socketexample.txt
  U   Zope3/branches/srichter-blow-services/src/zope/component/tests.py

-=-
Copied: Zope3/branches/srichter-blow-services/src/zope/component/README.txt (from rev 28643, Zope3/trunk/src/zope/component/README.txt)

Modified: Zope3/branches/srichter-blow-services/src/zope/component/__init__.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/__init__.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/__init__.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -16,8 +16,11 @@
 $Id$
 """
 import sys
-from zope.interface import moduleProvides, Interface, providedBy
+import zope.interface
+from zope.interface import moduleProvides, Interface
+from zope.interface import providedBy, implementedBy
 from zope.component.interfaces import IComponentArchitecture
+from zope.component.interfaces import IComponentRegistrationConvenience
 from zope.component.interfaces import IDefaultViewName
 from zope.component.interfaces import IFactory
 from zope.component.interfaces import ISiteManager
@@ -72,7 +75,7 @@
     def hookable(ob):
         return ob
 
-moduleProvides(IComponentArchitecture)
+moduleProvides(IComponentArchitecture, IComponentRegistrationConvenience)
 __all__ = tuple(IComponentArchitecture)
 
 # SiteManager API
@@ -165,7 +168,6 @@
         return []
     return sitemanager.getAdapters(objects, provided)
 
-
 def subscribers(objects, interface, context=None):
     try:
         sitemanager = getSiteManager(context)
@@ -174,6 +176,31 @@
         return []
     return sitemanager.subscribers(objects, interface)
 
+class _adapts_descr(object):
+    def __init__(self, interfaces):
+        self.interfaces = interfaces
+
+    def __get__(self, inst, cls):
+        if inst is None:
+            return self.interfaces
+        raise AttributeError, '__component_adapts__'
+
+def adapts(*interfaces):
+    frame = sys._getframe(1)
+    locals = frame.f_locals
+
+    # Try to make sure we were called from a class def. In 2.2.0 we can't
+    # check for __module__ since it doesn't seem to be added to the locals
+    # until later on.
+    if (locals is frame.f_globals) or (
+        ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)):
+        raise TypeError(name+" can be used only from a class definition.")
+
+    if '__component_adapts__' in locals:
+        raise TypeError("adapts can be used only once in a class definition.")
+
+    locals['__component_adapts__'] = _adapts_descr(interfaces)
+
 #############################################################################
 # Register the component architectures adapter hook, with the adapter hook
 # registry of the `zope.inteface` package. This way we will be able to call
@@ -234,3 +261,36 @@
                 if iface.isOrExtends(interface):
                     yield name, factory
                     break
+
+
+# The following APIs provide registration support for Python code:
+
+def provideUtility(component, provides=None, name=u''):
+    if provides is None:
+        provides = list(providedBy(component))
+        if len(provides) == 1:
+            provides = provides[0]
+        else:
+            raise TypeError("Missing 'provides' argument")
+
+    getGlobalSiteManager().provideUtility(provides, component, name)
+
+
+def provideAdapter(factory, adapts=None, provides=None, name=''):
+    if provides is None:
+        if IFactory.providedBy(factory):
+            provides = factory.getInterfaces()
+        else:
+            provides = list(implementedBy(factory))
+        if len(provides) == 1:
+            provides = provides[0]
+        else:
+            raise TypeError("Missing 'provides' argument")
+
+    if adapts is None:
+        try:
+            adapts = factory.__component_adapts__
+        except AttributeError:
+            raise TypeError("Missing 'adapts' argument")
+            
+    getGlobalSiteManager().provideAdapter(adapts, provides, name, factory)

Modified: Zope3/branches/srichter-blow-services/src/zope/component/bbb/adapter.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/bbb/adapter.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/bbb/adapter.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -126,7 +126,7 @@
         >>> registry.queryMultiAdapter((O1(), O2()), R1, '').__class__
         <class 'zope.component.bbb.adapter.O3'>
         """
-        self.sm.registerAdapter(required, provided, name, factory, info)
+        self.sm.provideAdapter(required, provided, name, factory, info)
 
     def subscribe(self, required, provided, factory, info=''):
         """Register an subscriptions adapter

Modified: Zope3/branches/srichter-blow-services/src/zope/component/bbb/service.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/bbb/service.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/bbb/service.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -93,7 +93,7 @@
         if name in names:
             raise DuplicationError(name)
 
-        self.sm.registerUtility(IServiceDefinition, (name, interface),
+        self.sm.provideUtility(IServiceDefinition, (name, interface),
                                 name=name, strict=False)
 
     def getServiceDefinitions(self):
@@ -129,7 +129,7 @@
             return
 
         directlyProvides(component, IService)
-        self.sm.registerUtility(IService, component, name)
+        self.sm.provideUtility(IService, component, name)
 
     def getService(self, name):
         """see IServiceService interface"""

Modified: Zope3/branches/srichter-blow-services/src/zope/component/bbb/tests/test_api.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/bbb/tests/test_api.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/bbb/tests/test_api.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -194,7 +194,7 @@
         context = ConformsToIServiceService(servicemanager)
         class I3(Interface):
             pass
-        servicemanager.sm.registerAdapter((I1,), I3, '', lambda x: 43)
+        servicemanager.sm.provideAdapter((I1,), I3, '', lambda x: 43)
 
         # If an object implements the interface you want to adapt to,
         # getAdapterInContext should simply return the object.

Modified: Zope3/branches/srichter-blow-services/src/zope/component/bbb/utility.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/bbb/utility.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/bbb/utility.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -62,7 +62,7 @@
         super(GlobalUtilityService, self).__init__(sitemanager)
 
     def provideUtility(self, providedInterface, component, name='', info=''):
-        self.sm.registerUtility(providedInterface, component, name, info)
+        self.sm.provideUtility(providedInterface, component, name, info)
 
     def registrations(self):
         for reg in self.sm.registrations():

Modified: Zope3/branches/srichter-blow-services/src/zope/component/factory.txt
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/factory.txt	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/factory.txt	2004-12-17 21:36:22 UTC (rev 28644)
@@ -107,7 +107,7 @@
   >>> gsm = capi.getGlobalSiteManager() 
 
   >>> from zope.component.interfaces import IFactory
-  >>> gsm.registerUtility(IFactory, factory, 'klass')
+  >>> gsm.provideUtility(IFactory, factory, 'klass')
 
 Creating an Object
 ++++++++++++++++++

Modified: Zope3/branches/srichter-blow-services/src/zope/component/interfaces.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/interfaces.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/interfaces.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -273,6 +273,14 @@
         required objects.
         """
 
+    def adapts(*interfaces):
+        """Declare that a class adapts the given interfaces.
+
+        This function can only be used in a class definition.
+
+        (TODO, allow classes to be passed as well as interfaces.)
+        """
+
     def queryUtility(interface, name='', default=None):
         """Look up a utility that provides an interface.
 
@@ -294,8 +302,53 @@
         returned.
         """
 
+        
+class IComponentRegistrationConvenience(Interface):
+    """API for registering components.
 
+    CAUTION: This API should only be used from test or
+    application-setup code. This api shouldn't be used by regular
+    library modules, as component registration is a configuration
+    activity. 
+    """
 
+    def provideUtility(component, provides=None, name=u''):
+        """Register a utility globally
+
+        A utility is registered to provide an interface with a
+        name. If a component provides only one interface, then the
+        provides argument can be omitted and the provided interface
+        will be used. (In this case, provides argument can still be
+        provided to provide a less specific interface.)
+
+        CAUTION: This API should only be used from test or
+        application-setup code. This api shouldn't be used by regular
+        library modules, as component registration is a configuration
+        activity. 
+        
+        """
+
+    def provideAdapter(factory, adapts=None, provides=None, name=u''):
+        """Register an adapter globally
+
+        An adapter is registered to provide an interface with a name
+        for some number of object types. If a factory implements only
+        one interface, then the provides argument can be omitted and
+        the provided interface will be used. (In this case, a provides
+        argument can still be provided to provide a less specific
+        interface.)
+
+        If the factory has an adapts declaration, then the adapts
+        argument can be omitted and the declaration will be used.  (An
+        adapts argument can be provided to override the declaration.)
+
+        CAUTION: This API should only be used from test or
+        application-setup code. This api shouldn't be used by regular
+        library modules, as component registration is a configuration
+        activity. 
+        
+        """
+
 class IRegistry(Interface):
     """Object that supports component registry
     """

Modified: Zope3/branches/srichter-blow-services/src/zope/component/site.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/site.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/site.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -28,7 +28,7 @@
 
 class IGlobalSiteManager(ISiteManager, IRegistry):
 
-    def registerAdapter(required, provided, name, factory, info=''):
+    def provideAdapter(required, provided, name, factory, info=''):
         """Register an adapter factory
 
         :Parameters:
@@ -52,8 +52,8 @@
           - `info`: Provide some info about this particular adapter.
         """
 
-    def registerUtility(providedInterface, component, name='', info='',
-                        strict=True):
+    def provideUtility(providedInterface, component, name='', info='',
+                       strict=True):
         """Register a utility
 
         If strict is true, then the specified component *must* implement the
@@ -116,7 +116,7 @@
         super(GlobalSiteManager, self).__init__()
         self._registrations = {}
 
-    def registerAdapter(self, required, provided, name, factory, info=''):
+    def provideAdapter(self, required, provided, name, factory, info=''):
         """Register an adapter
 
         >>> from zope.interface import Interface
@@ -130,8 +130,8 @@
         >>> class P2(P1):
         ...     pass
 
-        >>> registry.registerAdapter((R1, ), P2, 'bob', 'c1', 'd1')
-        >>> registry.registerAdapter((R1, ), P2,    '', 'c2', 'd2')
+        >>> registry.provideAdapter((R1, ), P2, 'bob', 'c1', 'd1')
+        >>> registry.provideAdapter((R1, ), P2,    '', 'c2', 'd2')
         >>> registry.adapters.lookup((R2, ), P1, '')
         'c2'
 
@@ -153,11 +153,11 @@
         ...     def __init__(self, obj1, obj2=None):
         ...         pass
 
-        >>> registry.registerAdapter((O1, ), R1, '', O3)
+        >>> registry.provideAdapter((O1, ), R1, '', O3)
         >>> registry.queryAdapter(O1(), R1, '').__class__
         <class 'zope.component.site.O3'>
 
-        >>> registry.registerAdapter((O1, O2), R1, '', O3)
+        >>> registry.provideAdapter((O1, O2), R1, '', O3)
         >>> registry.queryMultiAdapter((O1(), O2()), R1, '').__class__
         <class 'zope.component.site.O3'>
         """
@@ -218,7 +218,7 @@
 
         self.adapters.subscribe(required, provided, factory)
 
-    def registerUtility(self, providedInterface, component, name='', info='',
+    def provideUtility(self, providedInterface, component, name='', info='',
                         strict=True):
 
         if strict and not providedInterface.providedBy(component):

Modified: Zope3/branches/srichter-blow-services/src/zope/component/socketexample.txt
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/socketexample.txt	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/socketexample.txt	2004-12-17 21:36:22 UTC (rev 28644)
@@ -84,7 +84,7 @@
   >>> from zope import component as capi
   >>> gsm = capi.getGlobalSiteManager()
   
-  >>> gsm.registerAdapter((IGermanSocket,), IUSSocket, '',
+  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, '',
   ...                    GermanToUSSocketAdapter)
 
 `capi` is the component architecture API that is being presented by this
@@ -160,9 +160,9 @@
 Now, we need a way to keep the two adapters apart. Thus we register them with
 a name:
 
-  >>> gsm.registerAdapter((IGermanSocket,), IUSSocket, 'shaver',
+  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, 'shaver',
   ...                    GermanToUSSocketAdapter)
-  >>> gsm.registerAdapter((IGermanSocket,), IUSSocket, 'dvd',
+  >>> gsm.provideAdapter((IGermanSocket,), IUSSocket, 'dvd',
   ...                    GermanToUSSocketAdapterAndTransformer)
 
 Now we simply look up the adapters using their labels (called *name*):
@@ -236,7 +236,7 @@
 You now register the combination, so that you know you can create a
 `IUSGroundedSocket`:
 
-  >>> gsm.registerAdapter((IGermanSocket, IGrounder), IUSGroundedSocket, 'mp3',
+  >>> gsm.provideAdapter((IGermanSocket, IGrounder), IUSGroundedSocket, 'mp3',
   ...                    GroundedGermanToUSSocketAdapter)
 
 Given the grounder
@@ -373,7 +373,7 @@
 Like for adapters, we now have to add the newly-acquired generator to our
 inventory by registering it as a utility:
 
-  >>> gsm.registerUtility(IUSSocket, generator)
+  >>> gsm.provideUtility(IUSSocket, generator)
 
 We can now get the utility using
 
@@ -425,7 +425,7 @@
 
 Once it arrives, we add it to our inventory:
 
-  >>> gsm.registerUtility(IUSSocket, panel, 'Solar Panel')
+  >>> gsm.provideUtility(IUSSocket, panel, 'Solar Panel')
 
 You can now access the solar panel using
 
@@ -495,7 +495,7 @@
 implemented interface from the class. We now register the factory:
 
   >>> from zope.component.interfaces import IFactory
-  >>> gsm.registerUtility(IFactory, factory, 'SolarPanel')
+  >>> gsm.provideUtility(IFactory, factory, 'SolarPanel')
 
 We can now get a list of interfaces the produced object will provide:
 
@@ -522,7 +522,7 @@
 
 Once you register several factories
 
-  >>> gsm.registerUtility(IFactory, Factory(Generator), 'Generator')
+  >>> gsm.provideUtility(IFactory, Factory(Generator), 'Generator')
 
 you can also determine, which available factories will create objects
 providing a certian interface:

Modified: Zope3/branches/srichter-blow-services/src/zope/component/tests.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/component/tests.py	2004-12-17 17:35:34 UTC (rev 28643)
+++ Zope3/branches/srichter-blow-services/src/zope/component/tests.py	2004-12-17 21:36:22 UTC (rev 28644)
@@ -185,7 +185,7 @@
 
     We now register an adapter from `I1` to `I3`:
       
-      >>> sitemanager.registerAdapter((I1,), I3, '', lambda x: 43)
+      >>> sitemanager.provideAdapter((I1,), I3, '', lambda x: 43)
 
     If an object implements the interface you want to adapt to,
     `getAdapterInContext()` should simply return the object.
@@ -253,7 +253,7 @@
     Now get the global site manager and register an adapter from `I1` to `I2`
     without a name:
       
-      >>> capi.getGlobalSiteManager().registerAdapter((I1,), I2, '', Comp)
+      >>> capi.getGlobalSiteManager().provideAdapter((I1,), I2, '', Comp)
 
     You can now simply access the adapter using the `getAdapter()` API
     function:
@@ -272,7 +272,7 @@
 
     First, we need to register an adapter:
     
-      >>> capi.getGlobalSiteManager().registerAdapter([I1], I2, '', Comp)
+      >>> capi.getGlobalSiteManager().provideAdapter([I1], I2, '', Comp)
 
     Then we try to adapt `ob` to provide an `I2` interface by calling the `I2`
     interface with the obejct as first argument:
@@ -304,7 +304,7 @@
 
     First we register some named adapter:
 
-      >>> capi.getGlobalSiteManager().registerAdapter([I1], I2, 'foo',
+      >>> capi.getGlobalSiteManager().provideAdapter([I1], I2, 'foo',
       ...                                             lambda x: 0)
 
     If an adapter isn't registered for the given object and interface,
@@ -323,7 +323,7 @@
 
     But now we register an adapter for the object having the correct name
 
-      >>> capi.getGlobalSiteManager().registerAdapter([I1], I2, 'bar', Comp)
+      >>> capi.getGlobalSiteManager().provideAdapter([I1], I2, 'bar', Comp)
 
     so that the lookup succeeds:
     
@@ -372,7 +372,7 @@
 
     Now we can register the multi-adapter using
     
-      >>> capi.getGlobalSiteManager().registerAdapter((I1, I2), I3, '',
+      >>> capi.getGlobalSiteManager().provideAdapter((I1, I2), I3, '',
       ...                                        DoubleAdapter)
 
     Notice how the required interfaces are simply provided by a tuple. Now we
@@ -391,7 +391,7 @@
     """Providing an adapter for None says that your adapter can adapt anything
     to `I2`.
 
-      >>> capi.getGlobalSiteManager().registerAdapter((None,), I2, '', Comp)
+      >>> capi.getGlobalSiteManager().provideAdapter((None,), I2, '', Comp)
 
       >>> adapter = I2(ob)
       >>> adapter.__class__ is Comp
@@ -416,8 +416,8 @@
 
     Let's register some adapters first: 
     
-      >>> capi.getGlobalSiteManager().registerAdapter([I1], I2, '', Comp)
-      >>> capi.getGlobalSiteManager().registerAdapter([None], I2, 'foo', Comp)
+      >>> capi.getGlobalSiteManager().provideAdapter([I1], I2, '', Comp)
+      >>> capi.getGlobalSiteManager().provideAdapter([None], I2, 'foo', Comp)
 
     Now we get all the adapters that are registered for `ob` that provide
     `I2`:
@@ -452,7 +452,7 @@
 
     Now we declare `ob` to be the utility providing `I1`
 
-      >>> capi.getGlobalSiteManager().registerUtility(I1, ob)
+      >>> capi.getGlobalSiteManager().provideUtility(I1, ob)
 
     so that the component is now available:
     
@@ -465,7 +465,7 @@
 
     Just because you register an utility having no name
     
-      >>> capi.getGlobalSiteManager().registerUtility(I1, ob)
+      >>> capi.getGlobalSiteManager().provideUtility(I1, ob)
 
     does not mean that they are available when you specify a name:
     
@@ -483,7 +483,7 @@
 
     Registering the utility under the correct name 
 
-      >>> capi.getGlobalSiteManager().registerUtility(I1, ob, name='foo')
+      >>> capi.getGlobalSiteManager().provideUtility(I1, ob, name='foo')
 
     really helps:
 
@@ -510,10 +510,10 @@
     Now we register the new utilities:
 
       >>> gsm = capi.getGlobalSiteManager()
-      >>> gsm.registerUtility(I1, ob)
-      >>> gsm.registerUtility(I11, ob11)
-      >>> gsm.registerUtility(I1, ob_bob, name='bob')
-      >>> gsm.registerUtility(I2, Comp(2))
+      >>> gsm.provideUtility(I1, ob)
+      >>> gsm.provideUtility(I11, ob11)
+      >>> gsm.provideUtility(I1, ob_bob, name='bob')
+      >>> gsm.provideUtility(I2, Comp(2))
 
     We can now get all the utilities that provide interface `I1`:
 
@@ -545,12 +545,32 @@
       42
     """
 
+
+def testNo__component_adapts__leakage():
+    """
+    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()
+
+      >>> C.__component_adapts__
+      ()
+      >>> C().__component_adapts__
+      Traceback (most recent call last):
+      ...
+      AttributeError: __component_adapts__
+    """
+
 def test_suite():
     return unittest.TestSuite((
         doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
         doctest.DocTestSuite('zope.component.site'),
         doctest.DocFileSuite('README.txt',
                              setUp=setUp, tearDown=tearDown),
+        doctest.DocFileSuite('socketexample.txt',
+                             setUp=setUp, tearDown=tearDown),
         doctest.DocFileSuite('factory.txt',
                              setUp=setUp, tearDown=tearDown),
         ))



More information about the Zope3-Checkins mailing list