[Zope3-dev] class Object(Field) and the function _validate_fields

Dominik Huber dominik at projekt01.ch
Fri Nov 21 13:04:21 EST 2003


I would like to change the class Object(Field) and the function
_validate_fields of the module zope.schema._field.py because I think the
current implementation is buggy.

I'm not very comfortable with all zope3 principles and policies so I would
appreciate if an advanced zoper could check my suggestion and could answer
my questions before committing this to cvs.

thanks!
dominik



Questions:
What's the exception policy?
- Should I raise only ValidationErrors or are other Exceptions allowed too?
- The IField and IObject interface gives no appropriate answer. Do I have to
  extend the comment?
- What's the policy for the raised exception messages
  (i18n, default errormessages, ...)
How to suport the missing_value story properly? (-> see
test_validate_TestData)

############################
suggested changes: _field.py
############################

from zope.interface.interfaces import IMethod
from zope.interface import Interface

def _validate_fields(schema, value, errors=None):
    if errors is None:
        errors = []
    for name in schema.names(all=True):
        if not IMethod.isImplementedBy(schema[name]):
            try:
                field = schema[name]
                field.validate(getattr(value, name))
            except ValidationError, error:
                errors.append(error)
            except AttributeError, error:
                # attribute is not implemented yet
                raise error # XXX exception handling suffers

    return errors


class Object(Field):
    __doc__ = IObject.__doc__
    implements(IObject)

    def __init__(self, schema, **kw):
        if not (schema == None or Interface.isImplementedBy(schema)):
            raise TypeError # XXX exception handling suffers

        self.schema = schema
        super(Object, self).__init__(**kw)

    def _validate(self, value):
        super(Object, self)._validate(value)
        # always valid if no schema provided
        if self.schema == None:
            return
        # schema has to be implemented by value
        if not self.schema.isImplementedBy(value):
            raise TypeError # XXX exception handling suffers
        # check the value against the schema
        errors = _validate_fields(self.schema, value)
        if errors:
            raise ValidationError(WrongContainedType, errors)

##############################
suggestion: test_objectfield.py
##############################

from unittest import TestSuite, main, makeSuite
from zope.i18n import MessageIDFactory
from zope.interface import Interface, implements
from zope.schema import Object, TextLine
from zope.schema import errornames
from zope.schema.fieldproperty import FieldProperty
from zope.schema.interfaces import ValidationError
from zope.schema.tests.test_field import FieldTestBase

_ = MessageIDFactory('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)


class TestClass(object):

    implements(ITestSchema)

    foo = FieldProperty(ITestSchema['foo'])
    bar = FieldProperty(ITestSchema['bar'])


class WrongTestClass(object):

    implements(ITestSchema)

    foo = FieldProperty(ITestSchema['foo'])
    # bar = FieldProperty(ITestSchema['bar'])


class ObjectTest(FieldTestBase):
    """Test the Object Field."""

    def makeTestObject(self, **kw):
        kw['schema'] = kw.get('schema', None)
        return Object(**kw)

    _Field_Factory = makeTestObject

    def makeTestData(self):
        return TestClass()

    def makeWrongTestData(self):
        return WrongTestClass()

    def badSchema(self):
        return ['foo', 1, {}, []]

    def goodSchema(self):
        return [None, Interface, ITestSchema]

    def test_init(self):
        for good in self.goodSchema():
            field = Object(schema=good)
        for bad in self.badSchema():
            self.assertRaises(TypeError, Object, schema=bad)

    def test_validate_None(self):
        field = self.makeTestObject(required=False)
        field.validate(None)
        field = self.makeTestObject()
        self.assertRaises(ValidationError, field.validate, None)
        field.validate(self.makeTestData())

    def test_validate_TestData(self):
        field = self.makeTestObject(schema=ITestSchema, required=False)
        field.validate(self.makeTestData())
        #self.assertRaises(TypeError, field.validate, None)
        field.validate(None) # should fail! -> Field self.missing_value
        self.assertRaises(TypeError, field.validate, 'foo')

    def test_validate_WrongTestData(self):
        field = self.makeTestObject(schema=ITestSchema, required=False)
        data = self.makeWrongTestData()
        self.assertRaises(AttributeError, field.validate, data)

    def test_validate_required(self):
        field = self.makeTestObject(schema=ITestSchema, required=False)
        data = self.makeTestData()
        self.assertRaises(ValidationError, setattr, data, 'foo', None)
        self.assertRaises(ValidationError, setattr, data, 'foo', '')
        data.foo = u'bar'

def test_suite():
    suite = TestSuite()
    suite.addTest(makeSuite(ObjectTest))
    return suite

if __name__ == '__main__':
    main(defaultTest='test_suite')





More information about the Zope3-dev mailing list