[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