[Zope3-checkins] CVS: Zope3/src/zope/app/registration - registration.py:1.7

Jim Fulton jim at zope.com
Thu Apr 15 11:30:10 EDT 2004


Update of /cvs-repository/Zope3/src/zope/app/registration
In directory cvs.zope.org:/tmp/cvs-serv627/src/zope/app/registration

Modified Files:
	registration.py 
Log Message:
Fixed a bug in NotifyingRegistrationStack. Notifications weren't being
done in all necessary cases.  Added extensive doc tests.


=== Zope3/src/zope/app/registration/registration.py 1.6 => 1.7 ===
--- Zope3/src/zope/app/registration/registration.py:1.6	Thu Apr  8 17:02:42 2004
+++ Zope3/src/zope/app/registration/registration.py	Thu Apr 15 11:29:39 2004
@@ -92,18 +92,144 @@
 
 
 class RegistrationStack(Persistent, Contained):
+    """Registration registry implemention
 
-    """Registration registry implementation.
+       A registration stack provides support for a collection of
+       registrations such that, at any time, at most one is active.  The
+       "stack" aspect of the api is designed to support "uninstallation",
+       as will be described below.
 
-    The invariants for _data are as follows:
+       Registration stacks manage registrations.  They don't really care
+       what registrations are, as long as they can be activated and
+       deactivated:
 
-        (1) The last element (if any) is not None
+         >>> class Registration(object):
+         ...
+         ...     def __init__(self, name):
+         ...         self.name = name
+         ...         self.active = False
+         ...
+         ...     def __repr__(self):
+         ...         return self.name
+         ...
+         ...     def activated(self):
+         ...         self.active = True
+         ...
+         ...     def deactivated(self):
+         ...         self.active = False
 
-        (2) No value occurs more than once
+       We create a registration stack by providing it with a parent:
 
-        (3) Each value except None is a relative path from the nearest
-            service manager to an object implementing IRegistration
-    """
+         >>> stack = RegistrationStack(42)
+         >>> stack.__parent__
+         42
+
+       If a stack doesn't have any registrations, it's false:
+
+         >>> bool(stack)
+         False
+
+       And it has no active registration:
+
+         >>> stack.active()
+
+       We can register a registration:
+
+         >>> r1 = Registration('r1')
+         >>> stack.register(r1)
+
+       and then the stack is true:
+
+         >>> bool(stack)
+         True
+
+       But we still don't have an active registration:
+
+         >>> stack.active()
+
+       Until we activate one:
+
+         >>> stack.activate(r1)
+         >>> stack.active()
+         r1
+
+       at which point, the registration has been notified that it is
+       active:
+
+         >>> r1.active
+         True
+
+       We can't activate a registration unless it's registered:
+
+         >>> r2 = Registration('r2')
+         >>> stack.activate(r2)
+         Traceback (most recent call last):
+         ...
+         ValueError: ('Registration to be activated is not registered', r2)
+
+         >>> stack.register(r2)
+         >>> stack.activate(r2)
+
+       Note that activating r2, deactivated r1:
+
+         >>> r1.active
+         False
+
+       We can get status on the stack by calling it's info method:
+
+         >>> for info in stack.info():
+         ...     print info['registration'], info['active']
+         r2 True
+         r1 False
+
+       So why is this a stack? Unregistering an object is a bit like
+       poping an element. Suppose we unrgister r2:
+
+         >>> stack.unregister(r2)
+
+       Whenever we unregister an object, we make the object that was
+       previously active active again:
+
+         >>> stack.active()
+         r1
+
+         >>> r1.active
+         True
+
+       Now, let's deactivate r1:
+
+         >>> stack.deactivate(r1)
+         >>> stack.active()
+         >>> r1.active
+         False
+
+       And register and activate r2:
+       
+         >>> stack.register(r2)
+         >>> stack.activate(r2)
+         >>> stack.active()
+         r2
+
+       Now, if we unregister r2:
+
+         >>> stack.unregister(r2)
+
+       We won't have an active registration:
+
+         >>> stack.active()
+
+       Because there wasn't an active registration before we made r2
+       active. 
+       """
+
+#     The invariants for _data are as follows:
+#
+#         (1) The last element (if any) is not None
+#
+#         (2) No value occurs more than once
+#
+#         (3) Each value except None is a relative path from the nearest
+#             service manager to an object implementing IRegistration
 
     implements(interfaces.IRegistrationStack)
 
@@ -133,11 +259,11 @@
                 self.data = data
 
                 # Tell it that it is no longer active
-                registration.deactivated()
+                self._deactivate(registration)
 
                 if data and data[0] is not None:
                     # Activate the newly active component
-                    data[0].activated()
+                    self._activate(data[0])
             else:
                 # Remove it from our data
                 data = tuple([item for item in data if item != registration])
@@ -151,6 +277,12 @@
     def registered(self, registration):
         return registration in self.data
 
+    def _activate(self, registration):
+        registration.activated()
+
+    def _deactivate(self, registration):
+        registration.deactivated()
+
     def activate(self, registration):
         data = self.data
 
@@ -176,11 +308,11 @@
 
             if old is not None:
                 # Deactivated the currently active component
-                old.deactivated()
+                self._deactivate(old)
 
             if registration is not None:
                 # Tell it that it is now active
-                registration.activated()
+                self._activate(registration)
 
         else:
             raise ValueError(
@@ -209,11 +341,11 @@
         self.data = data
 
         # Tell it that it is no longer active
-        registration.deactivated()
+        self._deactivate(registration)
 
         if data[0] is not None:
             # Activate the newly active component
-            data[0].activated()
+            self._activate(data[0])
 
     def active(self):
         data = self.data
@@ -265,13 +397,124 @@
     #########################################################################
 
 class NotifyingRegistrationStack(RegistrationStack):
+    """Notifying registration registry implemention
 
-    def activate(self, registration):
-        RegistrationStack.activate(self, registration)
+       First, see RegistrationStack.
+
+       A notifying registration stack notifies both the registration
+       *and* the stacks parent when it changes.  It notifies the
+       parent by calling nothingActivated and notifyDeactivated:
+
+         >>> class Parent(object):
+         ...
+         ...     active = deactive = None
+         ...
+         ...     def notifyActivated(self, stack, registration):
+         ...         self.active = registration
+         ...
+         ...     def notifyDeactivated(self, stack, registration):
+         ...         self.active = None
+         ...         self.deactive = registration
+
+
+       To see this, we'll go through the same scenario we went through
+       in the RegistrationStack documentation.
+       A registration stack provides support for a collection of
+
+         >>> class Registration(object):
+         ...
+         ...     def __init__(self, name):
+         ...         self.name = name
+         ...         self.active = False
+         ...
+         ...     def __repr__(self):
+         ...         return self.name
+         ...
+         ...     def activated(self):
+         ...         self.active = True
+         ...
+         ...     def deactivated(self):
+         ...         self.active = False
+
+       We create a registration stack by providing it with a parent:
+
+         >>> parent = Parent()
+         >>> stack = NotifyingRegistrationStack(parent)
+
+       We can register a registration:
+
+         >>> r1 = Registration('r1')
+         >>> stack.register(r1)
+
+       But we still don't have an active registration:
+
+         >>> stack.active()
+         >>> parent.active
+
+       Until we activate one:
+
+         >>> stack.activate(r1)
+         >>> parent.active
+         r1
+
+       if we activate a new registration:
+
+         >>> r2 = Registration('r2')
+         >>> stack.register(r2)
+         >>> stack.activate(r2)
+
+       The parent will be notified of the activation and the
+       deactivation: 
+
+         >>> parent.active
+         r2
+         >>> parent.deactive
+         r1
+
+       If we unregister r2, it will become inactive and the parent
+       will be notified, but whenever we unregister an object, we make
+       the object that was previously active active again:
+
+         >>> stack.unregister(r2)
+         >>> parent.active
+         r1
+         >>> parent.deactive
+         r2
+
+       Now, let's deactivate r1:
+
+         >>> stack.deactivate(r1)
+         >>> parent.active
+         >>> parent.deactive
+         r1
+
+       And register and activate r2:
+       
+         >>> stack.register(r2)
+         >>> stack.activate(r2)
+         >>> parent.active
+         r2
+
+       Now, if we unregister r2:
+
+         >>> stack.unregister(r2)
+
+       We won't have an active registration:
+
+         >>> parent.active
+         >>> parent.deactive
+         r2
+
+       Because there wasn't an active registration before we made r2
+       active. 
+       """
+
+    def _activate(self, registration):
+        registration.activated()
         self.__parent__.notifyActivated(self, registration)
 
-    def deactivate(self, registration):
-        RegistrationStack.deactivate(self, registration)
+    def _deactivate(self, registration):
+        registration.deactivated()
         self.__parent__.notifyDeactivated(self, registration)
 
 class SimpleRegistrationRemoveSubscriber:




More information about the Zope3-Checkins mailing list