[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