[Checkins] SVN: Products.GenericSetup/trunk/Products/GenericSetup/ Added support for import / export of subscribers from component registry.

Laurence Rowe l at lrowe.co.uk
Fri Sep 18 15:43:24 EDT 2009


Log message for revision 104358:
  Added support for import / export of subscribers from component registry.

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-09-18 19:22:18 UTC (rev 104357)
+++ Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt	2009-09-18 19:43:23 UTC (rev 104358)
@@ -4,6 +4,8 @@
 GenericSetup 1.5.0 (unreleased)
 -------------------------------
 
+- Added support for import / export of subscribers from component registry.
+
 - Adapter removal.
 
 - Fix utility removal so utility is not added when it is missing from the

Modified: Products.GenericSetup/trunk/Products/GenericSetup/components.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/components.py	2009-09-18 19:22:18 UTC (rev 104357)
+++ Products.GenericSetup/trunk/Products/GenericSetup/components.py	2009-09-18 19:43:23 UTC (rev 104358)
@@ -64,6 +64,12 @@
         self._logger.info('Adapters exported.')
         fragment.appendChild(child)
 
+        child = self._doc.createElement('subscribers')
+        child.appendChild(self._extractSubscriptionAdapters())
+        child.appendChild(self._extractHandlers())
+        self._logger.info('Subscribers exported.')
+        fragment.appendChild(child)
+
         child = self._doc.createElement('utilities')
         child.appendChild(self._extractUtilities())
         self._logger.info('Utilities exported.')
@@ -77,6 +83,9 @@
         if self.environ.shouldPurge():
             self._purgeAdapters()
             self._logger.info('Adapters purged.')
+            self._purgeSubscriptionAdapters()
+            self._purgeHandlers()
+            self._logger.info('Subscribers purged.')
             self._purgeUtilities()
             self._logger.info('Utilities purged.')
 
@@ -84,6 +93,10 @@
             if child.nodeName == 'adapters':
                 self._initAdapters(child)
                 self._logger.info('Adapters registered.')
+            if child.nodeName == 'subscribers':
+                self._initSubscriptionAdapters(child)
+                self._initHandlers(child)
+                self._logger.info('Subscribers registered.')
             if child.nodeName == 'utilities':
                 self._initUtilities(child)
                 self._logger.info('Utilities registered.')
@@ -105,6 +118,30 @@
                                            provided=provided,
                                            name=name)
 
+    def _purgeSubscriptionAdapters(self):
+        registrations = tuple(self.context.registeredSubscriptionAdapters())
+        blacklist = self._constructBlacklist()
+
+        for registration in registrations:
+            factory = registration.factory
+            required = registration.required
+            provided = registration.provided
+            if _getDottedName(provided) in blacklist:
+                continue
+
+            self.context.unregisterSubscriptionAdapter(factory=factory,
+                                                       required=required,
+                                                       provided=provided)
+
+    def _purgeHandlers(self):
+        registrations = tuple(self.context.registeredHandlers())
+
+        for registration in registrations:
+            factory = registration.factory
+            required = registration.required
+
+            self.context.unregisterHandler(factory=factory, required=required)
+
     def _purgeUtilities(self):
         registrations = tuple(self.context.registeredUtilities())
         blacklist = self._constructBlacklist()
@@ -147,6 +184,83 @@
                                          provided=provided,
                                          name=name)
 
+    def _initSubscriptionAdapters(self, node):
+        blacklist = self._constructBlacklist()
+
+        for child in node.childNodes:
+            if child.nodeName != 'subscriber':
+                continue
+
+            factory = child.getAttribute('factory')
+            if not factory:
+                continue
+
+            handler = child.getAttribute('handler')
+            if handler:
+                raise ValueError, "Can not specify both a factory and a " \
+                                  "handler in a subscriber registration."
+
+            factory = _resolveDottedName(factory)
+
+            provided = child.getAttribute('provides')
+            if provided in blacklist:
+                continue
+
+            provided = _resolveDottedName(provided)
+
+            for_ = child.getAttribute('for') or child.getAttribute('for_') #BBB
+            required = []
+            for interface in for_.split():
+                required.append(_resolveDottedName(interface))
+
+            # Uninstall to prevent duplicate registrations. While this is
+            # allowed in ZCML, GS profiles can be run multiple times.
+            self.context.unregisterSubscriptionAdapter(factory,
+                                                       required=required,
+                                                       provided=provided)
+
+            if child.hasAttribute('remove'):
+                continue
+
+            self.context.registerSubscriptionAdapter(factory,
+                                                     required=required,
+                                                     provided=provided)
+
+    def _initHandlers(self, node):
+        for child in node.childNodes:
+            if child.nodeName != 'subscriber':
+                continue
+
+            handler = child.getAttribute('handler')
+            if not handler:
+                continue
+
+            factory = child.getAttribute('factory')
+            if factory:
+                raise ValueError, "Can not specify both a factory and a " \
+                                  "handler in a subscriber registration."
+            
+            if child.hasAttribute('provides'):
+                raise ValueError, "Cannot use handler with provides " \
+                                  "in a subscriber registration."
+
+            handler = _resolveDottedName(handler)
+
+            for_ = child.getAttribute('for') or child.getAttribute('for_') #BBB
+            required = []
+
+            for interface in for_.split():
+                required.append(_resolveDottedName(interface))
+
+            # Uninstall to prevent duplicate registrations. While this is
+            # allowed in ZCML, GS profiles can be run multiple times.
+            self.context.unregisterHandler(handler, required=required)
+
+            if child.hasAttribute('remove'):
+                continue
+
+            self.context.registerHandler(handler, required=required)
+
     def _getSite(self):
         # Get the site by either __parent__ or Acquisition
         site = getattr(self.context, '__parent__', None)
@@ -281,6 +395,58 @@
 
         return fragment
 
+    def _extractSubscriptionAdapters(self):
+        fragment = self._doc.createDocumentFragment()
+
+        registrations = [ {'factory': _getDottedName(reg.factory),
+                           'provided': _getDottedName(reg.provided),
+                           'required': reg.required}
+                          for reg in self.context.registeredSubscriptionAdapters() ]
+        registrations.sort(key=itemgetter('factory'))
+        registrations.sort(key=itemgetter('provided'))
+        blacklist = self._constructBlacklist()
+
+        for reg_info in registrations:
+            if reg_info['provided'] in blacklist:
+                continue
+
+            child = self._doc.createElement('subscriber')
+
+            for_ = u''
+            for interface in reg_info['required']:
+                for_ = for_ + _getDottedName(interface) + u'\n           '
+
+            child.setAttribute('factory', reg_info['factory'])
+            child.setAttribute('provides', reg_info['provided'])
+            child.setAttribute('for', for_.strip())
+
+            fragment.appendChild(child)
+
+        return fragment
+
+    def _extractHandlers(self):
+        fragment = self._doc.createDocumentFragment()
+
+        registrations = [ {'factory': _getDottedName(reg.factory),
+                           'required': reg.required}
+                          for reg in self.context.registeredHandlers() ]
+        registrations.sort(key=itemgetter('factory'))
+        registrations.sort(key=itemgetter('required'))
+
+        for reg_info in registrations:
+            child = self._doc.createElement('subscriber')
+
+            for_ = u''
+            for interface in reg_info['required']:
+                for_ = for_ + _getDottedName(interface) + u'\n           '
+
+            child.setAttribute('handler', reg_info['factory'])
+            child.setAttribute('for', for_.strip())
+
+            fragment.appendChild(child)
+
+        return fragment
+
     def _extractUtilities(self):
         fragment = self._doc.createDocumentFragment()
 

Modified: Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py	2009-09-18 19:22:18 UTC (rev 104357)
+++ Products.GenericSetup/trunk/Products/GenericSetup/tests/test_components.py	2009-09-18 19:43:23 UTC (rev 104358)
@@ -41,8 +41,10 @@
 from zope.component import getMultiAdapter
 from zope.component import getGlobalSiteManager
 from zope.component import getSiteManager
+from zope.component import handle
 from zope.component import queryAdapter
 from zope.component import queryUtility
+from zope.component import subscribers
 from zope.component.globalregistry import base
 from zope.interface import implements
 from zope.interface import Interface
@@ -88,10 +90,32 @@
     def verify(self):
         return True
 
+class IAnotherDummyInterface(Interface):
+    """A third dummy interface."""
+
+    def inc():
+        """Increments handle count"""
+
+class IAnotherDummyInterface2(Interface):
+    """A second dummy interface."""
+
+    def verify():
+        """Returns True."""
+
+class DummyObject(object):
+    """A dummy object to pass to the handler."""
+
+    implements(IAnotherDummyInterface)
+
+    handled = 0
+
+    def inc(self):
+        self.handled += 1
+
 class DummyAdapter(object):
     """A dummy adapter."""
 
-    implements(IDummyInterface)
+    implements(IAnotherDummyInterface2)
 
     def __init__(self, context):
         pass
@@ -99,6 +123,11 @@
     def verify(self):
         return True
 
+def dummy_handler(context):
+    """A dummy event handler."""
+    
+    context.inc()
+
 class DummyTool(SimpleItem):
     """A dummy tool."""
     implements(IDummyInterface)
@@ -144,12 +173,21 @@
  <adapters>
   <adapter factory="Products.GenericSetup.tests.test_components.DummyAdapter"
      for="zope.interface.Interface"
-     provides="Products.GenericSetup.tests.test_components.IDummyInterface"/>
+     provides="Products.GenericSetup.tests.test_components.IAnotherDummyInterface2"/>
   <adapter name="foo"
      factory="Products.GenericSetup.tests.test_components.DummyAdapter"
      for="zope.interface.Interface"
-     provides="Products.GenericSetup.tests.test_components.IDummyInterface"/>
+     provides="Products.GenericSetup.tests.test_components.IAnotherDummyInterface2"/>
  </adapters>
+ <subscribers>
+  <subscriber
+     factory="Products.GenericSetup.tests.test_components.DummyAdapter"
+     for="Products.GenericSetup.tests.test_components.IAnotherDummyInterface"
+     provides="Products.GenericSetup.tests.test_components.IAnotherDummyInterface2"/>
+  <subscriber
+     for="Products.GenericSetup.tests.test_components.IAnotherDummyInterface"
+     handler="Products.GenericSetup.tests.test_components.dummy_handler"/>
+ </subscribers>
  <utilities>
   <utility factory="Products.GenericSetup.tests.test_components.DummyUtility"
      id="dummy_utility"
@@ -172,9 +210,20 @@
 <componentregistry>
  <adapters>
   <adapter factory="Products.GenericSetup.tests.test_components.DummyAdapter"
-     provides="Products.GenericSetup.tests.test_components.IDummyInterface"
+     provides="Products.GenericSetup.tests.test_components.IAnotherDummyInterface2"
      for="*" remove="True"/>
  </adapters>
+ <subscribers>
+  <subscriber
+     factory="Products.GenericSetup.tests.test_components.DummyAdapter"
+     for="Products.GenericSetup.tests.test_components.IAnotherDummyInterface"
+     provides="Products.GenericSetup.tests.test_components.IAnotherDummyInterface2"
+     remove="True"/>
+  <subscriber
+     for="Products.GenericSetup.tests.test_components.IAnotherDummyInterface"
+     handler="Products.GenericSetup.tests.test_components.dummy_handler"
+     remove="True"/>
+ </subscribers>
  <utilities>
   <utility id="dummy_utility"
      factory="Products.GenericSetup.tests.test_components.DummyUtility"
@@ -204,7 +253,10 @@
     def _populate(self, obj):
         obj.registerAdapter(DummyAdapter, required=(None,))
         obj.registerAdapter(DummyAdapter, required=(None,), name=u'foo')
-        
+
+        obj.registerSubscriptionAdapter(DummyAdapter, required=(IAnotherDummyInterface,))
+        obj.registerHandler(dummy_handler, required=(IAnotherDummyInterface,))
+
         util = DummyUtility()
         name = 'dummy_utility'
         util.__name__ = name
@@ -228,14 +280,22 @@
         obj.registerUtility(tool2, IDummyInterface2, name=u'dummy tool name2')
 
     def _verifyImport(self, obj):
-        adapted = queryAdapter(object(), IDummyInterface)
-        self.failUnless(IDummyInterface.providedBy(adapted))
+        adapted = queryAdapter(object(), IAnotherDummyInterface2)
+        self.failUnless(IAnotherDummyInterface2.providedBy(adapted))
         self.failUnless(adapted.verify())
 
-        adapted = queryAdapter(object(), IDummyInterface, name=u'foo')
-        self.failUnless(IDummyInterface.providedBy(adapted))
+        adapted = queryAdapter(object(), IAnotherDummyInterface2, name=u'foo')
+        self.failUnless(IAnotherDummyInterface2.providedBy(adapted))
         self.failUnless(adapted.verify())
 
+        dummy = DummyObject()
+        results = [adap.verify() for adap in subscribers([dummy], IAnotherDummyInterface2)]
+        self.assertEquals(results, [True])
+
+        dummy = DummyObject()
+        handle(dummy)
+        self.assertEquals(dummy.handled, 1)
+
         util = queryUtility(IDummyInterface2, name=u'foo')
         self.failUnless(IDummyInterface.providedBy(util))
         self.failUnless(util.verify())
@@ -339,13 +399,21 @@
         context._files['componentregistry.xml'] = _REMOVE_IMPORT
         importComponentRegistry(context)
 
-        adapted = queryAdapter(object(), IDummyInterface)
+        adapted = queryAdapter(object(), IAnotherDummyInterface2)
         self.failUnless(adapted is None)
 
         # This one should still exist
-        adapted = queryAdapter(object(), IDummyInterface, name=u'foo')
+        adapted = queryAdapter(object(), IAnotherDummyInterface2, name=u'foo')
         self.failIf(adapted is None)
 
+        dummy = DummyObject()
+        results = [adap.verify() for adap in subscribers([dummy], IAnotherDummyInterface2)]
+        self.assertEquals(results, [])
+
+        dummy = DummyObject()
+        handle(dummy)
+        self.assertEquals(dummy.handled, 0)
+
         util = queryUtility(IDummyInterface2, name=u'foo')
         name = 'Products.GenericSetup.tests.test_components.IDummyInterface2-foo'
         self.failUnless(util is None)



More information about the checkins mailing list