[z3-checkins] r19221 - in z3/Five/trunk: . tests

efge at codespeak.net efge at codespeak.net
Mon Oct 31 02:44:26 CET 2005


Author: efge
Date: Mon Oct 31 02:44:26 2005
New Revision: 19221

Modified:
   z3/Five/trunk/deprecated.zcml
   z3/Five/trunk/event.py
   z3/Five/trunk/eventconfigure.py
   z3/Five/trunk/fivedirectives.py
   z3/Five/trunk/meta.zcml
   z3/Five/trunk/tests/event.txt
   z3/Five/trunk/tests/test_event.py
Log:
Added many five:deprecatedManageAddDelete for all Zope 2 classes that
have a manage_afterAdd & co method.

Simplified the transition, there are no more "phases", no more
transitional mode, it's either <five:containerEvents/> or not.

In event mode, even if a class doesn't have a five:deprecatedManageAddDelete,
we still try to call the manage_afterAdd & co methods.



Modified: z3/Five/trunk/deprecated.zcml
==============================================================================
--- z3/Five/trunk/deprecated.zcml	(original)
+++ z3/Five/trunk/deprecated.zcml	Mon Oct 31 02:44:26 2005
@@ -6,4 +6,46 @@
   <five:deprecatedManageAddDelete
       class="AccessControl.User.BasicUserFolder"/>
 
+  <five:deprecatedManageAddDelete
+      class="App.Factory.Factory"/>
+  <five:deprecatedManageAddDelete
+      class="App.Permission.Permission"/>
+
+  <five:deprecatedManageAddDelete
+      class="HelpSys.HelpTopic.HelpTopicBase"/>
+
+  <five:deprecatedManageAddDelete
+      class="OFS.Cache.CacheManager"/>
+
+  <five:deprecatedManageAddDelete
+      class="Products.OFSP.Draft.Draft"/>
+  <five:deprecatedManageAddDelete
+      class="Products.OFSP.Version.Version"/>
+
+  <five:deprecatedManageAddDelete
+      class="Products.PythonScripts.PythonScript.PythonScript"/>
+
+  <five:deprecatedManageAddDelete
+      class="Products.Sessions.BrowserIdManager.BrowserIdManager"/>
+  <five:deprecatedManageAddDelete
+      class="Products.Sessions.SessionDataManager.SessionDataManager"/>
+
+  <five:deprecatedManageAddDelete
+      class="Products.SiteAccess.VirtualHostMonster.VirtualHostMonster"/>
+  <five:deprecatedManageAddDelete
+      class="Products.SiteAccess.SiteRoot.Traverser"/>
+
+  <five:deprecatedManageAddDelete
+      class="Products.SiteErrorLog.SiteErrorLog.SiteErrorLog"/>
+
+  <five:deprecatedManageAddDelete
+      class="Products.ZCatalog.CatalogAwareness.CatalogAware"/>
+  <five:deprecatedManageAddDelete
+      class="Products.ZCatalog.CatalogPathAwareness.CatalogAware"/>
+
+  <five:deprecatedManageAddDelete
+      class="ZClasses.Property.ZCommonSheet"/>
+  <five:deprecatedManageAddDelete
+      class="ZClasses.ZClass.ZClass"/>
+
 </configure>

Modified: z3/Five/trunk/event.py
==============================================================================
--- z3/Five/trunk/event.py	(original)
+++ z3/Five/trunk/event.py	Mon Oct 31 02:44:26 2005
@@ -116,31 +116,47 @@
 from OFS.ObjectManager import BeforeDeleteException
 from OFS import Moniker
 from OFS.CopySupport import CopyError # Yuck, a string exception
-from OFS.CopySupport import eNoData, eNotFound, eInvalid, _cb_decode
-from OFS.CopySupport import cookie_path, sanity_check
+from OFS.CopySupport import eNoData, eNotFound, eInvalid, eNotSupported
+from OFS.CopySupport import cookie_path, sanity_check, _cb_decode
 from webdav.Lockable import ResourceLockedError
 FIVE_ORIGINAL_PREFIX = '__five_original_'
 
 
-previousConfigInfos = []
-containerEventsTransitional = None
-containerEventAwareClasses = []
+hasContainerEvents = False
 deprecatedManageAddDeleteClasses = []
 
 
 def hasDeprecatedMethods(ob):
     """Do we need to call the deprecated methods?
     """
-    if containerEventsTransitional:
-        for class_ in containerEventAwareClasses:
-            if isinstance(ob, class_):
-                return False
-        return True
-    else:
-        for class_ in deprecatedManageAddDeleteClasses:
-            if isinstance(ob, class_):
-                return True
-        return False
+    for class_ in deprecatedManageAddDeleteClasses:
+        if isinstance(ob, class_):
+            return True
+    return False
+
+def maybeCallDeprecated(method_name, ob, *args):
+    """Call a deprecated method, if the framework doesn't call it already.
+    """
+    if hasDeprecatedMethods(ob):
+        # Already deprecated through zcml
+        return
+    method = getattr(ob, method_name)
+    if isFiveMethod(method):
+        # Monkey-patched method
+        return
+    if deprecatedManageAddDeleteClasses:
+        # Not deprecated through zcml and directives fully loaded
+        class_ = ob.__class__
+        warnings.warn(
+            "Calling %s.%s.%s is deprecated when using Five, "
+            "instead use event subscribers or "
+            "mark the class with <five:deprecatedManageAddDelete/>"
+            % (class_.__module__, class_.__name__, method_name),
+            DeprecationWarning)
+    # Note that calling the method can lead to incorrect behavior
+    # but in the most common case that's better than not calling it.
+    method(ob, *args)
+
 
 ##################################################
 # Adapters and subscribers
@@ -210,14 +226,7 @@
     if container is None:
         # this is a remove
         return
-    if not isFiveMethod(ob.manage_afterAdd):
-        warnings.warn(
-            "Calling %s.manage_afterAdd is deprecated when using Five, "
-            "use an IObjectAddedEvent subscriber instead."
-            % ob.__class__.__name__,
-            DeprecationWarning)
-    item = event.object
-    ob.manage_afterAdd(item, container)
+    ob.manage_afterAdd(event.object, container)
 
 def callManageBeforeDelete(ob, event):
     """Compatibility subscriber for manage_beforeDelete.
@@ -226,15 +235,8 @@
     if container is None:
         # this is an add
         return
-    if not isFiveMethod(ob.manage_beforeDelete):
-        warnings.warn(
-            "Calling %s.manage_beforeDelete is deprecated when using Five, "
-            "use an IObjectWillBeRemovedEvent subscriber instead."
-            % ob.__class__.__name__,
-            DeprecationWarning)
-    item = event.object
     try:
-        ob.manage_beforeDelete(item, container)
+        ob.manage_beforeDelete(event.object, container)
     except BeforeDeleteException:
         raise
     except ConflictError:
@@ -249,15 +251,7 @@
 def callManageAfterClone(ob, event):
     """Compatibility subscriber for manage_afterClone.
     """
-    if not isFiveMethod(ob.manage_afterClone):
-        warnings.warn(
-            "Calling %s.manage_afterClone is deprecated when using Five, "
-            "use an IFiveObjectClonedEvent subscriber instead, or "
-            "better, an IObjectCopiedEvent or IObjectAddedEvent subscriber."
-            % ob.__class__.__name__,
-            DeprecationWarning)
-    item = event.object
-    ob.manage_afterClone(item)
+    ob.manage_afterClone(event.object)
 
 
 ##################################################
@@ -265,24 +259,37 @@
 
 _marker = object()
 
-# From ObjectManager
+# From ObjectManager / Item
 def manage_afterAdd(self, item, container):
     # Don't do recursion anymore, a subscriber does that.
-    # A warning is sent by the subscriber
     pass
 
-# From ObjectManager
+# From ObjectManager / Item
 def manage_beforeDelete(self, item, container):
     # Don't do recursion anymore, a subscriber does that.
-    # A warning is sent by the subscriber
     pass
 
-# From ObjectManager
+# From ObjectManager / Item
 def manage_afterClone(self, item):
     # Don't do recursion anymore, a subscriber does that.
-    # A warning is sent by the subscriber
     pass
 
+# From CatalogAware / CatalogPathAware
+def CA_manage_afterAdd(self, item, container):
+    # Don't do recursion anymore, a subscriber does that.
+    self.index_object()
+
+# From CatalogAware / CatalogPathAware
+def CA_manage_beforeDelete(self, item, container):
+    # Don't do recursion anymore, a subscriber does that.
+    self.unindex_object()
+
+# From CatalogAware / CatalogPathAware
+def CA_manage_afterClone(self, item):
+    # Don't do recursion anymore, a subscriber does that.
+    self.index_object()
+
+
 # From ObjectManager
 def _setObject(self, id, object, roles=None, user=None, set_owner=1,
                suppress_events=False):
@@ -327,7 +334,7 @@
     if not suppress_events:
         notify(ObjectAddedEvent(ob, self, id))
 
-    # manage_afterAdd was here
+    maybeCallDeprecated('manage_afterAdd', ob, self)
 
     return id
 
@@ -368,7 +375,7 @@
     if not suppress_events:
         notify(ObjectAddedEvent(ob, self, id))
 
-    # manage_afterAdd was here
+    maybeCallDeprecated('manage_afterAdd', ob, self)
 
     return id
 
@@ -381,7 +388,7 @@
     """
     ob = self._getOb(id)
 
-    # manage_beforeDelete was here
+    maybeCallDeprecated('manage_beforeDelete', ob, self)
 
     if not suppress_events:
         notify(ObjectWillBeRemovedEvent(ob, self, id))
@@ -408,7 +415,7 @@
 def BT_delObject(self, id, dp=1, suppress_events=False):
     ob = self._getOb(id)
 
-    # manage_beforeDelete was here
+    maybeCallDeprecated('manage_beforeDelete', ob, self)
 
     if not suppress_events:
         notify(ObjectWillBeRemovedEvent(ob, self, id))
@@ -537,6 +544,8 @@
 
             ob._postCopy(self, op=0)
 
+            maybeCallDeprecated('manage_afterClone', ob)
+
             notify(FiveObjectClonedEvent(ob))
 
         if REQUEST is not None:
@@ -635,11 +644,80 @@
 
     ob._postCopy(self, op=0)
 
+    maybeCallDeprecated('manage_afterClone', ob)
+
     notify(FiveObjectClonedEvent(ob))
 
     return ob
 
 ##################################################
+# Fix OFS.Application's creation of some objects.
+#
+# The application object creates root objects like error_log,
+# browser_id_manager, session_data_manager
+#
+# They all expects their manage_afterAdd to be called, but they are
+# created before Five 1.2 is initialized and has had a chance to do its
+# patches. So we call manage_afterAddd by hand.
+#
+# Remove this in Five 1.3, where subscribers and implements()
+# will be setup correctly earlier.
+
+def install_errorlog(self):
+    app = self.getApp()
+    if app._getInitializerFlag('error_log'):
+        # do nothing if we've already installed one
+        return
+    # Install an error_log
+    if not hasattr(app, 'error_log'):
+        from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog
+        error_log = SiteErrorLog()
+        app._setObject('error_log', error_log)
+        # Added for Five 1.2:
+        error_log = app.error_log
+        error_log.manage_afterAdd(error_log, app)
+        # End added
+        app._setInitializerFlag('error_log')
+        self.commit('Added site error_log at /error_log')
+
+def install_browser_id_manager(self):
+    app = self.getApp()
+    if app._getInitializerFlag('browser_id_manager'):
+        # do nothing if we've already installed one
+        return
+    # Ensure that a browser ID manager exists
+    if not hasattr(app, 'browser_id_manager'):
+        from Products.Sessions.BrowserIdManager import BrowserIdManager
+        bid = BrowserIdManager('browser_id_manager', 'Browser Id Manager')
+        app._setObject('browser_id_manager', bid)
+        # Added for Five 1.2:
+        browser_id_manager = app.browser_id_manager
+        browser_id_manager.manage_afterAdd(browser_id_manager, app)
+        # End added
+        app._setInitializerFlag('browser_id_manager')
+        self.commit('Added browser_id_manager')
+
+def install_session_data_manager(self):
+    app = self.getApp()
+    if app._getInitializerFlag('session_data_manager'):
+        # do nothing if we've already installed one
+        return
+    # Ensure that a session data manager exists
+    if not hasattr(app, 'session_data_manager'):
+        from Products.Sessions.SessionDataManager import SessionDataManager
+        sdm = SessionDataManager('session_data_manager',
+            title='Session Data Manager',
+            path='/temp_folder/session_data',
+            requestName='SESSION')
+        app._setObject('session_data_manager', sdm)
+        # Added for Five 1.2:
+        session_data_manager = app.session_data_manager
+        session_data_manager.manage_afterAdd(session_data_manager, app)
+        # End added
+        app._setInitializerFlag('session_data_manager')
+        self.commit('Added session_data_manager')
+
+##################################################
 # Structured monkey-patching
 
 import Products.Five
@@ -649,27 +727,19 @@
 
 _monkied = []
 
+from OFS.SimpleItem import Item
 from OFS.ObjectManager import ObjectManager
 from OFS.CopySupport import CopyContainer
 from OFS.OrderSupport import OrderSupport
 from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2Base
+from OFS.Application import AppInitializer
+from Products.ZCatalog import CatalogAwareness, CatalogPathAwareness
 
-def doMonkies(transitional, info=None, register_cleanup=True):
+def doMonkies(transitional, register_cleanup=True):
     """Monkey patch various methods to provide container events.
-
-    If passed, ``info`` is a zconfig information about where the
-    declaration was made.
     """
-    global containerEventsTransitional
-    if containerEventsTransitional is not None:
-        if containerEventsTransitional != transitional:
-            from zope.configuration.config import ConfigurationConflictError
-            conflicts = {'five:containerEvents': previousConfigInfos}
-            raise ConfigurationConflictError(conflicts)
-    if info is not None:
-        previousConfigInfos.append(info)
-
-    containerEventsTransitional = transitional
+    global hasContainerEvents
+    hasContainerEvents = True
 
     patchMethod(ObjectManager, '_setObject',
                 _setObject)
@@ -682,6 +752,13 @@
     patchMethod(ObjectManager, 'manage_afterClone',
                 manage_afterClone)
 
+    patchMethod(Item, 'manage_afterAdd',
+                manage_afterAdd)
+    patchMethod(Item, 'manage_beforeDelete',
+                manage_beforeDelete)
+    patchMethod(Item, 'manage_afterClone',
+                manage_afterClone)
+
     patchMethod(BTreeFolder2Base, '_setObject',
                 BT_setObject)
     patchMethod(BTreeFolder2Base, '_delObject',
@@ -697,6 +774,26 @@
     patchMethod(OrderSupport, '_old_manage_renameObject',
                 manage_renameObject)
 
+    patchMethod(AppInitializer, 'install_errorlog',
+                install_errorlog)
+    patchMethod(AppInitializer, 'install_browser_id_manager',
+                install_browser_id_manager)
+    patchMethod(AppInitializer, 'install_session_data_manager',
+                install_session_data_manager)
+
+    patchMethod(CatalogAwareness.CatalogAware, 'manage_afterAdd',
+                CA_manage_afterAdd)
+    patchMethod(CatalogAwareness.CatalogAware, 'manage_beforeDelete',
+                CA_manage_beforeDelete)
+    patchMethod(CatalogAwareness.CatalogAware, 'manage_afterClone',
+                CA_manage_afterClone)
+    patchMethod(CatalogPathAwareness.CatalogAware, 'manage_afterAdd',
+                CA_manage_afterAdd)
+    patchMethod(CatalogPathAwareness.CatalogAware, 'manage_beforeDelete',
+                CA_manage_beforeDelete)
+    patchMethod(CatalogPathAwareness.CatalogAware, 'manage_afterClone',
+                CA_manage_afterClone)
+
     # XXX remove this for Five 1.3, and put it in configure.zcml
     zcml.load_config('event.zcml', Products.Five)
 
@@ -715,10 +812,8 @@
 def undoMonkies():
     """Undo monkey patches.
     """
-    global containerEventsTransitional
+    global hasContainerEvents
     for class_, name in _monkied:
         killMonkey(class_, name, FIVE_ORIGINAL_PREFIX + name)
-    containerEventsTransitional = None
-    containerEventAwareClasses[:] = []
+    hasContainerEvents = False
     deprecatedManageAddDeleteClasses[:] = []
-    previousConfigInfos[:] = []

Modified: z3/Five/trunk/eventconfigure.py
==============================================================================
--- z3/Five/trunk/eventconfigure.py	(original)
+++ z3/Five/trunk/eventconfigure.py	Mon Oct 31 02:44:26 2005
@@ -19,35 +19,17 @@
 """
 
 from event import doMonkies
-from event import containerEventAwareClasses
 from event import deprecatedManageAddDeleteClasses
 
-def setContainerEvents(transitional, info):
-    doMonkies(transitional, info)
-
-def setContainerEventAware(class_):
-    """Instances of the class will receive object events."""
-    containerEventAwareClasses.append(class_)
-
 def setDeprecatedManageAddDelete(class_):
     """Instances of the class will still see their old methods called."""
     deprecatedManageAddDeleteClasses.append(class_)
 
-def containerEvents(_context, transitional=False):
-    # Remember context info to be able to provide information
-    # when resolving conflicts about this directive.
-    info = getattr(_context, 'info', '')
-    _context.action(
-        discriminator=None, # conflict resolution is done "by hand"
-        callable=setContainerEvents,
-        args=(transitional, info),
-        )
-
-def containerEventAware(_context, class_):
+def containerEvents(_context):
     _context.action(
-        discriminator=('five:containerEventAware', class_),
-        callable=setContainerEventAware,
-        args=(class_,),
+        discriminator=None,
+        callable=doMonkies,
+        args=(),
         )
 
 def deprecatedManageAddDelete(_context, class_):

Modified: z3/Five/trunk/fivedirectives.py
==============================================================================
--- z3/Five/trunk/fivedirectives.py	(original)
+++ z3/Five/trunk/fivedirectives.py	Mon Oct 31 02:44:26 2005
@@ -71,18 +71,6 @@
 class IContainerEventsDirective(Interface):
     """Global switch to enable container events
     """
-    transitional = Bool(
-        title=u"Transitional",
-        required=False,
-        )
-
-class IContainerEventAwareDirective(Interface):
-    """Send events for these contained content classes (transitional).
-    """
-    class_ = GlobalObject(
-        title=u"Class",
-        required=True,
-        )
 
 class IDeprecatedManageAddDeleteDirective(Interface):
     """Call manage_afterAdd & co for these contained content classes.

Modified: z3/Five/trunk/meta.zcml
==============================================================================
--- z3/Five/trunk/meta.zcml	(original)
+++ z3/Five/trunk/meta.zcml	Mon Oct 31 02:44:26 2005
@@ -134,12 +134,6 @@
        />
 
     <meta:directive
-       name="containerEventAware"
-       schema=".fivedirectives.IContainerEventAwareDirective"
-       handler=".eventconfigure.containerEventAware"
-       />
-
-    <meta:directive
        name="deprecatedManageAddDelete"
        schema=".fivedirectives.IDeprecatedManageAddDeleteDirective"
        handler=".eventconfigure.deprecatedManageAddDelete"

Modified: z3/Five/trunk/tests/event.txt
==============================================================================
--- z3/Five/trunk/tests/event.txt	(original)
+++ z3/Five/trunk/tests/event.txt	Mon Oct 31 02:44:26 2005
@@ -9,80 +9,36 @@
 These events replace the Zope 2 manage_afterAdd, manage_beforeDelete and
 manage_afterClone methods.
 
-Phases
-======
+To enable events, use::
 
-There are 4 steps to the migration process of having Zope 2 use Zope 3
-container events.
-
-Phase 1
--------
-
-Original Zope 2 status, where no events are sent, and manage_afterAdd &
-co are called on the children.
-
-Phase 2
--------
-
-<five:containerEvents transitional="true"/>
-
-Some content classes have been migrated to using Zope 3 events.
-
-All standard Zope containers send Zope 3 events. Their manage_afterAdd &
-co methods do not do recursion anymore, and send a deprecation warning
-if called. The dispatching to subobjects is done through the standard
-Zope 3 dispatchToSublocations subscriber.
-
-Containers will still call manage_afterAdd & co (with a deprecation
-warning) for content classes not specified in a::
-
-  <five:containerEventAware class="some.content.class"/>
-
-directive.
-
-Phase 3
--------
-
-<five:containerEvents/>
-
-Most content classes have been migrated to using Zope 3 events.
+  <five:containerEvents/>
 
 All standard Zope containers will only call manage_afterAdd & co on
-classes specified in a::
+classes specified with the directive::
 
   <five:deprecatedManageAddDelete class="some.content.class"/>
 
-directive. A deprecation warning is sent for these.
-
-<five:containerEventAware/> is deprecated, as it is now the default
-for other classes.
+Classes that don't have this directive but still have manage_afterAdd &
+co methods will trigger a warning when they are called (and this is
+strictly a compatibility call, behavior may not be strictly equivalent
+to the original one).
 
-Phase 4
--------
+Test setup
+==========
 
-All content classes use Zope 3 events. <five:containerEvents/> is
-deprecated as it is now the default. <five:deprecatedManageAddDelete/>
-is forbidden.
-
-
-Testing
-=======
-
-Let's see what happens for these phases. There is a bit of setup for the
-tests.
+A bit of setup for the tests. Because we'll test copy/paste, we need to
+work inside a database::
 
   >>> from zope.app.tests.placelesssetup import setUp, tearDown
   >>> setUp()
 
-Because we'll test copy/paste, we need to work inside a database.
-
   >>> import ZODB.tests.util
   >>> db = ZODB.tests.util.DB()
   >>> connection = db.open()
   >>> root = connection.root()
 
-We'll use two simple classes (defined in python code for picklability)
-and simple folders for our tests.
+We'll use a few simple classes (defined in python code for picklability)
+for our tests.
 
   >>> from Products.Five.tests.test_event import MyApp, MyContent
   >>> from Products.Five.tests.test_event import MyFolder, MyBTreeFolder
@@ -104,7 +60,7 @@
 subscribers print them. We'll actually do that for a specific interface,
 not for (None, IObjectEvent), and register our subscribers before the
 framework's ones, so ours will be called first. This has the effect that
-printed events will be in their "natural" order.
+printed events will be in their "natural" order::
 
   >>> from zope.app.event.interfaces import IObjectEvent
   >>> from zope.app.container.interfaces import IObjectMovedEvent
@@ -125,11 +81,12 @@
   >>> ztapi.handle([IItem, IFiveObjectClonedEvent], printObjectEvent)
   >>> ztapi.handle([None, IObjectEvent], printObjectEventExceptSome)
 
-Phase 1
--------
+
+Original behavior
+=================
 
 Let's test standard folder operations. The methods manage_afterAdd and
-manage_beforeDelete, and several others, are called.
+manage_beforeDelete, and several others, are called::
 
   >>> ob = MyContent('milou')
   >>> folder._setObject('milou', ob)
@@ -138,7 +95,7 @@
   >>> folder.manage_delObjects('milou')
   old manage_beforeDelete milou milou folder
 
-We can also move objects.
+We can also move objects::
 
   >>> ob = MyContent('tintin')
   >>> folder._setObject('tintin', ob)
@@ -150,7 +107,7 @@
   old manage_afterAdd tintin tintin folder
   [{'new_id': 'tintin', 'id': 'tintin'}]
 
-And we can copy them.
+And we can copy them::
 
   >>> cp = folder.manage_copyObjects('tintin')
   >>> folder.manage_pasteObjects(cp)
@@ -158,13 +115,13 @@
   old manage_afterClone copy_of_tintin copy_of_tintin
   [{'new_id': 'copy_of_tintin', 'id': 'tintin'}]
 
-We can rename objects:
+We can rename objects::
 
   >>> folder.manage_renameObject('copy_of_tintin', 'haddock')
   old manage_beforeDelete copy_of_tintin copy_of_tintin folder
   old manage_afterAdd haddock haddock folder
 
-We can also call manage_clone by hand:
+We can also call manage_clone by hand::
 
   >>> res = folder.manage_clone(folder.tintin, 'tournesol')
   old manage_afterAdd tournesol tournesol folder
@@ -172,7 +129,7 @@
   >>> res.getId()
   'tournesol'
 
-Let's also test with a BTreeFolder:
+Let's also test with a BTreeFolder::
 
   >>> ob = MyContent('castafiore')
   >>> btfolder._setObject('castafiore', ob)
@@ -182,7 +139,7 @@
   old manage_beforeDelete castafiore castafiore btfolder
 
 When a tree of objects is affected, the methods are called for all
-levels.
+levels::
 
   >>> subfolder = MyFolder('subfolder')
   >>> folder._setObject('subfolder', subfolder)
@@ -195,7 +152,7 @@
   'riri'
 
 Renaming a tree of objects. Note that manage_beforeDelete is called
-bottom-up.
+bottom-up::
 
   >>> folder.manage_renameObject('subfolder', 'bob')
   old manage_beforeDelete riri subfolder folder
@@ -203,7 +160,7 @@
   old manage_afterAdd bob bob folder
   old manage_afterAdd riri bob folder
 
-Cloning a tree of objects:
+Cloning a tree of objects::
 
   >>> res = folder.manage_clone(folder.bob, 'loulou')
   old manage_afterAdd loulou loulou folder
@@ -213,27 +170,60 @@
   >>> res.getId()
   'loulou'
 
-Phase 2
--------
 
-In this phase, transitional events are in effect.
+With events
+===========
 
 We need some of the Five setup, to get proper five:interfaces declared
-for Zope 2 classes.
+for Zope 2 classes::
 
   >>> from Products.Five import zcml
   >>> import Products.Five
   >>> zcml.load_config('meta.zcml', Products.Five)
   >>> zcml.load_config('interfaces.zcml', Products.Five)
 
-Phase 2 is when we're using <five:containerEvents transitional="true"/>
+Now execute the directive enabling events::
 
   >>> from Products.Five.event import doMonkies, undoMonkies
-  >>> doMonkies(transitional=True)
+  >>> doMonkies(transitional=False)
+
+Old class
+---------
 
-When we add an instance of an old class for which we haven't specified
-anything, some events are sent but the old manage_afterAdd method is
-also called.
+If we use an instance of an old class for which we haven't specified
+anything, events are sent and the manage_afterAdd & co methods are
+called but in a "compatibility" way.
+
+Because the bases classes of Zope have been changed to not recurse
+except through the event framework, unexpected behavior may happen
+(however a warning will be sent)::
+
+  >>> ob = MyContent('dog')
+  >>> folder._setObject('dog', ob)
+  ObjectWillBeAddedEvent dog
+  ObjectAddedEvent dog
+  old manage_afterAdd dog dog folder
+  'dog'
+
+And when we delete the object, manage_beforeDelete is also called and
+events are sent::
+
+  >>> folder.manage_delObjects('dog')
+  old manage_beforeDelete dog dog folder
+  ObjectWillBeRemovedEvent dog
+  ObjectRemovedEvent dog
+
+Old class with deprecatedManageAddDelete
+----------------------------------------
+
+We specifiy that our class is deprecated (using zcml in real life)::
+
+  >>> from Products.Five.eventconfigure import setDeprecatedManageAddDelete
+  >>> setDeprecatedManageAddDelete(MyContent)
+  >>> setDeprecatedManageAddDelete(MyFolder)
+
+Now some events are sent but the old manage_afterAdd method is also
+called correctly::
 
   >>> ob = MyContent('lassie')
   >>> folder._setObject('lassie', ob)
@@ -243,7 +233,7 @@
   'lassie'
 
 And when we delete the object, manage_beforeDelete is also called and
-events are sent.
+events are sent::
 
   >>> folder.manage_delObjects('lassie')
   ObjectWillBeRemovedEvent lassie
@@ -251,7 +241,7 @@
   ObjectRemovedEvent lassie
 
 The old behavior happens for a move or a copy, with events too.
-For a move:
+For a move::
 
   >>> ob = MyContent('blueberry')
   >>> folder._setObject('blueberry', ob)
@@ -267,7 +257,7 @@
   old manage_afterAdd blueberry blueberry folder
   [{'new_id': 'blueberry', 'id': 'blueberry'}]
 
-Old behavior with events for a copy:
+Old behavior with events for a copy::
 
   >>> cp = folder.manage_copyObjects('blueberry')
   >>> folder.manage_pasteObjects(cp)
@@ -279,7 +269,7 @@
   old manage_afterClone copy_of_blueberry copy_of_blueberry
   [{'new_id': 'copy_of_blueberry', 'id': 'blueberry'}]
 
-Old behavior with events for a renaming:
+Old behavior with events for a renaming::
 
   >>> folder.manage_renameObject('copy_of_blueberry', 'myrtille')
   ObjectWillBeMovedEvent copy_of_blueberry
@@ -287,7 +277,7 @@
   ObjectMovedEvent myrtille
   old manage_afterAdd myrtille myrtille folder
 
-Old behavior with events for a clone:
+Old behavior with events for a clone::
 
   >>> res = folder.manage_clone(folder.blueberry, 'strawberry')
   ObjectCopiedEvent strawberry
@@ -299,7 +289,7 @@
   >>> res.getId()
   'strawberry'
 
-Events are also sent when we work with a BTreeFolder:
+Events are also sent when we work with a BTreeFolder::
 
   >>> ob = MyContent('luckyluke')
   >>> btfolder._setObject('luckyluke', ob)
@@ -313,7 +303,7 @@
   old manage_beforeDelete luckyluke luckyluke btfolder
   ObjectRemovedEvent luckyluke
 
-Here is what happens for a tree of objects. Let's create a simple one.
+Here is what happens for a tree of objects. Let's create a simple one::
 
   >>> subfolder = MyFolder('subfolder')
   >>> folder._setObject('subfolder', subfolder)
@@ -330,7 +320,7 @@
   'donald'
 
 Renaming a tree of objects. Note that manage_beforeDelete is called
-bottom-up.
+bottom-up::
 
   >>> folder.manage_renameObject('subfolder', 'pluto')
   ObjectWillBeMovedEvent subfolder
@@ -342,7 +332,7 @@
   ObjectMovedEvent donald
   old manage_afterAdd donald pluto folder
 
-Cloning a tree of objects:
+Cloning a tree of objects::
 
   >>> res = folder.manage_clone(folder.pluto, 'mickey')
   ObjectCopiedEvent mickey
@@ -359,15 +349,23 @@
   >>> res.getId()
   'mickey'
 
-If however we specify using ZCML that our classes can react to events,
-the framework won't call manage_afterAdd and manage_beforeDelete
-anymore.
-
-  >>> from Products.Five.eventconfigure import setContainerEventAware
-  >>> setContainerEventAware(MyContent)
-  >>> setContainerEventAware(MyFolder)
+New class
+---------
+
+If we use classes that don't have any manage_afterAdd & co method,
+everything happens correctly::
 
-  >>> ob = MyContent('dogbert')
+  >>> from Products.Five.tests.test_event import MyNewFolder, MyNewContent
+  >>> app = MyApp('')
+  >>> root['app'] = app
+  >>> folder = MyNewFolder('folder')
+  >>> app._setObject('folder', folder)
+  ObjectWillBeAddedEvent folder
+  ObjectAddedEvent folder
+  'folder'
+  >>> folder = app.folder
+
+  >>> ob = MyNewContent('dogbert')
   >>> folder._setObject('dogbert', ob)
   ObjectWillBeAddedEvent dogbert
   ObjectAddedEvent dogbert
@@ -376,9 +374,9 @@
   ObjectWillBeRemovedEvent dogbert
   ObjectRemovedEvent dogbert
 
-Now move:
+Now move::
 
-  >>> ob = MyContent('dilbert')
+  >>> ob = MyNewContent('dilbert')
   >>> folder._setObject('dilbert', ob)
   ObjectWillBeAddedEvent dilbert
   ObjectAddedEvent dilbert
@@ -389,7 +387,7 @@
   ObjectMovedEvent dilbert
   [{'new_id': 'dilbert', 'id': 'dilbert'}]
 
-And copy:
+And copy::
 
   >>> cp = folder.manage_copyObjects('dilbert')
   >>> folder.manage_pasteObjects(cp)
@@ -399,13 +397,13 @@
   FiveObjectClonedEvent copy_of_dilbert
   [{'new_id': 'copy_of_dilbert', 'id': 'dilbert'}]
 
-Then rename:
+Then rename::
 
   >>> folder.manage_renameObject('copy_of_dilbert', 'wally')
   ObjectWillBeMovedEvent copy_of_dilbert
   ObjectMovedEvent wally
 
-Or copy using manage_clone:
+Or copy using manage_clone::
 
   >>> res = folder.manage_clone(folder.dilbert, 'phb')
   ObjectCopiedEvent phb
@@ -415,9 +413,9 @@
   >>> res.getId()
   'phb'
 
-Also on a BTreeFolder:
+Also on a BTreeFolder::
 
-  >>> ob = MyContent('alice')
+  >>> ob = MyNewContent('alice')
   >>> btfolder._setObject('alice', ob)
   ObjectWillBeAddedEvent alice
   ObjectAddedEvent alice
@@ -429,21 +427,21 @@
   ObjectWillBeRemovedEvent rabbit
   ObjectRemovedEvent rabbit
 
-Now for a tree of objects. Let's create a simple one.
+Now for a tree of objects. Let's create a simple one::
 
-  >>> subfolder = MyFolder('subfolder')
+  >>> subfolder = MyNewFolder('subfolder')
   >>> folder._setObject('subfolder', subfolder)
   ObjectWillBeAddedEvent subfolder
   ObjectAddedEvent subfolder
   'subfolder'
   >>> subfolder = folder.subfolder
-  >>> ob = MyContent('mel')
+  >>> ob = MyNewContent('mel')
   >>> subfolder._setObject('mel', ob)
   ObjectWillBeAddedEvent mel
   ObjectAddedEvent mel
   'mel'
 
-Renaming a tree of objects.
+Renaming a tree of objects::
 
   >>> folder.manage_renameObject('subfolder', 'firefly')
   ObjectWillBeMovedEvent subfolder
@@ -451,7 +449,7 @@
   ObjectMovedEvent firefly
   ObjectMovedEvent mel
 
-Cloning a tree of objects:
+Cloning a tree of objects::
 
   >>> res = folder.manage_clone(folder.firefly, 'serenity')
   ObjectCopiedEvent serenity
@@ -464,7 +462,7 @@
   >>> res.getId()
   'serenity'
 
-OrderedFolder has the same renaming behavior than before:
+OrderedFolder has the same renaming behavior than before::
 
   >>> ofolder = MyOrderedFolder('ofolder')
   >>> app._setObject('ofolder', ofolder)
@@ -472,12 +470,12 @@
   ObjectAddedEvent ofolder
   old manage_afterAdd ofolder ofolder
   'ofolder'
-  >>> ob1 = MyContent('ob1')
+  >>> ob1 = MyNewContent('ob1')
   >>> ofolder._setObject('ob1', ob1)
   ObjectWillBeAddedEvent ob1
   ObjectAddedEvent ob1
   'ob1'
-  >>> ob2 = MyContent('ob2')
+  >>> ob2 = MyNewContent('ob2')
   >>> ofolder._setObject('ob2', ob2)
   ObjectWillBeAddedEvent ob2
   ObjectAddedEvent ob2
@@ -489,46 +487,7 @@
   ['ob4', 'ob2']
 
 
-Now cleanup all the monkey patches:
-
-  >>> undoMonkies()
-
-Phase 3
--------
-
-This is the target phase.
-
-  >>> doMonkies(transitional=False)
-
-By default, events are sent and manage_afterAdd is not called.
-
-  >>> ob = MyContent('droopy')
-  >>> folder._setObject('droopy', ob)
-  ObjectWillBeAddedEvent droopy
-  ObjectAddedEvent droopy
-  'droopy'
-  >>> folder.manage_delObjects('droopy')
-  ObjectWillBeRemovedEvent droopy
-  ObjectRemovedEvent droopy
-
-Old methods are called only for classes where we have specified that
-they are old.
-
-  >>> from Products.Five.eventconfigure import setDeprecatedManageAddDelete
-  >>> setDeprecatedManageAddDelete(MyContent)
-
-  >>> ob = MyContent('rantanplan')
-  >>> folder._setObject('rantanplan', ob)
-  ObjectWillBeAddedEvent rantanplan
-  ObjectAddedEvent rantanplan
-  old manage_afterAdd rantanplan rantanplan folder
-  'rantanplan'
-  >>> folder.manage_delObjects('rantanplan')
-  ObjectWillBeRemovedEvent rantanplan
-  old manage_beforeDelete rantanplan rantanplan folder
-  ObjectRemovedEvent rantanplan
-
-Now cleanup:
+Now cleanup all the monkey patches::
 
   >>> import transaction
   >>> transaction.abort()

Modified: z3/Five/trunk/tests/test_event.py
==============================================================================
--- z3/Five/trunk/tests/test_event.py	(original)
+++ z3/Five/trunk/tests/test_event.py	Mon Oct 31 02:44:26 2005
@@ -28,13 +28,15 @@
 from OFS.OrderedFolder import OrderedFolder
 from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2
 
-class NotifyBase(object):
+class DontComplain(object):
     def _verifyObjectPaste(self, object, validate_src=1):
         pass
     def cb_isMoveable(self):
         return True
     def cb_isCopyable(self):
         return True
+
+class NotifyBase(DontComplain):
     def manage_afterAdd(self, item, container):
         print 'old manage_afterAdd %s %s %s' % (self.getId(), item.getId(),
                                                 container.getId())
@@ -65,6 +67,15 @@
     def __init__(self, id):
         self._setId(id)
 
+# These don't have manage_beforeDelete & co methods
+
+class MyNewContent(DontComplain, SimpleItem):
+    def __init__(self, id):
+        self._setId(id)
+
+class MyNewFolder(DontComplain, Folder):
+    pass
+
 
 def test_suite():
     from Testing.ZopeTestCase import ZopeDocFileSuite


More information about the z3-checkins mailing list