[Checkins] SVN: z3c.unconfigure/trunk/src/z3c/unconfigure/ Be more careful when unregistering handlers. It could be that the same

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


Log message for revision 89448:
  Be more careful when unregistering handlers.  It could be that the same
  subscriber has been registered twice (for different event types).  In that
  case we want to remove the right one.
  

Changed:
  U   z3c.unconfigure/trunk/src/z3c/unconfigure/config.py
  U   z3c.unconfigure/trunk/src/z3c/unconfigure/tests/fixtures/handlers.py
  U   z3c.unconfigure/trunk/src/z3c/unconfigure/tests/subscribers.txt

-=-
Modified: z3c.unconfigure/trunk/src/z3c/unconfigure/config.py
===================================================================
--- z3c.unconfigure/trunk/src/z3c/unconfigure/config.py	2008-08-06 15:42:59 UTC (rev 89447)
+++ z3c.unconfigure/trunk/src/z3c/unconfigure/config.py	2008-08-06 15:53:10 UTC (rev 89448)
@@ -29,22 +29,25 @@
 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).
+    wraps them in some security-related adapter factory) and the
+    required set of of interfaces ('for' parameter).
 
     This function assumes that the action in question is a subscriber
     action.  In other words, is_subscriber(*args) is True.
     """
     factory = args[1]
+    for_ = args[2]
     if isinstance(factory, (adapter.LocatingTrustedAdapterFactory,
                             adapter.LocatingUntrustedAdapterFactory,
                             adapter.TrustedAdapterFactory)):
         factory = factory.factory
-    return factory
+    return factory, for_
 
 class Unconfigure(ZopeConfigure):
 
     def __init__(self, context, **kw):
         super(Unconfigure, self).__init__(context, **kw)
+
         # Make a new actions list here.  This will shadow
         # context.actions which would otherwise be "inherited" by our
         # superclass's __getattr__.  By shadowing the original list,
@@ -58,26 +61,25 @@
         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.
+        # Special-case subscriber actions: Find all subscriber actions
+        # and store them as (factory, for) -> 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
+        # Now let's go through the actions within 'unconfigure' and
+        # use their discriminator to remove the real actions
         for unaction in self.actions:
-            # Special case subscriber actions.
+            # Special-case subscriber actions.
             if is_subscriber(*unaction):
-                factory = real_subscriber_factory(*unaction)
-                action = subscribers.get(factory)
+                factory, for_ = real_subscriber_factory(*unaction)
+                action = subscribers.get((factory, for_))
                 if action is None:
                     continue
                 self.remove_action(action)
-                del subscribers[factory]
+                del subscribers[(factory, for_)]
 
             # Generic from here
             discriminator = unaction[0]

Modified: z3c.unconfigure/trunk/src/z3c/unconfigure/tests/fixtures/handlers.py
===================================================================
--- z3c.unconfigure/trunk/src/z3c/unconfigure/tests/fixtures/handlers.py	2008-08-06 15:42:59 UTC (rev 89447)
+++ z3c.unconfigure/trunk/src/z3c/unconfigure/tests/fixtures/handlers.py	2008-08-06 15:53:10 UTC (rev 89448)
@@ -3,9 +3,12 @@
 class Event(object):
     pass
 
+class Event2(object):
+    pass
+
 @adapter(Event)
 def regular(event):
-    print "Regular subscriber"
+    print "Regular subscriber", event.__class__.__name__
 
 @adapter(Event)
 def trusted(event):

Modified: z3c.unconfigure/trunk/src/z3c/unconfigure/tests/subscribers.txt
===================================================================
--- z3c.unconfigure/trunk/src/z3c/unconfigure/tests/subscribers.txt	2008-08-06 15:42:59 UTC (rev 89447)
+++ z3c.unconfigure/trunk/src/z3c/unconfigure/tests/subscribers.txt	2008-08-06 15:53:10 UTC (rev 89448)
@@ -32,5 +32,34 @@
 happen when we send the event:
 
   >>> from zope.event import notify
-  >>> from z3c.unconfigure.tests.fixtures.handlers import Event
+  >>> from z3c.unconfigure.tests.fixtures.handlers import Event, Event2
   >>> notify(Event())
+
+When unconfiguring handlers, the mechanism is careful enough to
+distinguish multiple registrations of the same event handler (e.g. for
+different event types). For instance, consider a handler that's
+registered for its default event type and then registered again for
+another event type:
+
+  >>> zcml("""
+  ... <configure xmlns="http://namespaces.zope.org/zope">
+  ...   <include package="zope.component" file="meta.zcml" />
+  ...
+  ...   <subscriber handler=".handlers.regular" />
+  ...   <subscriber handler=".handlers.regular" for=".handlers.Event2" />
+  ...
+  ...   <unconfigure>
+  ...     <subscriber handler=".handlers.regular" />
+  ...   </unconfigure>
+  ... </configure>
+  ... """)
+
+We've unconfigured it for the original event type, so nothing will
+happen here:
+
+  >>> notify(Event())
+
+But for the other event, we'll get the subscriber just fine:
+
+  >>> notify(Event2())
+  Regular subscriber Event2



More information about the Checkins mailing list