[Checkins] SVN: zope.schema/trunk/ More work on bug 98287:
Introduced an event to signal that an object value is
Christian Theune
ct at gocept.com
Sun Jul 8 10:02:39 EDT 2007
Log message for revision 77624:
More work on bug 98287: Introduced an event to signal that an object value is
going to be assigned.
Changed:
A zope.schema/trunk/CHANGES.txt
U zope.schema/trunk/setup.py
U zope.schema/trunk/src/zope/schema/_field.py
U zope.schema/trunk/src/zope/schema/interfaces.py
U zope.schema/trunk/src/zope/schema/tests/test_objectfield.py
-=-
Added: zope.schema/trunk/CHANGES.txt
===================================================================
--- zope.schema/trunk/CHANGES.txt (rev 0)
+++ zope.schema/trunk/CHANGES.txt 2007-07-08 14:02:38 UTC (rev 77624)
@@ -0,0 +1,17 @@
+=======
+Changes
+=======
+
+After 3.4.0a1
+=============
+
+ - Added BeforeObjectAssignedEvent that is triggered before the object field
+ sets a value.
+
+
+Before 3.4
+==========
+
+This package was part of the Zope 3 distribution and did not have its own
+CHANGES.txt. For earlier changes please refer to either our subversion log or
+the CHANGES.txt of earlier Zope 3 releases.
Property changes on: zope.schema/trunk/CHANGES.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: zope.schema/trunk/setup.py
===================================================================
--- zope.schema/trunk/setup.py 2007-07-08 14:01:33 UTC (rev 77623)
+++ zope.schema/trunk/setup.py 2007-07-08 14:02:38 UTC (rev 77624)
@@ -50,6 +50,7 @@
install_requires=['setuptools',
'zope.i18nmessageid',
'zope.interface',
+ 'zope.event',
],
include_package_data = True,
Modified: zope.schema/trunk/src/zope/schema/_field.py
===================================================================
--- zope.schema/trunk/src/zope/schema/_field.py 2007-07-08 14:01:33 UTC (rev 77623)
+++ zope.schema/trunk/src/zope/schema/_field.py 2007-07-08 14:02:38 UTC (rev 77624)
@@ -23,6 +23,8 @@
from datetime import datetime, date, timedelta, time
from sets import Set as SetType
+from zope.event import notify
+
from zope.interface import classImplements, implements
from zope.interface.interfaces import IInterface, IMethod
@@ -33,7 +35,8 @@
from zope.schema.interfaces import IBytes, IASCII, IBytesLine, IASCIILine
from zope.schema.interfaces import IBool, IInt, IFloat, IDatetime, IFrozenSet
from zope.schema.interfaces import IChoice, ITuple, IList, ISet, IDict
-from zope.schema.interfaces import IPassword, IObject, IDate, ITimedelta
+from zope.schema.interfaces import IPassword, IDate, ITimedelta
+from zope.schema.interfaces import IObject, IBeforeObjectAssignedEvent
from zope.schema.interfaces import ITime, IDecimal
from zope.schema.interfaces import IURI, IId, IFromUnicode
from zope.schema.interfaces import ISource, IBaseVocabulary
@@ -464,7 +467,27 @@
if errors:
raise WrongContainedType(errors)
+ def set(self, object, value):
+ # Announce that we're going to assign the value to the object.
+ # Motivation: Widgets typically like to take care of policy-specific
+ # actions, like establishing location.
+ event = BeforeObjectAssignedEvent(value, self.__name__, object)
+ notify(event)
+ # The event subscribers are allowed to replace the object, thus we need
+ # to replace our previous value.
+ value = event.object
+ super(Object, self).set(object, value)
+class BeforeObjectAssignedEvent(object):
+ """An object is going to be assigned to an attribute on another object."""
+
+ implements(IBeforeObjectAssignedEvent)
+
+ def __init__(self, object, name, context):
+ self.object = object
+ self.name = name
+ self.context = context
+
class Dict(MinMaxLen, Iterable):
"""A field representing a Dict."""
implements(IDict)
Modified: zope.schema/trunk/src/zope/schema/interfaces.py
===================================================================
--- zope.schema/trunk/src/zope/schema/interfaces.py 2007-07-08 14:01:33 UTC (rev 77623)
+++ zope.schema/trunk/src/zope/schema/interfaces.py 2007-07-08 14:02:38 UTC (rev 77624)
@@ -439,6 +439,25 @@
schema = Attribute("schema",
_(u"The Interface that defines the Fields comprising the Object."))
+class IBeforeObjectAssignedEvent(Interface):
+ """An object is going to be assigned to an attribute on another object.
+
+ Subscribers to this event can change the object on this event to change
+ what object is going to be assigned. This is useful, e.g. for wrapping
+ or replacing objects before they get assigned to conform to application
+ policy.
+
+ """
+
+ object = Attribute("The object that is going to be assigned.")
+
+ name = Attribute("The name of the attribute under which the object "
+ "will be assigned.")
+
+ context = Attribute("The context object where the object will be "
+ "assigned to.")
+
+
class IDict(IMinMaxLen, IIterable, IContainer):
u"""Field containing a conventional dict.
Modified: zope.schema/trunk/src/zope/schema/tests/test_objectfield.py
===================================================================
--- zope.schema/trunk/src/zope/schema/tests/test_objectfield.py 2007-07-08 14:01:33 UTC (rev 77623)
+++ zope.schema/trunk/src/zope/schema/tests/test_objectfield.py 2007-07-08 14:02:38 UTC (rev 77624)
@@ -17,6 +17,7 @@
"""
from unittest import TestSuite, main, makeSuite
+import zope.event
from zope.i18nmessageid import MessageFactory
from zope.interface import Attribute, Interface, implements
from zope.schema import Object, TextLine
@@ -25,81 +26,83 @@
from zope.schema.interfaces import RequiredMissing, WrongContainedType
from zope.schema.interfaces import WrongType, SchemaNotFullyImplemented
from zope.schema.tests.test_field import FieldTestBase
+from zope.schema.interfaces import IBeforeObjectAssignedEvent
+from zope.testing.cleanup import CleanUp
_ = MessageFactory('zope')
class ITestSchema(Interface):
"""A test schema"""
-
+
foo = TextLine(
title=_(u"Foo"),
description=_(u"Foo description"),
default=u"",
required=True)
-
+
bar = TextLine(
title=_(u"Bar"),
description=_(u"Bar description"),
default=u"",
required=False)
-
+
attribute = Attribute("Test attribute, an attribute can't be validated.")
-
+
class TestClass(object):
-
+
implements(ITestSchema)
-
+
_foo = u''
_bar = u''
_attribute = u''
-
+
def getfoo(self):
return self._foo
-
+
def setfoo(self, value):
self._foo = value
-
+
foo = property(getfoo, setfoo, None, u'foo')
-
+
def getbar(self):
return self._bar
-
+
def setbar(self, value):
self._bar = value
-
+
bar = property(getbar, setbar, None, u'foo')
-
+
def getattribute(self):
return self._attribute
-
+
def setattribute(self, value):
self._attribute = value
-
+
attribute = property(getattribute, setattribute, None, u'attribute')
class FieldPropertyTestClass(object):
-
+
implements(ITestSchema)
-
-
+
+
foo = FieldProperty(ITestSchema['foo'])
bar = FieldProperty(ITestSchema['bar'])
attribute = FieldProperty(ITestSchema['attribute'])
-
+
class NotFullyImplementedTestClass(object):
-
+
implements(ITestSchema)
-
+
foo = FieldProperty(ITestSchema['foo'])
# bar = FieldProperty(ITestSchema['bar']): bar is not implemented
# attribute
-
-
-class ObjectTest(FieldTestBase):
+
+
+class ObjectTest(CleanUp, FieldTestBase):
"""Test the Object Field."""
def getErrors(self, f, *args, **kw):
try:
@@ -110,35 +113,35 @@
except:
return []
self.fail('Expected WrongContainedType Error')
-
+
def makeTestObject(self, **kw):
kw['schema'] = kw.get('schema', Interface)
return Object(**kw)
_Field_Factory = makeTestObject
-
+
def makeTestData(self):
return TestClass()
def makeFieldPropertyTestClass(self):
return FieldPropertyTestClass()
-
+
def makeNotFullyImplementedTestData(self):
return NotFullyImplementedTestClass()
-
+
def invalidSchemas(self):
return ['foo', 1, 0, {}, [], None]
-
+
def validSchemas(self):
return [Interface, ITestSchema]
-
+
def test_init(self):
for schema in self.validSchemas():
field = Object(schema=schema)
for schema in self.invalidSchemas():
self.assertRaises(ValidationError, Object, schema=schema)
self.assertRaises(WrongType, Object, schema=schema)
-
+
def testValidate(self):
# this test of the base class is not applicable
pass
@@ -146,13 +149,13 @@
def testValidateRequired(self):
# this test of the base class is not applicable
pass
-
+
def test_validate_required(self):
field = self._Field_Factory(
title=u'Required field', description=u'',
readonly=False, required=True)
self.assertRaises(RequiredMissing, field.validate, None)
-
+
def test_validate_TestData(self):
field = self.makeTestObject(schema=ITestSchema, required=False)
data = self.makeTestData()
@@ -173,7 +176,7 @@
field.validate(data)
self.assertRaises(ValidationError, setattr, data, 'foo', None)
self.assertRaises(RequiredMissing, setattr, data, 'foo', None)
-
+
def test_validate_NotFullyImplementedTestData(self):
field = self.makeTestObject(schema=ITestSchema, required=False)
data = self.makeNotFullyImplementedTestData()
@@ -182,6 +185,26 @@
errors = self.getErrors(field.validate, data)
self.assert_(isinstance(errors[0], SchemaNotFullyImplemented))
+ def test_beforeAssignEvent(self):
+ field = self.makeTestObject(schema=ITestSchema, required=False,
+ __name__='object_field')
+ data = self.makeTestData()
+ events = []
+ def register_event(event):
+ events.append(event)
+ zope.event.subscribers.append(register_event)
+ class Dummy(object):
+ pass
+ context = Dummy()
+ field.set(context, data)
+ self.assertEquals(1, len(events))
+ event = events[0]
+ self.failUnless(IBeforeObjectAssignedEvent.providedBy(event))
+ self.assertEquals(data, event.object)
+ self.assertEquals('object_field', event.name)
+ self.assertEquals(context, event.context)
+
+
def test_suite():
suite = TestSuite()
suite.addTest(makeSuite(ObjectTest))
More information about the Checkins
mailing list