[Zope-CMF] Re: Tools as local utilities

Hanno Schlichting plone at hannosch.info
Mon Dec 11 18:14:51 EST 2006


Hi Jens, all!

I haven't seen any progress on the tools as local utilities story for
some time now. Is there anything specific I can help with?

Jens Vagelpohl wrote:
> On 22 Nov 2006, at 12:15, Hanno Schlichting wrote:
>> At the time I wrote this it was kind of experimental and I didn't know
>> if I could make it work. So I put it in an add-on with the clear
>> intention to merge it back into GenericSetup once it was reasonably
>> stable and working. Thx for taking over that part :)
> 
> Thanks for the code ;)

I have taken another look at the code and fixed some obvious bugs. As I
still have no commit rights for the svn repo (yes, entirely my fault)
could somebody commit the attached patch (against GS trunk) for me?

With this patch applied I think at least the utility handlers are fully
functional. As I haven't written tests for the adapter handlers so far,
I'm not sure for those yet ;)

Thx in advance,
Hanno
-------------- next part --------------
Index: tests/test_components.py
===================================================================
--- tests/test_components.py	(revision 71534)
+++ tests/test_components.py	(working copy)
@@ -24,10 +24,14 @@
 
 from Products.Five.component import enableSite
 from Products.Five.component.interfaces import IObjectManagerSite
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.testing import BodyAdapterTestCase
 from Products.GenericSetup.testing import ExportImportZCMLLayer
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
 
 from zope.app.component.hooks import setSite, clearSite, setHooks
+from zope.component import getMultiAdapter
 from zope.component import getSiteManager
 from zope.component import queryUtility
 from zope.component.globalregistry import base
@@ -50,12 +54,6 @@
     def verify():
         """Returns True."""
 
-class IDummyInterface2(Interface):
-    """A second dummy interface."""
-
-    def verify():
-        """Returns True."""
-
 class DummyUtility(object):
     """A dummy utility."""
 
@@ -64,28 +62,31 @@
     def verify(self):
         return True
 
-class DummyUtility2(object):
-    """A second dummy utility."""
+class DummyTool(SimpleItem):
+    """A dummy tool."""
+    implements(IDummyInterface)
 
-    implements(IDummyInterface2)
+    id = 'dummy_tool'
+    meta_type = 'dummy tool'
+    security = ClassSecurityInfo()
 
+    security.declarePublic('verify')
     def verify(self):
         return True
 
-dummy2 = DummyUtility2()
-
-class DummyTool(SimpleItem):
-    """A dummy tool."""
+class DummyTool2(SimpleItem):
+    """A second dummy tool."""
     implements(IDummyInterface)
 
-    id = 'dummy_tool'
-    meta_type = 'dummy tool'
+    id = 'dummy_tool2'
+    meta_type = 'dummy tool2'
     security = ClassSecurityInfo()
 
     security.declarePublic('verify')
     def verify(self):
         return True
 
+
 InitializeClass(DummyTool)
 
 _COMPONENTS_BODY = """\
@@ -100,12 +101,10 @@
      object="/dummy_tool"/>
   <utility name="dummy tool name2"
      interface="Products.GenericSetup.tests.test_components.IDummyInterface"
-     object="/test_folder_1_/dummy_tool"/>
+     object="/test_folder_1_/dummy_tool2"/>
   <utility name="foo"
      factory="Products.GenericSetup.tests.test_components.DummyUtility"
      interface="Products.GenericSetup.tests.test_components.IDummyInterface"/>
-  <utility component="Products.GenericSetup.tests.test_components.dummy2"
-     interface="Products.GenericSetup.tests.test_components.IDummyInterface2"/>
  </utilities>
 </componentregistry>
 """
@@ -115,6 +114,32 @@
 
     layer = ExportImportZCMLLayer
 
+    def test_body_get(self):
+        self._populate(self._obj)
+        context = DummyExportContext(self.app)
+        adapted = getMultiAdapter((self._obj, context), IBody)
+        self.assertEqual(adapted.body, self._BODY)
+
+    def test_body_set(self):
+        context = DummyImportContext(self.app)
+        adapted = getMultiAdapter((self._obj, context), IBody)
+        adapted.body = self._BODY
+        self._verifyImport(self._obj)
+        self.assertEqual(adapted.body, self._BODY)
+
+        # now in update mode
+        context._should_purge = False
+        adapted = getMultiAdapter((self._obj, context), IBody)
+        adapted.body = self._BODY
+        self._verifyImport(self._obj)
+        self.assertEqual(adapted.body, self._BODY)
+
+        # and again in update mode
+        adapted = getMultiAdapter((self._obj, context), IBody)
+        adapted.body = self._BODY
+        self._verifyImport(self._obj)
+        self.assertEqual(adapted.body, self._BODY)
+
     def _getTargetClass(self):
         from Products.GenericSetup.components import \
             ComponentRegistryXMLAdapter
@@ -139,19 +164,15 @@
         self.assertEqual(tool.meta_type, 'dummy tool')
         self.assertEquals(repr(util), repr(tool))
 
-        util = queryUtility(IDummyInterface2)
-        self.failUnless(IDummyInterface2.providedBy(util))
-        self.failUnless(util.verify())
-
         util = queryUtility(IDummyInterface, name='dummy tool name2')
         self.failUnless(IDummyInterface.providedBy(util))
         self.failUnless(util.verify())
-        self.assertEqual(util.meta_type, 'dummy tool')
+        self.assertEqual(util.meta_type, 'dummy tool2')
 
         # make sure we can get the tool by normal means
-        tool = getattr(self.app.test_folder_1_, 'dummy_tool2')
-        self.assertEqual(tool.meta_type, 'dummy tool')
-        self.assertEquals(repr(util), repr(tool))
+        tool = getattr(self.folder, 'dummy_tool2')
+        self.assertEqual(tool.meta_type, 'dummy tool2')
+        self.assertEquals(repr(util.aq_base), repr(tool.aq_base))
 
     def afterSetUp(self):
         BodyAdapterTestCase.setUp(self)
@@ -164,17 +185,15 @@
 
         sm.registerUtility(DummyUtility(), IDummyInterface)
         sm.registerUtility(DummyUtility(), IDummyInterface, name=u'foo')
-        sm.registerUtility(dummy2, IDummyInterface2)
 
         tool = DummyTool()
         self.app._setObject(tool.id, tool)
         obj = self.app[tool.id]
         sm.registerUtility(obj, IDummyInterface, name=u'dummy tool name')
 
-        folder = self.app.test_folder_1_
-        tool2 = DummyTool()
-        folder._setObject('dummy_tool2', tool2)
-        obj = folder['dummy_tool2']
+        tool2 = DummyTool2()
+        self.folder._setObject(tool2.id, tool2)
+        obj = self.folder[tool2.id]
         sm.registerUtility(obj, IDummyInterface, name=u'dummy tool name2')
 
         self._obj = sm
Index: components.py
===================================================================
--- components.py	(revision 71534)
+++ components.py	(working copy)
@@ -15,7 +15,6 @@
 $Id$
 """
 
-from zope.app.component.hooks import getSite
 from zope.component import adapts
 from zope.component import getSiteManager
 from zope.component.interfaces import IComponentRegistry
@@ -71,7 +70,7 @@
                 self._logger.info('Utilities registered.')
 
     def _purgeAdapters(self):
-        registrations = self.context.registeredAdapters()
+        registrations = tuple(self.context.registeredAdapters())
         
         for registration in registrations:
             factory = registration.factory
@@ -85,7 +84,7 @@
                                            name=name)
 
     def _purgeUtilities(self):
-        registrations = self.context.registeredAdapters()
+        registrations = tuple(self.context.registeredUtilities())
         
         for registration in registrations:
             provided = registration.provided
@@ -128,22 +127,20 @@
 
             obj_path = child.getAttribute('object')
             if obj_path:
-                site = getSite()
+                site = self.environ.getSite()
                 # we support registering aq_wrapped objects only for now
                 if hasattr(site, 'aq_base'):
                     # filter out empty path segments
                     path = [f for f in obj_path.split('/') if f]
-                    # XXX add support for nested folder
-                    if len(path) > 1:
-                        return
-                    obj = getattr(site, path[0], None)
+                    # support for nested folder
+                    obj = self._recurseFolder(site, path)
                     if obj is not None:
                         self.context.registerUtility(obj, provided, name)
                 else:
                     # Log an error, not aq_wrapped
                     self._logger.warning("The object %s was not acquisition "
                                          "wrapped. Registering these is not "
-                                         "supported right now." % obj)
+                                         "supported right now." % obj_path)
             elif component:
                 self.context.registerUtility(component, provided, name)
             else:
@@ -156,9 +153,9 @@
         # which is needed for the tests we convert to a sorted list
         registrations = [reg for reg in self.context.registeredAdapters()]
         registrations.sort()
-        
+
         for registration in registrations:
-            child=self._doc.createElement('adapter')
+            child = self._doc.createElement('adapter')
 
             factory = _getDottedName(registration.factory)
             provided = _getDottedName(registration.provided)
@@ -187,7 +184,7 @@
         registrations.sort()
 
         for registration in registrations:
-            child=self._doc.createElement('utility')
+            child = self._doc.createElement('utility')
 
             provided = _getDottedName(registration.provided)
             child.setAttribute('interface', provided)
@@ -198,45 +195,34 @@
 
             comp = registration.component
             # check if the component is acquisition wrapped. If it is export
-            # an object reference instead of a component / factory reference
+            # an object reference instead of a factory reference
             if hasattr(comp, 'aq_base'):
                 # if the site is acquistion wrapped as well, get the relative
                 # path to the site
                 path = '/'.join(comp.getPhysicalPath())
-                site = getSite()
+                site = self.environ.getSite()
                 if hasattr(site, 'aq_base'):
                     site_path = '/'.join(site.getPhysicalPath())
                     rel_path = path[len(site_path):]
                 child.setAttribute('object', rel_path)
             else:
                 factory = _getDottedName(type(comp))
-                reference = self.resolveName(comp)
-                if reference:
-                    module = _getDottedName(comp.__module__)
-                    component = "%s.%s" % (module, reference)
-                    child.setAttribute('component', component)
-                else:
-                    child.setAttribute('factory', factory)
+                child.setAttribute('factory', factory)
 
             fragment.appendChild(child)
 
         return fragment
 
-    def resolveName(self, component):
-        # extremly ugly hack to get to the reference name, this only
-        # works if the utility reference is defined in the namespace of the
-        # same module as the class itself
-        module = _resolveDottedName(component.__module__)
-        namespace = module.__dict__
-        name = ''
-        for ref in namespace:
-            if namespace[ref] is component:
-                name = ref
-        del module
-        del namespace
-        return name
+    def _recurseFolder(self, site, path):
+        root = site
+        for pathsegment in path:
+            if root is None:
+                break
+            root = getattr(root, pathsegment, None)
 
+        return root
 
+
 def dummyGetId():
     return ''
 


More information about the Zope-CMF mailing list