summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2018-09-07 08:16:02 -0500
committerJason Madden <jamadden@gmail.com>2018-09-07 08:16:02 -0500
commit6d68cccd48a41bd29d1a076f6fd95b0480768bdd (patch)
tree8892af5da16720876aeaa7fe40aac71d83f35dcc
parent6d439c606443c1d2ea24eec598e37a02ad1145fd (diff)
downloadzope-schema-issue13.tar.gz
Move ObjectTests from test__field to test__bootstrapfield to match Object itself.issue13
-rw-r--r--src/zope/schema/_bootstrapfields.py7
-rw-r--r--src/zope/schema/tests/test__bootstrapfields.py492
-rw-r--r--src/zope/schema/tests/test__field.py506
3 files changed, 501 insertions, 504 deletions
diff --git a/src/zope/schema/_bootstrapfields.py b/src/zope/schema/_bootstrapfields.py
index 6c8c389..cde9df0 100644
--- a/src/zope/schema/_bootstrapfields.py
+++ b/src/zope/schema/_bootstrapfields.py
@@ -709,9 +709,10 @@ def get_schema_validation_errors(schema, value,
# it's python represenation. A previous version was setting a volatile
# attribute which didn't work with security proxy
id_value = id(value)
- if id_value in _validating_objects.ids_being_validated:
+ ids_being_validated = _validating_objects.ids_being_validated
+ if id_value in ids_being_validated:
return errors
- _validating_objects.ids_being_validated.add(id_value)
+ ids_being_validated.add(id_value)
# (If we have gotten here, we know that `value` provides an interface
# other than zope.interface.Interface;
# iow, we can rely on the fact that it is an instance
@@ -735,7 +736,7 @@ def get_schema_validation_errors(schema, value,
# property for the given name is not implemented
errors[name] = SchemaNotFullyImplemented(error).with_field_and_value(attribute, None)
finally:
- _validating_objects.ids_being_validated.remove(id_value)
+ ids_being_validated.remove(id_value)
return errors
diff --git a/src/zope/schema/tests/test__bootstrapfields.py b/src/zope/schema/tests/test__bootstrapfields.py
index 419378a..733d5c9 100644
--- a/src/zope/schema/tests/test__bootstrapfields.py
+++ b/src/zope/schema/tests/test__bootstrapfields.py
@@ -14,7 +14,7 @@
import doctest
import unittest
-# pylint:disable=protected-access
+# pylint:disable=protected-access,inherit-non-class,blacklisted-name
class EqualityTestsMixin(object):
@@ -991,6 +991,496 @@ class IntTests(IntegralTests):
self.assertEqual(txt._type, integer_types)
+class ObjectTests(EqualityTestsMixin,
+ unittest.TestCase):
+
+ def setUp(self):
+ from zope.event import subscribers
+ self._before = subscribers[:]
+
+ def tearDown(self):
+ from zope.event import subscribers
+ subscribers[:] = self._before
+
+ def _getTargetClass(self):
+ from zope.schema._field import Object
+ return Object
+
+ def _getTargetInterface(self):
+ from zope.schema.interfaces import IObject
+ return IObject
+
+ def _makeOneFromClass(self, cls, schema=None, *args, **kw):
+ if schema is None:
+ schema = self._makeSchema()
+ return super(ObjectTests, self)._makeOneFromClass(cls, schema, *args, **kw)
+
+ def _makeSchema(self, **kw):
+ from zope.interface import Interface
+ from zope.interface.interface import InterfaceClass
+ return InterfaceClass('ISchema', (Interface,), kw)
+
+ def _getErrors(self, f, *args, **kw):
+ from zope.schema.interfaces import WrongContainedType
+ with self.assertRaises(WrongContainedType) as e:
+ f(*args, **kw)
+ return e.exception.args[0]
+
+ def _makeCycles(self):
+ from zope.interface import Interface
+ from zope.interface import implementer
+ from zope.schema import Object
+ from zope.schema import List
+ from zope.schema._messageid import _
+
+ class IUnit(Interface):
+ """A schema that participate to a cycle"""
+ boss = Object(
+ schema=Interface,
+ title=_("Boss"),
+ description=_("Boss description"),
+ required=False,
+ )
+ members = List(
+ value_type=Object(schema=Interface),
+ title=_("Member List"),
+ description=_("Member list description"),
+ required=False,
+ )
+
+ class IPerson(Interface):
+ """A schema that participate to a cycle"""
+ unit = Object(
+ schema=IUnit,
+ title=_("Unit"),
+ description=_("Unit description"),
+ required=False,
+ )
+
+ IUnit['boss'].schema = IPerson
+ IUnit['members'].value_type.schema = IPerson
+
+ @implementer(IUnit)
+ class Unit(object):
+ def __init__(self, person, person_list):
+ self.boss = person
+ self.members = person_list
+
+ @implementer(IPerson)
+ class Person(object):
+ def __init__(self, unit):
+ self.unit = unit
+
+ return IUnit, Person, Unit
+
+ def test_class_conforms_to_IObject(self):
+ from zope.interface.verify import verifyClass
+ from zope.schema.interfaces import IObject
+ verifyClass(IObject, self._getTargetClass())
+
+ def test_instance_conforms_to_IObject(self):
+ from zope.interface.verify import verifyObject
+ from zope.schema.interfaces import IObject
+ verifyObject(IObject, self._makeOne())
+
+ def test_ctor_w_bad_schema(self):
+ from zope.schema.interfaces import WrongType
+ self.assertRaises(WrongType, self._makeOne, object())
+
+ def test_validate_not_required(self):
+ schema = self._makeSchema()
+ objf = self._makeOne(schema, required=False)
+ objf.validate(None) # doesn't raise
+
+ def test_validate_required(self):
+ from zope.schema.interfaces import RequiredMissing
+ field = self._makeOne(required=True)
+ self.assertRaises(RequiredMissing, field.validate, None)
+
+ def test__validate_w_empty_schema(self):
+ from zope.interface import Interface
+ objf = self._makeOne(Interface)
+ objf.validate(object()) # doesn't raise
+
+ def test__validate_w_value_not_providing_schema(self):
+ from zope.schema.interfaces import SchemaNotProvided
+ from zope.schema._bootstrapfields import Text
+ schema = self._makeSchema(foo=Text(), bar=Text())
+ objf = self._makeOne(schema)
+ bad_value = object()
+ with self.assertRaises(SchemaNotProvided) as exc:
+ objf.validate(bad_value)
+
+ not_provided = exc.exception
+ self.assertIs(not_provided.field, objf)
+ self.assertIs(not_provided.value, bad_value)
+ self.assertEqual(not_provided.args, (schema, bad_value), )
+
+ def test__validate_w_value_providing_schema_but_missing_fields(self):
+ from zope.interface import implementer
+ from zope.schema.interfaces import SchemaNotFullyImplemented
+ from zope.schema.interfaces import SchemaNotCorrectlyImplemented
+ from zope.schema._bootstrapfields import Text
+ schema = self._makeSchema(foo=Text(), bar=Text())
+
+ @implementer(schema)
+ class Broken(object):
+ pass
+
+ objf = self._makeOne(schema)
+ broken = Broken()
+ with self.assertRaises(SchemaNotCorrectlyImplemented) as exc:
+ objf.validate(broken)
+
+ wct = exc.exception
+ self.assertIs(wct.field, objf)
+ self.assertIs(wct.value, broken)
+ self.assertEqual(wct.invariant_errors, [])
+ self.assertEqual(
+ sorted(wct.schema_errors),
+ ['bar', 'foo']
+ )
+ for name in ('foo', 'bar'):
+ error = wct.schema_errors[name]
+ self.assertIsInstance(error,
+ SchemaNotFullyImplemented)
+ self.assertEqual(schema[name], error.field)
+ self.assertIsNone(error.value)
+
+ # The legacy arg[0] errors list
+ errors = self._getErrors(objf.validate, Broken())
+ self.assertEqual(len(errors), 2)
+ errors = sorted(errors,
+ key=lambda x: (type(x).__name__, str(x.args[0])))
+ err = errors[0]
+ self.assertIsInstance(err, SchemaNotFullyImplemented)
+ nested = err.args[0]
+ self.assertIsInstance(nested, AttributeError)
+ self.assertIn("'bar'", str(nested))
+ err = errors[1]
+ self.assertIsInstance(err, SchemaNotFullyImplemented)
+ nested = err.args[0]
+ self.assertIsInstance(nested, AttributeError)
+ self.assertIn("'foo'", str(nested))
+
+ def test__validate_w_value_providing_schema_but_invalid_fields(self):
+ from zope.interface import implementer
+ from zope.schema.interfaces import SchemaNotCorrectlyImplemented
+ from zope.schema.interfaces import RequiredMissing
+ from zope.schema.interfaces import WrongType
+ from zope.schema._bootstrapfields import Text
+ from zope.schema._compat import text_type
+ schema = self._makeSchema(foo=Text(), bar=Text())
+
+ @implementer(schema)
+ class Broken(object):
+ foo = None
+ bar = 1
+
+ objf = self._makeOne(schema)
+ broken = Broken()
+ with self.assertRaises(SchemaNotCorrectlyImplemented) as exc:
+ objf.validate(broken)
+
+ wct = exc.exception
+ self.assertIs(wct.field, objf)
+ self.assertIs(wct.value, broken)
+ self.assertEqual(wct.invariant_errors, [])
+ self.assertEqual(
+ sorted(wct.schema_errors),
+ ['bar', 'foo']
+ )
+ self.assertIsInstance(wct.schema_errors['foo'], RequiredMissing)
+ self.assertIsInstance(wct.schema_errors['bar'], WrongType)
+
+ # The legacy arg[0] errors list
+ errors = self._getErrors(objf.validate, Broken())
+ self.assertEqual(len(errors), 2)
+ errors = sorted(errors, key=lambda x: type(x).__name__)
+ err = errors[0]
+ self.assertIsInstance(err, RequiredMissing)
+ self.assertEqual(err.args, ('foo',))
+ err = errors[1]
+ self.assertIsInstance(err, WrongType)
+ self.assertEqual(err.args, (1, text_type, 'bar'))
+
+ def test__validate_w_value_providing_schema(self):
+ from zope.interface import implementer
+ from zope.schema._bootstrapfields import Text
+ from zope.schema._field import Choice
+
+ schema = self._makeSchema(
+ foo=Text(),
+ bar=Text(),
+ baz=Choice(values=[1, 2, 3]),
+ )
+
+ @implementer(schema)
+ class OK(object):
+ foo = u'Foo'
+ bar = u'Bar'
+ baz = 2
+ objf = self._makeOne(schema)
+ objf.validate(OK()) # doesn't raise
+
+ def test_validate_w_cycles(self):
+ IUnit, Person, Unit = self._makeCycles()
+ field = self._makeOne(schema=IUnit)
+ person1 = Person(None)
+ person2 = Person(None)
+ unit = Unit(person1, [person1, person2])
+ person1.unit = unit
+ person2.unit = unit
+ field.validate(unit) # doesn't raise
+
+ def test_validate_w_cycles_object_not_valid(self):
+ from zope.schema.interfaces import WrongContainedType
+ IUnit, Person, Unit = self._makeCycles()
+ field = self._makeOne(schema=IUnit)
+ person1 = Person(None)
+ person2 = Person(None)
+ person3 = Person(object())
+ unit = Unit(person3, [person1, person2])
+ person1.unit = unit
+ person2.unit = unit
+ self.assertRaises(WrongContainedType, field.validate, unit)
+
+ def test_validate_w_cycles_collection_not_valid(self):
+ from zope.schema.interfaces import WrongContainedType
+ IUnit, Person, Unit = self._makeCycles()
+ field = self._makeOne(schema=IUnit)
+ person1 = Person(None)
+ person2 = Person(None)
+ person3 = Person(object())
+ unit = Unit(person1, [person2, person3])
+ person1.unit = unit
+ person2.unit = unit
+ self.assertRaises(WrongContainedType, field.validate, unit)
+
+ def test_set_emits_IBOAE(self):
+ from zope.event import subscribers
+ from zope.interface import implementer
+ from zope.schema.interfaces import IBeforeObjectAssignedEvent
+ from zope.schema._bootstrapfields import Text
+ from zope.schema._field import Choice
+
+ schema = self._makeSchema(
+ foo=Text(),
+ bar=Text(),
+ baz=Choice(values=[1, 2, 3]),
+ )
+
+ @implementer(schema)
+ class OK(object):
+ foo = u'Foo'
+ bar = u'Bar'
+ baz = 2
+ log = []
+ subscribers.append(log.append)
+ objf = self._makeOne(schema, __name__='field')
+ inst = DummyInst()
+ value = OK()
+ objf.set(inst, value)
+ self.assertIs(inst.field, value)
+ self.assertEqual(len(log), 5)
+ self.assertEqual(IBeforeObjectAssignedEvent.providedBy(log[-1]), True)
+ self.assertEqual(log[-1].object, value)
+ self.assertEqual(log[-1].name, 'field')
+ self.assertEqual(log[-1].context, inst)
+
+ def test_set_allows_IBOAE_subscr_to_replace_value(self):
+ from zope.event import subscribers
+ from zope.interface import implementer
+ from zope.schema._bootstrapfields import Text
+ from zope.schema._field import Choice
+
+ schema = self._makeSchema(
+ foo=Text(),
+ bar=Text(),
+ baz=Choice(values=[1, 2, 3]),
+ )
+
+ @implementer(schema)
+ class OK(object):
+ def __init__(self, foo=u'Foo', bar=u'Bar', baz=2):
+ self.foo = foo
+ self.bar = bar
+ self.baz = baz
+ ok1 = OK()
+ ok2 = OK(u'Foo2', u'Bar2', 3)
+ log = []
+ subscribers.append(log.append)
+
+ def _replace(event):
+ event.object = ok2
+ subscribers.append(_replace)
+ objf = self._makeOne(schema, __name__='field')
+ inst = DummyInst()
+ self.assertEqual(len(log), 4)
+ objf.set(inst, ok1)
+ self.assertIs(inst.field, ok2)
+ self.assertEqual(len(log), 5)
+ self.assertEqual(log[-1].object, ok2)
+ self.assertEqual(log[-1].name, 'field')
+ self.assertEqual(log[-1].context, inst)
+
+ def test_validates_invariants_by_default(self):
+ from zope.interface import invariant
+ from zope.interface import Interface
+ from zope.interface import implementer
+ from zope.interface import Invalid
+ from zope.schema import Text
+ from zope.schema import Bytes
+
+ class ISchema(Interface):
+
+ foo = Text()
+ bar = Bytes()
+
+ @invariant
+ def check_foo(self):
+ if self.foo == u'bar':
+ raise Invalid("Foo is not valid")
+
+ @invariant
+ def check_bar(self):
+ if self.bar == b'foo':
+ raise Invalid("Bar is not valid")
+
+ @implementer(ISchema)
+ class O(object):
+ foo = u''
+ bar = b''
+
+
+ field = self._makeOne(ISchema)
+ inst = O()
+
+ # Fine at first
+ field.validate(inst)
+
+ inst.foo = u'bar'
+ errors = self._getErrors(field.validate, inst)
+ self.assertEqual(len(errors), 1)
+ self.assertEqual(errors[0].args[0], "Foo is not valid")
+
+ del inst.foo
+ inst.bar = b'foo'
+ errors = self._getErrors(field.validate, inst)
+ self.assertEqual(len(errors), 1)
+ self.assertEqual(errors[0].args[0], "Bar is not valid")
+
+ # Both invalid
+ inst.foo = u'bar'
+ errors = self._getErrors(field.validate, inst)
+ self.assertEqual(len(errors), 2)
+ errors.sort(key=lambda i: i.args)
+ self.assertEqual(errors[0].args[0], "Bar is not valid")
+ self.assertEqual(errors[1].args[0], "Foo is not valid")
+
+ # We can specifically ask for invariants to be turned off.
+ field = self._makeOne(ISchema, validate_invariants=False)
+ field.validate(inst)
+
+ def test_schema_defined_by_subclass(self):
+ from zope import interface
+ from zope.schema.interfaces import SchemaNotProvided
+
+ class IValueType(interface.Interface):
+ "The value type schema"
+
+ class Field(self._getTargetClass()):
+ schema = IValueType
+
+ field = Field()
+ self.assertIs(field.schema, IValueType)
+
+ # Non implementation is bad
+ self.assertRaises(SchemaNotProvided, field.validate, object())
+
+ # Actual implementation works
+ @interface.implementer(IValueType)
+ class ValueType(object):
+ "The value type"
+
+
+ field.validate(ValueType())
+
+ def test_bound_field_of_collection_with_choice(self):
+ # https://github.com/zopefoundation/zope.schema/issues/17
+ from zope.interface import Interface, implementer
+ from zope.interface import Attribute
+
+ from zope.schema import Choice, Object, Set
+ from zope.schema.fieldproperty import FieldProperty
+ from zope.schema.interfaces import IContextSourceBinder
+ from zope.schema.interfaces import WrongContainedType
+ from zope.schema.interfaces import SchemaNotCorrectlyImplemented
+ from zope.schema.vocabulary import SimpleVocabulary
+
+
+ @implementer(IContextSourceBinder)
+ class EnumContext(object):
+ def __call__(self, context):
+ return SimpleVocabulary.fromValues(list(context))
+
+ class IMultipleChoice(Interface):
+ choices = Set(value_type=Choice(source=EnumContext()))
+ # Provide a regular attribute to prove that binding doesn't
+ # choke. NOTE: We don't actually verify the existence of this attribute.
+ non_field = Attribute("An attribute")
+
+ @implementer(IMultipleChoice)
+ class Choices(object):
+
+ def __init__(self, choices):
+ self.choices = choices
+
+ def __iter__(self):
+ # EnumContext calls this to make the vocabulary.
+ # Fields of the schema of the IObject are bound to the value being
+ # validated.
+ return iter(range(5))
+
+ class IFavorites(Interface):
+ fav = Object(title=u"Favorites number", schema=IMultipleChoice)
+
+
+ @implementer(IFavorites)
+ class Favorites(object):
+ fav = FieldProperty(IFavorites['fav'])
+
+ # must not raise
+ good_choices = Choices({1, 3})
+ IFavorites['fav'].validate(good_choices)
+
+ # Ranges outside the context fail
+ bad_choices = Choices({1, 8})
+ with self.assertRaises(WrongContainedType) as exc:
+ IFavorites['fav'].validate(bad_choices)
+
+ e = exc.exception
+ self.assertEqual(IFavorites['fav'], e.field)
+ self.assertEqual(bad_choices, e.value)
+
+ # Validation through field property
+ favorites = Favorites()
+ favorites.fav = good_choices
+
+ # And validation through a field that wants IFavorites
+ favorites_field = Object(IFavorites)
+ favorites_field.validate(favorites)
+
+ # Check the field property error
+ with self.assertRaises(SchemaNotCorrectlyImplemented) as exc:
+ favorites.fav = bad_choices
+
+ e = exc.exception
+ self.assertEqual(IFavorites['fav'], e.field)
+ self.assertEqual(bad_choices, e.value)
+ self.assertEqual(['choices'], list(e.schema_errors))
+
+
class DummyInst(object):
missing_value = object()
diff --git a/src/zope/schema/tests/test__field.py b/src/zope/schema/tests/test__field.py
index 7224d4a..c176326 100644
--- a/src/zope/schema/tests/test__field.py
+++ b/src/zope/schema/tests/test__field.py
@@ -796,9 +796,9 @@ class ChoiceTests(EqualityTestsMixin,
pass
source = self._makeOne(vocabulary=Vocab())
- instance = DummyInstance()
+ instance = object()
target = source.bind(instance)
- self.assertTrue(target.vocabulary is source.vocabulary)
+ self.assertIs(target.vocabulary, source.vocabulary)
def test_bind_w_voc_is_ICSB(self):
from zope.interface import implementer
@@ -818,9 +818,9 @@ class ChoiceTests(EqualityTestsMixin,
source = self._makeOne(vocabulary='temp')
source.vocabulary = Vocab(source)
source.vocabularyName = None
- instance = DummyInstance()
+ instance = object()
target = source.bind(instance)
- self.assertEqual(target.vocabulary.context, instance)
+ self.assertIs(target.vocabulary.context, instance)
def test_bind_w_voc_is_ICSB_but_not_ISource(self):
from zope.interface import implementer
@@ -838,7 +838,7 @@ class ChoiceTests(EqualityTestsMixin,
source = self._makeOne(vocabulary='temp')
source.vocabulary = Vocab(source)
source.vocabularyName = None
- instance = DummyInstance()
+ instance = object()
self.assertRaises(ValueError, source.bind, instance)
def test_fromUnicode_miss(self):
@@ -1630,496 +1630,6 @@ class FrozenSetTests(SetTests):
return IFrozenSet
-class ObjectTests(EqualityTestsMixin,
- unittest.TestCase):
-
- def setUp(self):
- from zope.event import subscribers
- self._before = subscribers[:]
-
- def tearDown(self):
- from zope.event import subscribers
- subscribers[:] = self._before
-
- def _getTargetClass(self):
- from zope.schema._field import Object
- return Object
-
- def _getTargetInterface(self):
- from zope.schema.interfaces import IObject
- return IObject
-
- def _makeOneFromClass(self, cls, schema=None, *args, **kw):
- if schema is None:
- schema = self._makeSchema()
- return super(ObjectTests, self)._makeOneFromClass(cls, schema, *args, **kw)
-
- def _makeSchema(self, **kw):
- from zope.interface import Interface
- from zope.interface.interface import InterfaceClass
- return InterfaceClass('ISchema', (Interface,), kw)
-
- def _getErrors(self, f, *args, **kw):
- from zope.schema.interfaces import WrongContainedType
- with self.assertRaises(WrongContainedType) as e:
- f(*args, **kw)
- return e.exception.args[0]
-
- def _makeCycles(self):
- from zope.interface import Interface
- from zope.interface import implementer
- from zope.schema import Object
- from zope.schema import List
- from zope.schema._messageid import _
-
- class IUnit(Interface):
- """A schema that participate to a cycle"""
- boss = Object(
- schema=Interface,
- title=_("Boss"),
- description=_("Boss description"),
- required=False,
- )
- members = List(
- value_type=Object(schema=Interface),
- title=_("Member List"),
- description=_("Member list description"),
- required=False,
- )
-
- class IPerson(Interface):
- """A schema that participate to a cycle"""
- unit = Object(
- schema=IUnit,
- title=_("Unit"),
- description=_("Unit description"),
- required=False,
- )
-
- IUnit['boss'].schema = IPerson
- IUnit['members'].value_type.schema = IPerson
-
- @implementer(IUnit)
- class Unit(object):
- def __init__(self, person, person_list):
- self.boss = person
- self.members = person_list
-
- @implementer(IPerson)
- class Person(object):
- def __init__(self, unit):
- self.unit = unit
-
- return IUnit, Person, Unit
-
- def test_class_conforms_to_IObject(self):
- from zope.interface.verify import verifyClass
- from zope.schema.interfaces import IObject
- verifyClass(IObject, self._getTargetClass())
-
- def test_instance_conforms_to_IObject(self):
- from zope.interface.verify import verifyObject
- from zope.schema.interfaces import IObject
- verifyObject(IObject, self._makeOne())
-
- def test_ctor_w_bad_schema(self):
- from zope.schema.interfaces import WrongType
- self.assertRaises(WrongType, self._makeOne, object())
-
- def test_validate_not_required(self):
- schema = self._makeSchema()
- objf = self._makeOne(schema, required=False)
- objf.validate(None) # doesn't raise
-
- def test_validate_required(self):
- from zope.schema.interfaces import RequiredMissing
- field = self._makeOne(required=True)
- self.assertRaises(RequiredMissing, field.validate, None)
-
- def test__validate_w_empty_schema(self):
- from zope.interface import Interface
- objf = self._makeOne(Interface)
- objf.validate(object()) # doesn't raise
-
- def test__validate_w_value_not_providing_schema(self):
- from zope.schema.interfaces import SchemaNotProvided
- from zope.schema._bootstrapfields import Text
- schema = self._makeSchema(foo=Text(), bar=Text())
- objf = self._makeOne(schema)
- bad_value = object()
- with self.assertRaises(SchemaNotProvided) as exc:
- objf.validate(bad_value)
-
- not_provided = exc.exception
- self.assertIs(not_provided.field, objf)
- self.assertIs(not_provided.value, bad_value)
- self.assertEqual(not_provided.args, (schema, bad_value), )
-
- def test__validate_w_value_providing_schema_but_missing_fields(self):
- from zope.interface import implementer
- from zope.schema.interfaces import SchemaNotFullyImplemented
- from zope.schema.interfaces import SchemaNotCorrectlyImplemented
- from zope.schema._bootstrapfields import Text
- schema = self._makeSchema(foo=Text(), bar=Text())
-
- @implementer(schema)
- class Broken(object):
- pass
-
- objf = self._makeOne(schema)
- broken = Broken()
- with self.assertRaises(SchemaNotCorrectlyImplemented) as exc:
- objf.validate(broken)
-
- wct = exc.exception
- self.assertIs(wct.field, objf)
- self.assertIs(wct.value, broken)
- self.assertEqual(wct.invariant_errors, [])
- self.assertEqual(
- sorted(wct.schema_errors),
- ['bar', 'foo']
- )
- for name in ('foo', 'bar'):
- error = wct.schema_errors[name]
- self.assertIsInstance(error,
- SchemaNotFullyImplemented)
- self.assertEqual(schema[name], error.field)
- self.assertIsNone(error.value)
-
- # The legacy arg[0] errors list
- errors = self._getErrors(objf.validate, Broken())
- self.assertEqual(len(errors), 2)
- errors = sorted(errors,
- key=lambda x: (type(x).__name__, str(x.args[0])))
- err = errors[0]
- self.assertIsInstance(err, SchemaNotFullyImplemented)
- nested = err.args[0]
- self.assertIsInstance(nested, AttributeError)
- self.assertIn("'bar'", str(nested))
- err = errors[1]
- self.assertIsInstance(err, SchemaNotFullyImplemented)
- nested = err.args[0]
- self.assertIsInstance(nested, AttributeError)
- self.assertIn("'foo'", str(nested))
-
- def test__validate_w_value_providing_schema_but_invalid_fields(self):
- from zope.interface import implementer
- from zope.schema.interfaces import SchemaNotCorrectlyImplemented
- from zope.schema.interfaces import RequiredMissing
- from zope.schema.interfaces import WrongType
- from zope.schema._bootstrapfields import Text
- from zope.schema._compat import text_type
- schema = self._makeSchema(foo=Text(), bar=Text())
-
- @implementer(schema)
- class Broken(object):
- foo = None
- bar = 1
-
- objf = self._makeOne(schema)
- broken = Broken()
- with self.assertRaises(SchemaNotCorrectlyImplemented) as exc:
- objf.validate(broken)
-
- wct = exc.exception
- self.assertIs(wct.field, objf)
- self.assertIs(wct.value, broken)
- self.assertEqual(wct.invariant_errors, [])
- self.assertEqual(
- sorted(wct.schema_errors),
- ['bar', 'foo']
- )
- self.assertIsInstance(wct.schema_errors['foo'], RequiredMissing)
- self.assertIsInstance(wct.schema_errors['bar'], WrongType)
-
- # The legacy arg[0] errors list
- errors = self._getErrors(objf.validate, Broken())
- self.assertEqual(len(errors), 2)
- errors = sorted(errors, key=lambda x: type(x).__name__)
- err = errors[0]
- self.assertIsInstance(err, RequiredMissing)
- self.assertEqual(err.args, ('foo',))
- err = errors[1]
- self.assertIsInstance(err, WrongType)
- self.assertEqual(err.args, (1, text_type, 'bar'))
-
- def test__validate_w_value_providing_schema(self):
- from zope.interface import implementer
- from zope.schema._bootstrapfields import Text
- from zope.schema._field import Choice
-
- schema = self._makeSchema(
- foo=Text(),
- bar=Text(),
- baz=Choice(values=[1, 2, 3]),
- )
-
- @implementer(schema)
- class OK(object):
- foo = u'Foo'
- bar = u'Bar'
- baz = 2
- objf = self._makeOne(schema)
- objf.validate(OK()) # doesn't raise
-
- def test_validate_w_cycles(self):
- IUnit, Person, Unit = self._makeCycles()
- field = self._makeOne(schema=IUnit)
- person1 = Person(None)
- person2 = Person(None)
- unit = Unit(person1, [person1, person2])
- person1.unit = unit
- person2.unit = unit
- field.validate(unit) # doesn't raise
-
- def test_validate_w_cycles_object_not_valid(self):
- from zope.schema.interfaces import WrongContainedType
- IUnit, Person, Unit = self._makeCycles()
- field = self._makeOne(schema=IUnit)
- person1 = Person(None)
- person2 = Person(None)
- person3 = Person(DummyInstance())
- unit = Unit(person3, [person1, person2])
- person1.unit = unit
- person2.unit = unit
- self.assertRaises(WrongContainedType, field.validate, unit)
-
- def test_validate_w_cycles_collection_not_valid(self):
- from zope.schema.interfaces import WrongContainedType
- IUnit, Person, Unit = self._makeCycles()
- field = self._makeOne(schema=IUnit)
- person1 = Person(None)
- person2 = Person(None)
- person3 = Person(DummyInstance())
- unit = Unit(person1, [person2, person3])
- person1.unit = unit
- person2.unit = unit
- self.assertRaises(WrongContainedType, field.validate, unit)
-
- def test_set_emits_IBOAE(self):
- from zope.event import subscribers
- from zope.interface import implementer
- from zope.schema.interfaces import IBeforeObjectAssignedEvent
- from zope.schema._bootstrapfields import Text
- from zope.schema._field import Choice
-
- schema = self._makeSchema(
- foo=Text(),
- bar=Text(),
- baz=Choice(values=[1, 2, 3]),
- )
-
- @implementer(schema)
- class OK(object):
- foo = u'Foo'
- bar = u'Bar'
- baz = 2
- log = []
- subscribers.append(log.append)
- objf = self._makeOne(schema, __name__='field')
- inst = DummyInstance()
- value = OK()
- objf.set(inst, value)
- self.assertEqual(inst.field is value, True)
- self.assertEqual(len(log), 5)
- self.assertEqual(IBeforeObjectAssignedEvent.providedBy(log[-1]), True)
- self.assertEqual(log[-1].object, value)
- self.assertEqual(log[-1].name, 'field')
- self.assertEqual(log[-1].context, inst)
-
- def test_set_allows_IBOAE_subscr_to_replace_value(self):
- from zope.event import subscribers
- from zope.interface import implementer
- from zope.schema._bootstrapfields import Text
- from zope.schema._field import Choice
-
- schema = self._makeSchema(
- foo=Text(),
- bar=Text(),
- baz=Choice(values=[1, 2, 3]),
- )
-
- @implementer(schema)
- class OK(object):
- def __init__(self, foo=u'Foo', bar=u'Bar', baz=2):
- self.foo = foo
- self.bar = bar
- self.baz = baz
- ok1 = OK()
- ok2 = OK(u'Foo2', u'Bar2', 3)
- log = []
- subscribers.append(log.append)
-
- def _replace(event):
- event.object = ok2
- subscribers.append(_replace)
- objf = self._makeOne(schema, __name__='field')
- inst = DummyInstance()
- self.assertEqual(len(log), 4)
- objf.set(inst, ok1)
- self.assertEqual(inst.field is ok2, True)
- self.assertEqual(len(log), 5)
- self.assertEqual(log[-1].object, ok2)
- self.assertEqual(log[-1].name, 'field')
- self.assertEqual(log[-1].context, inst)
-
- def test_validates_invariants_by_default(self):
- from zope.interface import invariant
- from zope.interface import Interface
- from zope.interface import implementer
- from zope.interface import Invalid
- from zope.schema import Text
- from zope.schema import Bytes
-
- class ISchema(Interface):
-
- foo = Text()
- bar = Bytes()
-
- @invariant
- def check_foo(self):
- if self.foo == u'bar':
- raise Invalid("Foo is not valid")
-
- @invariant
- def check_bar(self):
- if self.bar == b'foo':
- raise Invalid("Bar is not valid")
-
- @implementer(ISchema)
- class O(object):
- foo = u''
- bar = b''
-
-
- field = self._makeOne(ISchema)
- inst = O()
-
- # Fine at first
- field.validate(inst)
-
- inst.foo = u'bar'
- errors = self._getErrors(field.validate, inst)
- self.assertEqual(len(errors), 1)
- self.assertEqual(errors[0].args[0], "Foo is not valid")
-
- del inst.foo
- inst.bar = b'foo'
- errors = self._getErrors(field.validate, inst)
- self.assertEqual(len(errors), 1)
- self.assertEqual(errors[0].args[0], "Bar is not valid")
-
- # Both invalid
- inst.foo = u'bar'
- errors = self._getErrors(field.validate, inst)
- self.assertEqual(len(errors), 2)
- errors.sort(key=lambda i: i.args)
- self.assertEqual(errors[0].args[0], "Bar is not valid")
- self.assertEqual(errors[1].args[0], "Foo is not valid")
-
- # We can specifically ask for invariants to be turned off.
- field = self._makeOne(ISchema, validate_invariants=False)
- field.validate(inst)
-
- def test_schema_defined_by_subclass(self):
- from zope import interface
- from zope.schema.interfaces import SchemaNotProvided
-
- class IValueType(interface.Interface):
- "The value type schema"
-
- class Field(self._getTargetClass()):
- schema = IValueType
-
- field = Field()
- self.assertIs(field.schema, IValueType)
-
- # Non implementation is bad
- self.assertRaises(SchemaNotProvided, field.validate, object())
-
- # Actual implementation works
- @interface.implementer(IValueType)
- class ValueType(object):
- "The value type"
-
-
- field.validate(ValueType())
-
- def test_bound_field_of_collection_with_choice(self):
- # https://github.com/zopefoundation/zope.schema/issues/17
- from zope.interface import Interface, implementer
- from zope.interface import Attribute
-
- from zope.schema import Choice, Object, Set
- from zope.schema.fieldproperty import FieldProperty
- from zope.schema.interfaces import IContextSourceBinder
- from zope.schema.interfaces import WrongContainedType
- from zope.schema.interfaces import SchemaNotCorrectlyImplemented
- from zope.schema.vocabulary import SimpleVocabulary
-
-
- @implementer(IContextSourceBinder)
- class EnumContext(object):
- def __call__(self, context):
- return SimpleVocabulary.fromValues(list(context))
-
- class IMultipleChoice(Interface):
- choices = Set(value_type=Choice(source=EnumContext()))
- # Provide a regular attribute to prove that binding doesn't
- # choke. NOTE: We don't actually verify the existence of this attribute.
- non_field = Attribute("An attribute")
-
- @implementer(IMultipleChoice)
- class Choices(object):
-
- def __init__(self, choices):
- self.choices = choices
-
- def __iter__(self):
- # EnumContext calls this to make the vocabulary.
- # Fields of the schema of the IObject are bound to the value being
- # validated.
- return iter(range(5))
-
- class IFavorites(Interface):
- fav = Object(title=u"Favorites number", schema=IMultipleChoice)
-
-
- @implementer(IFavorites)
- class Favorites(object):
- fav = FieldProperty(IFavorites['fav'])
-
- # must not raise
- good_choices = Choices({1, 3})
- IFavorites['fav'].validate(good_choices)
-
- # Ranges outside the context fail
- bad_choices = Choices({1, 8})
- with self.assertRaises(WrongContainedType) as exc:
- IFavorites['fav'].validate(bad_choices)
-
- e = exc.exception
- self.assertEqual(IFavorites['fav'], e.field)
- self.assertEqual(bad_choices, e.value)
-
- # Validation through field property
- favorites = Favorites()
- favorites.fav = good_choices
-
- # And validation through a field that wants IFavorites
- favorites_field = Object(IFavorites)
- favorites_field.validate(favorites)
-
- # Check the field property error
- with self.assertRaises(SchemaNotCorrectlyImplemented) as exc:
- favorites.fav = bad_choices
-
- e = exc.exception
- self.assertEqual(IFavorites['fav'], e.field)
- self.assertEqual(bad_choices, e.value)
- self.assertEqual(['choices'], list(e.schema_errors))
-
-
class MappingTests(EqualityTestsMixin,
unittest.TestCase):
@@ -2221,7 +1731,7 @@ class MappingTests(EqualityTestsMixin,
def test_bind_binds_key_and_value_types(self):
from zope.schema import Int
field = self._makeOne(key_type=Int(), value_type=Int())
- context = DummyInstance()
+ context = object()
field2 = field.bind(context)
self.assertEqual(field2.key_type.context, context)
self.assertEqual(field2.value_type.context, context)
@@ -2295,10 +1805,6 @@ class DictTests(MutableMappingTests):
super(DictTests, self).test_mutable_mapping()
-class DummyInstance(object):
- pass
-
-
def _makeSampleVocabulary():
from zope.interface import implementer
from zope.schema.interfaces import IVocabulary