[Zope3-checkins] SVN: Zope3/branches/jim-adapter/src/zope/ Moved tests for elementary CA directives to zope.component/zcml.txt (also

Philipp von Weitershausen philikon at philikon.de
Wed Apr 12 14:27:11 EDT 2006


Log message for revision 66900:
  Moved tests for elementary CA directives to zope.component/zcml.txt (also
  converted them to doctests and sanitized a whole bunch of them that were stupid
  for oen reason or another)
  

Changed:
  U   Zope3/branches/jim-adapter/src/zope/app/component/meta.zcml
  U   Zope3/branches/jim-adapter/src/zope/app/component/tests/test_directives.py
  A   Zope3/branches/jim-adapter/src/zope/component/meta.zcml
  U   Zope3/branches/jim-adapter/src/zope/component/tests.py
  A   Zope3/branches/jim-adapter/src/zope/component/zcml.txt

-=-
Modified: Zope3/branches/jim-adapter/src/zope/app/component/meta.zcml
===================================================================
--- Zope3/branches/jim-adapter/src/zope/app/component/meta.zcml	2006-04-12 18:09:30 UTC (rev 66899)
+++ Zope3/branches/jim-adapter/src/zope/app/component/meta.zcml	2006-04-12 18:27:10 UTC (rev 66900)
@@ -2,33 +2,10 @@
     xmlns="http://namespaces.zope.org/zope"
     xmlns:meta="http://namespaces.zope.org/meta">
 
+  <include package="zope.component" file="meta.zcml" />
+
   <meta:directives namespace="http://namespaces.zope.org/zope">
 
-    <meta:directive
-        name="interface"
-        schema="zope.component.zcml.IInterfaceDirective"
-        handler="zope.component.zcml.interface"
-        />
-
-    <meta:directive
-        name="adapter"
-        schema="zope.component.zcml.IAdapterDirective"
-        handler="zope.component.zcml.adapter"
-        />
-
-    <meta:directive
-        name="subscriber"
-        schema="zope.component.zcml.ISubscriberDirective"
-        handler="zope.component.zcml.subscriber"
-        />
-
-    <meta:directive
-        name="utility"
-        schema="zope.component.zcml.IUtilityDirective"
-        handler="zope.component.zcml.utility"
-        />
-
-
     <!-- BBB 2006/02/24, to be removed after 12 months -->
     <meta:directive
         name="factory"

Modified: Zope3/branches/jim-adapter/src/zope/app/component/tests/test_directives.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/app/component/tests/test_directives.py	2006-04-12 18:09:30 UTC (rev 66899)
+++ Zope3/branches/jim-adapter/src/zope/app/component/tests/test_directives.py	2006-04-12 18:27:10 UTC (rev 66900)
@@ -28,7 +28,6 @@
 from zope.component.registry import SubscriptionRegistration
 from zope.component.interfaces import ComponentLookupError
 from zope.component.interface import queryInterface
-from zope.component.zcml import interface
 
 from zope.configuration.xmlconfig import xmlconfig, XMLConfig
 from zope.configuration.exceptions import ConfigurationError
@@ -66,27 +65,6 @@
         return (''.join(atre.split(r))).strip()
 
 
-def testInterface():
-    """
-    >>> context = Context()
-    >>> class I(Interface):
-    ...     pass
-    >>> IContentType.providedBy(I)
-    False
-    >>> interface(context, I, IContentType)
-    >>> context
-    ((None,
-      <function provideInterface>,
-      ('',
-       <InterfaceClass zope.app.component.tests.test_directives.I>,
-       <InterfaceClass zope.app.content.interfaces.IContentType>)),)
-    >>> from zope.interface.interfaces import IInterface
-    >>> IContentType.extends(IInterface)
-    True
-    >>> IInterface.providedBy(I)
-    True
-    """
-
 template = """<configure
    xmlns='http://namespaces.zope.org/zope'
    xmlns:test='http://www.zope.org/NS/Zope3/test'
@@ -108,861 +86,6 @@
         XMLConfig('meta.zcml', zope.app.component)()
         XMLConfig('meta.zcml', zope.app.security)()
 
-    def testSubscriber(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = A1()
-        subscribers = zapi.subscribers((content, a1), IS)
-
-        a3 = subscribers[0]
-
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, (content, a1))
-
-
-    def testSubscriberDocumentation(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              />
-            '''
-            )))
-
-        gsm = zapi.getGlobalSiteManager()
-        doc = [reg.info
-               for reg in gsm.registrations()
-               if (isinstance(reg, SubscriptionRegistration) and
-                   reg.provided is IS)][0]
-
-        self.assertEqual(`doc`, 'File "<string>", line 6.12-11.16')
-
-    def testSubscriberWithPermission(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <permission
-                id="y.x"
-                title="XY"
-                description="Allow XY." />
-
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              permission="y.x"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = A1()
-        subscribers = zapi.subscribers((content, a1), IS)
-
-        a3 = subscribers[0]
-
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, (content, a1))
-        self.assertEqual(type(a3).__name__, 'LocationProxy')
-
-    def testSubscriber_wo_for(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = A1()
-        a2 = A2()
-        subscribers = zapi.subscribers((content, a1, a2), IS)
-
-        a3 = subscribers[0]
-
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, (content, a1, a2))
-
-    def testHandlerSubscriber_no_for(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              handler="zope.app.component.tests.adapter.A3"
-              />
-            '''
-            )))
-
-        sm = zapi.getSiteManager()
-        a3 = sm.adapters.subscriptions((IContent, I1, I2), None)[0]
-        self.assertEqual(a3, A3)
-
-
-    def testTrustedSubscriber(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              trusted="yes"
-              />
-            '''
-            )))
-        # With an unproxied object, business as usual
-        content = Content()
-        a1 = A1()
-        subscribers = zapi.subscribers((content, a1), IS)
-
-        a3 = subscribers[0]
-
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(type(a3).__name__, 'A3')
-        self.assertEqual(a3.context, (content, a1))
-
-        # Now with a proxied object:
-        from zope.security.checker import ProxyFactory
-        p = ProxyFactory(content)
-
-        # we get a proxied subscriber:
-        a3 = zapi.subscribers((p, a1), IS)[0]
-        from zope.security.proxy import Proxy
-        self.assertEqual(type(a3), Proxy)
-
-
-        # behind the security proxy is no locatin proxy:
-        from zope.security.proxy import removeSecurityProxy
-        self.assert_(removeSecurityProxy(a3).context[0] is content)
-        self.assertEqual(type(removeSecurityProxy(a3)).__name__, 'A3')
-
-
-    def testLocatableTrustedSubscriber(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              trusted="yes"
-              locate="yes"
-              />
-            '''
-            )))
-        # With an unproxied object, business as usual
-        content = Content()
-        a1 = A1()
-        subscribers = zapi.subscribers((content, a1), IS)
-
-        a3 = subscribers[0]
-
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(type(a3).__name__, 'A3')
-        self.assertEqual(a3.context, (content, a1))
-
-        # Now with a proxied object:
-        from zope.security.checker import ProxyFactory
-        p = ProxyFactory(content)
-
-        # we get a proxied subscriber:
-        a3 = zapi.subscribers((p, a1), IS)[0]
-        from zope.security.proxy import Proxy
-        self.assertEqual(type(a3), Proxy)
-
-        # behind the security proxy is a locatio proxy:
-        from zope.security.proxy import removeSecurityProxy
-        self.assert_(removeSecurityProxy(a3).context[0] is content)
-        self.assertEqual(type(removeSecurityProxy(a3)).__name__,
-                         'LocationProxy')
-
-    def testSubscriber_w_no_provides(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              handler="zope.app.component.tests.adapter.Handler"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = A1()
-        list(zapi.subscribers((content, a1), None))
-
-        self.assertEqual(content.args, ((a1,),))
-
-    def testSubscriberHavingARequiredClass(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              for="zope.app.component.tests.components.Content"
-              provides="zope.app.component.tests.adapter.I1"
-              factory="zope.app.component.tests.adapter.A1"
-              />
-            '''
-            )))
-
-        subs = zapi.subscribers((Content(),), I1)
-        self.assert_(isinstance(subs[0], A1))
-
-        class MyContent:
-            implements(IContent)
-
-        self.assertEqual(zapi.subscribers((MyContent(),), I1), [])
-
-    def testMultiSubscriber(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              />
-            <subscriber
-              provides="zope.app.component.tests.adapter.IS"
-              factory="zope.app.component.tests.adapter.A2"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = A1()
-        subscribers = zapi.subscribers((content, a1), IS)
-
-        expectedLength = 2
-        self.assertEqual(len(subscribers), expectedLength)
-        classesNotFound = [A2, A3]
-        for a in subscribers:
-            classesNotFound.remove(a.__class__)
-        self.failIf(classesNotFound)
-
-    def testAdapter(self):
-        # Full import is critical!
-        self.assertEqual(IV(Content(), None), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.components.Comp"
-              provides="zope.app.component.tests.components.IApp"
-              for="zope.app.component.tests.components.IContent"
-              />
-            '''
-            )))
-
-        self.assertEqual(IApp(Content()).__class__, Comp)
-
-    def testAdapterWithPermission(self):
-        # Full import is critical!
-        self.assertEqual(IV(Content(), None), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <permission
-                id="y.x"
-                title="XY"
-                description="Allow XY." />
-
-            <adapter
-              factory="zope.app.component.tests.components.Comp"
-              provides="zope.app.component.tests.components.IApp"
-              for="zope.app.component.tests.components.IContent"
-              permission="y.x"
-              />
-            '''
-            )))
-
-        self.assertEqual(IApp(Content()).__class__, Comp)
-        self.assertEqual(type(IApp(Content())).__name__, 'LocationProxy')
-
-    def testAdapter_wo_provides_or_for(self):
-        # Full import is critical!
-        self.assertEqual(IV(Content(), None), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.components.Comp"
-              />
-            '''
-            )))
-
-        self.assertEqual(IApp(Content()).__class__, Comp)
-
-    def testAdapter_wo_provides_and_no_implented_fails(self):
-        try:
-            xmlconfig(StringIO(template % (
-                '''
-                <adapter
-                  factory="zope.app.component.tests.adapter.A4"
-                  for="zope.app.component.tests.components.IContent"
-                  />
-                '''
-                )))
-        except ConfigurationError, v:
-            self.assert_("Missing 'provides' attribute" in str(v))
-
-    def testAdapter_wo_provides_and_too_many_implented_fails(self):
-        try:
-            xmlconfig(StringIO(template % (
-                '''
-                <adapter
-                  factory="zope.app.component.tests.adapter.A4"
-                  for="zope.app.component.tests.components.IContent"
-                  />
-                '''
-                )))
-        except ConfigurationError, v:
-            self.assert_("Missing 'provides' attribute" in str(v))
-
-    def testTrustedAdapter(self):
-        # Full import is critical!
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A1"
-              provides="zope.app.component.tests.adapter.I1"
-              for="zope.app.component.tests.components.IContent"
-              trusted="yes"
-              />
-            '''
-            )))
-
-        # With an unproxied object, business as usual
-        ob = Content()
-        self.assertEqual(type(I1(ob)).__name__, 'A1')
-
-        # Now with a proxied object:
-        from zope.security.checker import ProxyFactory
-        p = ProxyFactory(ob)
-
-        # we get a proxied adapter:
-        a = I1(p)
-        from zope.security.proxy import Proxy
-        self.assertEqual(type(a), Proxy)
-
-        # around an unproxied object:
-        from zope.security.proxy import removeSecurityProxy
-        a = removeSecurityProxy(a)
-        self.assertEqual(type(a).__name__, 'A1')
-        self.assert_(a.context[0] is ob)
-
-
-    def testTrustedAdapterWithPermission(self):
-        # Full import is critical!
-        xmlconfig(StringIO(template % (
-            '''
-            <permission
-                id="y.x"
-                title="XY"
-                description="Allow XY." />
-
-            <adapter
-              factory="zope.app.component.tests.adapter.A1"
-              provides="zope.app.component.tests.adapter.I1"
-              for="zope.app.component.tests.components.IContent"
-              permission="y.x"
-              trusted="yes"
-              />
-            '''
-            )))
-
-        # With an unproxied object, business as usual
-        ob = Content()
-        self.assertEqual(type(I1(ob)).__name__, 'A1')
-
-        # Now with a proxied object:
-        from zope.security.checker import ProxyFactory
-        p = ProxyFactory(ob)
-
-        # we get a proxied adapter:
-        a = I1(p)
-        from zope.security.proxy import Proxy
-        self.assertEqual(type(a), Proxy)
-
-        # behind the security proxy is location proxy
-        # if non-public permission is used
-        from zope.security.proxy import removeSecurityProxy
-        a = removeSecurityProxy(a)
-        self.assertEqual(type(a).__name__, 'LocationProxy')
-        self.assert_(a.context[0] is ob)
-
-
-    def testTrustedAdapterWithPublicPermission(self):
-        # Full import is critical!
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A1"
-              provides="zope.app.component.tests.adapter.I1"
-              for="zope.app.component.tests.components.IContent"
-              permission="zope.Public"
-              trusted="yes"
-              />
-            '''
-            )))
-
-        # With an unproxied object, business as usual
-        ob = Content()
-        self.assertEqual(type(I1(ob)).__name__, 'A1')
-
-        # Now with a proxied object:
-        from zope.security.checker import ProxyFactory
-        p = ProxyFactory(ob)
-
-        # we get a proxied adapter:
-        a = I1(p)
-        from zope.security.proxy import Proxy
-        self.assertEqual(type(a), Proxy)
-
-        # behind the security proxy is no location proxy
-        from zope.security.proxy import removeSecurityProxy
-        a = removeSecurityProxy(a)
-        self.assertEqual(type(a).__name__, 'A1')
-        self.assert_(a.context[0] is ob)
-
-
-    def testLocatableTrustedAdapter(self):
-        # Full import is critical!
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A1"
-              provides="zope.app.component.tests.adapter.I1"
-              for="zope.app.component.tests.components.IContent"
-              trusted="yes"
-              locate="yes"
-              />
-            '''
-            )))
-
-        # With an unproxied object, business as usual
-        ob = Content()
-        self.assertEqual(type(I1(ob)).__name__, 'A1')
-
-        # Now with a proxied object:
-        from zope.security.checker import ProxyFactory
-        p = ProxyFactory(ob)
-
-        # we get a proxied adapter:
-        a = I1(p)
-        from zope.security.proxy import Proxy
-        self.assertEqual(type(a), Proxy)
-
-        # behind the security proxy is always location proxy:
-        from zope.security.proxy import removeSecurityProxy
-        a = removeSecurityProxy(a)
-        self.assertEqual(type(a).__name__, 'LocationProxy')
-        self.assert_(a.context[0] is ob) 
-
-    def testAdapter_w_multiple_factories(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A1
-                       zope.app.component.tests.adapter.A2
-                       zope.app.component.tests.adapter.A3
-                      "
-              provides="zope.app.component.tests.components.IApp"
-              for="zope.app.component.tests.components.IContent"
-              />
-            '''
-            )))
-
-        # The resulting adapter should be an A3, around an A2, around
-        # an A1, andround the content:
-
-        content = Content()
-        a3 = IApp(content)
-        self.assertEqual(a3.__class__, A3)
-        a2 = a3.context[0]
-        self.assertEqual(a2.__class__, A2)
-        a1 = a2.context[0]
-        self.assertEqual(a1.__class__, A1)
-        self.assertEqual(a1.context[0], content)
-
-    def testAdapter_fails_w_no_factories(self):
-        self.assertRaises(ConfigurationError,
-                          xmlconfig,
-                          StringIO(template % (
-                             '''
-                             <adapter
-                             factory="
-                                     "
-                             provides="zope.app.component.tests.components.IApp"
-                             for="zope.app.component.tests.components.IContent"
-                             />
-                             '''
-                             )),
-                          )
-
-    def testAdapterHavingARequiredClass(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              for="zope.app.component.tests.components.Content"
-              provides="zope.app.component.tests.adapter.I1"
-              factory="zope.app.component.tests.adapter.A1"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = zapi.getAdapter(content, I1, '')
-        self.assert_(isinstance(a1, A1))
-
-        class MyContent:
-            implements(IContent)
-
-        self.assertRaises(ComponentLookupError, zapi.getAdapter,
-                          MyContent(), I1, '')
-
-
-    def testMultiAdapter(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A3
-                      "
-              provides="zope.app.component.tests.adapter.I3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1
-                   zope.app.component.tests.adapter.I2"
-              />
-            '''
-            )))
-        content = Content()
-        a1 = A1()
-        a2 = A2()
-        a3 = zapi.queryMultiAdapter((content, a1, a2), I3)
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, (content, a1, a2))
-
-    def testProtectedMultiAdapter(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A3
-                      "
-              provides="zope.app.component.tests.adapter.I3"
-              for="zope.app.component.tests.components.IContent
-                   zope.app.component.tests.adapter.I1
-                   zope.app.component.tests.adapter.I2
-                  "
-              permission="zope.Public"
-              />
-            '''
-            )))
-        content = Content()
-        a1 = A1()
-        a2 = A2()
-        a3 = ProxyFactory(zapi.queryMultiAdapter((content, a1, a2), I3))
-        self.assertEqual(a3.__class__, A3)
-        items = [item[0] for item in getTestProxyItems(a3)]
-        self.assertEqual(items, ['f1', 'f2', 'f3'])
-
-    def testMultiAdapter_wo_for_or_provides(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A3"
-              />
-            '''
-            )))
-
-        content = Content()
-        a1 = A1()
-        a2 = A2()
-        a3 = zapi.queryMultiAdapter((content, a1, a2), I3)
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, (content, a1, a2))
-
-    def testNullAdapter(self):
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.adapter.A3"
-              provides="zope.app.component.tests.adapter.I3"
-              for=""
-              />
-            '''
-            )))
-
-        a3 = zapi.queryMultiAdapter((), I3)
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, ())
-
-    def testMultiAdapterFails_w_multiple_factories(self):
-        self.assertRaises(ConfigurationError,
-                          xmlconfig,
-                          StringIO(template % (
-                             '''
-                             <adapter
-                             factory="zope.app.component.tests.adapter.A1
-                                      zope.app.component.tests.adapter.A2
-                                     "
-                             for="zope.app.component.tests.components.IContent
-                                  zope.app.component.tests.adapter.I1
-                                  zope.app.component.tests.adapter.I2
-                                  "
-                             provides="zope.app.component.tests.components.IApp"
-                             />
-                             '''
-                             )),
-                          )
-
-        self.assertRaises(ConfigurationError,
-                          xmlconfig,
-                          StringIO(template % (
-                             '''
-                             <adapter
-                             factory="zope.app.component.tests.adapter.A1
-                                      zope.app.component.tests.adapter.A2
-                                     "
-                             for=""
-                             provides="zope.app.component.tests.components.IApp"
-                             />
-                             '''
-                             )),
-                          )
-
-
-    def testNamedAdapter(self):
-        self.testAdapter()
-        self.assertEqual(IApp(Content()).__class__, Comp)
-        self.assertEqual(zapi.queryAdapter(Content(), IV, 'test'), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.components.Comp"
-              provides="zope.app.component.tests.components.IApp"
-              for="zope.app.component.tests.components.IContent"
-              name="test"
-              />
-            '''
-            )))
-
-        self.assertEqual(
-            zapi.getAdapter(Content(), IApp, "test").__class__, Comp)
-
-    def testProtectedAdapter(self):
-        self.assertEqual(IV(Content(), None), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.components.Comp"
-              provides="zope.app.component.tests.components.IApp"
-              for="zope.app.component.tests.components.IContent"
-              permission="zope.Public"
-              />
-            '''
-            )))
-
-        adapter = ProxyFactory(IApp(Content()))
-        items = [item[0] for item in getTestProxyItems(adapter)]
-        self.assertEqual(items, ['a', 'f'])
-        self.assertEqual(removeSecurityProxy(adapter).__class__, Comp)
-
-    def testProtectedAdapter_wo_for_or_provides(self):
-        self.assertEqual(IV(Content(), None), None)
-        xmlconfig(StringIO(template % (
-            '''
-            <adapter
-              factory="zope.app.component.tests.components.Comp"
-              permission="zope.Public"
-              />
-            '''
-            )))
-
-        adapter = ProxyFactory(IApp(Content()))
-        items = [item[0] for item in getTestProxyItems(adapter)]
-        self.assertEqual(items, ['a', 'f'])
-        self.assertEqual(removeSecurityProxy(adapter).__class__, Comp)
-
-    def testAdapterUndefinedPermission(self):
-        config = StringIO(template % (
-             '''
-             <adapter
-              factory="zope.app.component.tests.components.Comp"
-              provides="zope.app.component.tests.components.IApp"
-              for="zope.app.component.tests.components.IContent"
-              permission="zope.UndefinedPermission"
-              />
-            '''
-            ))
-        self.assertRaises(ValueError, xmlconfig, config, testing=1)
-
-    def testUtility(self):
-        self.assertEqual(zapi.queryUtility(IV), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <utility
-              component="zope.app.component.tests.components.comp"
-              provides="zope.app.component.tests.components.IApp"
-              />
-            '''
-            )))
-
-        self.assertEqual(zapi.getUtility(IApp), comp)
-
-    def testUtility_wo_provides(self):
-        self.assertEqual(zapi.queryUtility(IV), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <utility
-              component="zope.app.component.tests.components.comp"
-              />
-            '''
-            )))
-
-        self.assertEqual(zapi.getUtility(IApp), comp)
-
-    def testUtility_wo_provides_fails_if_no_provides(self):
-        try:
-            xmlconfig(StringIO(template % (
-                '''
-                <utility
-                  component="zope.app.component.tests.adapter.a4"
-                  />
-                '''
-                )))
-        except ConfigurationError, v:
-            self.assert_("Missing 'provides' attribute" in str(v))
-
-    def testUtility_wo_provides_fails_if_too_many_provided(self):
-        try:
-            xmlconfig(StringIO(template % (
-                '''
-                <utility
-                  component="zope.app.component.tests.adapter.a5"
-                  />
-                '''
-                )))
-        except ConfigurationError, v:
-            self.assert_("Missing 'provides' attribute" in str(v))
-
-    def testUtility_wo_provides_fails_if_no_implemented(self):
-        try:
-            xmlconfig(StringIO(template % (
-                '''
-                <utility
-                  factory="zope.app.component.tests.adapter.A4"
-                  />
-                '''
-                )))
-        except ConfigurationError, v:
-            self.assert_("Missing 'provides' attribute" in str(v))
-
-    def testUtility_wo_provides_fails_if_too_many_implemented(self):
-        try:
-            xmlconfig(StringIO(template % (
-                '''
-                <utility
-                  factory="zope.app.component.tests.adapter.A5"
-                  />
-                '''
-                )))
-        except ConfigurationError, v:
-            self.assert_("Missing 'provides' attribute" in str(v))
-
-    def testNamedUtility(self):
-        self.testUtility()
-        self.assertEqual(zapi.queryUtility(IV, 'test'), None)
-        xmlconfig(StringIO(template % (
-            '''
-            <utility
-              component="zope.app.component.tests.components.comp"
-              provides="zope.app.component.tests.components.IApp"
-              name="test"
-              />
-            '''
-            )))
-
-        self.assertEqual(zapi.getUtility(IApp, "test"), comp)
-
-    def testUtilityFactory(self):
-        self.assertEqual(zapi.queryUtility(IV), None)
-
-        xmlconfig(StringIO(template % (
-            '''
-            <utility
-              factory="zope.app.component.tests.components.Comp"
-              provides="zope.app.component.tests.components.IApp"
-              />
-            '''
-            )))
-
-        self.assertEqual(zapi.getUtility(IApp).__class__, Comp)
-
-    def testProtectedUtility(self):
-        """Test that we can protect a utility.
-
-        Also:
-        Check that multiple configurations for the same utility and
-        don't interfere.
-        """
-        self.assertEqual(zapi.queryUtility(IV), None)
-        xmlconfig(StringIO(template % (
-            '''
-            <permission id="tell.everyone" title="Yay" />
-            <utility
-              component="zope.app.component.tests.components.comp"
-              provides="zope.app.component.tests.components.IApp"
-              permission="tell.everyone"
-              />
-            <permission id="top.secret" title="shhhh" />
-            <utility
-              component="zope.app.component.tests.components.comp"
-              provides="zope.app.component.tests.components.IAppb"
-              permission="top.secret"
-              />
-            '''
-            )))
-
-        utility = ProxyFactory(zapi.getUtility(IApp))
-        items = getTestProxyItems(utility)
-        self.assertEqual(items, [('a', 'tell.everyone'),
-                                 ('f', 'tell.everyone')
-                                 ])
-        self.assertEqual(removeSecurityProxy(utility), comp)
-
-    def testUtilityUndefinedPermission(self):
-        config = StringIO(template % (
-             '''
-             <utility
-              component="zope.app.component.tests.components.comp"
-              provides="zope.app.component.tests.components.IApp"
-              permission="zope.UndefinedPermission"
-              />
-            '''
-            ))
-        self.assertRaises(ValueError, xmlconfig, config,
-                          testing=1)
-
-
     def testView(self):
         ob = Ob()
         request = Request(IV)

Copied: Zope3/branches/jim-adapter/src/zope/component/meta.zcml (from rev 66842, Zope3/branches/jim-adapter/src/zope/app/component/meta.zcml)
===================================================================
--- Zope3/branches/jim-adapter/src/zope/app/component/meta.zcml	2006-04-11 10:03:07 UTC (rev 66842)
+++ Zope3/branches/jim-adapter/src/zope/component/meta.zcml	2006-04-12 18:27:10 UTC (rev 66900)
@@ -0,0 +1,33 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/zope">
+
+    <meta:directive
+        name="interface"
+        schema="zope.component.zcml.IInterfaceDirective"
+        handler="zope.component.zcml.interface"
+        />
+
+    <meta:directive
+        name="adapter"
+        schema="zope.component.zcml.IAdapterDirective"
+        handler="zope.component.zcml.adapter"
+        />
+
+    <meta:directive
+        name="subscriber"
+        schema="zope.component.zcml.ISubscriberDirective"
+        handler="zope.component.zcml.subscriber"
+        />
+
+    <meta:directive
+        name="utility"
+        schema="zope.component.zcml.IUtilityDirective"
+        handler="zope.component.zcml.utility"
+        />
+
+  </meta:directives>
+
+</configure>

Modified: Zope3/branches/jim-adapter/src/zope/component/tests.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/component/tests.py	2006-04-12 18:09:30 UTC (rev 66899)
+++ Zope3/branches/jim-adapter/src/zope/component/tests.py	2006-04-12 18:27:10 UTC (rev 66900)
@@ -796,6 +796,13 @@
     import zope.event
     zope.event.subscribers.pop()
 
+def clearZCML(test=None):
+    tearDown()
+    setUp()
+
+    from zope.configuration.xmlconfig import XMLConfig
+    XMLConfig('meta.zcml', component)()
+
 def test_suite():
     checker = renormalizing.RENormalizing([
         (re.compile('at 0x[0-9a-f]+'), 'at <SOME ADDRESS>'),
@@ -803,6 +810,8 @@
 
     return unittest.TestSuite((
         doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
+        doctest.DocTestSuite('zope.component.interface',
+                             setUp=setUp, tearDown=tearDown),
         doctest.DocFileSuite('README.txt',
                              setUp=setUp, tearDown=tearDown),
         doctest.DocFileSuite('socketexample.txt',
@@ -813,7 +822,7 @@
                              tearDown=tearDownRegistryTests),
         doctest.DocFileSuite('event.txt',
                              setUp=setUp, tearDown=tearDown),
-        doctest.DocTestSuite('zope.component.interface',
+        doctest.DocFileSuite('zcml.txt',
                              setUp=setUp, tearDown=tearDown),
         ))
 

Copied: Zope3/branches/jim-adapter/src/zope/component/zcml.txt (from rev 66842, Zope3/branches/jim-adapter/src/zope/app/component/tests/test_directives.py)
===================================================================
--- Zope3/branches/jim-adapter/src/zope/app/component/tests/test_directives.py	2006-04-11 10:03:07 UTC (rev 66842)
+++ Zope3/branches/jim-adapter/src/zope/component/zcml.txt	2006-04-12 18:27:10 UTC (rev 66900)
@@ -0,0 +1,1013 @@
+ZCML directives
+===============
+
+Components may be registered using the registration API exposed by
+``zope.component`` (provideAdapter, provideUtility, etc.).  They may
+also be registered using configuration files.  The common way to do
+that is by using ZCML (Zope Configuration Markup Language), an XML
+spelling of component registration.
+
+In ZCML, each XML element is a *directive*.  There are different
+top-level directives that let us register components.  We will
+introduce them one by one here.
+
+This helper will let us easily execute ZCML snippets:
+
+  >>> from cStringIO import StringIO
+  >>> from zope.configuration.xmlconfig import xmlconfig
+  >>> def runSnippet(snippet):
+  ...     template = """\
+  ...     <configure xmlns='http://namespaces.zope.org/zope'
+  ...                i18n_domain="zope">
+  ...     %s
+  ...     </configure>"""
+  ...     xmlconfig(StringIO(template % snippet))
+
+adapter
+-------
+
+Adapters play a key role in the Component Architecture.  In ZCML, they
+are registered with the <adapter /> directive.
+
+  >>> from zope.app.component.tests.adapter import A1, A2, A3, Handler
+  >>> from zope.app.component.tests.adapter import I1, I2, I3, IS
+  >>> from zope.app.component.tests.components import IContent, Content, Comp, comp
+
+Before we register the first test adapter, we can verify that adapter
+lookup doesn't work yet:
+
+  >>> from zope.component.tests import clearZCML
+  >>> clearZCML()
+  >>> from zope.app.component.tests.components import IApp
+  >>> IApp(Content(), None) is None
+  True
+
+Then we register the adapter and see that the lookup works:
+
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       />''')
+
+  >>> IApp(Content()).__class__
+  <class 'zope.app.component.tests.components.Comp'>
+
+It is also possible to give adapters names.  Then the combination of
+required interface, provided interface and name makes the adapter
+lookup unique.  The name is supplied using the ``name`` argument to
+the <adapter /> directive:
+
+  >>> from zope.component.tests import clearZCML
+  >>> clearZCML()
+  >>> import zope.component
+  >>> zope.component.queryAdapter(Content(), IApp, 'test') is None
+  True
+
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       name="test"
+  ...       />''')
+
+  >>> zope.component.getAdapter(Content(), IApp, 'test').__class__
+  <class 'zope.app.component.tests.components.Comp'>
+
+Adapter factories
+~~~~~~~~~~~~~~~~~
+
+It is possible to supply more than one adapter factory.  In this case,
+during adapter lookup each factory will be called and the return value
+will be given to the next factory.  The return value of the last
+factory is returned as the result of the adapter lookup.  For examle:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.adapter.A1
+  ...                zope.app.component.tests.adapter.A2
+  ...                zope.app.component.tests.adapter.A3"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       />''')
+
+The resulting adapter is an A3, around an A2, around an A1, around the
+adapted object:
+
+  >>> content = Content()
+  >>> a3 = IApp(content)
+  >>> a3.__class__ is A3
+  True
+
+  >>> a2 = a3.context[0]
+  >>> a2.__class__ is A2
+  True
+
+  >>> a1 = a2.context[0]
+  >>> a1.__class__ is A1
+  True
+
+  >>> a1.context[0] is content
+  True
+
+Of course, if no factory is provided at all, we will get an error:
+
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory=""
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-8.8
+      ValueError: No factory specified
+
+Declaring ``for`` and ``provides`` in Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The <adapter /> directive can figure out from the in-line Python
+declaration (using ``zope.component.adapts()`` or
+``zope.component.adapter()`` as well as ``zope.interface.implements``)
+what the adapter should be registered for and what it provides::
+
+  >>> clearZCML()
+  >>> IApp(Content(), None) is None
+  True
+
+  >>> runSnippet('''
+  ...   <adapter factory="zope.app.component.tests.components.Comp" />''')
+
+  >>> IApp(Content()).__class__
+  <class 'zope.app.component.tests.components.Comp'>
+
+Of course, if the adapter has no ``implements()`` declaration, ZCML
+can't figure out what it provides:
+
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.adapter.A4"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-7.8
+      TypeError: Missing 'provides' attribute
+
+On the other hand, if the factory implements more than one interface,
+ZCML can't figure out what it should provide either:
+
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.adapter.A5"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-7.8
+      TypeError: Missing 'provides' attribute
+
+A not so common edge case is registering adapters directly for
+classes, not for interfaces.  For example:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.Content"
+  ...       provides="zope.app.component.tests.adapter.I1"
+  ...       factory="zope.app.component.tests.adapter.A1"
+  ...       />''')
+
+  >>> content = Content()
+  >>> a1 = zope.component.getAdapter(content, I1, '')
+  >>> isinstance(a1, A1)
+  True
+
+This time, any object providing ``IContent`` won't work if it's not an
+instance of the ``Content`` class:
+
+  >>> import zope.interface
+  >>> class MyContent:
+  ...     zope.interface.implements(IContent)
+  >>> zope.component.getAdapter(MyContent(), I1, '')  # doctest: +ELLIPSIS
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: ...
+
+Multi-adapters
+~~~~~~~~~~~~~~
+
+Conventional adapters adapt one object to provide another interface.
+Multi-adapters adapt several objects at once:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1
+  ...            zope.app.component.tests.adapter.I2"
+  ...       provides="zope.app.component.tests.adapter.I3"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       />''')
+
+  >>> content = Content()
+  >>> a1 = A1()
+  >>> a2 = A2()
+  >>> a3 = zope.component.queryMultiAdapter((content, a1, a2), I3)
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == (content, a1, a2)
+  True
+
+You can even adapt an empty list of objects (we call this a
+null-adapter):
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for=""
+  ...       provides="zope.app.component.tests.adapter.I3"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       />''')
+
+  >>> a3 = zope.component.queryMultiAdapter((), I3)
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == ()
+  True
+
+Even with multi-adapters, ZCML can figure out the ``for`` and
+``provides`` parameters from the Python declarations:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter factory="zope.app.component.tests.adapter.A3" />''')
+
+  >>> a3 = zope.component.queryMultiAdapter((content, a1, a2), I3)
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == (content, a1, a2)
+  True
+
+Chained factories are not supported for multi-adapters, though:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1
+  ...            zope.app.component.tests.adapter.I2"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       factory="zope.app.component.tests.adapter.A1
+  ...                zope.app.component.tests.adapter.A2"
+  ...       />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-11.8
+      ValueError: Can't use multiple factories and multiple for
+
+And neither for null-adapters:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for=""
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       factory="zope.app.component.tests.adapter.A1
+  ...                zope.app.component.tests.adapter.A2"
+  ...       />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-9.8
+      ValueError: Can't use multiple factories and multiple for
+
+Protected adapters
+~~~~~~~~~~~~~~~~~~
+
+Adapters can be protected with a permission.  First we have to define
+a permission for which we'll have to register the <permission />
+directive:
+
+  >>> clearZCML()
+  >>> IApp(Content(), None) is None
+  True
+
+  >>> import zope.app.security
+  >>> from zope.configuration.xmlconfig import XMLConfig
+  >>> XMLConfig('meta.zcml', zope.app.security)()
+  >>> runSnippet('''
+  ...   <permission
+  ...       id="y.x"
+  ...       title="XY"
+  ...       description="Allow XY."
+  ...       />
+  ...   <adapter
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       permission="y.x"
+  ...       />''')
+
+We see that the adapter is a location proxy now so that the
+appropriate permissions can be found from the context:
+
+  >>> IApp(Content()).__class__
+  <class 'zope.app.component.tests.components.Comp'>
+  >>> type(IApp(Content()))
+  <class 'zope.location.location.LocationProxy'>
+
+We can also go about it a different way.  Let's make a public adapter
+and wrap the adapter in a security proxy.  That often happens when
+an adapter is turned over to untrusted code:
+
+  >>> clearZCML()
+  >>> IApp(Content(), None) is None
+  True
+
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       permission="zope.Public"
+  ...       />''')
+
+  >>> from zope.security.checker import ProxyFactory
+  >>> adapter = ProxyFactory(IApp(Content()))
+  >>> from zope.security.proxy import getTestProxyItems
+  >>> items = [item[0] for item in getTestProxyItems(adapter)]
+  >>> items
+  ['a', 'f']
+
+  >>> from zope.security.proxy import removeSecurityProxy
+  >>> removeSecurityProxy(adapter).__class__ is Comp
+  True
+
+Of course, this still works when we let the ZCML directive handler
+figure out ``for`` and ``provides`` from the Python declarations:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       permission="zope.Public"
+  ...       />''')
+
+  >>> adapter = ProxyFactory(IApp(Content()))
+  >>> [item[0] for item in getTestProxyItems(adapter)]
+  ['a', 'f']
+  >>> removeSecurityProxy(adapter).__class__ is Comp
+  True
+
+It also works with multi adapters:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       provides="zope.app.component.tests.adapter.I3"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1
+  ...            zope.app.component.tests.adapter.I2"
+  ...       permission="zope.Public"
+  ...       />''')
+
+  >>> content = Content()
+  >>> a1 = A1()
+  >>> a2 = A2()
+  >>> a3 = ProxyFactory(zope.component.queryMultiAdapter((content, a1, a2), I3))
+  >>> a3.__class__ == A3
+  True
+  >>> [item[0] for item in getTestProxyItems(a3)]
+  ['f1', 'f2', 'f3']
+
+It's probably not worth mentioning, but when we try to protect an
+adapter with a permission that doesn't exist, we'll obviously get an
+error:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       permission="zope.UndefinedPermission"
+  ...       />''')
+  Traceback (most recent call last):
+    ...
+  ConfigurationExecutionError: exceptions.ValueError: ('Undefined permission id', 'zope.UndefinedPermission')
+    in:
+    File "<string>", line 4.2-9.8
+    Could not read source.
+
+Trusted adapters
+~~~~~~~~~~~~~~~~
+
+Trusted adapters are adapters that are trusted to do anything with the
+objects they are given so that these objects are not security-proxied.
+They are registered using the ``trusted`` argument to the <adapter />
+directive:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       provides="zope.app.component.tests.adapter.I1"
+  ...       factory="zope.app.component.tests.adapter.A1"
+  ...       trusted="yes"
+  ...       />''')
+
+With an unproxied object, it's business as usual:
+
+  >>> ob = Content()
+  >>> type(I1(ob)) is A1
+  True
+
+With a security-proxied object, however, we get a security-proxied
+adapter:
+
+  >>> p = ProxyFactory(ob)
+  >>> a = I1(p)
+  >>> type(a)
+  <type 'zope.security._proxy._Proxy'>
+
+While the adapter is security-proxied, the object it adapts is now
+proxy-free.  The adapter has umlimited access to it:
+
+  >>> a = removeSecurityProxy(a)
+  >>> type(a) is A1
+  True
+  >>> a.context[0] is ob
+  True
+
+We can also protect the trusted adapter with a permission:
+
+  >>> clearZCML()
+  >>> XMLConfig('meta.zcml', zope.app.security)()
+  >>> runSnippet('''
+  ...   <permission
+  ...       id="y.x"
+  ...       title="XY"
+  ...       description="Allow XY."
+  ...       />
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       provides="zope.app.component.tests.adapter.I1"
+  ...       factory="zope.app.component.tests.adapter.A1"
+  ...       permission="y.x"
+  ...       trusted="yes"
+  ...       />''')
+
+Again, with an unproxied object, it's business as usual:
+
+  >>> ob = Content()
+  >>> type(I1(ob)) is A1
+  True
+
+With a security-proxied object, we again get a security-proxied
+adapter:
+
+  >>> p = ProxyFactory(ob)
+  >>> a = I1(p)
+  >>> type(a)
+  <type 'zope.security._proxy._Proxy'>
+
+Since we protected the adapter with a permission, we now encounter a
+location proxy behind the security proxy:
+
+  >>> a = removeSecurityProxy(a)
+  >>> type(a)
+  <class 'zope.location.location.LocationProxy'>
+  >>> a.context[0] is ob
+  True
+
+There's one exception to all of this: When you use the public
+permission (``zope.Public``), there will be no location proxy:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       provides="zope.app.component.tests.adapter.I1"
+  ...       factory="zope.app.component.tests.adapter.A1"
+  ...       permission="zope.Public"
+  ...       trusted="yes"
+  ...       />''')
+
+  >>> ob = Content()
+  >>> p = ProxyFactory(ob)
+  >>> a = I1(p)
+  >>> type(a)
+  <type 'zope.security._proxy._Proxy'>
+
+  >>> a = removeSecurityProxy(a)
+  >>> type(a) is A1
+  True
+
+We can also explicitply pass the ``locate`` argument to make sure we
+get location proxies:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <adapter
+  ...       for="zope.app.component.tests.components.IContent"
+  ...       provides="zope.app.component.tests.adapter.I1"
+  ...       factory="zope.app.component.tests.adapter.A1"
+  ...       trusted="yes"
+  ...       locate="yes"
+  ...       />''')
+
+  >>> ob = Content()
+  >>> p = ProxyFactory(ob)
+  >>> a = I1(p)
+  >>> type(a)
+  <type 'zope.security._proxy._Proxy'>
+
+  >>> a = removeSecurityProxy(a)
+  >>> type(a)
+  <class 'zope.location.location.LocationProxy'>
+
+
+subscriber
+----------
+
+With the <subscriber /> directive you can register subscription
+adapters or event subscribers with the adapter registry.  Consider
+this very typical example of a <subscriber /> directive:
+ 
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       />''')
+
+  >>> content = Content()
+  >>> a1 = A1()
+
+  >>> subscribers = zope.component.subscribers((content, a1), IS)
+  >>> a3 = subscribers[0]
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == (content, a1)
+  True
+
+Note how ZCML provides some additional information when registering
+components, such as the ZCML filename and line numbers:
+
+  >>> gsm = zope.component.getGlobalSiteManager()
+  >>> doc = [reg.info for reg in gsm.registeredSubscriptionAdapters()
+  ...        if reg.provided is IS][0]
+  >>> print doc
+  File "<string>", line 4.2-9.8
+    Could not read source.
+
+The "fun" behind subscription adapters/subscribers is that when
+several ones are declared for the same for/provides, they are all
+found.  With regular adapters, the most specific one (and in doubt the
+one registered last) wins.  Consider these two subscribers:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       />
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A2"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       />''')
+
+  >>> subscribers = zope.component.subscribers((content, a1), IS)
+  >>> len(subscribers)
+  2
+  >>> sorted([a.__class__.__name__ for a in subscribers])
+  ['A2', 'A3']
+
+Declaring ``for`` and ``provides`` in Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Like the <adapter /> directive, the <subscriber /> directive can
+figure out from the in-line Python declaration (using
+``zope.component.adapts()`` or ``zope.component.adapter()``) what the
+subscriber should be registered for:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       />''')
+
+  >>> content = Content()
+  >>> a2 = A2()
+  >>> subscribers = zope.component.subscribers((content, a1, a2), IS)
+
+  >>> a3 = subscribers[0]
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == (content, a1, a2)
+  True
+
+In the same way the directive can figure out what a subscriber
+provides:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber handler="zope.app.component.tests.adapter.A3" />''')
+
+  >>> sm = zope.component.getSiteManager()
+  >>> a3 = sm.adapters.subscriptions((IContent, I1, I2), None)[0]
+  >>> a3 is A3
+  True
+
+A not so common edge case is declaring subscribers directly for
+classes, not for interfaces.  For example:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       for="zope.app.component.tests.components.Content"
+  ...       provides="zope.app.component.tests.adapter.I1"
+  ...       factory="zope.app.component.tests.adapter.A1"
+  ...       />''')
+
+  >>> subs = list(zope.component.subscribers((Content(),), I1))
+  >>> isinstance(subs[0], A1)
+  True
+
+This time, any object providing ``IContent`` won't work if it's not an
+instance of the ``Content`` class:
+
+  >>> list(zope.component.subscribers((MyContent(),), I1))
+  []
+
+Protected subscribers
+~~~~~~~~~~~~~~~~~~~~~
+
+Subscribers can also be protected with a permission.  First we have to
+define a permission for which we'll have to register the <permission />
+directive:
+
+  >>> clearZCML()
+  >>> XMLConfig('meta.zcml', zope.app.security)()
+  >>> runSnippet('''
+  ...   <permission
+  ...       id="y.x"
+  ...       title="XY"
+  ...       description="Allow XY."
+  ...       />
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       permission="y.x"
+  ...       />''')
+
+  >>> subscribers = zope.component.subscribers((content, a1), IS)
+  >>> a3 = subscribers[0]
+  >>> a3.__class__ is A3
+  True
+  >>> type(a3)
+  <class 'zope.location.location.LocationProxy'>
+  >>> a3.context == (content, a1)
+  True
+
+Trusted subscribers
+~~~~~~~~~~~~~~~~~~~
+
+Like trusted adapters, trusted subscribers are subscribers that are
+trusted to do anything with the objects they are given so that these
+objects are not security-proxied.  In analogy to the <adapter />
+directive, they are registered using the ``trusted`` argument to the
+<subscriber /> directive:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       trusted="yes"
+  ...       />''')
+
+With an unproxied object, it's business as usual:
+
+  >>> subscribers = zope.component.subscribers((content, a1), IS)
+  >>> a3 = subscribers[0]
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == (content, a1)
+  True
+  >>> type(a3) is A3
+  True
+
+Now with a proxied object.  We will see that the subscriber has
+unproxied access to it, but the subscriber itself is proxied:
+
+  >>> p = ProxyFactory(content)
+  >>> a3 = zope.component.subscribers((p, a1), IS)[0]
+  >>> type(a3)
+  <type 'zope.security._proxy._Proxy'>
+
+There's no location proxy behind the security proxy:
+
+  >>> removeSecurityProxy(a3).context[0] is content
+  True
+  >>> type(removeSecurityProxy(a3)) is A3
+  True
+
+If you want the trusted subscriber to be located, you'll also have to
+use the ``locate`` argument:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       provides="zope.app.component.tests.adapter.IS"
+  ...       factory="zope.app.component.tests.adapter.A3"
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       trusted="yes"
+  ...       locate="yes"
+  ...       />''')
+
+Again, it's business as usual with an unproxied object:
+
+  >>> subscribers = zope.component.subscribers((content, a1), IS)
+  >>> a3 = subscribers[0]
+  >>> a3.__class__ is A3
+  True
+  >>> a3.context == (content, a1)
+  True
+  >>> type(a3) is A3
+  True
+
+With a proxied object, we again get a security-proxied subscriber:
+
+  >>> p = ProxyFactory(content)
+  >>> a3 = zope.component.subscribers((p, a1), IS)[0]
+
+  >>> type(a3)
+  <type 'zope.security._proxy._Proxy'>
+
+  >>> removeSecurityProxy(a3).context[0] is content
+  True
+
+However, thanks to the ``locate`` argument, we now have a location
+proxy behind the security proxy:
+
+  >>> type(removeSecurityProxy(a3))
+  <class 'zope.location.location.LocationProxy'>
+
+Event subscriber (handlers)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes, subscribers don't need to be adapters that actually provide
+anything.  It's enough that a callable is called for a certain event.
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <subscriber
+  ...       for="zope.app.component.tests.components.IContent
+  ...            zope.app.component.tests.adapter.I1"
+  ...       handler="zope.app.component.tests.adapter.Handler"
+  ...       />''')
+
+In this case, simply getting the subscribers is enough to invoke them:
+
+  >>> list(zope.component.subscribers((content, a1), None))
+  []
+  >>> content.args == ((a1,),)
+  True
+
+
+utility
+-------
+
+Apart from adapters (and subscription adapters), the Component
+Architecture knows a second kind of component: utilities.  They are
+registered using the <utility /> directive.
+
+Before we register the first test utility, we can verify that utility
+lookup doesn't work yet:
+
+  >>> clearZCML()
+  >>> zope.component.queryUtility(IApp) is None
+  True
+
+Then we register the utility:
+
+  >>> runSnippet('''
+  ...   <utility
+  ...       component="zope.app.component.tests.components.comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       />''')
+  >>> zope.component.getUtility(IApp) is comp
+  True
+
+Like adapters, utilities can also have names.  There can be more than
+one utility registered for a certain interface, as long as they each
+have a different name.
+
+First, we make sure that there's no utility yet:
+
+  >>> clearZCML()
+  >>> zope.component.queryUtility(IApp, 'test') is None
+  True
+
+Then we register it:
+
+  >>> runSnippet('''
+  ...   <utility
+  ...       component="zope.app.component.tests.components.comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       name="test"
+  ...       />''')
+  >>> zope.component.getUtility(IApp, 'test') is comp
+  True
+
+Utilities can also be registered from a factory.  In this case, the
+ZCML handler calls the factory (without any arguments) and registers
+the returned value as a utility.  Typically, you'd pass a class for
+the factory:
+
+  >>> clearZCML()
+  >>> zope.component.queryUtility(IApp) is None
+  True
+
+  >>> runSnippet('''
+  ...   <utility
+  ...       factory="zope.app.component.tests.components.Comp"
+  ...       provides="zope.app.component.tests.components.IApp"
+  ...       />''')
+  >>> zope.component.getUtility(IApp).__class__ is Comp
+  True
+
+Declaring ``provides`` in Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Like other directives, <utility /> can also figure out which interface
+a utility provides from the Python declaration:
+
+  >>> clearZCML()
+  >>> zope.component.queryUtility(IApp) is None
+  True
+
+  >>> runSnippet('''
+  ...   <utility component="zope.app.component.tests.components.comp" />''')
+  >>> zope.component.getUtility(IApp) is comp
+  True
+
+It won't work if the component that is to be registered doesn't
+provide anything:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <utility component="zope.app.component.tests.adapter.a4" />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
+      TypeError: Missing 'provides' attribute
+
+Or if more than one interface is provided (then the ZCML directive
+handler doesn't know under which the utility should be registered):
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <utility component="zope.app.component.tests.adapter.a5" />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
+      TypeError: Missing 'provides' attribute
+
+We can repeat the same drill for utility factories:
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <utility component="zope.app.component.tests.adapter.A4" />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
+      TypeError: Missing 'provides' attribute
+
+  >>> clearZCML()
+  >>> runSnippet('''
+  ...   <utility component="zope.app.component.tests.adapter.A5" />''')
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
+      TypeError: Missing 'provides' attribute
+
+Protected utilities
+~~~~~~~~~~~~~~~~~~~
+
+    def testProtectedUtility(self):
+        """Test that we can protect a utility.
+
+        Also:
+        Check that multiple configurations for the same utility and
+        don't interfere.
+        """
+        self.assertEqual(zope.component.queryUtility(IV), None)
+        xmlconfig(StringIO(template % (
+            '''
+            <permission id="tell.everyone" title="Yay" />
+            <utility
+              component="zope.app.component.tests.components.comp"
+              provides="zope.app.component.tests.components.IApp"
+              permission="tell.everyone"
+              />
+            <permission id="top.secret" title="shhhh" />
+            <utility
+              component="zope.app.component.tests.components.comp"
+              provides="zope.app.component.tests.components.IAppb"
+              permission="top.secret"
+              />
+            '''
+            )))
+
+        utility = ProxyFactory(zope.component.getUtility(IApp))
+        items = getTestProxyItems(utility)
+        self.assertEqual(items, [('a', 'tell.everyone'),
+                                 ('f', 'tell.everyone')
+                                 ])
+        self.assertEqual(removeSecurityProxy(utility), comp)
+
+    def testUtilityUndefinedPermission(self):
+        config = StringIO(template % (
+             '''
+             <utility
+              component="zope.app.component.tests.components.comp"
+              provides="zope.app.component.tests.components.IApp"
+              permission="zope.UndefinedPermission"
+              />
+            '''
+            ))
+        self.assertRaises(ValueError, xmlconfig, config,
+                          testing=1)
+
+interface
+---------
+
+The <interface /> directive lets us register an interface.  Interfaces
+are registered as named utilities.  We therefore needn't go though all
+the lookup details again, it is sufficient to see whether the
+directive handler emits the right actions.
+
+First we provide a stub configuration context:
+
+  >>> import re, pprint
+  >>> atre = re.compile(' at [0-9a-fA-Fx]+')
+  >>> class Context(object):
+  ...    actions = ()
+  ...    def action(self, discriminator, callable, args):
+  ...        self.actions += ((discriminator, callable, args), )
+  ...    def __repr__(self):
+  ...        stream = StringIO()
+  ...        pprinter = pprint.PrettyPrinter(stream=stream, width=60)
+  ...        pprinter.pprint(self.actions)
+  ...        r = stream.getvalue()
+  ...        return (''.join(atre.split(r))).strip()
+  >>> context = Context()
+
+Then we provide a test interface that we'd like to register:
+
+  >>> from zope.interface import Interface
+  >>> class I(Interface):
+  ...     pass
+
+It doesn't yet provide ``ITestType``:
+
+  >>> from zope.component.tests import ITestType
+  >>> ITestType.providedBy(I)
+  False
+
+However, after calling the directive handler...
+
+  >>> from zope.component.zcml import interface
+  >>> interface(context, I, ITestType)
+  >>> context
+  ((None,
+    <function provideInterface>,
+    ('',
+     <InterfaceClass __builtin__.I>,
+     <InterfaceClass zope.component.tests.ITestType>)),)
+
+...it does provide ``ITestType``:
+
+  >>> from zope.interface.interfaces import IInterface
+  >>> ITestType.extends(IInterface)
+  True
+  >>> IInterface.providedBy(I)
+  True



More information about the Zope3-Checkins mailing list