diff --git a/CHANGES.txt b/CHANGES.txt index 9fd31c8..66f179c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,8 @@ Changes Next release ------------ +- Various error message improvements. + - Add ``colander.Length`` validator class. 0.2 (2010-03-23) diff --git a/colander/__init__.py b/colander/__init__.py index 81aa562..5a23ef4 100644 --- a/colander/__init__.py +++ b/colander/__init__.py @@ -98,13 +98,13 @@ class Range(object): if value < self.min: raise Invalid( node, - '%r is less than minimum value %r' % (value, self.min)) + '%s is less than minimum value %s' % (value, self.min)) if self.max is not None: if value > self.max: raise Invalid( node, - '%r is greater than maximum value %r' % (value, self.max)) + '%s is greater than maximum value %s' % (value, self.max)) class Length(object): """ Validator which succeeds if the value passed to it has a @@ -190,7 +190,7 @@ class Mapping(object): if subnode.required: raise Invalid( subnode, - '%r is required but missing' % subnode.name) + '"%s" is required but missing' % subnode.name) result[name] = default_callback(subnode) else: result[name] = callback(subnode, subval) @@ -400,13 +400,13 @@ class Integer(object): if node.required: raise Invalid(node, 'Required') return node.default - raise Invalid(node, '%r is not a number' % value) + raise Invalid(node, '"%s" is not a number' % value) def serialize(self, node, value): try: return str(int(value)) except Exception: - raise Invalid(node, '%r is not a number' % value) + raise Invalid(node, '"%s" is not a number' % value) Int = Integer @@ -424,13 +424,13 @@ class Float(object): if node.required: raise Invalid(node, 'Required') return node.default - raise Invalid(node, '%r is not a number' % value) + raise Invalid(node, '"%s" is not a number' % value) def serialize(self, node, value): try: return str(float(value)) except Exception: - raise Invalid(node, '%r is not a number' % value) + raise Invalid(node, '"%s" is not a number' % value) Int = Integer @@ -512,7 +512,7 @@ class GlobalObject(object): if not self.package: raise Invalid( node, - 'relative name %r irresolveable without package' % value) + 'relative name "%s" irresolveable without package' % value) if value in ['.', ':']: value = self.package.__name__ else: @@ -527,7 +527,7 @@ class GlobalObject(object): if self.package is None: raise Invalid( node, - "relative name %r irresolveable without package" % value) + 'relative name "%s" irresolveable without package' % value) name = module.split('.') else: name = value.split('.') @@ -535,7 +535,7 @@ class GlobalObject(object): if module is None: raise Invalid( node, - "relative name %r irresolveable without package" % + 'relative name "%s" irresolveable without package' % value) module = module.split('.') name.pop(0) @@ -558,7 +558,7 @@ class GlobalObject(object): def deserialize(self, node, value): if not isinstance(value, basestring): - raise Invalid(node, '%r is not a string' % value) + raise Invalid(node, '"%s" is not a string' % value) try: if ':' in value: return self._pkg_resources_style(node, value) @@ -566,7 +566,7 @@ class GlobalObject(object): return self._zope_dottedname_style(node, value) except ImportError: raise Invalid(node, - 'The dotted name %r cannot be imported' % value) + 'The dotted name "%s" cannot be imported' % value) def serialize(self, node, value): try: diff --git a/colander/tests.py b/colander/tests.py index c75b98b..6a2244a 100644 --- a/colander/tests.py +++ b/colander/tests.py @@ -255,7 +255,7 @@ class TestMapping(unittest.TestCase): ] typ = self._makeOne() e = invalid_exc(typ.deserialize, node, {'a':1}) - self.assertEqual(e.children[0].msg, "'b' is required but missing") + self.assertEqual(e.children[0].msg, '"b" is required but missing') def test_serialize_not_a_mapping(self): node = DummySchemaNode(None) @@ -320,7 +320,7 @@ class TestMapping(unittest.TestCase): ] typ = self._makeOne() e = invalid_exc(typ.serialize, node, {'a':1}) - self.assertEqual(e.children[0].msg, "'b' is required but missing") + self.assertEqual(e.children[0].msg, '"b" is required but missing') class TestTuple(unittest.TestCase): def _makeOne(self): @@ -776,13 +776,13 @@ class TestGlobalObject(unittest.TestCase): e = invalid_exc(typ._zope_dottedname_style, None, '.') self.assertEqual( e.msg, - "relative name '.' irresolveable without package") + 'relative name "." irresolveable without package') def test_zope_dottedname_style_resolve_relative_nocurrentpackage(self): typ = self._makeOne() e = invalid_exc(typ._zope_dottedname_style, None, '.whatever') self.assertEqual( - e.msg, "relative name '.whatever' irresolveable without package") + e.msg, 'relative name ".whatever" irresolveable without package') def test_zope_dottedname_style_irrresolveable_relative(self): import colander.tests @@ -852,7 +852,7 @@ class TestGlobalObject(unittest.TestCase): def test_deserialize_not_a_string(self): typ = self._makeOne() e = invalid_exc(typ.deserialize, None, None) - self.assertEqual(e.msg, "None is not a string") + self.assertEqual(e.msg, '"None" is not a string') def test_deserialize_using_pkgresources_style(self): typ = self._makeOne() @@ -868,7 +868,7 @@ class TestGlobalObject(unittest.TestCase): typ = self._makeOne() e = invalid_exc(typ.deserialize, None, 'cant.be.found') self.assertEqual(e.msg, - "The dotted name 'cant.be.found' cannot be imported") + 'The dotted name "cant.be.found" cannot be imported') def test_serialize_ok(self): import colander.tests @@ -1028,16 +1028,16 @@ class TestFunctional(object): def test_invalid_asdict(self): expected = { 'int': '20 is greater than maximum value 10', - 'ob': "The dotted name 'no.way.this.exists' cannot be imported", - 'seq.0.0': "'q' is not a number", - 'seq.1.0': "'w' is not a number", - 'seq.2.0': "'e' is not a number", - 'seq.3.0': "'r' is not a number", - 'seq2.0.key': "'t' is not a number", - 'seq2.0.key2': "'y' is not a number", - 'seq2.1.key': "'u' is not a number", - 'seq2.1.key2': "'i' is not a number", - 'tup.0': "'s' is not a number"} + 'ob': 'The dotted name "no.way.this.exists" cannot be imported', + 'seq.0.0': '"q" is not a number', + 'seq.1.0': '"w" is not a number', + 'seq.2.0': '"e" is not a number', + 'seq.3.0': '"r" is not a number', + 'seq2.0.key': '"t" is not a number', + 'seq2.0.key2': '"y" is not a number', + 'seq2.1.key': '"u" is not a number', + 'seq2.1.key2': '"i" is not a number', + 'tup.0': '"s" is not a number'} data = { 'int':'20', 'ob':'no.way.this.exists',