[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