[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