[Python-modules-commits] [voluptuous] 01/08: Add the tests which are missing from PyPI tarball.
Barry Warsaw
barry at moszumanska.debian.org
Tue Aug 2 19:01:49 UTC 2016
This is an automated email from the git hooks/post-receive script.
barry pushed a commit to branch master
in repository voluptuous.
commit 16548658044a65ca84051912460826694f97bebe
Author: Barry Warsaw <barry at ubuntu.com>
Date: Tue Aug 2 14:05:07 2016 -0400
Add the tests which are missing from PyPI tarball.
Bug: https://github.com/alecthomas/voluptuous/issues/188
Forwarded: not-needed
Patch-Name: restore-tests.patch
---
voluptuous/tests/__init__.py | 1 +
voluptuous/tests/tests.md | 268 +++++++++++++++++++++++++++
voluptuous/tests/tests.py | 421 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 690 insertions(+)
diff --git a/voluptuous/tests/__init__.py b/voluptuous/tests/__init__.py
new file mode 100644
index 0000000..f29719c
--- /dev/null
+++ b/voluptuous/tests/__init__.py
@@ -0,0 +1 @@
+__author__ = 'tusharmakkar08'
diff --git a/voluptuous/tests/tests.md b/voluptuous/tests/tests.md
new file mode 100644
index 0000000..18f6fba
--- /dev/null
+++ b/voluptuous/tests/tests.md
@@ -0,0 +1,268 @@
+Error reporting should be accurate:
+
+ >>> from voluptuous import *
+ >>> schema = Schema(['one', {'two': 'three', 'four': ['five'],
+ ... 'six': {'seven': 'eight'}}])
+ >>> schema(['one'])
+ ['one']
+ >>> schema([{'two': 'three'}])
+ [{'two': 'three'}]
+
+It should show the exact index and container type, in this case a list
+value:
+
+ >>> try:
+ ... schema(['one', 'two'])
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc) == 'expected a dictionary @ data[1]'
+ True
+
+It should also be accurate for nested values:
+
+ >>> try:
+ ... schema([{'two': 'nine'}])
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc)
+ "not a valid value for dictionary value @ data[0]['two']"
+
+ >>> try:
+ ... schema([{'four': ['nine']}])
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc)
+ "not a valid value @ data[0]['four'][0]"
+
+ >>> try:
+ ... schema([{'six': {'seven': 'nine'}}])
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc)
+ "not a valid value for dictionary value @ data[0]['six']['seven']"
+
+Errors should be reported depth-first:
+
+ >>> validate = Schema({'one': {'two': 'three', 'four': 'five'}})
+ >>> try:
+ ... validate({'one': {'four': 'six'}})
+ ... except Invalid as e:
+ ... print(e)
+ ... print(e.path)
+ not a valid value for dictionary value @ data['one']['four']
+ ['one', 'four']
+
+Voluptuous supports validation when extra fields are present in the
+data:
+
+ >>> schema = Schema({'one': 1, Extra: object})
+ >>> schema({'two': 'two', 'one': 1}) == {'two': 'two', 'one': 1}
+ True
+ >>> schema = Schema({'one': 1})
+ >>> try:
+ ... schema({'two': 2})
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc)
+ "extra keys not allowed @ data['two']"
+
+dict, list, and tuple should be available as type validators:
+
+ >>> Schema(dict)({'a': 1, 'b': 2}) == {'a': 1, 'b': 2}
+ True
+ >>> Schema(list)([1,2,3])
+ [1, 2, 3]
+ >>> Schema(tuple)((1,2,3))
+ (1, 2, 3)
+
+Validation should return instances of the right types when the types are
+subclasses of dict or list:
+
+ >>> class Dict(dict):
+ ... pass
+ >>>
+ >>> d = Schema(dict)(Dict(a=1, b=2))
+ >>> d == {'a': 1, 'b': 2}
+ True
+ >>> type(d) is Dict
+ True
+ >>> class List(list):
+ ... pass
+ >>>
+ >>> l = Schema(list)(List([1,2,3]))
+ >>> l
+ [1, 2, 3]
+ >>> type(l) is List
+ True
+
+Multiple errors are reported:
+
+ >>> schema = Schema({'one': 1, 'two': 2})
+ >>> try:
+ ... schema({'one': 2, 'two': 3, 'three': 4})
+ ... except MultipleInvalid as e:
+ ... errors = sorted(e.errors, key=lambda k: str(k))
+ ... print([str(i) for i in errors]) # doctest: +NORMALIZE_WHITESPACE
+ ["extra keys not allowed @ data['three']",
+ "not a valid value for dictionary value @ data['one']",
+ "not a valid value for dictionary value @ data['two']"]
+ >>> schema = Schema([[1], [2], [3]])
+ >>> try:
+ ... schema([1, 2, 3])
+ ... except MultipleInvalid as e:
+ ... print([str(i) for i in e.errors]) # doctest: +NORMALIZE_WHITESPACE
+ ['expected a list @ data[0]',
+ 'expected a list @ data[1]',
+ 'expected a list @ data[2]']
+
+Required fields in dictionary which are invalid should not have required :
+
+ >>> from voluptuous import *
+ >>> schema = Schema({'one': {'two': 3}}, required=True)
+ >>> try:
+ ... schema({'one': {'two': 2}})
+ ... except MultipleInvalid as e:
+ ... errors = e.errors
+ >>> 'required' in ' '.join([x.msg for x in errors])
+ False
+
+Multiple errors for nested fields in dicts and objects:
+
+> \>\>\> from collections import namedtuple \>\>\> validate = Schema({
+> ... 'anobject': Object({ ... 'strfield': str, ... 'intfield': int ...
+> }) ... }) \>\>\> try: ... SomeObj = namedtuple('SomeObj', ('strfield',
+> 'intfield')) ... validate({'anobject': SomeObj(strfield=123,
+> intfield='one')}) ... except MultipleInvalid as e: ...
+> print(sorted(str(i) for i in e.errors)) \# doctest:
+> +NORMALIZE\_WHITESPACE ["expected int for object value @
+> data['anobject']['intfield']", "expected str for object value @
+> data['anobject']['strfield']"]
+
+Custom classes validate as schemas:
+
+ >>> class Thing(object):
+ ... pass
+ >>> schema = Schema(Thing)
+ >>> t = schema(Thing())
+ >>> type(t) is Thing
+ True
+
+Classes with custom metaclasses should validate as schemas:
+
+ >>> class MyMeta(type):
+ ... pass
+ >>> class Thing(object):
+ ... __metaclass__ = MyMeta
+ >>> schema = Schema(Thing)
+ >>> t = schema(Thing())
+ >>> type(t) is Thing
+ True
+
+Schemas built with All() should give the same error as the original
+validator (Issue \#26):
+
+ >>> schema = Schema({
+ ... Required('items'): All([{
+ ... Required('foo'): str
+ ... }])
+ ... })
+
+ >>> try:
+ ... schema({'items': [{}]})
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc)
+ "required key not provided @ data['items'][0]['foo']"
+
+Validator should return same instance of the same type for object:
+
+ >>> class Structure(object):
+ ... def __init__(self, q=None):
+ ... self.q = q
+ ... def __repr__(self):
+ ... return '{0.__name__}(q={1.q!r})'.format(type(self), self)
+ ...
+ >>> schema = Schema(Object({'q': 'one'}, cls=Structure))
+ >>> type(schema(Structure(q='one'))) is Structure
+ True
+
+Object validator should treat cls argument as optional. In this case it
+shouldn't check object type:
+
+ >>> from collections import namedtuple
+ >>> NamedTuple = namedtuple('NamedTuple', ('q',))
+ >>> schema = Schema(Object({'q': 'one'}))
+ >>> named = NamedTuple(q='one')
+ >>> schema(named) == named
+ True
+ >>> schema(named)
+ NamedTuple(q='one')
+
+If cls argument passed to object validator we should check object type:
+
+ >>> schema = Schema(Object({'q': 'one'}, cls=Structure))
+ >>> schema(NamedTuple(q='one')) # doctest: +IGNORE_EXCEPTION_DETAIL
+ Traceback (most recent call last):
+ ...
+ MultipleInvalid: expected a <class 'Structure'>
+ >>> schema = Schema(Object({'q': 'one'}, cls=NamedTuple))
+ >>> schema(NamedTuple(q='one'))
+ NamedTuple(q='one')
+
+Ensure that objects with \_\_slots\_\_ supported properly:
+
+ >>> class SlotsStructure(Structure):
+ ... __slots__ = ['q']
+ ...
+ >>> schema = Schema(Object({'q': 'one'}))
+ >>> schema(SlotsStructure(q='one'))
+ SlotsStructure(q='one')
+ >>> class DictStructure(object):
+ ... __slots__ = ['q', '__dict__']
+ ... def __init__(self, q=None, page=None):
+ ... self.q = q
+ ... self.page = page
+ ... def __repr__(self):
+ ... return '{0.__name__}(q={1.q!r}, page={1.page!r})'.format(type(self), self)
+ ...
+ >>> structure = DictStructure(q='one')
+ >>> structure.page = 1
+ >>> try:
+ ... schema(structure)
+ ... raise AssertionError('MultipleInvalid not raised')
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> str(exc)
+ "extra keys not allowed @ data['page']"
+
+ >>> schema = Schema(Object({'q': 'one', Extra: object}))
+ >>> schema(structure)
+ DictStructure(q='one', page=1)
+
+Ensure that objects can be used with other validators:
+
+ >>> schema = Schema({'meta': Object({'q': 'one'})})
+ >>> schema({'meta': Structure(q='one')})
+ {'meta': Structure(q='one')}
+
+Ensure that subclasses of Invalid of are raised as is.
+
+ >>> class SpecialInvalid(Invalid):
+ ... pass
+ ...
+ >>> def custom_validator(value):
+ ... raise SpecialInvalid('boom')
+ ...
+ >>> schema = Schema({'thing': custom_validator})
+ >>> try:
+ ... schema({'thing': 'not an int'})
+ ... except MultipleInvalid as e:
+ ... exc = e
+ >>> exc.errors[0].__class__.__name__
+ 'SpecialInvalid'
diff --git a/voluptuous/tests/tests.py b/voluptuous/tests/tests.py
new file mode 100644
index 0000000..2b77272
--- /dev/null
+++ b/voluptuous/tests/tests.py
@@ -0,0 +1,421 @@
+import copy
+from nose.tools import assert_equal, assert_raises
+
+from voluptuous import (
+ Schema, Required, Extra, Invalid, In, Remove, Literal,
+ Url, MultipleInvalid, LiteralInvalid, NotIn, Match, Email,
+ Replace, Range, Coerce, All, Any, Length, FqdnUrl, ALLOW_EXTRA, PREVENT_EXTRA,
+ validate_schema,
+)
+from voluptuous.humanize import humanize_error
+
+
+def test_required():
+ """Verify that Required works."""
+ schema = Schema({Required('q'): 1})
+ # Can't use nose's raises (because we need to access the raised
+ # exception, nor assert_raises which fails with Python 2.6.9.
+ try:
+ schema({})
+ except Invalid as e:
+ assert_equal(str(e), "required key not provided @ data['q']")
+ else:
+ assert False, "Did not raise Invalid"
+
+
+def test_extra_with_required():
+ """Verify that Required does not break Extra."""
+ schema = Schema({Required('toaster'): str, Extra: object})
+ r = schema({'toaster': 'blue', 'another_valid_key': 'another_valid_value'})
+ assert_equal(
+ r, {'toaster': 'blue', 'another_valid_key': 'another_valid_value'})
+
+
+def test_iterate_candidates():
+ """Verify that the order for iterating over mapping candidates is right."""
+ schema = {
+ "toaster": str,
+ Extra: object,
+ }
+ # toaster should be first.
+ from voluptuous.schema_builder import _iterate_mapping_candidates
+ assert_equal(_iterate_mapping_candidates(schema)[0][0], 'toaster')
+
+
+def test_in():
+ """Verify that In works."""
+ schema = Schema({"color": In(frozenset(["blue", "red", "yellow"]))})
+ schema({"color": "blue"})
+
+
+def test_not_in():
+ """Verify that NotIn works."""
+ schema = Schema({"color": NotIn(frozenset(["blue", "red", "yellow"]))})
+ schema({"color": "orange"})
+ try:
+ schema({"color": "blue"})
+ except Invalid as e:
+ assert_equal(str(e), "value is not allowed for dictionary value @ data['color']")
+ else:
+ assert False, "Did not raise NotInInvalid"
+
+
+def test_remove():
+ """Verify that Remove works."""
+ # remove dict keys
+ schema = Schema({"weight": int,
+ Remove("color"): str,
+ Remove("amount"): int})
+ out_ = schema({"weight": 10, "color": "red", "amount": 1})
+ assert "color" not in out_ and "amount" not in out_
+
+ # remove keys by type
+ schema = Schema({"weight": float,
+ "amount": int,
+ # remvove str keys with int values
+ Remove(str): int,
+ # keep str keys with str values
+ str: str})
+ out_ = schema({"weight": 73.4,
+ "condition": "new",
+ "amount": 5,
+ "left": 2})
+ # amount should stay since it's defined
+ # other string keys with int values will be removed
+ assert "amount" in out_ and "left" not in out_
+ # string keys with string values will stay
+ assert "condition" in out_
+
+ # remove value from list
+ schema = Schema([Remove(1), int])
+ out_ = schema([1, 2, 3, 4, 1, 5, 6, 1, 1, 1])
+ assert_equal(out_, [2, 3, 4, 5, 6])
+
+ # remove values from list by type
+ schema = Schema([1.0, Remove(float), int])
+ out_ = schema([1, 2, 1.0, 2.0, 3.0, 4])
+ assert_equal(out_, [1, 2, 1.0, 4])
+
+
+def test_extra_empty_errors():
+ schema = Schema({'a': {Extra: object}}, required=True)
+ schema({'a': {}})
+
+
+def test_literal():
+ """ test with Literal """
+
+ schema = Schema([Literal({"a": 1}), Literal({"b": 1})])
+ schema([{"a": 1}])
+ schema([{"b": 1}])
+ schema([{"a": 1}, {"b": 1}])
+
+ try:
+ schema([{"c": 1}])
+ except Invalid as e:
+ assert_equal(str(e), "{'c': 1} not match for {'b': 1} @ data[0]")
+ else:
+ assert False, "Did not raise Invalid"
+
+ schema = Schema(Literal({"a": 1}))
+ try:
+ schema({"b": 1})
+ except MultipleInvalid as e:
+ assert_equal(str(e), "{'b': 1} not match for {'a': 1}")
+ assert_equal(len(e.errors), 1)
+ assert_equal(type(e.errors[0]), LiteralInvalid)
+ else:
+ assert False, "Did not raise Invalid"
+
+
+def test_email_validation():
+ """ test with valid email """
+ schema = Schema({"email": Email()})
+ out_ = schema({"email": "example at example.com"})
+
+ assert 'example at example.com"', out_.get("url")
+
+
+def test_email_validation_with_none():
+ """ test with invalid None Email"""
+ schema = Schema({"email": Email()})
+ try:
+ schema({"email": None})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected an Email for dictionary value @ data['email']")
+ else:
+ assert False, "Did not raise Invalid for None url"
+
+
+def test_email_validation_with_empty_string():
+ """ test with empty string Email"""
+ schema = Schema({"email": Email()})
+ try:
+ schema({"email": ''})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected an Email for dictionary value @ data['email']")
+ else:
+ assert False, "Did not raise Invalid for empty string url"
+
+
+def test_email_validation_without_host():
+ """ test with empty host name in email """
+ schema = Schema({"email": Email()})
+ try:
+ schema({"email": 'a at .com'})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected an Email for dictionary value @ data['email']")
+ else:
+ assert False, "Did not raise Invalid for empty string url"
+
+
+def test_fqdn_url_validation():
+ """ test with valid fully qualified domain name url """
+ schema = Schema({"url": FqdnUrl()})
+ out_ = schema({"url": "http://example.com/"})
+
+ assert 'http://example.com/', out_.get("url")
+
+
+def test_fqdn_url_without_domain_name():
+ """ test with invalid fully qualified domain name url """
+ schema = Schema({"url": FqdnUrl()})
+ try:
+ schema({"url": "http://localhost/"})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a Fully qualified domain name URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for None url"
+
+
+def test_fqdnurl_validation_with_none():
+ """ test with invalid None FQDN url"""
+ schema = Schema({"url": FqdnUrl()})
+ try:
+ schema({"url": None})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a Fully qualified domain name URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for None url"
+
+
+def test_fqdnurl_validation_with_empty_string():
+ """ test with empty string FQDN URL """
+ schema = Schema({"url": FqdnUrl()})
+ try:
+ schema({"url": ''})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a Fully qualified domain name URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for empty string url"
+
+
+def test_fqdnurl_validation_without_host():
+ """ test with empty host FQDN URL """
+ schema = Schema({"url": FqdnUrl()})
+ try:
+ schema({"url": 'http://'})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a Fully qualified domain name URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for empty string url"
+
+
+def test_url_validation():
+ """ test with valid URL """
+ schema = Schema({"url": Url()})
+ out_ = schema({"url": "http://example.com/"})
+
+ assert 'http://example.com/', out_.get("url")
+
+
+def test_url_validation_with_none():
+ """ test with invalid None url"""
+ schema = Schema({"url": Url()})
+ try:
+ schema({"url": None})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for None url"
+
+
+def test_url_validation_with_empty_string():
+ """ test with empty string URL """
+ schema = Schema({"url": Url()})
+ try:
+ schema({"url": ''})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for empty string url"
+
+
+def test_url_validation_without_host():
+ """ test with empty host URL """
+ schema = Schema({"url": Url()})
+ try:
+ schema({"url": 'http://'})
+ except MultipleInvalid as e:
+ assert_equal(str(e),
+ "expected a URL for dictionary value @ data['url']")
+ else:
+ assert False, "Did not raise Invalid for empty string url"
+
+
+def test_copy_dict_undefined():
+ """ test with a copied dictionary """
+ fields = {
+ Required("foo"): int
+ }
+ copied_fields = copy.deepcopy(fields)
+
+ schema = Schema(copied_fields)
+
+ # This used to raise a `TypeError` because the instance of `Undefined`
+ # was a copy, so object comparison would not work correctly.
+ try:
+ schema({"foo": "bar"})
+ except Exception as e:
+ assert isinstance(e, MultipleInvalid)
+
+
+def test_sorting():
+ """ Expect alphabetic sorting """
+ foo = Required('foo')
+ bar = Required('bar')
+ items = [foo, bar]
+ expected = [bar, foo]
+ result = sorted(items)
+ assert result == expected
+
+
+def test_schema_extend():
+ """Verify that Schema.extend copies schema keys from both."""
+
+ base = Schema({'a': int}, required=True)
+ extension = {'b': str}
+ extended = base.extend(extension)
+
+ assert base.schema == {'a': int}
+ assert extension == {'b': str}
+ assert extended.schema == {'a': int, 'b': str}
+ assert extended.required == base.required
+ assert extended.extra == base.extra
+
+
+def test_schema_extend_overrides():
+ """Verify that Schema.extend can override required/extra parameters."""
+
+ base = Schema({'a': int}, required=True)
+ extended = base.extend({'b': str}, required=False, extra=ALLOW_EXTRA)
+
+ assert base.required is True
+ assert base.extra == PREVENT_EXTRA
+ assert extended.required is False
+ assert extended.extra == ALLOW_EXTRA
+
+
+def test_repr():
+ """Verify that __repr__ returns valid Python expressions"""
+ match = Match('a pattern', msg='message')
+ replace = Replace('you', 'I', msg='you and I')
+ range_ = Range(min=0, max=42, min_included=False,
+ max_included=False, msg='number not in range')
+ coerce_ = Coerce(int, msg="moo")
+ all_ = All('10', Coerce(int), msg='all msg')
+
+ assert_equal(repr(match), "Match('a pattern', msg='message')")
+ assert_equal(repr(replace), "Replace('you', 'I', msg='you and I')")
+ assert_equal(
+ repr(range_),
+ "Range(min=0, max=42, min_included=False, max_included=False, msg='number not in range')"
+ )
+ assert_equal(repr(coerce_), "Coerce(int, msg='moo')")
+ assert_equal(repr(all_), "All('10', Coerce(int, msg=None), msg='all msg')")
+
+
+def test_list_validation_messages():
+ """ Make sure useful error messages are available """
+
+ def is_even(value):
+ if value % 2:
+ raise Invalid('%i is not even' % value)
+ return value
+
+ schema = Schema(dict(even_numbers=[All(int, is_even)]))
+
+ try:
+ schema(dict(even_numbers=[3]))
+ except Invalid as e:
+ assert_equal(len(e.errors), 1, e.errors)
+ assert_equal(str(e.errors[0]), "3 is not even @ data['even_numbers'][0]")
+ assert_equal(str(e), "3 is not even @ data['even_numbers'][0]")
+ else:
+ assert False, "Did not raise Invalid"
+
+
+def test_nested_multiple_validation_errors():
+ """ Make sure useful error messages are available """
+
+ def is_even(value):
+ if value % 2:
+ raise Invalid('%i is not even' % value)
+ return value
+
+ schema = Schema(dict(even_numbers=All([All(int, is_even)],
+ Length(min=1))))
+
+ try:
+ schema(dict(even_numbers=[3]))
+ except Invalid as e:
+ assert_equal(len(e.errors), 1, e.errors)
+ assert_equal(str(e.errors[0]), "3 is not even @ data['even_numbers'][0]")
+ assert_equal(str(e), "3 is not even @ data['even_numbers'][0]")
+ else:
+ assert False, "Did not raise Invalid"
+
+
+def test_humanize_error():
+ data = {
+ 'a': 'not an int',
+ 'b': [123]
+ }
+ schema = Schema({
+ 'a': int,
+ 'b': [str]
+ })
+ try:
+ schema(data)
+ except MultipleInvalid as e:
+ assert_equal(
+ humanize_error(data, e),
+ "expected int for dictionary value @ data['a']. Got 'not an int'\n"
+ "expected str @ data['b'][0]. Got 123"
+ )
+ else:
+ assert False, 'Did not raise MultipleInvalid'
+
+
+def test_fix_157():
+ s = Schema(All([Any('one', 'two', 'three')]), Length(min=1))
+ assert_equal(['one'], s(['one']))
+ assert_raises(MultipleInvalid, s, ['four'])
+
+
+def test_schema_decorator():
+ @validate_schema(int)
+ def fn(arg):
+ return arg
+
+ fn(1)
+ assert_raises(Invalid, fn, 1.0)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/voluptuous.git
More information about the Python-modules-commits
mailing list