Log message for revision 97155:
  OFS.ObjectManager now fully implements the zope.container.IContainer 
interface and no longer just claims to do so. See the changelog for details and 
how backwards compatibility is handled.
  

Changed:
  U   Zope/trunk/doc/CHANGES.rst
  U   Zope/trunk/src/OFS/ObjectManager.py
  U   Zope/trunk/src/OFS/interfaces.py
  U   Zope/trunk/src/OFS/tests/testObjectManager.py

-=-
Modified: Zope/trunk/doc/CHANGES.rst
===================================================================
--- Zope/trunk/doc/CHANGES.rst  2009-02-23 12:24:48 UTC (rev 97154)
+++ Zope/trunk/doc/CHANGES.rst  2009-02-23 12:49:08 UTC (rev 97155)
@@ -114,7 +114,24 @@
 Features added
 ++++++++++++++
 
-- Acquisition has been made aware of __parent__ pointers. This allows
+- OFS.ObjectManager now fully implements the zope.container.IContainer
+  interface. For the last Zope2 releases it already claimed to implement the
+  interface, but didn't actually full-fill the interface contract. This means
+  you can start using more commonly used Python idioms to access objects inside
+  object managers. Complete dictionary-like access and container methods
+  including iteration are now supported. For each class derived from
+  ObjectManager you can use for any instance om: `om.keys()` instead of
+  `om.objectIds()`, `om.values()` instead of `om.objectValues()`, but also
+  `om.items()`, `ob.get('id')`, `ob['id']`, `'id' in om`, `iter(om)`,
+  `len(om)`, `om['id'] = object()` instead of `om._setObject('id', object())`
+  and `del ob['id']`. Should contained items of the object manager have ids
+  equal to any of the new method names, the objects will override the method,
+  as expected in Acquisition enabled types. Adding new objects into object
+  managers by those new names will no longer work, though. The added methods
+  call the already existing methods internally, so if a derived type overwrote
+  those, the new interface will provide the same functionality.
+
+- Acquisition has been made aware of `__parent__` pointers. This allows
   direct access to many Zope 3 classes without the need to mixin
   Acquisition base classes for the security to work.
 

Modified: Zope/trunk/src/OFS/ObjectManager.py
===================================================================
--- Zope/trunk/src/OFS/ObjectManager.py 2009-02-23 12:24:48 UTC (rev 97154)
+++ Zope/trunk/src/OFS/ObjectManager.py 2009-02-23 12:49:08 UTC (rev 97155)
@@ -54,7 +54,6 @@
 from zope.container.contained import ObjectAddedEvent
 from zope.container.contained import ObjectRemovedEvent
 from zope.container.contained import notifyContainerModified
-from zope.container.interfaces import IContainer
 
 from OFS.CopySupport import CopyContainer
 from OFS.interfaces import IObjectManager
@@ -156,7 +155,7 @@
     # The claim to implement IContainer has been made during the Zope3
     # integration project called Five but hasn't been completed in full.
 
-    implements(IObjectManager, IContainer)
+    implements(IObjectManager)
 
     security = ClassSecurityInfo()
     security.declareObjectProtected(access_contents_information)
@@ -765,6 +764,9 @@
                 break
         return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
 
+    def __delitem__(self, name):
+        return self.manage_delObjects(ids=[name])
+
     def __getitem__(self, key):
         v=self._getOb(key, None)
         if v is not None: return v
@@ -775,6 +777,34 @@
                 return NullResource(self, key, request).__of__(self)
         raise KeyError, key
 
+    def __setitem__(self, key, value):
+        return self._setObject(key, value)
+
+    def __contains__(self, name):
+        return name in self.objectIds()
+
+    def __iter__(self):
+        return iter(self.objectIds())
+
+    def __len__(self):
+        return len(self.objectIds())
+
+    security.declareProtected(access_contents_information, 'get')
+    def get(self, key, default=None):
+        return self._getOb(key, default)
+
+    security.declareProtected(access_contents_information, 'keys')
+    def keys(self):
+        return self.objectIds()
+
+    security.declareProtected(access_contents_information, 'get')
+    def items(self):
+        return self.objectItems()
+
+    security.declareProtected(access_contents_information, 'values')
+    def values(self):
+        return self.objectValues()
+
 # Don't InitializeClass, there is a specific __class_init__ on ObjectManager
 # InitializeClass(ObjectManager)
 

Modified: Zope/trunk/src/OFS/interfaces.py
===================================================================
--- Zope/trunk/src/OFS/interfaces.py    2009-02-23 12:24:48 UTC (rev 97154)
+++ Zope/trunk/src/OFS/interfaces.py    2009-02-23 12:49:08 UTC (rev 97155)
@@ -14,6 +14,7 @@
 
 $Id$
 """
+from zope.container.interfaces import IContainer
 from zope.interface import Attribute
 from zope.interface import Interface
 from zope.schema import Bool, BytesLine, Tuple
@@ -474,7 +475,7 @@
 #      based on OFS.ObjectManager.ObjectManager
 class IObjectManager(IZopeObject, ICopyContainer, INavigation, IManageable,
                      IAcquirer, IPersistent, IDAVCollection, ITraversable,
-                     IPossibleSite):
+                     IPossibleSite, IContainer):
     """Generic object manager
 
     This interface provides core behavior for collections of heterogeneous
@@ -582,11 +583,7 @@
         """
         """
 
-    def __getitem__(key):
-        """
-        """
 
-
 # XXX: might contain non-API methods and outdated comments;
 #      not synced with ZopeBook API Reference;
 #      based on OFS.FindSupport.FindSupport

Modified: Zope/trunk/src/OFS/tests/testObjectManager.py
===================================================================
--- Zope/trunk/src/OFS/tests/testObjectManager.py       2009-02-23 12:24:48 UTC 
(rev 97154)
+++ Zope/trunk/src/OFS/tests/testObjectManager.py       2009-02-23 12:49:08 UTC 
(rev 97155)
@@ -1,19 +1,22 @@
 import unittest
 
+from zope.app.testing.placelesssetup import PlacelessSetup
+
 from AccessControl.Owned import EmergencyUserCannotOwn
 from AccessControl.SecurityManagement import newSecurityManager
 from AccessControl.SecurityManagement import noSecurityManager
 from AccessControl.User import User # before SpecialUsers
 from AccessControl.SpecialUsers import emergency_user, nobody, system
+from Acquisition import aq_base
 from Acquisition import Implicit
 from App.config import getConfiguration
 from logging import getLogger
 from OFS.ObjectManager import ObjectManager
 from OFS.SimpleItem import SimpleItem
-from zope.app.testing.placelesssetup import PlacelessSetup
 import Products.Five
 from Products.Five import zcml
 from Products.Five.eventconfigure import setDeprecatedManageAddDelete
+from zExceptions import BadRequest
 
 logger = getLogger('OFS.subscribers')            
 
@@ -87,7 +90,6 @@
         return ObjectManagerWithIItem
 
     def _makeOne( self, *args, **kw ):
-
         return self._getTargetClass()( *args, **kw ).__of__( FauxRoot() )
 
     def test_z3interfaces(self):
@@ -98,175 +100,102 @@
         verifyClass(IObjectManager, ObjectManager)
 
     def test_setObject_set_owner_with_no_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, None )
-
         si = SimpleItem( 'no_user' )
-
         om._setObject( 'no_user', si )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_set_owner_with_emergency_user( self ):
         om = self._makeOne()
-
         newSecurityManager( None, emergency_user )
-
         si = SimpleItem( 'should_fail' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         self.assertRaises( EmergencyUserCannotOwn
                          , om._setObject, 'should_fail', si )
 
     def test_setObject_set_owner_with_system_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, system )
-
         si = SimpleItem( 'system' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'system', si )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_set_owner_with_anonymous_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, nobody )
-
         si = SimpleItem( 'anon' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'anon', si )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_set_owner_with_user( self ):
-
         om = self._makeOne()
-
         user = User( 'user', '123', (), () ).__of__( FauxRoot() )
-
         newSecurityManager( None, user )
-
         si = SimpleItem( 'user_creation' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'user_creation', si )
-
         self.assertEqual( si.__ac_local_roles__, { 'user': ['Owner'] } )
 
     def test_setObject_set_owner_with_faux_user( self ):
-
         om = self._makeOne()
-
         user = FauxUser( 'user_id', 'user_login' ).__of__( FauxRoot() )
-
         newSecurityManager( None, user )
-
         si = SimpleItem( 'faux_creation' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'faux_creation', si )
-
         self.assertEqual( si.__ac_local_roles__, { 'user_id': ['Owner'] } )
 
     def test_setObject_no_set_owner_with_no_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, None )
-
         si = SimpleItem( 'should_be_okay' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'should_be_okay', si, set_owner=0 )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_no_set_owner_with_emergency_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, emergency_user )
-
         si = SimpleItem( 'should_be_okay' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'should_be_okay', si, set_owner=0 )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_no_set_owner_with_system_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, system )
-
         si = SimpleItem( 'should_be_okay' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'should_be_okay', si, set_owner=0 )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_no_set_owner_with_anonymous_user( self ):
-
         om = self._makeOne()
-
         newSecurityManager( None, nobody )
-
         si = SimpleItem( 'should_be_okay' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'should_be_okay', si, set_owner=0 )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_no_set_owner_with_user( self ):
-
         om = self._makeOne()
-
         user = User( 'user', '123', (), () ).__of__( FauxRoot() )
-
         newSecurityManager( None, user )
-
         si = SimpleItem( 'should_be_okay' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'should_be_okay', si, set_owner=0 )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_setObject_no_set_owner_with_faux_user( self ):
-
         om = self._makeOne()
-
         user = FauxUser( 'user_id', 'user_login' ).__of__( FauxRoot() )
-
         newSecurityManager( None, user )
-
         si = SimpleItem( 'should_be_okay' )
-
         self.assertEqual( si.__ac_local_roles__, None )
-
         om._setObject( 'should_be_okay', si, set_owner=0 )
-
         self.assertEqual( si.__ac_local_roles__, None )
 
     def test_delObject_before_delete(self):
@@ -382,7 +311,6 @@
         om._setObject('.bashrc', si)
 
     def test_setObject_checkId_bad(self):
-        from zExceptions import BadRequest
         om = self._makeOne()
         si = SimpleItem('111')
         om._setObject('111', si)
@@ -401,6 +329,116 @@
         self.assertRaises(BadRequest, om._setObject, 'REQUEST', si)
         self.assertRaises(BadRequest, om._setObject, '/', si)
 
+    def test_getsetitem(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        si2 = SimpleItem('2')
+        om['1'] = si1
+        self.failUnless('1' in om)
+        self.failUnless(si1 in om.objectValues())
+        self.failUnless('1' in om.objectIds())
+        om['2'] = si2
+        self.failUnless('2' in om)
+        self.failUnless(si2 in om.objectValues())
+        self.failUnless('2' in om.objectIds())
+        self.assertRaises(BadRequest, om._setObject, '1', si2)
+        self.assertRaises(BadRequest, om.__setitem__, '1', si2)
+
+    def test_delitem(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        si2 = SimpleItem('2')
+        om['1'] = si1
+        om['2'] = si2
+        self.failUnless('1' in om)
+        self.failUnless('2' in om)
+        del om['1']
+        self.failIf('1' in om)
+        self.failUnless('2' in om)
+        om._delObject('2')
+        self.failIf('2' in om)
+
+    def test_iterator(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        si2 = SimpleItem('2')
+        om['1'] = si1
+        om['2'] = si2
+        iterator = iter(om)
+        self.failUnless(hasattr(iterator, '__iter__'))
+        self.failUnless(hasattr(iterator, 'next'))
+        result = [i for i in iterator]
+        self.failUnless('1' in result)
+        self.failUnless('2' in result)
+
+    def test_len(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        si2 = SimpleItem('2')
+        om['1'] = si1
+        om['2'] = si2
+        self.failUnless(len(om) == 2)
+
+    def test_get(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        self.assertRaises(BadRequest, om.__setitem__, 'get', si1)
+        om['1'] = si1
+        self.failUnless(om.get('1') == si1)
+        # A contained item overwrites the method
+        self.failUnless(hasattr(om.get, 'im_func'))
+        om.__dict__['get'] = si1
+        self.failUnless(aq_base(om.get) is si1)
+        self.failUnless(aq_base(om['get']) is si1)
+        # Once the object is gone, the method is back
+        del om['get']
+        self.failUnless(hasattr(om.get, 'im_func'))
+
+    def test_items(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        self.assertRaises(BadRequest, om.__setitem__, 'items', si1)
+        om['1'] = si1
+        self.failUnless(('1', si1) in om.items())
+        # A contained item overwrites the method
+        self.failUnless(hasattr(om.items, 'im_func'))
+        om.__dict__['items'] = si1
+        self.failUnless(aq_base(om.items) is si1)
+        self.failUnless(aq_base(om['items']) is si1)
+        # Once the object is gone, the method is back
+        del om['items']
+        self.failUnless(hasattr(om.items, 'im_func'))
+
+    def test_keys(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        self.assertRaises(BadRequest, om.__setitem__, 'keys', si1)
+        om['1'] = si1
+        self.failUnless('1' in om.keys())
+        # A contained item overwrites the method
+        self.failUnless(hasattr(om.keys, 'im_func'))
+        om.__dict__['keys'] = si1
+        self.failUnless(aq_base(om.keys) is si1)
+        self.failUnless(aq_base(om['keys']) is si1)
+        # Once the object is gone, the method is back
+        del om['keys']
+        self.failUnless(hasattr(om.keys, 'im_func'))
+
+    def test_values(self):
+        om = self._makeOne()
+        si1 = SimpleItem('1')
+        self.assertRaises(BadRequest, om.__setitem__, 'values', si1)
+        om['1'] = si1
+        self.failUnless(si1 in om.values())
+        # A contained item overwrites the method
+        self.failUnless(hasattr(om.values, 'im_func'))
+        om.__dict__['values'] = si1
+        self.failUnless(aq_base(om.values) is si1)
+        self.failUnless(aq_base(om['values']) is si1)
+        # Once the object is gone, the method is back
+        del om['values']
+        self.failUnless(hasattr(om.values, 'im_func'))
+
     def test_list_imports(self):
         om = self._makeOne()
         # This must work whether we've done "make instance" or not.

_______________________________________________
Zope-Checkins maillist  -  Zope-Checkins@zope.org
http://mail.zope.org/mailman/listinfo/zope-checkins

Reply via email to