[Zope-Checkins] SVN: Zope/trunk/ 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.

Hanno Schlichting plone at hannosch.info
Mon Feb 23 07:49:08 EST 2009


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.



More information about the Zope-Checkins mailing list