[Zope-dev] Request for comment on zope.schema patch for bug 969350
Marius Gedminas
marius at gedmin.as
Fri Mar 30 20:54:41 UTC 2012
On Fri, Mar 30, 2012 at 06:36:13PM +0200, Alexandre Garel wrote:
> Hello,
>
> I fill a bug report for zope.schema :
>
> "zope.schema does not handle well nested object fields"
> https://bugs.launchpad.net/zope.schema/+bug/969350
>
> my patch change a particular behaviour (binding of Choice field
> nested in Object field)
>
> I explain why on the ticket.
>
> Any comment would be appreciated.
Here's the diff attached to that bug:
> Index: src/zope/schema/tests/test_objectfield_nested.py
> ===================================================================
> --- src/zope/schema/tests/test_objectfield_nested.py (révision 0)
> +++ src/zope/schema/tests/test_objectfield_nested.py (révision 0)
> @@ -0,0 +1,74 @@
> +##############################################################################
> +#
> +# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
Probably should be 2012 ;)
> +# All Rights Reserved.
> +#
> +# This software is subject to the provisions of the Zope Public License,
> +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
> +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
> +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
> +# FOR A PARTICULAR PURPOSE.
> +#
> +##############################################################################
> +"""This test exercises Object fields in the case of nestment inside list
s/netsment/nesting/, although the sentence could use some rewriting.
> +to verify binding correcly happens at validation time
> +"""
> +
> +from unittest import TestCase, TestSuite, main, makeSuite
> +
> +from zope.interface import Interface, implementer
> +from zope.schema import Choice, Object, Set
> +from zope.schema.interfaces import IContextSourceBinder, WrongContainedType
> +from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
> +from zope.testing.cleanup import CleanUp
> +
> +
> + at implementer(IContextSourceBinder)
> +class EnumContext(object):
> +
> + def __call__(self, context):
> + return SimpleVocabulary([
> + SimpleTerm(value=v, token=v, title='Letter %s' % v)
> + for v in context])
> +
> +
> +class IMultipleChoice(Interface):
> + choices = Set(value_type=Choice(source=EnumContext()))
> +
> +
> + at implementer(IMultipleChoice)
> +class Choices(object):
> +
> + def __iter__(self):
> + return iter(range(5)) # to have EnumSource work
EnumSource? Do you mean EnumContext?
> +
> + def __init__(self, choices):
> + self.choices = choices
> +
> +
> +class IFavorites(Interface):
> + fav = Object(title=u"Favorites number", schema=IMultipleChoice)
> +
> +
> +class ObjectNestedTest(CleanUp, TestCase):
> + """Test the Object Field in cases of nested fields"""
> +
> + def test_validate_nested(self):
> + context = range(5)
This is a bit confusing. IField.bind() is usually passed a context that
is an object that has an attribute with that field. You're passing a
list of numbers. Would the test also work if you had context = object()?
> + # must not raise
> + IFavorites['fav'].bind(context).validate(Choices(set([1, 3])))
> + # checking against dictionnary do work
I don't see any dictionaries... Perhaps you meant 'checking of set
values against the source works'?
> + self.assertRaises(
> + WrongContainedType,
> + IFavorites['fav'].bind(context).validate, Choices(set([1, 8])))
> +
> +
> +def test_suite():
> + suite = TestSuite()
> + suite.addTest(makeSuite(ObjectNestedTest))
> + return suite
> +
> +
> +if __name__ == '__main__':
> + main(defaultTest='test_suite')
> Index: src/zope/schema/_field.py
> ===================================================================
> --- src/zope/schema/_field.py (révision 124803)
> +++ src/zope/schema/_field.py (copie de travail)
> @@ -492,12 +492,7 @@
> if not IMethod.providedBy(schema[name]):
> try:
> attribute = schema[name]
> - if IChoice.providedBy(attribute):
> - # Choice must be bound before validation otherwise
> - # IContextSourceBinder is not iterable in validation
> - bound = attribute.bind(value)
> - bound.validate(getattr(value, name))
> - elif IField.providedBy(attribute):
> + if IField.providedBy(attribute):
> # validate attributes that are fields
> attribute.validate(getattr(value, name))
> except ValidationError as error:
> @@ -510,6 +505,24 @@
> return errors
>
>
> +class BindedSchema(object):
BoundSchema would be a more grammatically correct name.
> + """This class proxies a schema to get its fields binded to a context
s/binded/bound/
> + """
> +
> + def __init__(self, schema, context):
> + self.schema = schema
> + self.context = context
> +
> + # we redefine getitem
> + def __getitem__(self, name):
> + attr = self.schema[name]
> + return attr.bind(self.context)
Shouldn't this be
return attr.bind(getattr(self.context, name))
?
> +
> + # but let all the rest slip to schema
> + def __getattr__(self, name):
> + return getattr(self.schema, name)
The comments don't really add anything to the code.
> +
> +
> @implementer(IObject)
> class Object(Field):
> __doc__ = IObject.__doc__
> @@ -521,6 +534,11 @@
> self.schema = schema
> super(Object, self).__init__(**kw)
>
> + def bind(self, context=None):
> + binded = super(Object, self).bind(context)
> + binded.schema = BindedSchema(self.schema, context)
s/binded/bound/
> + return binded
> +
> def _validate(self, value):
> super(Object, self)._validate(value)
Marius Gedminas
--
http://pov.lt/ -- Zope 3/BlueBream consulting and development
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://mail.zope.org/pipermail/zope-dev/attachments/20120330/4d5512c8/attachment.sig>
More information about the Zope-Dev
mailing list