[Checkins] SVN: Products.GenericSetup/trunk/Products/GenericSetup/ Added new feature to the component handler. For factory based utilities you can now specify an addit

Hanno Schlichting hannosch at hannosch.eu
Sun May 17 14:05:34 EDT 2009


Log message for revision 100050:
  Added new feature to the component handler. For factory based utilities you can now specify an addit
  ional id. All factory based utilities will now by default be added to the site manager (being an Obj
  ectManager itself) as an object and this persistent object is registered as the utility. On removal 
  both the registration and the object are removed. The new id argument is used to specify the id of t
  he object as set via `__name__`. This change makes these utilities introspectable in the ZMI and cle
  arly separates the persistent object and utility registration aspect.
  

Changed:
  U   Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt
  U   Products.GenericSetup/trunk/Products/GenericSetup/components.py
  U   Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py

-=-
Modified: Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt	2009-05-17 17:53:56 UTC (rev 100049)
+++ Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt	2009-05-17 18:05:33 UTC (rev 100050)
@@ -4,6 +4,15 @@
 GenericSetup 1.5.0 (unreleased)
 -------------------------------
 
+- Added new feature to the component handler. For factory based utilities you
+  can now specify an additional id. All factory based utilities will now by
+  default be added to the site manager (being an ObjectManager itself) as an
+  object and this persistent object is registered as the utility. On removal
+  both the registration and the object are removed. The new id argument is
+  used to specify the id of the object as set via `__name__`. This change
+  makes these utilities introspectable in the ZMI and clearly separates the
+  persistent object and utility registration aspect.
+
 - Adjusted TarballImportContext to work with Python 2.6's tarfile module.
 
 - Cleaned up / normalized imports:

Modified: Products.GenericSetup/trunk/Products/GenericSetup/components.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/components.py	2009-05-17 17:53:56 UTC (rev 100049)
+++ Products.GenericSetup/trunk/Products/GenericSetup/components.py	2009-05-17 18:05:33 UTC (rev 100050)
@@ -175,6 +175,9 @@
 
             if ( child.hasAttribute('remove') and 
                  self.context.queryUtility(provided, name) is not None ):
+                ofs_id = self._ofs_id(child)
+                if ofs_id in self.context.objectIds():
+                    self.context._delObject(ofs_id, suppress_events=True)
                 self.context.unregisterUtility(provided=provided, name=name)
                 continue
 
@@ -207,22 +210,37 @@
                 self.context.registerUtility(component, provided, name)
             elif factory:
                 current = [ utility for utility in current_utilities
-                                    if utility.provided==provided and 
+                                    if utility.provided==provided and
                                        utility.name==name ]
-                assert len(current) <=1
 
                 if current and getattr(current[0], "factory", None)==factory:
                     continue
 
-                try:
-                    self.context.registerUtility(None, provided, name, factory=factory)
-                except TypeError:
-                    # zope.component < 3.5.0
-                    self.context.registerUtility(factory(), provided, name)
+                obj = factory()
+                ofs_id = self._ofs_id(child)
+                if ofs_id not in self.context.objectIds():
+                    self.context._setObject(ofs_id, aq_base(obj),
+                        set_owner=False, suppress_events=True)
+                obj = self.context.get(ofs_id)
+                obj.__name__ = ofs_id
+                obj.__parent__ = aq_base(self.context)
+                self.context.registerUtility(aq_base(obj), provided, name)
             else:
                 self._logger.warning("Invalid utility registration for "
                                      "interface %s" % provided)
 
+    def _ofs_id(self, child):
+        # We build a valid OFS id by using the interface's full
+        # dotted path or using the specified id
+        name = str(child.getAttribute('name'))
+        ofs_id = str(child.getAttribute('id'))
+        if not ofs_id:
+            ofs_id = str(child.getAttribute('interface'))
+            # In case of named utilities we append the name
+            if name:
+                ofs_id += '-' + str(name)
+        return ofs_id
+
     def _extractAdapters(self):
         fragment = self._doc.createDocumentFragment()
 
@@ -279,8 +297,10 @@
                 child.setAttribute('name', reg_info['name'])
 
             if reg_info['factory'] is not None:
-                child.setAttribute('factory', _getDottedName(reg_info['factory']))
+                factory = _getDottedName(reg_info['factory'])
+                child.setAttribute('factory', factory)
             else:
+                factory = None
                 comp = reg_info['component']
                 # check if the component is acquisition wrapped. If it is, export
                 # an object reference instead of a factory reference
@@ -296,6 +316,11 @@
                 else:
                     factory = _getDottedName(type(comp))
                     child.setAttribute('factory', factory)
+                if factory is not None:
+                    ofs_id = self._ofs_id(child)
+                    name = getattr(comp, '__name__', '')
+                    if ofs_id != name:
+                        child.setAttribute('id', name)
 
             fragment.appendChild(child)
 

Modified: Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py	2009-05-17 17:53:56 UTC (rev 100049)
+++ Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py	2009-05-17 18:05:33 UTC (rev 100050)
@@ -54,7 +54,7 @@
 def createComponentRegistry(context):
     enableSite(context, iface=IObjectManagerSite)
 
-    components = PersistentComponents()
+    components = PersistentComponents('++etc++site')
     components.__bases__ = (base,)
     components.__parent__ = aq_base(context)
     context.setSiteManager(components)
@@ -125,6 +125,7 @@
  <adapters/>
  <utilities>
   <utility factory="Products.GenericSetup.tests.test_components.DummyUtility"
+     id="dummy_utility"
      interface="Products.GenericSetup.tests.test_components.IDummyInterface"/>
   <utility name="dummy tool name"
      interface="Products.GenericSetup.tests.test_components.IDummyInterface"
@@ -143,7 +144,8 @@
 <?xml version="1.0"?>
 <componentregistry>
  <utilities>
-  <utility factory="Products.GenericSetup.tests.test_components.DummyUtility"
+  <utility id="dummy_utility"
+     factory="Products.GenericSetup.tests.test_components.DummyUtility"
      interface="Products.GenericSetup.tests.test_components.IDummyInterface"
      remove="True"/>
   <utility name="dummy tool name"
@@ -168,9 +170,22 @@
         return ComponentRegistryXMLAdapter
 
     def _populate(self, obj):
-        obj.registerUtility(DummyUtility(), IDummyInterface)
-        obj.registerUtility(DummyUtility(), IDummyInterface2, name=u'foo')
+        util = DummyUtility()
+        name = 'dummy_utility'
+        util.__name__ = name
+        util.__parent__ = aq_base(obj)
+        obj._setObject(name, aq_base(util),
+            set_owner=False, suppress_events=True)
+        obj.registerUtility(aq_base(obj[name]), IDummyInterface)
 
+        util = DummyUtility()
+        name = 'Products.GenericSetup.tests.test_components.IDummyInterface2-foo'
+        util.__name__ = name
+        util.__parent__ = aq_base(obj)
+        obj._setObject(name, aq_base(util),
+            set_owner=False, suppress_events=True)
+        obj.registerUtility(aq_base(obj[name]), IDummyInterface2, name=u'foo')
+
         tool = aq_base(obj.aq_parent['dummy_tool'])
         obj.registerUtility(tool, IDummyInterface, name=u'dummy tool name')
 
@@ -181,10 +196,18 @@
         util = queryUtility(IDummyInterface2, name=u'foo')
         self.failUnless(IDummyInterface.providedBy(util))
         self.failUnless(util.verify())
+        self.failUnless(util.__parent__ == obj)
+        name = 'Products.GenericSetup.tests.test_components.IDummyInterface2-foo'
+        self.assertEquals(util.__name__, name)
+        self.failUnless(name in obj.objectIds())
 
         util = queryUtility(IDummyInterface)
         self.failUnless(IDummyInterface.providedBy(util))
         self.failUnless(util.verify())
+        self.failUnless(util.__parent__ == obj)
+        name = 'dummy_utility'
+        self.assertEquals(util.__name__, name)
+        self.failUnless(name in obj.objectIds())
 
         util = queryUtility(IDummyInterface, name='dummy tool name')
         self.failUnless(IDummyInterface.providedBy(util))
@@ -274,10 +297,13 @@
         importComponentRegistry(context)
 
         util = queryUtility(IDummyInterface2, name=u'foo')
+        name = 'Products.GenericSetup.tests.test_components.IDummyInterface2-foo'
         self.failUnless(util is None)
+        self.failIf(name in obj.objectIds())
 
         util = queryUtility(IDummyInterface)
         self.failUnless(util is None)
+        self.failIf('dummy_utility' in obj.objectIds())
 
         util = queryUtility(IDummyInterface, name='dummy tool name')
         self.failUnless(util is None)



More information about the Checkins mailing list