[Checkins] SVN: z3c.unconfigure/trunk/s Allow the unregistration of even thandlers

Philipp von Weitershausen philikon at philikon.de
Wed Aug 6 11:30:32 EDT 2008


Log message for revision 89442:
  Allow the unregistration of even thandlers
  

Changed:
  U   z3c.unconfigure/trunk/setup.py
  U   z3c.unconfigure/trunk/src/z3c/unconfigure/config.py
  A   z3c.unconfigure/trunk/src/z3c/unconfigure/testfixtures/handlers.py
  U   z3c.unconfigure/trunk/src/z3c/unconfigure/tests.txt

-=-
Modified: z3c.unconfigure/trunk/setup.py
===================================================================
--- z3c.unconfigure/trunk/setup.py	2008-08-06 13:39:44 UTC (rev 89441)
+++ z3c.unconfigure/trunk/setup.py	2008-08-06 15:30:29 UTC (rev 89442)
@@ -35,6 +35,9 @@
     zip_safe=False,
     install_requires=['setuptools',
                       'zope.configuration',
+                      'zope.component', # technically [zcml]
+                      'zope.security',
+                      'zope.event',
                       'zope.testing',
                       ],
     )

Modified: z3c.unconfigure/trunk/src/z3c/unconfigure/config.py
===================================================================
--- z3c.unconfigure/trunk/src/z3c/unconfigure/config.py	2008-08-06 13:39:44 UTC (rev 89441)
+++ z3c.unconfigure/trunk/src/z3c/unconfigure/config.py	2008-08-06 15:30:29 UTC (rev 89442)
@@ -14,7 +14,33 @@
 """The 'unconfigure' grouping directive
 """
 from zope.configuration.zopeconfigure import ZopeConfigure
+from zope.security import adapter
+import zope.component.zcml
 
+def is_subscriber(discriminator, callable=None, args=(), kw={},
+                  includepath=(), info='', order=0):
+    """Determines whether an action has been emitted from the
+    <subscriber /> directive.
+    """
+    return (discriminator is None and
+            callable is zope.component.zcml.handler and
+            args[0] == 'registerHandler')
+
+def real_subscriber_factory(discriminator, callable=None, args=(), kw={},
+                            includepath=(), info='', order=0):
+    """Returns the real subscriber factory (<subscriber /> sometimes
+    wraps them in some security-related adapter factory).
+
+    This function assumes that the action in question is a subscriber
+    action.  In other words, is_subscriber(*args) is True.
+    """
+    factory = args[1]
+    if isinstance(factory, (adapter.LocatingTrustedAdapterFactory,
+                            adapter.LocatingUntrustedAdapterFactory,
+                            adapter.TrustedAdapterFactory)):
+        factory = factory.factory
+    return factory
+
 class Unconfigure(ZopeConfigure):
 
     def __init__(self, context, **kw):
@@ -29,15 +55,33 @@
     def after(self):
         # Get a discriminator -> action representation of all the
         # actions that have been churned out so far.
-        unique = dict((action[0], action) for action in self.context.actions)
+        unique = dict((action[0], action) for action in self.context.actions
+                      if action[0] is not None)
 
+        # Find all subscriber actions and store them as factory -> action.
+        # They're a special case because their discriminators are None,
+        # so we can't pull the same trick as with other directives.
+        subscribers = dict((real_subscriber_factory(*action), action)
+                           for action in self.context.actions
+                           if is_subscriber(*action))
+        # XXX should make mapping (factory, required) -> action
+
         # Now let's go through the actions within 'unconfigure'
         # (hereafter called "unactions" :)) and use their
         # discriminator to remove the real actions
         for unaction in self.actions:
+            # Special case subscriber actions.
+            if is_subscriber(*unaction):
+                factory = real_subscriber_factory(*unaction)
+                action = subscribers.get(factory)
+                if action is None:
+                    continue
+                self.remove_action(action)
+                del subscribers[factory]
+
+            # Generic from here
             discriminator = unaction[0]
             if discriminator is None:
-                # XXX apply special majyck for subscribers here
                 continue
             action = unique.get(discriminator)
             if action is None:
@@ -45,13 +89,16 @@
                 # configured in the first place.  Ignore.
                 continue
 
-            # An action with the same discriminator has been found.
-            # We can't remove it because we mustn't change the length
-            # of the actions list (because includeOverrides relies on
-            # this not to change and we could easily be included via
-            # includeOverrides).
-            i = self.context.actions.index(action)
-            self.context.actions[i] = (None, None)
+            self.remove_action(action)
+            del unique[discriminator]
 
-            # Action has been replaced, no longer need to remember.
-            del unique[discriminator]
+    def remove_action(self, action):
+        # We can't actually remove actions because we mustn't change
+        # the length of the actions list.  The main reason is that
+        # includeOverrides relies on the length of the action list
+        # (and we could easily be included via includeOverrides and
+        # therefore run into this problem).  So let's simply replace
+        # actions with a null value.  Actions whose callable is None
+        # won't be executed.
+        i = self.context.actions.index(action)
+        self.context.actions[i] = (None, None)

Added: z3c.unconfigure/trunk/src/z3c/unconfigure/testfixtures/handlers.py
===================================================================
--- z3c.unconfigure/trunk/src/z3c/unconfigure/testfixtures/handlers.py	                        (rev 0)
+++ z3c.unconfigure/trunk/src/z3c/unconfigure/testfixtures/handlers.py	2008-08-06 15:30:29 UTC (rev 89442)
@@ -0,0 +1,21 @@
+from zope.component import adapter
+
+class Event(object):
+    pass
+
+ at adapter(Event)
+def regular(event):
+    print "Regular subscriber"
+
+ at adapter(Event)
+def trusted(event):
+    print "Trusted subscriber"
+
+ at adapter(Event)
+def located(event):
+    print "Located subscriber"
+
+ at adapter(Event)
+def locatedtrusted(event):
+    print "Located trusted subscriber"
+


Property changes on: z3c.unconfigure/trunk/src/z3c/unconfigure/testfixtures/handlers.py
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: z3c.unconfigure/trunk/src/z3c/unconfigure/tests.txt
===================================================================
--- z3c.unconfigure/trunk/src/z3c/unconfigure/tests.txt	2008-08-06 13:39:44 UTC (rev 89441)
+++ z3c.unconfigure/trunk/src/z3c/unconfigure/tests.txt	2008-08-06 15:30:29 UTC (rev 89442)
@@ -44,3 +44,45 @@
   Goodbye World!
   This is the last directive
   I can has hamburger?
+
+
+Unconfiguring event handlers
+----------------------------
+
+This package also supports unconfiguring event handlers.
+
+  >>> import zope.component.eventtesting
+  >>> zope.component.eventtesting.setUp()
+
+Consider a bunch of event handlers configured in various ways:
+
+  >>> zcml("""
+  ... <configure xmlns="http://namespaces.zope.org/zope">
+  ...   <include package="zope.component" file="meta.zcml" />
+  ...
+  ...   <subscriber handler=".handlers.regular" />
+  ...   <subscriber handler=".handlers.trusted" trusted="yes" />
+  ...   <subscriber handler=".handlers.located" locate="yes" />
+  ...   <subscriber handler=".handlers.locatedtrusted"
+  ...               trusted="yes" locate="yes" />
+  ...
+  ...   <unconfigure>
+  ...     <subscriber handler=".handlers.regular" />
+  ...     <subscriber handler=".handlers.trusted" trusted="yes" />
+  ...     <subscriber handler=".handlers.located" locate="yes" />
+  ...     <subscriber handler=".handlers.locatedtrusted"
+  ...                 trusted="yes" locate="yes" />
+  ...   </unconfigure>
+  ... </configure>
+  ... """)
+
+Since we've unconfigured the handlers, we expect that nothing will
+happen when we send the event:
+
+  >>> from zope.event import notify
+  >>> from z3c.unconfigure.testfixtures.handlers import Event
+  >>> notify(Event())
+
+  >>> import zope.testing.cleanup
+  >>> zope.testing.cleanup.cleanUp()
+



More information about the Checkins mailing list