[CMF-checkins] SVN: CMF/trunk/CMFUid/ - Forward-port CMFUid changes
from the 2.1-branch:
Jens Vagelpohl
jens at dataflake.org
Mon Apr 2 04:31:27 EDT 2007
Log message for revision 73977:
- Forward-port CMFUid changes from the 2.1-branch:
- CMFUid.UniqueIdAnnotationTool: Annotation handling has been switched
from triggering it through old-style manage_*-methods to using
events. UID assigning behavior has been made more flexible. Please
review CMFUid/README.txt for information about the current
behavior and the new features.
(http://www.zope.org/Collectors/CMF/474)
Changed:
U CMF/trunk/CMFUid/README.txt
U CMF/trunk/CMFUid/UniqueIdAnnotationTool.py
U CMF/trunk/CMFUid/configure.zcml
A CMF/trunk/CMFUid/event.zcml
U CMF/trunk/CMFUid/interfaces.py
A CMF/trunk/CMFUid/profiles/default/catalog.xml
U CMF/trunk/CMFUid/profiles/default/componentregistry.xml
A CMF/trunk/CMFUid/testing.py
U CMF/trunk/CMFUid/tests/test_uidannotation.py
-=-
Modified: CMF/trunk/CMFUid/README.txt
===================================================================
--- CMF/trunk/CMFUid/README.txt 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/README.txt 2007-04-02 08:31:27 UTC (rev 73977)
@@ -15,7 +15,8 @@
The 'portal_uidgenerator' tools responsibility is to generate
unique ids. The 'portal_uidannotation' tool is responsible to
- attach unique ids to a content object. The 'portal_uidhandler'
+ attach unique ids to a content object, and enforce rules about
+ what happens on object move/create/delete. The 'portal_uidhandler'
manages registering and accessing unique ids.
This design was chosen to allow users replacing only parts of
@@ -40,7 +41,14 @@
The current implementation of get/queryBrain and get/queryObject
do not return invisible objects (and brains of invisible objects).
+ By invisible objects, we mean objects that would be filtered out
+ by portal_catalog.searchResults due to expiry/effective date and/or
+ user roles.
+ It is often necessary to avoid this filtering in an application.
+ To do this, use the unrestrictedGet/QueryBrain and
+ unrestrictedGet/QueryObject as this will avoid 'None' results.
+
Have a look at the interfaces.
CMFUid's functionality is used by CMFDefault's favorite content type
@@ -50,3 +58,43 @@
See 'CMFDefault.Favorite.Favorite'.
gregweb/2004-08-05
+
+UPDATE 2007-03-30
+=================
+
+The annotation code has been updated to use events for assigning/removing
+uids. The settings for this live in the portal_uidannotation tool.
+
+The default behaviour is:
+
+ - uids are NOT assigned when an object is created
+ (it is assumed that other code is responsible for this)
+
+ - when an object is moved, a UID is not changed
+
+ - when an object is imported, any EXISTING UID is removed
+ (this can be controlled via the 'remove_on_add' property)
+
+ - when an object is copied, any EXISTING UID is removed
+ (this can be controlled via the 'remove_on_clone' property)
+
+A more natural behaviour is for UIDs to be assigned automatically on
+creation. To enable this feature:
+
+ - tick the 'assign UIDs on add' tickbox
+ (uids will now be assigned when content is added or imported and any
+ EXISTING uid will be replaced)
+
+ - tick the 'assign UIDs on copy' tickbox
+ (objects will get a NEW uid when they are copied which will replace
+ any EXISTING uid)
+
+In order to preserve the original behaviour of the tool, automatic
+assignment of uids is NOT enabled by default - it must be turned on in
+the uidannotation tool.
+
+The behaviour is hooked in based on object creating/deletion/move events
+for any IContentish objects. The event handlers live in the
+UniqueIdAnnotation tool.
+
+
Modified: CMF/trunk/CMFUid/UniqueIdAnnotationTool.py
===================================================================
--- CMF/trunk/CMFUid/UniqueIdAnnotationTool.py 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/UniqueIdAnnotationTool.py 2007-04-02 08:31:27 UTC (rev 73977)
@@ -24,16 +24,20 @@
from Globals import Persistent
from OFS.PropertyManager import PropertyManager
from OFS.SimpleItem import SimpleItem
-from zope.component import getUtility
+from zope.component import queryUtility
from zope.interface import implements
from Products.CMFCore.ActionProviderBase import ActionProviderBase
from Products.CMFCore.utils import registerToolInterface
from Products.CMFCore.utils import UniqueObject
+from Products.CMFUid.interfaces import IUniqueIdHandler
from Products.CMFUid.interfaces import IUniqueIdAnnotation
from Products.CMFUid.interfaces import IUniqueIdAnnotationManagement
+from Products.CMFUid.interfaces import UniqueIdError
+from OFS.interfaces import IObjectClonedEvent
+from zope.app.container.interfaces import IObjectAddedEvent
class UniqueIdAnnotation(Persistent, Implicit):
@@ -64,50 +68,47 @@
"""
self._uid = uid
- def manage_afterClone(self, item):
- """See IUniqueIdAnnotation.
- """
- # Duplicated unique ids on the copied object have to be avoided.
- # the uid object may already be removed by the 'manage_afterAdd'.
- # To be independent of the implementation of 'manage_afterAdd'
- # the unique id object probably gets removed another time.
- anno_tool = getUtility(IUniqueIdAnnotationManagement)
- if anno_tool.remove_on_clone:
- try:
- delattr( aq_parent( aq_inner(self) ), self.id )
- except (KeyError, AttributeError):
- pass
+InitializeClass(UniqueIdAnnotation)
- def manage_beforeDelete(self, item, container):
- """See IUniqueIdAnnotation.
- """
- # This helps in distinguishing renaming from copying/adding and
- # importing in 'manage_afterAdd' (see below)
- anno_tool = getUtility(IUniqueIdAnnotationManagement)
- if anno_tool.remove_on_add:
- self._cmf_uid_is_rename = True
+def handleUidAnnotationEvent(ob, event):
+ """ Event subscriber for (IUniqueIdAnnotation, IObjectEvent) events
+ """
- def manage_afterAdd(self, item, container):
- """See IUniqueIdAnnotation.
- """
- # 'is_rename' is set if deletion was caused by a rename/move.
- # The unique id is deleted only if the call is not part of
- # a rename operation.
- # This way I the unique id gets deleted on imports.
- _is_rename = getattr(aq_base(self), '_cmf_uid_is_rename', None)
- anno_tool = getUtility(IUniqueIdAnnotationManagement)
- if anno_tool.remove_on_add and anno_tool.remove_on_clone \
- and not _is_rename:
- try:
- delattr( aq_parent( aq_inner(self) ), self.id )
- except (KeyError, AttributeError):
- pass
- if _is_rename is not None:
- del self._cmf_uid_is_rename
+ if IObjectAddedEvent.providedBy(event):
+ if event.newParent is not None:
+ anno_tool = queryUtility(IUniqueIdAnnotationManagement)
+ uid_handler = queryUtility(IUniqueIdHandler)
+ if anno_tool is not None:
+ remove_on_add = anno_tool.getProperty('remove_on_add',False)
+ remove_on_clone = anno_tool.getProperty('remove_on_clone',False)
+ assign_on_add = anno_tool.getProperty('assign_on_add',False)
-InitializeClass(UniqueIdAnnotation)
-
-
+ if (remove_on_add and remove_on_clone) or assign_on_add:
+ try:
+ uid_handler.unregister(ob)
+ except UniqueIdError:
+ # did not have one
+ pass
+ if assign_on_add:
+ # assign new uid
+ uid_handler.register(ob)
+
+ elif IObjectClonedEvent.providedBy(event):
+ anno_tool = queryUtility(IUniqueIdAnnotationManagement)
+ uid_handler = queryUtility(IUniqueIdHandler)
+ if anno_tool is not None:
+ remove_on_clone = anno_tool.getProperty('remove_on_clone', False)
+ assign_on_clone = anno_tool.getProperty('assign_on_clone', False)
+ if remove_on_clone or assign_on_clone:
+ try:
+ uid_handler.unregister(ob)
+ except UniqueIdError:
+ # did not have one
+ pass
+ if assign_on_clone:
+ # assign new uid
+ uid_handler.register(ob)
+
class UniqueIdAnnotationTool(UniqueObject, SimpleItem, PropertyManager,
ActionProviderBase):
@@ -129,11 +130,17 @@
remove_on_add = True
remove_on_clone = True
+ assign_on_add = False
+ assign_on_clone = False
_properties = (
{'id': 'remove_on_add', 'type': 'boolean', 'mode': 'w',
'label': "Remove the objects unique id on add (and import)"},
{'id': 'remove_on_clone', 'type': 'boolean', 'mode': 'w',
'label': 'Remove the objects unique id on clone (CAUTION !!!)'},
+ {'id': 'assign_on_add', 'type': 'boolean', 'mode': 'w',
+ 'label': "Assign a unique ID when an object is added"},
+ {'id': 'assign_on_clone', 'type': 'boolean', 'mode': 'w',
+ 'label': "Assign a unique ID when an object is cloned"},
)
security.declarePrivate('__call__')
Modified: CMF/trunk/CMFUid/configure.zcml
===================================================================
--- CMF/trunk/CMFUid/configure.zcml 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/configure.zcml 2007-04-02 08:31:27 UTC (rev 73977)
@@ -3,6 +3,8 @@
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
i18n_domain="cmf_default">
+ <include file="event.zcml" />
+
<!-- profiles -->
<genericsetup:registerProfile
Added: CMF/trunk/CMFUid/event.zcml
===================================================================
--- CMF/trunk/CMFUid/event.zcml 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/event.zcml 2007-04-02 08:31:27 UTC (rev 73977)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope">
+
+ <subscriber
+ for="Products.CMFCore.interfaces.IContentish
+ zope.component.interfaces.IObjectEvent"
+ handler=".UniqueIdAnnotationTool.handleUidAnnotationEvent"
+ />
+
+</configure>
Property changes on: CMF/trunk/CMFUid/event.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: CMF/trunk/CMFUid/interfaces.py
===================================================================
--- CMF/trunk/CMFUid/interfaces.py 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/interfaces.py 2007-04-02 08:31:27 UTC (rev 73977)
@@ -60,7 +60,7 @@
"""
-class IUniqueIdAnnotation(ICallableOpaqueItem, ICallableOpaqueItemEvents):
+class IUniqueIdAnnotation(ICallableOpaqueItem):
"""Opaque unique id item handling adding, copying, and deletion events.
"""
Added: CMF/trunk/CMFUid/profiles/default/catalog.xml
===================================================================
--- CMF/trunk/CMFUid/profiles/default/catalog.xml 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/profiles/default/catalog.xml 2007-04-02 08:31:27 UTC (rev 73977)
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<object name="portal_catalog" meta_type="CMF Catalog">
+ <index name="cmf_uid" meta_type="FieldIndex">
+ <indexed_attr value="cmf_uid"/>
+ </index>
+ <column value="cmf_uid"/>
+</object>
Property changes on: CMF/trunk/CMFUid/profiles/default/catalog.xml
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: CMF/trunk/CMFUid/profiles/default/componentregistry.xml
===================================================================
--- CMF/trunk/CMFUid/profiles/default/componentregistry.xml 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/profiles/default/componentregistry.xml 2007-04-02 08:31:27 UTC (rev 73977)
@@ -3,13 +3,13 @@
<adapters/>
<utilities>
<utility
- interface="Products.CMFUid.interfaces.IUniqueIdAnnotationManagement"
- object="/portal_uidannotation"/>
- <utility
interface="Products.CMFUid.interfaces.IUniqueIdGenerator"
object="/portal_uidgenerator"/>
<utility
interface="Products.CMFUid.interfaces.IUniqueIdHandler"
object="/portal_uidhandler"/>
+ <utility
+ interface="Products.CMFUid.interfaces.IUniqueIdAnnotationManagement"
+ object="/portal_uidannotation"/>
</utilities>
</componentregistry>
Added: CMF/trunk/CMFUid/testing.py
===================================================================
--- CMF/trunk/CMFUid/testing.py 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/testing.py 2007-04-02 08:31:27 UTC (rev 73977)
@@ -0,0 +1,19 @@
+from zope.app.component.hooks import setHooks
+from zope.testing.cleanup import cleanUp
+from Products.Five import zcml
+
+class UidEventZCMLLayer:
+
+ @classmethod
+ def testSetUp(cls):
+ import Products
+
+ zcml.load_config('meta.zcml', Products.Five)
+ zcml.load_config('event.zcml', Products.Five)
+ zcml.load_config('event.zcml', Products.CMFUid)
+ setHooks()
+
+ @classmethod
+ def testTearDown(cls):
+ cleanUp()
+
Property changes on: CMF/trunk/CMFUid/testing.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: CMF/trunk/CMFUid/tests/test_uidannotation.py
===================================================================
--- CMF/trunk/CMFUid/tests/test_uidannotation.py 2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/tests/test_uidannotation.py 2007-04-02 08:31:27 UTC (rev 73977)
@@ -18,25 +18,55 @@
import unittest
import Testing
-from OFS.event import ObjectClonedEvent
+from Acquisition import Implicit
-from zope.app.container.contained import ObjectAddedEvent
from zope.component import getSiteManager
-from zope.event import notify
+from zope.component import getUtility
from zope.interface.verify import verifyClass
+from zope.interface import implements
from Products.CMFCore.PortalFolder import PortalFolder
-from Products.CMFCore.testing import EventZCMLLayer
+from Products.CMFUid.testing import UidEventZCMLLayer
from Products.CMFCore.tests.base.dummy import DummyContent
from Products.CMFCore.tests.base.testcase import SecurityTest
from Products.CMFUid.interfaces import IUniqueIdAnnotationManagement
+from Products.CMFUid.interfaces import IUniqueIdHandler
+from Products.CMFUid.interfaces import UniqueIdError
+from Products.CMFCore.tests.test_PortalFolder import _AllowedUser
+from Products.CMFCore.tests.test_PortalFolder import _SensitiveSecurityPolicy
+from AccessControl.SecurityManagement import newSecurityManager
+from Products.CMFCore.tests.test_CMFCatalogAware import TheClass
+from Products.CMFCore.tests.test_CMFCatalogAware import SimpleFolder
+
+import transaction
+
UID_ATTRNAME = 'cmf_uid'
+class DummyUniqueIdHandlerTool(Implicit):
+ implements(IUniqueIdHandler)
+
+ def __init__(self):
+ self.counter = 0
+
+ def register(self, ob):
+
+ uid_assigner = getUtility(IUniqueIdAnnotationManagement)
+ annotation = uid_assigner(ob, UID_ATTRNAME)
+ annotation.setUid( self.counter )
+ self.counter += 1
+
+ def unregister(self, ob):
+
+ try:
+ delattr(ob, UID_ATTRNAME)
+ except AttributeError:
+ raise UniqueIdError
+
class UniqueIdAnnotationToolTests(SecurityTest):
- layer = EventZCMLLayer
+ layer = UidEventZCMLLayer
def _getTargetClass(self):
from Products.CMFUid.UniqueIdAnnotationTool \
@@ -47,13 +77,44 @@
def setUp(self):
SecurityTest.setUp(self)
self.root._setObject('portal_uidannotation', self._getTargetClass()())
- self.root._setObject('dummy', DummyContent(id='dummy'))
+ self.root._setObject('portal_uidhandler', DummyUniqueIdHandlerTool())
sm = getSiteManager()
sm.registerUtility( self.root.portal_uidannotation
, IUniqueIdAnnotationManagement
)
+ sm.registerUtility( self.root.portal_uidhandler
+ , IUniqueIdHandler)
+ self.root._setObject('dummy', DummyContent(id='dummy'))
+ self.root._setObject('site', SimpleFolder('site'))
+
+ transaction.savepoint(optimistic=True)
+
+ def _initPolicyAndUser( self
+ , a_lambda=None
+ , v_lambda=None
+ , c_lambda=None
+ ):
+ from AccessControl import SecurityManager
+
+ def _promiscuous( *args, **kw ):
+ return 1
+
+ if a_lambda is None:
+ a_lambda = _promiscuous
+
+ if v_lambda is None:
+ v_lambda = _promiscuous
+
+ if c_lambda is None:
+ c_lambda = _promiscuous
+
+ scp = _SensitiveSecurityPolicy( v_lambda, c_lambda )
+ SecurityManager.setSecurityPolicy( scp )
+ newSecurityManager( None
+ , _AllowedUser(a_lambda).__of__(self.app.acl_users))
+
def test_interfaces(self):
from Products.CMFUid.interfaces import IUniqueIdAnnotation
from Products.CMFUid.interfaces import IUniqueIdAnnotationManagement
@@ -84,70 +145,139 @@
# obj.manage_afterAdd(obj_at_target, obj_at_target, target_folder)
# obj.manage_afterClone(obj_at_target, obj_at_target)
+ def test_simulateItemAddAssigningUid(self):
+ # an annotated object is set in place
+ dummy = DummyContent(id='dummycontent')
+ self.root.portal_uidannotation.assign_on_add = True
+ self.root._setObject('dummycontent', dummy)
+
+ annotation = getattr(dummy, UID_ATTRNAME, None)
+
+ self.failUnless(annotation is not None)
+
def test_simulateItemAddRemovingUid(self):
- dummy = self.root.dummy
+ # an annotated object is set in place
+ dummy = DummyContent(id='dummycontent')
annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+ self.root._setObject('dummycontent', dummy)
- annotation.__of__(dummy).manage_afterAdd(dummy, None)
self.assertRaises(AttributeError, getattr, dummy, UID_ATTRNAME)
+ def test_simulateItemAddAssignsNewUid(self):
+ # an annotated object is set in place
+ dummy = DummyContent(id='dummycontent')
+ annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+ self.root.portal_uidannotation.assign_on_add = True
+ self.root._setObject('dummycontent', dummy)
+
+ self.failIf( getattr(dummy, UID_ATTRNAME)()==annotation() )
+
def test_simulateItemAddDoesNotTouchUid(self):
- dummy = self.root.dummy
+ # an annotated object is set in place
+ dummy = DummyContent(id='dummycontent')
annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+ self.root.portal_uidannotation.remove_on_add = False
+ self.root._setObject('dummycontent', dummy)
- self.root.portal_uidannotation.remove_on_add = False
- annotation.__of__(dummy).manage_afterAdd(dummy, None)
self.assertEqual(getattr(dummy, UID_ATTRNAME), annotation)
def test_simulateItemRename(self):
- dummy = self.root.dummy
+ # an object is set in place, annotated and then renamed
+ self._initPolicyAndUser() # allow copy/paste operations
+ dummy = TheClass('dummy')
+ site = self.root.site
+ site._setObject('dummy', dummy)
annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
- annotation.__of__(dummy).manage_beforeDelete(dummy, None)
- annotation.__of__(dummy).manage_afterAdd(dummy, None)
- self.assertEqual(getattr(dummy, UID_ATTRNAME), annotation)
+ transaction.savepoint(optimistic=True)
+ site.manage_renameObject(id='dummy', new_id='dummy2')
+ new_annotation = getattr(site.dummy2, UID_ATTRNAME)
+ self.assertEqual(annotation(), new_annotation())
+
def test_simulateItemCloneRemovingUid1(self):
- dummy = self.root.dummy
+ # an object is set in place, annotated and then copied
+ self._initPolicyAndUser() # allow copy/paste operations
+ dummy = TheClass('dummy')
+ site = self.root.site
+ site._setObject('dummy', dummy)
annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+ self.root._setObject('folder1', SimpleFolder('folder1'))
- annotation.__of__(dummy).manage_afterAdd(dummy, None)
- annotation.__of__(dummy).manage_afterClone(dummy)
- self.assertRaises(AttributeError, getattr, dummy, UID_ATTRNAME)
+ transaction.savepoint(optimistic=True)
+ cookie = site.manage_copyObjects(ids=['dummy'])
+ self.root.folder1.manage_pasteObjects( cookie )
+ self.assertRaises(AttributeError, getattr, self.root.folder1.dummy, UID_ATTRNAME)
+
def test_simulateItemCloneRemovingUid2(self):
- dummy = self.root.dummy
+ # an object is set in place, annotated and then copied
+ self._initPolicyAndUser() # allow copy/paste operations
+ dummy = TheClass('dummy')
+ site = self.root.site
+ site._setObject('dummy', dummy)
annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
-
self.root.portal_uidannotation.remove_on_add = False
- annotation.__of__(dummy).manage_afterAdd(dummy, None)
- annotation.__of__(dummy).manage_afterClone(dummy)
- self.assertRaises(AttributeError, getattr, dummy, UID_ATTRNAME)
+ self.root._setObject('folder1', SimpleFolder('folder1'))
+ transaction.savepoint(optimistic=True)
+ cookie = site.manage_copyObjects(ids=['dummy'])
+ self.root.folder1.manage_pasteObjects( cookie )
+
+ self.assertRaises(AttributeError, getattr, self.root.folder1.dummy, UID_ATTRNAME)
+
def test_simulateItemCloneDoesNotTouchUid(self):
- dummy = self.root.dummy
+ # an object is set in place, annotated, and then copied
+ self._initPolicyAndUser() # allow copy/paste operations
+ dummy = TheClass('dummy')
+ site = self.root.site
+ site._setObject('dummy', dummy)
annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
-
self.root.portal_uidannotation.remove_on_clone = False
- annotation.__of__(dummy).manage_afterAdd(dummy, None)
- annotation.__of__(dummy).manage_afterClone(dummy)
- self.assertEqual(getattr(dummy, UID_ATTRNAME), annotation)
+ self.root._setObject('folder1', SimpleFolder('folder1'))
+ transaction.savepoint(optimistic=True)
+ cookie = site.manage_copyObjects(ids=['dummy'])
+ self.root.folder1.manage_pasteObjects( cookie )
+ new_annotation = getattr(self.root.folder1.dummy, UID_ATTRNAME)
+
+ self.assertEqual(annotation(), new_annotation() )
+
+ def test_simulateItemCloneAssignsNewUid(self):
+ # an object is set in place, annotated, and then copied
+ self._initPolicyAndUser() # allow copy/paste operations
+ dummy = TheClass('dummy')
+ site = self.root.site
+ site._setObject('dummy', dummy)
+ annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+ self.root.portal_uidannotation.assign_on_clone = True
+ self.root._setObject('folder1', SimpleFolder('folder1'))
+
+ transaction.savepoint(optimistic=True)
+ cookie = site.manage_copyObjects(ids=['dummy'])
+ self.root.folder1.manage_pasteObjects( cookie )
+ new_annotation = getattr(self.root.folder1.dummy, UID_ATTRNAME)
+
+ self.failIf( annotation() == new_annotation() )
+
def test_simulateNestedFolderCloneRemovingUid1(self):
- self.root._setObject( 'foo', PortalFolder(id='foo') )
- foo = self.root.foo
- foo._setObject( 'sub1', PortalFolder(id='sub1') )
- foo.sub1._setObject( 'sub2', PortalFolder(id='sub2') )
+ self.root.site._setObject( 'foo', SimpleFolder(id='foo') )
+ self.root.site._setObject( 'foo2', SimpleFolder(id='foo2') )
+ foo = self.root.site.foo
+ foo._setObject( 'sub1', SimpleFolder(id='sub1') )
+ foo.sub1._setObject( 'sub2', SimpleFolder(id='sub2') )
foo.sub1.sub2._setObject( 'baz', DummyContent(id='baz', catalog=1) )
baz = foo.sub1.sub2.baz
annotation = self.root.portal_uidannotation(baz, UID_ATTRNAME)
self.assertEqual( getattr(baz, UID_ATTRNAME), annotation )
- notify(ObjectAddedEvent(foo, foo))
- notify(ObjectClonedEvent(foo))
- self.assertRaises(AttributeError, getattr, baz, UID_ATTRNAME)
+ transaction.savepoint(optimistic=True)
+ cookie = self.root.site.manage_copyObjects(ids='foo')
+ self.root.site.foo2.manage_pasteObjects(cookie)
+ self.assertRaises(AttributeError, getattr, self.root.site.foo2.foo.sub1.sub2.baz, UID_ATTRNAME)
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(UniqueIdAnnotationToolTests),
More information about the CMF-checkins
mailing list