[Checkins] SVN: zope.schema/trunk/src/zope/schema/ Add FieldProperty class that uses Field.get and Field.set methods instead of storing directly on the instance __dict__

Jean-Francois Roche jfroche at jfroche.be
Tue Nov 24 09:42:21 EST 2009


Log message for revision 105992:
  Add FieldProperty class that uses Field.get and Field.set methods instead of storing directly on the instance __dict__

Changed:
  U   zope.schema/trunk/src/zope/schema/fieldproperty.py
  U   zope.schema/trunk/src/zope/schema/tests/test_fieldproperty.py

-=-
Modified: zope.schema/trunk/src/zope/schema/fieldproperty.py
===================================================================
--- zope.schema/trunk/src/zope/schema/fieldproperty.py	2009-11-24 14:31:11 UTC (rev 105991)
+++ zope.schema/trunk/src/zope/schema/fieldproperty.py	2009-11-24 14:42:21 UTC (rev 105992)
@@ -15,8 +15,10 @@
 
 $Id$
 """
+from copy import copy
 _marker = object()
 
+
 class FieldProperty(object):
     """Computed attributes based on schema fields
 
@@ -56,3 +58,52 @@
 
     def __getattr__(self, name):
         return getattr(self.__field, name)
+
+
+class FieldPropertyStoredThroughField(object):
+
+    def __init__(self, field, name=None):
+        if name is None:
+            name = field.__name__
+
+        self.__field = copy(field)
+        self.__field.__name__ = "__st_%s_st" % self.__field.__name__
+        self.__name = name
+
+    def setValue(self, inst, field, value):
+        field.set(inst, value)
+
+    def getValue(self, inst, field):
+        return field.query(inst, _marker)
+
+    def queryValue(self, inst, field, default):
+        return field.query(inst, default)
+
+    def __getattr__(self, name):
+        return getattr(self.__field, name)
+
+    def __get__(self, inst, klass):
+        if inst is None:
+            return self
+
+        field = self.__field.bind(inst)
+        value = self.getValue(inst, field)
+        if value is _marker:
+            value = getattr(field, 'default', _marker)
+            if value is _marker:
+                raise AttributeError(self.__name)
+
+        return value
+
+    def __set__(self, inst, value):
+        field = self.__field.bind(inst)
+        field.validate(value)
+        if field.readonly:
+            if self.queryValue(inst, field, _marker) is _marker:
+                field.readonly = False
+                self.setValue(inst, field, value)
+                field.readonly = True
+                return
+            else:
+                raise ValueError(self.__name, 'field is readonly')
+        self.setValue(inst, field, value)

Modified: zope.schema/trunk/src/zope/schema/tests/test_fieldproperty.py
===================================================================
--- zope.schema/trunk/src/zope/schema/tests/test_fieldproperty.py	2009-11-24 14:31:11 UTC (rev 105991)
+++ zope.schema/trunk/src/zope/schema/tests/test_fieldproperty.py	2009-11-24 14:42:21 UTC (rev 105992)
@@ -20,9 +20,11 @@
 
 from zope.interface import Interface
 from zope.schema import Float, Text, Bytes
-from zope.schema.fieldproperty import FieldProperty
 from zope.schema.interfaces import ValidationError
+from zope.schema.fieldproperty import (FieldProperty,
+                                       FieldPropertyStoredThroughField)
 
+
 class I(Interface):
 
     title = Text(description=u"Short summary", default=u'say something')
@@ -38,10 +40,12 @@
     code = FieldProperty(I['code'])
     date = FieldProperty(I['date'])
 
+
 class Test(TestCase):
+    klass = C
 
     def test_basic(self):
-        c = C()
+        c = self.klass()
         self.assertEqual(c.title, u'say something')
         self.assertEqual(c.weight, None)
         self.assertEqual(c.code, 'xxxxxx')
@@ -62,17 +66,30 @@
         self.assertEqual(c.code, 'abcdef')
 
     def test_readonly(self):
-        c = C()
+        c = self.klass()
         # The date should be only settable once
         c.date = 0.0
         # Setting the value a second time should fail.
         self.assertRaises(ValueError, setattr, c, 'date', 1.0)
 
 
+class D(object):
+
+    title = FieldPropertyStoredThroughField(I['title'])
+    weight = FieldPropertyStoredThroughField(I['weight'])
+    code = FieldPropertyStoredThroughField(I['code'])
+    date = FieldPropertyStoredThroughField(I['date'])
+
+
+class TestStoredThroughField(Test):
+    klass = D
+
+
 def test_suite():
     return TestSuite((
         makeSuite(Test),
+        makeSuite(TestStoredThroughField),
         ))
 
-if __name__=='__main__':
+if __name__ == '__main__':
     main(defaultTest='test_suite')



More information about the checkins mailing list