[Checkins] SVN: zope.app.form/trunk/ Went for a different strategy to fix bug #98278: use an event from the object

Christian Theune ct at gocept.com
Sun Jul 8 11:23:47 EDT 2007


Log message for revision 77626:
  Went for a different strategy to fix bug #98278: use an event from the object
  field to establish location
  --This line, and those below, will be ignored--
  
  M    CHANGES.txt
  M    src/zope/app/form/browser/configure.zcml
  M    src/zope/app/form/browser/objectwidget.txt
  M    src/zope/app/form/browser/objectwidget.py
  M    src/zope/app/form/browser/ftests/test_objectwidget.py
  M    setup.py
  

Changed:
  U   zope.app.form/trunk/CHANGES.txt
  U   zope.app.form/trunk/setup.py
  U   zope.app.form/trunk/src/zope/app/form/browser/configure.zcml
  U   zope.app.form/trunk/src/zope/app/form/browser/ftests/test_objectwidget.py
  U   zope.app.form/trunk/src/zope/app/form/browser/objectwidget.py
  U   zope.app.form/trunk/src/zope/app/form/browser/objectwidget.txt

-=-
Modified: zope.app.form/trunk/CHANGES.txt
===================================================================
--- zope.app.form/trunk/CHANGES.txt	2007-07-08 15:04:50 UTC (rev 77625)
+++ zope.app.form/trunk/CHANGES.txt	2007-07-08 15:23:47 UTC (rev 77626)
@@ -5,8 +5,8 @@
 After 3.4.0b1
 =============
 
- - Made the object widget set up location for objects that are instanciated by
-   the object widget itself. (#98287)
+ - Provide a subscriber for the object field that sets up location information
+   when an object is set. (#98287)
 
 
 Before 3.4

Modified: zope.app.form/trunk/setup.py
===================================================================
--- zope.app.form/trunk/setup.py	2007-07-08 15:04:50 UTC (rev 77625)
+++ zope.app.form/trunk/setup.py	2007-07-08 15:23:47 UTC (rev 77626)
@@ -25,7 +25,7 @@
           "zope.interface",
           "zope.proxy",
           "zope.publisher",
-          "zope.schema",
+          "zope.schema>=3.4.0b1dev-r77624",
           "zope.security",
           "zope.app.basicskin",
           "zope.location>=3.4.0a1-1",

Modified: zope.app.form/trunk/src/zope/app/form/browser/configure.zcml
===================================================================
--- zope.app.form/trunk/src/zope/app/form/browser/configure.zcml	2007-07-08 15:04:50 UTC (rev 77625)
+++ zope.app.form/trunk/src/zope/app/form/browser/configure.zcml	2007-07-08 15:23:47 UTC (rev 77626)
@@ -584,6 +584,8 @@
       permission="zope.Public"
       />
 
+  <subscriber handler=".objectwidget.setup_object_location" />
+
   <!-- Register the form documentation with the apidoc tool -->
   <configure
       xmlns:apidoc="http://namespaces.zope.org/apidoc"

Modified: zope.app.form/trunk/src/zope/app/form/browser/ftests/test_objectwidget.py
===================================================================
--- zope.app.form/trunk/src/zope/app/form/browser/ftests/test_objectwidget.py	2007-07-08 15:04:50 UTC (rev 77625)
+++ zope.app.form/trunk/src/zope/app/form/browser/ftests/test_objectwidget.py	2007-07-08 15:23:47 UTC (rev 77626)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# Copyright (c) 2001-2007 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -21,20 +21,25 @@
 from zope.publisher.browser import TestRequest
 from zope.schema import Object, TextLine
 import zope.security.checker
+import zope.location.location
+
 from zope.app.form.browser import ObjectWidget
 from zope.app.testing.functional import BrowserTestCase
 from zope.app.form.browser.tests import support
 from zope.app.form.testing import AppFormLayer
 
+
 class ITestContact(Interface):
     name = TextLine()
     email = TextLine()
-    
+
+
 class TestContact(object):
     implements(ITestContact)
 
+
 class Test(BrowserTestCase, support.VerifyResults):
-    
+
     def setUp(self):
         BrowserTestCase.setUp(self)
         self.field = Object(ITestContact, __name__=u'foo')
@@ -66,6 +71,38 @@
         )
         self.verifyResult(widget(), check_list)
 
+    def test_location(self):
+        # Objects that are managed through an object field are automatically.
+        # This is done to make objects created through sub-forms compatible
+        # with the Zope security policy which bases it's decisions on the
+        # location of objects.
+        context = zope.location.location.Location()
+        value = TestContact()
+        field = zope.schema.Object(Interface,
+                                   __name__='test_object')
+        field.set(context, value)
+
+        self.assertEquals(context, context.test_object.__parent__)
+        self.assertEquals('test_object', context.test_object.__name__)
+
+    def test_location_wrapper(self):
+        # Objects that do not implement the ILocation interface will be
+        # wrapped with a location proxy.
+        class Dummy(object):
+            pass
+        context = Dummy()
+        value = TestContact()
+        field = zope.schema.Object(Interface,
+                                   __name__='test_object')
+        field.set(context, value)
+
+        self.failIf(zope.location.interfaces.ILocation.providedBy(value))
+        self.failUnless(zope.location.interfaces.ILocation.providedBy(
+            context.test_object))
+        self.assertEquals(context, context.test_object.__parent__)
+        self.assertEquals('test_object', context.test_object.__name__)
+
+
 def test_suite():
     suite = unittest.TestSuite()
     Test.layer = AppFormLayer
@@ -74,6 +111,3 @@
 
 if __name__=='__main__':
     unittest.main(defaultTest='test_suite')
-
-
-

Modified: zope.app.form/trunk/src/zope/app/form/browser/objectwidget.py
===================================================================
--- zope.app.form/trunk/src/zope/app/form/browser/objectwidget.py	2007-07-08 15:04:50 UTC (rev 77625)
+++ zope.app.form/trunk/src/zope/app/form/browser/objectwidget.py	2007-07-08 15:23:47 UTC (rev 77626)
@@ -141,7 +141,7 @@
                 errors.append(e)
                 if self._error is None:
                     self._error = {}
-                
+
                 if name not in self._error:
                     self._error[name] = e
 
@@ -158,13 +158,6 @@
             # objects are updated, not re-created.
             obj = self.factory()
             # TODO: ObjectCreatedEvent here would be nice
-
-            # Locate the new object
-            if not zope.location.interfaces.ILocation.providedBy(obj):
-                obj = zope.location.location.LocationProxy(obj)
-            obj.__parent__ = content
-            obj.__name__ = field.__name__
-
         # Apply the actual changes to the object. 
         changes = applyWidgetsChanges(self, field.schema, target=obj,
                                       names=self.names)
@@ -195,3 +188,14 @@
         self._setUpEditWidgets()
         for name in self.names:
             self.getSubWidget(name).setRenderedValue(getattr(value, name, None))
+
+
+ at component.adapter(zope.schema.interfaces.IBeforeObjectAssignedEvent)
+def setup_object_location(event):
+    # Locate an object that was the new object
+    obj = event.object
+    if not zope.location.interfaces.ILocation.providedBy(obj):
+        obj = zope.location.location.LocationProxy(obj)
+    obj.__parent__ = event.context
+    obj.__name__ = event.name
+    event.object = obj

Modified: zope.app.form/trunk/src/zope/app/form/browser/objectwidget.txt
===================================================================
--- zope.app.form/trunk/src/zope/app/form/browser/objectwidget.txt	2007-07-08 15:04:50 UTC (rev 77625)
+++ zope.app.form/trunk/src/zope/app/form/browser/objectwidget.txt	2007-07-08 15:23:47 UTC (rev 77626)
@@ -149,60 +149,3 @@
 use the Object field and the ObjectWidget.
 
 
-Locating objects from the object field
-======================================
-
-Objects that are created through the object field are located automatically.
-If they do not implement the ILocation interface, they will be wrapped with a
-location proxy. We need to do this to make location-based security work
-correctly.
-
-Read carefully (again): Only when the objects are created through the object
-field, they will be located by the object field. If you create the objects
-yourself, you're responsible for setting up any location that is required.
-
-Let's start with a new family. The existing Person class doesn't implement
-ILocation, but it still receives a parent and a name. This is done by using a
-location proxy:
-
-  >>> family = Family()
-  >>> widget.applyChanges(family)
-  True
-  >>> from zope.location.interfaces import ILocation
-  >>> ILocation.implementedBy(family.mother.__class__)
-  False
-  >>> family.mother.__parent__
-  <Family object at 0x...>
-  >>> family.mother.__name__
-  'mother'
-  >>> type(family.mother)
-  <class 'zope.location.location.LocationProxy'>
-
-To demonstrate this with a class that implements ILocation, we derive Person
-to a LocatedPerson, and we start with a fresh family to force the widget to
-re-create the object:
-
-  >>> from zope.location.location import Location
-  >>> class LocatedPerson(Location, Person):
-  ...     pass
-  >>> family = Family()
-
-We create a widget that uses this class as the factory, apply the request
-again, and see that this time, the object is not wrapped by a location proxy:
-
-  >>> factory = LocatedPerson
-  >>> request.form['field.mother.name'] = u'Isabel Ineichen'
-  >>> widget = ObjectWidget(mother_field, request, factory)
-  >>> widget.applyChanges(family)
-  True
-
-  >>> ILocation.implementedBy(family.mother.__class__)
-  True
-  >>> family.mother.__parent__
-  <Family object at 0x...>
-  >>> family.mother.__name__
-  'mother'
-  >>> family.mother
-  <LocatedPerson object at 0x...>
-  >>> type(family.mother)
-  <class 'LocatedPerson'>



More information about the Checkins mailing list