From 503f7da25dc9f245b9bb4c42cc1b7ba62d9032f2 Mon Sep 17 00:00:00 2001 From: Antoni Szych Date: Fri, 15 Dec 2023 13:50:16 +0100 Subject: [PATCH] normalize strings --- pyproject.toml | 1 - setup.py | 48 ++-- voluptuous/__init__.py | 4 +- voluptuous/error.py | 6 +- voluptuous/humanize.py | 6 +- voluptuous/schema_builder.py | 68 ++--- voluptuous/tests/__init__.py | 2 +- voluptuous/tests/tests.py | 512 +++++++++++++++++------------------ voluptuous/util.py | 12 +- voluptuous/validators.py | 130 ++++----- 10 files changed, 394 insertions(+), 395 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index af6fa6b..71e754a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,5 @@ [tool.black] target-version = ["py38", "py39", "py310", "py311", "py312"] -skip-string-normalization = true [tool.isort] skip_gitignore = true diff --git a/setup.py b/setup.py index efaa50c..32e83e6 100644 --- a/setup.py +++ b/setup.py @@ -3,41 +3,41 @@ from setuptools import setup -sys.path.insert(0, '.') -version = __import__('voluptuous').__version__ +sys.path.insert(0, ".") +version = __import__("voluptuous").__version__ -with io.open('README.md', encoding='utf-8') as f: +with io.open("README.md", encoding="utf-8") as f: long_description = f.read() setup( - name='voluptuous', - url='https://github.com/alecthomas/voluptuous', - download_url='https://pypi.python.org/pypi/voluptuous', + name="voluptuous", + url="https://github.com/alecthomas/voluptuous", + download_url="https://pypi.python.org/pypi/voluptuous", version=version, - description='Python data validation library', + description="Python data validation library", long_description=long_description, - long_description_content_type='text/markdown', - license='BSD-3-Clause', - platforms=['any'], - packages=['voluptuous'], + long_description_content_type="text/markdown", + license="BSD-3-Clause", + platforms=["any"], + packages=["voluptuous"], package_data={ - 'voluptuous': ['py.typed'], + "voluptuous": ["py.typed"], }, - author='Alec Thomas', - author_email='alec@swapoff.org', + author="Alec Thomas", + author_email="alec@swapoff.org", python_requires=">=3.8", classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], ) diff --git a/voluptuous/__init__.py b/voluptuous/__init__.py index ad6669b..2357096 100644 --- a/voluptuous/__init__.py +++ b/voluptuous/__init__.py @@ -8,5 +8,5 @@ # fmt: on -__version__ = '0.14.1' -__author__ = 'alecthomas' +__version__ = "0.14.1" +__author__ = "alecthomas" diff --git a/voluptuous/error.py b/voluptuous/error.py index 9dab943..f68c273 100644 --- a/voluptuous/error.py +++ b/voluptuous/error.py @@ -47,10 +47,10 @@ def error_message(self) -> str: return self._error_message def __str__(self) -> str: - path = ' @ data[%s]' % ']['.join(map(repr, self.path)) if self.path else '' + path = " @ data[%s]" % "][".join(map(repr, self.path)) if self.path else "" output = Exception.__str__(self) if self.error_type: - output += ' for ' + self.error_type + output += " for " + self.error_type return output + path def prepend(self, path: typing.List[typing.Hashable]) -> None: @@ -62,7 +62,7 @@ def __init__(self, errors: typing.Optional[typing.List[Invalid]] = None) -> None self.errors = errors[:] if errors else [] def __repr__(self) -> str: - return 'MultipleInvalid(%r)' % self.errors + return "MultipleInvalid(%r)" % self.errors @property def msg(self) -> str: diff --git a/voluptuous/humanize.py b/voluptuous/humanize.py index eabfd02..7e9b371 100644 --- a/voluptuous/humanize.py +++ b/voluptuous/humanize.py @@ -33,7 +33,7 @@ def humanize_error( and MultipleInvalid.__str__ only provides the first error. """ if isinstance(validation_error, MultipleInvalid): - return '\n'.join( + return "\n".join( sorted( humanize_error(data, sub_error, max_sub_error_length) for sub_error in validation_error.errors @@ -43,9 +43,9 @@ def humanize_error( offending_item_summary = repr(_nested_getitem(data, validation_error.path)) if len(offending_item_summary) > max_sub_error_length: offending_item_summary = ( - offending_item_summary[: max_sub_error_length - 3] + '...' + offending_item_summary[: max_sub_error_length - 3] + "..." ) - return '%s. Got %s' % (validation_error, offending_item_summary) + return "%s. Got %s" % (validation_error, offending_item_summary) def validate_with_humanized_errors( diff --git a/voluptuous/schema_builder.py b/voluptuous/schema_builder.py index 6ad8758..4005544 100644 --- a/voluptuous/schema_builder.py +++ b/voluptuous/schema_builder.py @@ -99,7 +99,7 @@ def _isnamedtuple(obj): - return isinstance(obj, tuple) and hasattr(obj, '_fields') + return isinstance(obj, tuple) and hasattr(obj, "_fields") class Undefined(object): @@ -107,7 +107,7 @@ def __nonzero__(self): return False def __repr__(self): - return '...' + return "..." UNDEFINED = Undefined() @@ -134,9 +134,9 @@ def raises( yield except exc as e: if msg is not None: - assert str(e) == msg, '%r != %r' % (str(e), msg) + assert str(e) == msg, "%r != %r" % (str(e), msg) if regex is not None: - assert re.search(regex, str(e)), '%r does not match %r' % (str(e), regex) + assert re.search(regex, str(e)), "%r does not match %r" % (str(e), regex) else: raise AssertionError(f"Did not raise exception {exc.__name__}") @@ -186,9 +186,9 @@ class Schema(object): """ _extra_to_name = { - REMOVE_EXTRA: 'REMOVE_EXTRA', - ALLOW_EXTRA: 'ALLOW_EXTRA', - PREVENT_EXTRA: 'PREVENT_EXTRA', + REMOVE_EXTRA: "REMOVE_EXTRA", + ALLOW_EXTRA: "ALLOW_EXTRA", + PREVENT_EXTRA: "PREVENT_EXTRA", } def __init__( @@ -270,7 +270,7 @@ def __str__(self): def __repr__(self): return "" % ( self.schema, - self._extra_to_name.get(self.extra, '??'), + self._extra_to_name.get(self.extra, "??"), self.required, id(self), ) @@ -307,11 +307,11 @@ def _compile(self, schema): type_ = schema if type_ in (*primitive_types, object, type(None)) or callable(schema): return _compile_scalar(schema) - raise er.SchemaError('unsupported schema data type %r' % type(schema).__name__) + raise er.SchemaError("unsupported schema data type %r" % type(schema).__name__) def _compile_mapping(self, schema, invalid_msg=None): """Create validator for given mapping.""" - invalid_msg = invalid_msg or 'mapping value' + invalid_msg = invalid_msg or "mapping value" # Keys that may be required all_required_keys = set( @@ -443,15 +443,15 @@ def validate_mapping(path, iterable, out): elif self.extra == ALLOW_EXTRA: out[key] = value elif self.extra != REMOVE_EXTRA: - errors.append(er.Invalid('extra keys not allowed', key_path)) + errors.append(er.Invalid("extra keys not allowed", key_path)) # else REMOVE_EXTRA: ignore the key so it's removed from output # for any required keys left that weren't found and don't have defaults: for key in required_keys: msg = ( key.msg - if hasattr(key, 'msg') and key.msg - else 'required key not provided' + if hasattr(key, "msg") and key.msg + else "required key not provided" ) errors.append(er.RequiredFieldInvalid(msg, path + [key])) if errors: @@ -479,11 +479,11 @@ def _compile_object(self, schema): ... validate(Structure(one='three')) """ - base_validate = self._compile_mapping(schema, invalid_msg='object value') + base_validate = self._compile_mapping(schema, invalid_msg="object value") def validate_object(path, data): if schema.cls is not UNDEFINED and not isinstance(data, schema.cls): - raise er.ObjectInvalid('expected a {0!r}'.format(schema.cls), path) + raise er.ObjectInvalid("expected a {0!r}".format(schema.cls), path) iterable = _iterate_object(data) iterable = filter(lambda item: item[1] is not None, iterable) out = base_validate(path, iterable, {}) @@ -567,7 +567,7 @@ def _compile_dict(self, schema): "expected str for dictionary value @ data['adict']['strfield']"] """ - base_validate = self._compile_mapping(schema, invalid_msg='dictionary value') + base_validate = self._compile_mapping(schema, invalid_msg="dictionary value") groups_of_exclusion = {} groups_of_inclusion = {} @@ -581,7 +581,7 @@ def _compile_dict(self, schema): def validate_dict(path, data): if not isinstance(data, dict): - raise er.DictInvalid('expected a dictionary', path) + raise er.DictInvalid("expected a dictionary", path) errors = [] for label, group in groups_of_exclusion.items(): @@ -591,7 +591,7 @@ def validate_dict(path, data): if exists: msg = ( exclusive.msg - if hasattr(exclusive, 'msg') and exclusive.msg + if hasattr(exclusive, "msg") and exclusive.msg else "two or more values in the same group of exclusion '%s'" % label ) @@ -611,7 +611,7 @@ def validate_dict(path, data): % label ) for g in group: - if hasattr(g, 'msg') and g.msg: + if hasattr(g, "msg") and g.msg: msg = g.msg break next_path = path + [VirtualPathComponent(label)] @@ -644,13 +644,13 @@ def _compile_sequence(self, schema, seq_type): def validate_sequence(path, data): if not isinstance(data, seq_type): - raise er.SequenceTypeInvalid('expected a %s' % seq_type_name, path) + raise er.SequenceTypeInvalid("expected a %s" % seq_type_name, path) # Empty seq schema, reject any data. if not schema: if data: raise er.MultipleInvalid( - [er.ValueInvalid('not a valid value', path if path else data)] + [er.ValueInvalid("not a valid value", path if path else data)] ) return data @@ -731,7 +731,7 @@ def _compile_set(self, schema): def validate_set(path, data): if not isinstance(data, type_): - raise er.Invalid('expected a %s' % type_name, path) + raise er.Invalid("expected a %s" % type_name, path) _compiled = [self._compile(s) for s in schema] errors = [] @@ -743,7 +743,7 @@ def validate_set(path, data): except er.Invalid: pass else: - invalid = er.Invalid('invalid value in %s' % type_name, path) + invalid = er.Invalid("invalid value in %s" % type_name, path) errors.append(invalid) if errors: @@ -774,7 +774,7 @@ def extend( assert isinstance(self.schema, dict) and isinstance( schema, dict - ), 'Both schemas must be dictionary-based' + ), "Both schemas must be dictionary-based" result = self.schema.copy() @@ -843,7 +843,7 @@ def validate_instance(path, data): if isinstance(data, schema): return data else: - msg = 'expected %s' % schema.__name__ + msg = "expected %s" % schema.__name__ raise er.TypeInvalid(msg, path) return validate_instance @@ -854,7 +854,7 @@ def validate_callable(path, data): try: return schema(data) except ValueError: - raise er.ValueInvalid('not a valid value', path) + raise er.ValueInvalid("not a valid value", path) except er.Invalid as e: e.prepend(path) raise @@ -863,14 +863,14 @@ def validate_callable(path, data): def validate_value(path, data): if data != schema: - raise er.ScalarInvalid('not a valid value', path) + raise er.ScalarInvalid("not a valid value", path) return data return validate_value def _compile_itemsort(): - '''return sort function of mappings''' + """return sort function of mappings""" def is_extra(key_): return key_ is Extra @@ -932,7 +932,7 @@ def _iterate_object(obj): d = vars(obj) except TypeError: # maybe we have named tuple here? - if hasattr(obj, '_asdict'): + if hasattr(obj, "_asdict"): d = obj._asdict() for item in d.items(): yield item @@ -942,7 +942,7 @@ def _iterate_object(obj): pass else: for key in slots: - if key != '__dict__': + if key != "__dict__": yield (key, getattr(obj, key)) @@ -1000,7 +1000,7 @@ def __call__(self, v): raise (self.cls or er.Invalid)(self.msg) def __repr__(self): - return 'Msg(%s, %s, cls=%s)' % (self._schema, self.msg, self.cls) + return "Msg(%s, %s, cls=%s)" % (self._schema, self.msg, self.cls) class Object(dict): @@ -1013,7 +1013,7 @@ def __init__(self, schema: typing.Any, cls: object = UNDEFINED) -> None: class VirtualPathComponent(str): def __str__(self): - return '<' + self + '>' + return "<" + self + ">" def __repr__(self): return self.__str__() @@ -1296,7 +1296,7 @@ def wrapper(*args, **kwargs): return f(*args, **kwargs) except ValueError: raise (clsoverride or cls or er.ValueInvalid)( - msg or default or 'invalid value' + msg or default or "invalid value" ) return wrapper @@ -1347,7 +1347,7 @@ def validate(*a, **kw) -> typing.Callable: ... return arg1 * 2 """ - RETURNS_KEY = '__return__' + RETURNS_KEY = "__return__" def validate_schema_decorator(func): returns_defined = False diff --git a/voluptuous/tests/__init__.py b/voluptuous/tests/__init__.py index f29719c..ab1b4d0 100644 --- a/voluptuous/tests/__init__.py +++ b/voluptuous/tests/__init__.py @@ -1 +1 @@ -__author__ = 'tusharmakkar08' +__author__ = "tusharmakkar08" diff --git a/voluptuous/tests/tests.py b/voluptuous/tests/tests.py index 05b7e8e..a3e8127 100644 --- a/voluptuous/tests/tests.py +++ b/voluptuous/tests/tests.py @@ -25,7 +25,7 @@ def test_new_required_test(): schema = Schema( { - 'my_key': All(int, Range(1, 20)), + "my_key": All(int, Range(1, 20)), }, required=True, ) @@ -41,7 +41,7 @@ def test_exact_sequence(): def test_required(): """Verify that Required works.""" - schema = Schema({Required('q'): int}) + schema = Schema({Required("q"): int}) schema({"q": 123}) with raises(Invalid, "required key not provided @ data['q']"): schema({}) @@ -49,9 +49,9 @@ def test_required(): 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 r == {'toaster': 'blue', 'another_valid_key': 'another_valid_value'} + schema = Schema({Required("toaster"): str, Extra: object}) + r = schema({"toaster": "blue", "another_valid_key": "another_valid_value"}) + assert r == {"toaster": "blue", "another_valid_key": "another_valid_value"} def test_iterate_candidates(): @@ -63,7 +63,7 @@ def test_iterate_candidates(): # toaster should be first. from voluptuous.schema_builder import _iterate_mapping_candidates - assert _iterate_mapping_candidates(schema)[0][0] == 'toaster' + assert _iterate_mapping_candidates(schema)[0][0] == "toaster" def test_in(): @@ -94,13 +94,13 @@ def test_not_in(): def test_contains(): """Verify contains validation method.""" - schema = Schema({'color': Contains('red')}) - schema({'color': ['blue', 'red', 'yellow']}) + schema = Schema({"color": Contains("red")}) + schema({"color": ["blue", "red", "yellow"]}) with pytest.raises( MultipleInvalid, match=r"value is not allowed for dictionary value @ data\['color'\]", ) as ctx: - schema({'color': ['blue', 'yellow']}) + schema({"color": ["blue", "yellow"]}) assert len(ctx.value.errors) == 1 assert isinstance(ctx.value.errors[0], ContainsInvalid) @@ -142,8 +142,8 @@ def test_remove(): def test_extra_empty_errors(): - schema = Schema({'a': {Extra: object}}, required=True) - schema({'a': {}}) + schema = Schema({"a": {Extra: object}}, required=True) + schema({"a": {}}) def test_literal(): @@ -210,7 +210,7 @@ def test_email_validation_with_empty_string(): MultipleInvalid, match=r"expected an email address for dictionary value @ data\['email'\]", ) as ctx: - schema({"email": ''}) + schema({"email": ""}) assert len(ctx.value.errors) == 1 assert isinstance(ctx.value.errors[0], EmailInvalid) @@ -222,13 +222,13 @@ def test_email_validation_without_host(): MultipleInvalid, match=r"expected an email address for dictionary value @ data\['email'\]", ) as ctx: - schema({"email": 'a@.com'}) + schema({"email": "a@.com"}) assert len(ctx.value.errors) == 1 assert isinstance(ctx.value.errors[0], EmailInvalid) @pytest.mark.parametrize( - 'input_value', ['john@voluptuous.com>', 'john!@voluptuous.org!@($*!'] + "input_value", ["john@voluptuous.com>", "john!@voluptuous.org!@($*!"] ) def test_email_validation_with_bad_data(input_value: str): """Test with bad data in email address""" @@ -247,11 +247,11 @@ def test_fqdn_url_validation(): schema = Schema({"url": FqdnUrl()}) out_ = schema({"url": "http://example.com/"}) - assert 'http://example.com/', out_.get("url") + assert "http://example.com/", out_.get("url") @pytest.mark.parametrize( - 'input_value', + "input_value", [ pytest.param("http://localhost/", id="without domain name"), pytest.param(None, id="None"), @@ -275,11 +275,11 @@ def test_url_validation(): schema = Schema({"url": Url()}) out_ = schema({"url": "http://example.com/"}) - assert 'http://example.com/', out_.get("url") + assert "http://example.com/", out_.get("url") @pytest.mark.parametrize( - 'input_value', + "input_value", [ pytest.param(None, id="None"), pytest.param("", id="empty string"), @@ -313,8 +313,8 @@ def test_copy_dict_undefined(): def test_sorting(): """Expect alphabetic sorting""" - foo = Required('foo') - bar = Required('bar') + foo = Required("foo") + bar = Required("bar") items = [foo, bar] expected = [bar, foo] result = sorted(items) @@ -324,13 +324,13 @@ def test_sorting(): def test_schema_extend(): """Verify that Schema.extend copies schema keys from both.""" - base = Schema({'a': int}, required=True) - extension = {'b': str} + 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 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 assert isinstance(extended, Schema) @@ -338,8 +338,8 @@ def test_schema_extend(): 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) + 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 @@ -349,8 +349,8 @@ def test_schema_extend_overrides(): def test_schema_extend_key_swap(): """Verify that Schema.extend can replace keys, even when different markers are used""" - base = Schema({Optional('a'): int}) - extension = {Required('a'): int} + base = Schema({Optional("a"): int}) + extension = {Required("a"): int} extended = base.extend(extension) assert len(base.schema) == 1 @@ -361,13 +361,13 @@ def test_schema_extend_key_swap(): def test_subschema_extension(): """Verify that Schema.extend adds and replaces keys in a subschema""" - base = Schema({'a': {'b': int, 'c': float}}) - extension = {'d': str, 'a': {'b': str, 'e': int}} + base = Schema({"a": {"b": int, "c": float}}) + extension = {"d": str, "a": {"b": str, "e": int}} extended = base.extend(extension) - assert base.schema == {'a': {'b': int, 'c': float}} - assert extension == {'d': str, 'a': {'b': str, 'e': int}} - assert extended.schema == {'a': {'b': str, 'c': float, 'e': int}, 'd': str} + assert base.schema == {"a": {"b": int, "c": float}} + assert extension == {"d": str, "a": {"b": str, "e": int}} + assert extended.schema == {"a": {"b": str, "c": float, "e": int}, "d": str} def test_schema_extend_handles_schema_subclass(): @@ -376,85 +376,85 @@ def test_schema_extend_handles_schema_subclass(): class S(Schema): pass - base = S({Required('a'): int}) - extension = {Optional('b'): str} + base = S({Required("a"): int}) + extension = {Optional("b"): str} extended = base.extend(extension) - expected_schema = {Required('a'): int, Optional('b'): str} + expected_schema = {Required("a"): int, Optional("b"): str} assert extended.schema == expected_schema assert isinstance(extended, S) def test_equality(): - assert Schema('foo') == Schema('foo') + assert Schema("foo") == Schema("foo") - assert Schema(['foo', 'bar', 'baz']) == Schema(['foo', 'bar', 'baz']) + assert Schema(["foo", "bar", "baz"]) == Schema(["foo", "bar", "baz"]) # Ensure two Schemas w/ two equivalent dicts initialized in a different # order are considered equal. dict_a = {} - dict_a['foo'] = 1 - dict_a['bar'] = 2 - dict_a['baz'] = 3 + dict_a["foo"] = 1 + dict_a["bar"] = 2 + dict_a["baz"] = 3 dict_b = {} - dict_b['baz'] = 3 - dict_b['bar'] = 2 - dict_b['foo'] = 1 + dict_b["baz"] = 3 + dict_b["bar"] = 2 + dict_b["foo"] = 1 assert Schema(dict_a) == Schema(dict_b) def test_equality_negative(): """Verify that Schema objects are not equal to string representations""" - assert not Schema('foo') == 'foo' + assert not Schema("foo") == "foo" - assert not Schema(['foo', 'bar']) == "['foo', 'bar']" - assert not Schema(['foo', 'bar']) == Schema("['foo', 'bar']") + assert not Schema(["foo", "bar"]) == "['foo', 'bar']" + assert not Schema(["foo", "bar"]) == Schema("['foo', 'bar']") - assert not Schema({'foo': 1, 'bar': 2}) == "{'foo': 1, 'bar': 2}" - assert not Schema({'foo': 1, 'bar': 2}) == Schema("{'foo': 1, 'bar': 2}") + assert not Schema({"foo": 1, "bar": 2}) == "{'foo': 1, 'bar': 2}" + assert not Schema({"foo": 1, "bar": 2}) == Schema("{'foo': 1, 'bar': 2}") def test_inequality(): - assert Schema('foo') != 'foo' + assert Schema("foo") != "foo" - assert Schema(['foo', 'bar']) != "['foo', 'bar']" - assert Schema(['foo', 'bar']) != Schema("['foo', 'bar']") + assert Schema(["foo", "bar"]) != "['foo', 'bar']" + assert Schema(["foo", "bar"]) != Schema("['foo', 'bar']") - assert Schema({'foo': 1, 'bar': 2}) != "{'foo': 1, 'bar': 2}" - assert Schema({'foo': 1, 'bar': 2}) != Schema("{'foo': 1, 'bar': 2}") + assert Schema({"foo": 1, "bar": 2}) != "{'foo': 1, 'bar': 2}" + assert Schema({"foo": 1, "bar": 2}) != Schema("{'foo': 1, 'bar': 2}") def test_inequality_negative(): - assert not Schema('foo') != Schema('foo') + assert not Schema("foo") != Schema("foo") - assert not Schema(['foo', 'bar', 'baz']) != Schema(['foo', 'bar', 'baz']) + assert not Schema(["foo", "bar", "baz"]) != Schema(["foo", "bar", "baz"]) # Ensure two Schemas w/ two equivalent dicts initialized in a different # order are considered equal. dict_a = {} - dict_a['foo'] = 1 - dict_a['bar'] = 2 - dict_a['baz'] = 3 + dict_a["foo"] = 1 + dict_a["bar"] = 2 + dict_a["baz"] = 3 dict_b = {} - dict_b['baz'] = 3 - dict_b['bar'] = 2 - dict_b['foo'] = 1 + dict_b["baz"] = 3 + dict_b["bar"] = 2 + dict_b["foo"] = 1 assert not Schema(dict_a) != Schema(dict_b) def test_repr(): """Verify that __repr__ returns valid Python expressions""" - match = Match('a pattern', msg='message') - replace = Replace('you', 'I', msg='you and I') + 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' + 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') + all_ = All("10", Coerce(int), msg="all msg") maybe_int = Maybe(int) assert repr(match) == "Match('a pattern', msg='message')" @@ -473,7 +473,7 @@ def test_list_validation_messages(): def is_even(value): if value % 2: - raise Invalid('%i is not even' % value) + raise Invalid("%i is not even" % value) return value schema = Schema(dict(even_numbers=[All(int, is_even)])) @@ -493,7 +493,7 @@ def test_nested_multiple_validation_errors(): def is_even(value): if value % 2: - raise Invalid('%i is not even' % value) + raise Invalid("%i is not even" % value) return value schema = Schema(dict(even_numbers=All([All(int, is_even)], Length(min=1)))) @@ -509,8 +509,8 @@ def is_even(value): def test_humanize_error(): - data = {'a': 'not an int', 'b': [123]} - schema = Schema({'a': int, 'b': [str]}) + data = {"a": "not an int", "b": [123]} + schema = Schema({"a": int, "b": [str]}) with pytest.raises(MultipleInvalid) as ctx: schema(data) assert len(ctx.value.errors) == 2 @@ -520,10 +520,10 @@ def test_humanize_error(): def test_fix_157(): - s = Schema(All([Any('one', 'two', 'three')]), Length(min=1)) - assert ['one'] == s(['one']) + s = Schema(All([Any("one", "two", "three")]), Length(min=1)) + assert ["one"] == s(["one"]) with pytest.raises(MultipleInvalid): - s(['four']) + s(["four"]) def test_range_inside(): @@ -555,7 +555,7 @@ def test_range_no_lower_limit(): def test_range_excludes_nan(): s = Schema(Range(min=0, max=10)) - pytest.raises(MultipleInvalid, s, float('nan')) + pytest.raises(MultipleInvalid, s, float("nan")) def test_range_excludes_none(): @@ -604,7 +604,7 @@ def test_clamp_invalid(): def test_length_ok(): - v1 = ['a', 'b', 'c'] + v1 = ["a", "b", "c"] s = Schema(Length(min=1, max=10)) assert v1 == s(v1) v2 = "abcde" @@ -617,12 +617,12 @@ def test_length_too_short(): with pytest.raises(MultipleInvalid): s(v1) with pytest.raises(MultipleInvalid): - v2 = '' + v2 = "" s(v2) def test_length_too_long(): - v = ['a', 'b', 'c'] + v = ["a", "b", "c"] s = Schema(Length(min=0, max=2)) with pytest.raises(MultipleInvalid): s(v) @@ -639,16 +639,16 @@ def test_equal(): s = Schema(Equal(1)) s(1) pytest.raises(Invalid, s, 2) - s = Schema(Equal('foo')) - s('foo') - pytest.raises(Invalid, s, 'bar') + s = Schema(Equal("foo")) + s("foo") + pytest.raises(Invalid, s, "bar") s = Schema(Equal([1, 2])) s([1, 2]) pytest.raises(Invalid, s, []) pytest.raises(Invalid, s, [1, 2, 3]) # Evaluates exactly, not through validators s = Schema(Equal(str)) - pytest.raises(Invalid, s, 'foo') + pytest.raises(Invalid, s, "foo") def test_unordered(): @@ -664,14 +664,14 @@ def test_unordered(): pytest.raises(Invalid, s, [1, 2, 0]) pytest.raises(MultipleInvalid, s, [1, 2, 0, 0]) # Other type than list or tuple is NOK - pytest.raises(Invalid, s, 'foo') + pytest.raises(Invalid, s, "foo") pytest.raises(Invalid, s, 10) # Validators are evaluated through as schemas s = Schema(Unordered([int, str])) - s([1, '2']) - s(['1', 2]) - s = Schema(Unordered([{'foo': int}, []])) - s([{'foo': 3}, []]) + s([1, "2"]) + s(["1", 2]) + s = Schema(Unordered([{"foo": int}, []])) + s([{"foo": 3}, []]) # Most accurate validators must be positioned on left s = Schema(Unordered([int, 3])) pytest.raises(Invalid, s, [3, 2]) @@ -683,17 +683,17 @@ def test_maybe(): s = Schema(Maybe(int)) assert s(1) == 1 assert s(None) is None - pytest.raises(Invalid, s, 'foo') + pytest.raises(Invalid, s, "foo") s = Schema(Maybe({str: Coerce(int)})) - assert s({'foo': '100'}) == {'foo': 100} + assert s({"foo": "100"}) == {"foo": 100} assert s(None) is None - pytest.raises(Invalid, s, {'foo': 'bar'}) + pytest.raises(Invalid, s, {"foo": "bar"}) def test_maybe_accepts_msg(): - s = Schema(Maybe(int, msg='int or None expected')) - with raises(MultipleInvalid, 'int or None expected'): + s = Schema(Maybe(int, msg="int or None expected")) + with raises(MultipleInvalid, "int or None expected"): assert s([]) @@ -726,7 +726,7 @@ def test_schema_empty_list(): assert False, "Did not raise correct Invalid" try: - s({'var': 123}) + s({"var": 123}) except MultipleInvalid as e: assert str(e) == "expected a list" else: @@ -738,7 +738,7 @@ def test_schema_empty_dict(): s({}) try: - s({'var': 123}) + s({"var": 123}) except MultipleInvalid as e: assert str(e) == "extra keys not allowed @ data['var']" else: @@ -754,11 +754,11 @@ def test_schema_empty_dict(): def test_schema_empty_dict_key(): """https://github.com/alecthomas/voluptuous/pull/434""" - s = Schema({'var': []}) - s({'var': []}) + s = Schema({"var": []}) + s({"var": []}) try: - s({'var': [123]}) + s({"var": [123]}) except MultipleInvalid as e: assert str(e) == "not a valid value for dictionary value @ data['var']" else: @@ -881,7 +881,7 @@ def test_number_validation_with_string(): """Test with Number with string""" schema = Schema({"number": Number(precision=6, scale=2)}) try: - schema({"number": 'teststr'}) + schema({"number": "teststr"}) except MultipleInvalid as e: assert ( str(e) @@ -895,7 +895,7 @@ def test_number_validation_with_invalid_precision_invalid_scale(): """Test with Number with invalid precision and scale""" schema = Schema({"number": Number(precision=6, scale=2)}) try: - schema({"number": '123456.712'}) + schema({"number": "123456.712"}) except MultipleInvalid as e: assert ( str(e) @@ -908,28 +908,28 @@ def test_number_validation_with_invalid_precision_invalid_scale(): def test_number_validation_with_valid_precision_scale_yield_decimal_true(): """Test with Number with valid precision and scale""" schema = Schema({"number": Number(precision=6, scale=2, yield_decimal=True)}) - out_ = schema({"number": '1234.00'}) + out_ = schema({"number": "1234.00"}) assert float(out_.get("number")) == 1234.00 def test_number_when_precision_scale_none_yield_decimal_true(): """Test with Number with no precision and scale""" schema = Schema({"number": Number(yield_decimal=True)}) - out_ = schema({"number": '12345678901234'}) + out_ = schema({"number": "12345678901234"}) assert out_.get("number") == 12345678901234 def test_number_when_precision_none_n_valid_scale_case1_yield_decimal_true(): """Test with Number with no precision and valid scale case 1""" schema = Schema({"number": Number(scale=2, yield_decimal=True)}) - out_ = schema({"number": '123456789.34'}) + out_ = schema({"number": "123456789.34"}) assert float(out_.get("number")) == 123456789.34 def test_number_when_precision_none_n_valid_scale_case2_yield_decimal_true(): """Test with Number with no precision and valid scale case 2 with zero in decimal part""" schema = Schema({"number": Number(scale=2, yield_decimal=True)}) - out_ = schema({"number": '123456789012.00'}) + out_ = schema({"number": "123456789012.00"}) assert float(out_.get("number")) == 123456789012.00 @@ -937,7 +937,7 @@ def test_number_when_precision_none_n_invalid_scale_yield_decimal_true(): """Test with Number with no precision and invalid scale""" schema = Schema({"number": Number(scale=2, yield_decimal=True)}) try: - schema({"number": '12345678901.234'}) + schema({"number": "12345678901.234"}) except MultipleInvalid as e: assert ( str(e) == "Scale must be equal to 2 for dictionary value @ data['number']" @@ -949,7 +949,7 @@ def test_number_when_precision_none_n_invalid_scale_yield_decimal_true(): def test_number_when_valid_precision_n_scale_none_yield_decimal_true(): """Test with Number with no precision and valid scale""" schema = Schema({"number": Number(precision=14, yield_decimal=True)}) - out_ = schema({"number": '1234567.8901234'}) + out_ = schema({"number": "1234567.8901234"}) assert float(out_.get("number")) == 1234567.8901234 @@ -957,7 +957,7 @@ def test_number_when_invalid_precision_n_scale_none_yield_decimal_true(): """Test with Number with no precision and invalid scale""" schema = Schema({"number": Number(precision=14, yield_decimal=True)}) try: - schema({"number": '12345674.8901234'}) + schema({"number": "12345674.8901234"}) except MultipleInvalid as e: assert ( str(e) @@ -970,12 +970,12 @@ def test_number_when_invalid_precision_n_scale_none_yield_decimal_true(): def test_number_validation_with_valid_precision_scale_yield_decimal_false(): """Test with Number with valid precision, scale and no yield_decimal""" schema = Schema({"number": Number(precision=6, scale=2, yield_decimal=False)}) - out_ = schema({"number": '1234.00'}) - assert out_.get("number") == '1234.00' + out_ = schema({"number": "1234.00"}) + assert out_.get("number") == "1234.00" def test_named_tuples_validate_as_tuples(): - NT = collections.namedtuple('NT', ['a', 'b']) + NT = collections.namedtuple("NT", ["a", "b"]) nt = NT(1, 2) t = (1, 2) @@ -1004,7 +1004,7 @@ def test_date_custom_format(): def test_ordered_dict(): - if not hasattr(collections, 'OrderedDict'): + if not hasattr(collections, "OrderedDict"): # collections.OrderedDict was added in Python2.7; only run if present return schema = Schema({Number(): Number()}) # x, y pairs (for interpolation or something) @@ -1020,53 +1020,53 @@ def test_ordered_dict(): ] ) out = schema(data) - assert isinstance(out, collections.OrderedDict), 'Collection is no longer ordered' - assert data.keys() == out.keys(), 'Order is not consistent' + assert isinstance(out, collections.OrderedDict), "Collection is no longer ordered" + assert data.keys() == out.keys(), "Order is not consistent" def test_marker_hashable(): """Verify that you can get schema keys, even if markers were used""" definition = { - Required('x'): int, - Optional('y'): float, - Remove('j'): int, + Required("x"): int, + Optional("y"): float, + Remove("j"): int, Remove(int): str, int: int, } - assert definition.get('x') == int - assert definition.get('y') == float - assert Required('x') == Required('x') - assert Required('x') != Required('y') + assert definition.get("x") == int + assert definition.get("y") == float + assert Required("x") == Required("x") + assert Required("x") != Required("y") # Remove markers are not hashable - assert definition.get('j') is None + assert definition.get("j") is None def test_schema_infer(): - schema = Schema.infer({'str': 'foo', 'bool': True, 'int': 42, 'float': 3.14}) + schema = Schema.infer({"str": "foo", "bool": True, "int": 42, "float": 3.14}) assert schema == Schema( { - Required('str'): str, - Required('bool'): bool, - Required('int'): int, - Required('float'): float, + Required("str"): str, + Required("bool"): bool, + Required("int"): int, + Required("float"): float, } ) def test_schema_infer_dict(): - schema = Schema.infer({'a': {'b': {'c': 'foo'}}}) + schema = Schema.infer({"a": {"b": {"c": "foo"}}}) - assert schema == Schema({Required('a'): {Required('b'): {Required('c'): str}}}) + assert schema == Schema({Required("a"): {Required("b"): {Required("c"): str}}}) def test_schema_infer_list(): - schema = Schema.infer({'list': ['foo', True, 42, 3.14]}) + schema = Schema.infer({"list": ["foo", True, 42, 3.14]}) - assert schema == Schema({Required('list'): [str, bool, int, float]}) + assert schema == Schema({Required("list"): [str, bool, int, float]}) def test_schema_infer_scalar(): - assert Schema.infer('foo') == Schema(str) + assert Schema.infer("foo") == Schema(str) assert Schema.infer(True) == Schema(bool) assert Schema.infer(42) == Schema(int) assert Schema.infer(3.14) == Schema(float) @@ -1075,21 +1075,21 @@ def test_schema_infer_scalar(): def test_schema_infer_accepts_kwargs(): - schema = Schema.infer({'str': 'foo', 'bool': True}, required=False, extra=True) + schema = Schema.infer({"str": "foo", "bool": True}, required=False, extra=True) # Subset of schema should be acceptable thanks to required=False. - schema({'bool': False}) + schema({"bool": False}) # Keys that are in schema should still match required types. try: - schema({'str': 42}) + schema({"str": 42}) except Invalid: pass else: - assert False, 'Did not raise Invalid for Number' + assert False, "Did not raise Invalid for Number" # Extra fields should be acceptable thanks to extra=True. - schema({'str': 'bar', 'int': 42}) + schema({"str": "bar", "int": 42}) def test_validation_performance(): @@ -1156,20 +1156,20 @@ def test_PathExists(): def test_description(): - marker = Marker(Schema(str), description='Hello') - assert marker.description == 'Hello' + marker = Marker(Schema(str), description="Hello") + assert marker.description == "Hello" - optional = Optional('key', description='Hello') - assert optional.description == 'Hello' + optional = Optional("key", description="Hello") + assert optional.description == "Hello" - exclusive = Exclusive('alpha', 'angles', description='Hello') - assert exclusive.description == 'Hello' + exclusive = Exclusive("alpha", "angles", description="Hello") + assert exclusive.description == "Hello" - inclusive = Inclusive('alpha', 'angles', description='Hello') - assert inclusive.description == 'Hello' + inclusive = Inclusive("alpha", "angles", description="Hello") + assert inclusive.description == "Hello" - required = Required('key', description='Hello') - assert required.description == 'Hello' + required = Required("key", description="Hello") + assert required.description == "Hello" def test_SomeOf_min_validation(): @@ -1178,39 +1178,39 @@ def test_SomeOf_min_validation(): SomeOf( min_valid=3, validators=[ - Match(r'.*[A-Z]', 'no uppercase letters'), - Match(r'.*[a-z]', 'no lowercase letters'), - Match(r'.*[0-9]', 'no numbers'), - Match(r'.*[$@$!%*#?&^:;/<,>|{}()\-\'._+=]', 'no symbols'), + Match(r".*[A-Z]", "no uppercase letters"), + Match(r".*[a-z]", "no lowercase letters"), + Match(r".*[0-9]", "no numbers"), + Match(r".*[$@$!%*#?&^:;/<,>|{}()\-\'._+=]", "no symbols"), ], ), ) - validator('ffe532A1!') - with raises(MultipleInvalid, 'length of value must be at least 8'): - validator('a') + validator("ffe532A1!") + with raises(MultipleInvalid, "length of value must be at least 8"): + validator("a") - with raises(MultipleInvalid, 'no uppercase letters, no lowercase letters'): - validator('1232!#4111') + with raises(MultipleInvalid, "no uppercase letters, no lowercase letters"): + validator("1232!#4111") - with raises(MultipleInvalid, 'no lowercase letters, no symbols'): - validator('3A34SDEF5') + with raises(MultipleInvalid, "no lowercase letters, no symbols"): + validator("3A34SDEF5") def test_SomeOf_max_validation(): validator = SomeOf( max_valid=2, validators=[ - Match(r'.*[A-Z]', 'no uppercase letters'), - Match(r'.*[a-z]', 'no lowercase letters'), - Match(r'.*[0-9]', 'no numbers'), + Match(r".*[A-Z]", "no uppercase letters"), + Match(r".*[a-z]", "no lowercase letters"), + Match(r".*[0-9]", "no numbers"), ], - msg='max validation test failed', + msg="max validation test failed", ) - validator('Aa') - with raises(TooManyValid, 'max validation test failed'): - validator('Aa1') + validator("Aa") + with raises(TooManyValid, "max validation test failed"): + validator("Aa1") def test_self_validation(): @@ -1219,7 +1219,7 @@ def test_self_validation(): schema({"number": "abc"}) with raises(MultipleInvalid): - schema({"follow": {"number": '123456.712'}}) + schema({"follow": {"number": "123456.712"}}) schema({"follow": {"number": 123456}}) schema({"follow": {"follow": {"number": 123456}}}) @@ -1227,26 +1227,26 @@ def test_self_validation(): def test_any_error_has_path(): """https://github.com/alecthomas/voluptuous/issues/347""" - s = Schema({Optional('q'): int, Required('q2'): Any(int, msg='toto')}) + s = Schema({Optional("q"): int, Required("q2"): Any(int, msg="toto")}) with pytest.raises(MultipleInvalid) as ctx: - s({'q': 'str', 'q2': 'tata'}) + s({"q": "str", "q2": "tata"}) assert ( - ctx.value.errors[0].path == ['q'] and ctx.value.errors[1].path == ['q2'] - ) or (ctx.value.errors[1].path == ['q'] and ctx.value.errors[0].path == ['q2']) + ctx.value.errors[0].path == ["q"] and ctx.value.errors[1].path == ["q2"] + ) or (ctx.value.errors[1].path == ["q"] and ctx.value.errors[0].path == ["q2"]) def test_all_error_has_path(): """https://github.com/alecthomas/voluptuous/issues/347""" s = Schema( { - Optional('q'): int, - Required('q2'): All([str, Length(min=10)], msg='toto'), + Optional("q"): int, + Required("q2"): All([str, Length(min=10)], msg="toto"), } ) with pytest.raises(MultipleInvalid) as ctx: - s({'q': 'str', 'q2': 12}) + s({"q": "str", "q2": 12}) assert len(ctx.value.errors) == 2 assert ( @@ -1257,49 +1257,49 @@ def test_all_error_has_path(): and isinstance(ctx.value.errors[0], AllInvalid) ) assert ( - ctx.value.errors[0].path == ['q'] and ctx.value.errors[1].path == ['q2'] - ) or (ctx.value.errors[1].path == ['q'] and ctx.value.errors[0].path == ['q2']) + ctx.value.errors[0].path == ["q"] and ctx.value.errors[1].path == ["q2"] + ) or (ctx.value.errors[1].path == ["q"] and ctx.value.errors[0].path == ["q2"]) def test_match_error_has_path(): """https://github.com/alecthomas/voluptuous/issues/347""" s = Schema( { - Required('q2'): Match("a"), + Required("q2"): Match("a"), } ) with pytest.raises(MultipleInvalid) as ctx: - s({'q2': 12}) + s({"q2": 12}) assert len(ctx.value.errors) == 1 assert isinstance(ctx.value.errors[0], MatchInvalid) - assert ctx.value.errors[0].path == ['q2'] + assert ctx.value.errors[0].path == ["q2"] def test_path_with_string(): """Most common dict use with strings as keys""" - s = Schema({'string_key': int}) + s = Schema({"string_key": int}) with pytest.raises(MultipleInvalid) as ctx: - s({'string_key': 'str'}) - assert ctx.value.errors[0].path == ['string_key'] + s({"string_key": "str"}) + assert ctx.value.errors[0].path == ["string_key"] def test_path_with_list_index(): """Position of the offending list index included in path as int""" - s = Schema({'string_key': [int]}) + s = Schema({"string_key": [int]}) with pytest.raises(MultipleInvalid) as ctx: - s({'string_key': [123, 'should be int']}) - assert ctx.value.errors[0].path == ['string_key', 1] + s({"string_key": [123, "should be int"]}) + assert ctx.value.errors[0].path == ["string_key", 1] def test_path_with_tuple_index(): """Position of the offending tuple index included in path as int""" - s = Schema({'string_key': (int,)}) + s = Schema({"string_key": (int,)}) with pytest.raises(MultipleInvalid) as ctx: - s({'string_key': (123, 'should be int')}) - assert ctx.value.errors[0].path == ['string_key', 1] + s({"string_key": (123, "should be int")}) + assert ctx.value.errors[0].path == ["string_key", 1] def test_path_with_integer_dict_key(): @@ -1307,7 +1307,7 @@ def test_path_with_integer_dict_key(): s = Schema({1337: int}) with pytest.raises(MultipleInvalid) as ctx: - s({1337: 'should be int'}) + s({1337: "should be int"}) assert ctx.value.errors[0].path == [1337] @@ -1316,17 +1316,17 @@ def test_path_with_float_dict_key(): s = Schema({13.37: int}) with pytest.raises(MultipleInvalid) as ctx: - s({13.37: 'should be int'}) + s({13.37: "should be int"}) assert ctx.value.errors[0].path == [13.37] def test_path_with_tuple_dict_key(): """Not obvious case with dict having not strings, but tuples as keys""" - s = Schema({('fancy', 'key'): int}) + s = Schema({("fancy", "key"): int}) with pytest.raises(MultipleInvalid) as ctx: - s({('fancy', 'key'): 'should be int'}) - assert ctx.value.errors[0].path == [('fancy', 'key')] + s({("fancy", "key"): "should be int"}) + assert ctx.value.errors[0].path == [("fancy", "key")] def test_path_with_arbitrary_hashable_dict_key(): @@ -1341,7 +1341,7 @@ def __hash__(self): hashable_obj_provided_in_input = HashableObjectWhichWillBeKeyInDict() with pytest.raises(MultipleInvalid) as ctx: - s({hashable_obj_provided_in_input: [0, 1, 'should be int']}) + s({hashable_obj_provided_in_input: [0, 1, "should be int"]}) assert ctx.value.errors[0].path == [hashable_obj_provided_in_input, 2] @@ -1353,7 +1353,7 @@ def test_self_any(): assert isinstance(ctx.value.errors[0], TypeInvalid) with raises(MultipleInvalid): - schema({"follow": {"number": '123456.712'}}) + schema({"follow": {"number": "123456.712"}}) schema({"follow": {"number": 123456}}) schema({"follow": {"follow": {"number": 123456}}}) @@ -1374,7 +1374,7 @@ def test_self_all(): assert isinstance(ctx.value.errors[0], TypeInvalid) with pytest.raises(MultipleInvalid) as ctx: - schema({"follow": {"number": '123456.712'}}) + schema({"follow": {"number": "123456.712"}}) assert len(ctx.value.errors) == 1 assert isinstance(ctx.value.errors[0], TypeInvalid) @@ -1397,29 +1397,29 @@ def test_SomeOf_on_bounds_assertion(): def test_comparing_voluptuous_object_to_str(): - assert Optional('Classification') < 'Name' + assert Optional("Classification") < "Name" def test_set_of_integers(): schema = Schema({int}) - with raises(Invalid, 'expected a set'): + with raises(Invalid, "expected a set"): schema(42) - with raises(Invalid, 'expected a set'): + with raises(Invalid, "expected a set"): schema(frozenset([42])) schema(set()) schema(set([42])) schema(set([42, 43, 44])) with pytest.raises(MultipleInvalid, match="invalid value in set") as ctx: - schema(set(['abc'])) + schema(set(["abc"])) assert len(ctx.value.errors) == 1 def test_frozenset_of_integers(): schema = Schema(frozenset([int])) - with raises(Invalid, 'expected a frozenset'): + with raises(Invalid, "expected a frozenset"): schema(42) - with raises(Invalid, 'expected a frozenset'): + with raises(Invalid, "expected a frozenset"): schema(set([42])) schema(frozenset()) @@ -1427,19 +1427,19 @@ def test_frozenset_of_integers(): schema(frozenset([42, 43, 44])) with pytest.raises(MultipleInvalid, match="invalid value in frozenset") as ctx: - schema(frozenset(['abc'])) + schema(frozenset(["abc"])) assert len(ctx.value.errors) == 1 def test_set_of_integers_and_strings(): schema = Schema({int, str}) - with raises(Invalid, 'expected a set'): + with raises(Invalid, "expected a set"): schema(42) schema(set()) schema(set([42])) - schema(set(['abc'])) - schema(set([42, 'abc'])) + schema(set(["abc"])) + schema(set([42, "abc"])) with pytest.raises(MultipleInvalid, match="invalid value in set") as ctx: schema(set([None])) @@ -1448,13 +1448,13 @@ def test_set_of_integers_and_strings(): def test_frozenset_of_integers_and_strings(): schema = Schema(frozenset([int, str])) - with raises(Invalid, 'expected a frozenset'): + with raises(Invalid, "expected a frozenset"): schema(42) schema(frozenset()) schema(frozenset([42])) - schema(frozenset(['abc'])) - schema(frozenset([42, 'abc'])) + schema(frozenset(["abc"])) + schema(frozenset([42, "abc"])) with pytest.raises(MultipleInvalid, match="invalid value in frozenset") as ctx: schema(frozenset([None])) @@ -1463,43 +1463,43 @@ def test_frozenset_of_integers_and_strings(): def test_lower_util_handles_various_inputs(): assert Lower(3) == "3" - assert Lower(u"3") == u"3" - assert Lower(b'\xe2\x98\x83'.decode("UTF-8")) == b'\xe2\x98\x83'.decode("UTF-8") - assert Lower(u"A") == u"a" + assert Lower("3") == "3" + assert Lower(b"\xe2\x98\x83".decode("UTF-8")) == b"\xe2\x98\x83".decode("UTF-8") + assert Lower("A") == "a" def test_upper_util_handles_various_inputs(): assert Upper(3) == "3" - assert Upper(u"3") == u"3" - assert Upper(b'\xe2\x98\x83'.decode("UTF-8")) == b'\xe2\x98\x83'.decode("UTF-8") - assert Upper(u"a") == u"A" + assert Upper("3") == "3" + assert Upper(b"\xe2\x98\x83".decode("UTF-8")) == b"\xe2\x98\x83".decode("UTF-8") + assert Upper("a") == "A" def test_capitalize_util_handles_various_inputs(): assert Capitalize(3) == "3" - assert Capitalize(u"3") == u"3" - assert Capitalize(b'\xe2\x98\x83'.decode("UTF-8")) == b'\xe2\x98\x83'.decode( + assert Capitalize("3") == "3" + assert Capitalize(b"\xe2\x98\x83".decode("UTF-8")) == b"\xe2\x98\x83".decode( "UTF-8" ) - assert Capitalize(u"aaa aaa") == u"Aaa aaa" + assert Capitalize("aaa aaa") == "Aaa aaa" def test_title_util_handles_various_inputs(): assert Title(3) == "3" - assert Title(u"3") == u"3" - assert Title(b'\xe2\x98\x83'.decode("UTF-8")) == b'\xe2\x98\x83'.decode("UTF-8") - assert Title(u"aaa aaa") == u"Aaa Aaa" + assert Title("3") == "3" + assert Title(b"\xe2\x98\x83".decode("UTF-8")) == b"\xe2\x98\x83".decode("UTF-8") + assert Title("aaa aaa") == "Aaa Aaa" def test_strip_util_handles_various_inputs(): assert Strip(3) == "3" - assert Strip(u"3") == u"3" - assert Strip(b'\xe2\x98\x83'.decode("UTF-8")) == b'\xe2\x98\x83'.decode("UTF-8") - assert Strip(u" aaa ") == u"aaa" + assert Strip("3") == "3" + assert Strip(b"\xe2\x98\x83".decode("UTF-8")) == b"\xe2\x98\x83".decode("UTF-8") + assert Strip(" aaa ") == "aaa" def test_any_required(): - schema = Schema(Any({'a': int}, {'b': str}, required=True)) + schema = Schema(Any({"a": int}, {"b": str}, required=True)) with raises(MultipleInvalid, "required key not provided @ data['a']"): schema({}) @@ -1507,7 +1507,7 @@ def test_any_required(): def test_any_required_with_subschema(): schema = Schema( - Any({'a': Any(float, int)}, {'b': int}, {'c': {'aa': int}}, required=True) + Any({"a": Any(float, int)}, {"b": int}, {"c": {"aa": int}}, required=True) ) with raises(MultipleInvalid, "required key not provided @ data['a']"): @@ -1517,81 +1517,81 @@ def test_any_required_with_subschema(): def test_inclusive(): schema = Schema( { - Inclusive('x', 'stuff'): int, - Inclusive('y', 'stuff'): int, + Inclusive("x", "stuff"): int, + Inclusive("y", "stuff"): int, } ) r = schema({}) assert r == {} - r = schema({'x': 1, 'y': 2}) - assert r == {'x': 1, 'y': 2} + r = schema({"x": 1, "y": 2}) + assert r == {"x": 1, "y": 2} with raises( MultipleInvalid, "some but not all values in the same group of inclusion 'stuff' @ data[]", ): - schema({'x': 1}) + schema({"x": 1}) def test_inclusive_defaults(): schema = Schema( { - Inclusive('x', 'stuff', default=3): int, - Inclusive('y', 'stuff', default=4): int, + Inclusive("x", "stuff", default=3): int, + Inclusive("y", "stuff", default=4): int, } ) r = schema({}) - assert r == {'x': 3, 'y': 4} + assert r == {"x": 3, "y": 4} with raises( MultipleInvalid, "some but not all values in the same group of inclusion 'stuff' @ data[]", ): - r = schema({'x': 1}) + r = schema({"x": 1}) def test_exclusive(): schema = Schema( { - Exclusive('x', 'stuff'): int, - Exclusive('y', 'stuff'): int, + Exclusive("x", "stuff"): int, + Exclusive("y", "stuff"): int, } ) r = schema({}) assert r == {} - r = schema({'x': 1}) - assert r == {'x': 1} + r = schema({"x": 1}) + assert r == {"x": 1} with raises( MultipleInvalid, "two or more values in the same group of exclusion 'stuff' @ data[]", ): - r = schema({'x': 1, 'y': 2}) + r = schema({"x": 1, "y": 2}) def test_any_with_discriminant(): schema = Schema( { - 'implementation': Union( + "implementation": Union( { - 'type': 'A', - 'a-value': str, + "type": "A", + "a-value": str, }, { - 'type': 'B', - 'b-value': int, + "type": "B", + "b-value": int, }, { - 'type': 'C', - 'c-value': bool, + "type": "C", + "c-value": bool, }, discriminant=lambda value, alternatives: filter( - lambda v: v['type'] == value['type'], alternatives + lambda v: v["type"] == value["type"], alternatives ), ) } @@ -1600,7 +1600,7 @@ def test_any_with_discriminant(): MultipleInvalid, "expected bool for dictionary value @ data['implementation']['c-value']", ): - schema({'implementation': {'type': 'C', 'c-value': None}}) + schema({"implementation": {"type": "C", "c-value": None}}) def test_key1(): @@ -1611,10 +1611,10 @@ def as_int(a): with pytest.raises(MultipleInvalid) as ctx: schema( { - '1': 'one', - 'two': '2', - '3': 'three', - 'four': '4', + "1": "one", + "two": "2", + "3": "three", + "four": "4", } ) @@ -1628,16 +1628,16 @@ def as_int(a): try: return int(a) except ValueError: - raise Invalid('expecting a number') + raise Invalid("expecting a number") schema = Schema({as_int: str}) with pytest.raises(MultipleInvalid) as ctx: schema( { - '1': 'one', - 'two': '2', - '3': 'three', - 'four': '4', + "1": "one", + "two": "2", + "3": "three", + "four": "4", } ) assert len(ctx.value.errors) == 2 @@ -1679,7 +1679,7 @@ def __init__(self, value=None): def test_object(): - s = Schema(Object({'value': 1}), required=True) + s = Schema(Object({"value": 1}), required=True) s(MyValueClass(value=1)) pytest.raises(MultipleInvalid, s, MyValueClass(value=2)) pytest.raises(MultipleInvalid, s, 345) diff --git a/voluptuous/util.py b/voluptuous/util.py index 0bf9302..81fd1f1 100644 --- a/voluptuous/util.py +++ b/voluptuous/util.py @@ -9,7 +9,7 @@ # fmt: on -__author__ = 'tusharmakkar08' +__author__ = "tusharmakkar08" def Lower(v: str) -> str: @@ -83,7 +83,7 @@ def __call__(self, v): return v def __repr__(self): - return 'DefaultTo(%s)' % (self.default_value(),) + return "DefaultTo(%s)" % (self.default_value(),) class SetTo(object): @@ -103,7 +103,7 @@ def __call__(self, v): return self.value() def __repr__(self): - return 'SetTo(%s)' % (self.value(),) + return "SetTo(%s)" % (self.value(),) class Set(object): @@ -125,11 +125,11 @@ def __call__(self, v): try: set_v = set(v) except Exception as e: - raise TypeInvalid(self.msg or 'cannot be presented as set: {0}'.format(e)) + raise TypeInvalid(self.msg or "cannot be presented as set: {0}".format(e)) return set_v def __repr__(self): - return 'Set()' + return "Set()" class Literal(object): @@ -138,7 +138,7 @@ def __init__(self, lit) -> None: def __call__(self, value, msg: typing.Optional[str] = None): if self.lit != value: - raise LiteralInvalid(msg or '%s not match for %s' % (value, self.lit)) + raise LiteralInvalid(msg or "%s not match for %s" % (value, self.lit)) else: return self.lit diff --git a/voluptuous/validators.py b/voluptuous/validators.py index 348dc04..29199f1 100644 --- a/voluptuous/validators.py +++ b/voluptuous/validators.py @@ -52,17 +52,17 @@ # start anchor, because fullmatch is not available in python 2.7 "(?:" # domain - r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+' + r"(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+" # tld - r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' + r"(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)" # literal form, ipv4 address (SMTP 4.1.3) - r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$' + r"|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$" # end anchor, because fullmatch is not available in python 2.7 r")\Z", re.IGNORECASE, ) -__author__ = 'tusharmakkar08' +__author__ = "tusharmakkar08" def truth(f: typing.Callable) -> typing.Callable: @@ -122,16 +122,16 @@ def __call__(self, v): try: return self.type(v) except (ValueError, TypeError, InvalidOperation): - msg = self.msg or ('expected %s' % self.type_name) + msg = self.msg or ("expected %s" % self.type_name) if not self.msg and Enum and issubclass(self.type, Enum): msg += " or one of %s" % str([e.value for e in self.type])[1:-1] raise CoerceInvalid(msg) def __repr__(self): - return 'Coerce(%s, msg=%r)' % (self.type_name, self.msg) + return "Coerce(%s, msg=%r)" % (self.type_name, self.msg) -@message('value was not true', cls=TrueInvalid) +@message("value was not true", cls=TrueInvalid) @truth def IsTrue(v): """Assert that a value is true, in the Python sense. @@ -158,7 +158,7 @@ def IsTrue(v): return v -@message('value was not false', cls=FalseInvalid) +@message("value was not false", cls=FalseInvalid) def IsFalse(v): """Assert that a value is false, in the Python sense. @@ -180,7 +180,7 @@ def IsFalse(v): return v -@message('expected boolean', cls=BooleanInvalid) +@message("expected boolean", cls=BooleanInvalid) def Boolean(v): """Convert human-readable boolean values to a bool. @@ -203,9 +203,9 @@ def Boolean(v): """ if isinstance(v, basestring): v = v.lower() - if v in ('1', 'true', 'yes', 'on', 'enable'): + if v in ("1", "true", "yes", "on", "enable"): return True - if v in ('0', 'false', 'no', 'off', 'disable'): + if v in ("0", "false", "no", "off", "disable"): return False raise ValueError return bool(v) @@ -250,7 +250,7 @@ def __call__(self, v): return self._exec((Schema(val) for val in self.validators), v) def __repr__(self): - return '%s(%s, msg=%r)' % ( + return "%s(%s, msg=%r)" % ( self.__class__.__name__, ", ".join(repr(v) for v in self.validators), self.msg, @@ -304,7 +304,7 @@ def _exec(self, funcs, v, path=None): else: if error: raise error if self.msg is None else AnyInvalid(self.msg, path=path) - raise AnyInvalid(self.msg or 'no valid value found', path=path) + raise AnyInvalid(self.msg or "no valid value found", path=path) # Convenience alias @@ -346,7 +346,7 @@ def _exec(self, funcs, v, path=None): else: if error: raise error if self.msg is None else AnyInvalid(self.msg, path=path) - raise AnyInvalid(self.msg or 'no valid value found', path=path) + raise AnyInvalid(self.msg or "no valid value found", path=path) # Convenience alias @@ -417,12 +417,12 @@ def __call__(self, v): if not match: raise MatchInvalid( self.msg - or 'does not match regular expression {}'.format(self.pattern.pattern) + or "does not match regular expression {}".format(self.pattern.pattern) ) return v def __repr__(self): - return 'Match(%r, msg=%r)' % (self.pattern.pattern, self.msg) + return "Match(%r, msg=%r)" % (self.pattern.pattern, self.msg) class Replace(object): @@ -450,7 +450,7 @@ def __call__(self, v): return self.pattern.sub(self.substitution, v) def __repr__(self): - return 'Replace(%r, %r, msg=%r)' % ( + return "Replace(%r, %r, msg=%r)" % ( self.pattern.pattern, self.substitution, self.msg, @@ -464,7 +464,7 @@ def _url_validation(v: str) -> urlparse.ParseResult: return parsed -@message('expected an email address', cls=EmailInvalid) +@message("expected an email address", cls=EmailInvalid) def Email(v): """Verify that the value is an email address or not. @@ -481,7 +481,7 @@ def Email(v): try: if not v or "@" not in v: raise EmailInvalid("Invalid email address") - user_part, domain_part = v.rsplit('@', 1) + user_part, domain_part = v.rsplit("@", 1) if not (USER_REGEX.match(user_part) and DOMAIN_REGEX.match(domain_part)): raise EmailInvalid("Invalid email address") @@ -490,7 +490,7 @@ def Email(v): raise ValueError -@message('expected a fully qualified domain name URL', cls=UrlInvalid) +@message("expected a fully qualified domain name URL", cls=UrlInvalid) def FqdnUrl(v): """Verify that the value is a fully qualified domain name URL. @@ -509,7 +509,7 @@ def FqdnUrl(v): raise ValueError -@message('expected a URL', cls=UrlInvalid) +@message("expected a URL", cls=UrlInvalid) def Url(v): """Verify that the value is a URL. @@ -526,7 +526,7 @@ def Url(v): raise ValueError -@message('Not a file', cls=FileInvalid) +@message("Not a file", cls=FileInvalid) @truth def IsFile(v): """Verify the file exists. @@ -543,12 +543,12 @@ def IsFile(v): v = str(v) return os.path.isfile(v) else: - raise FileInvalid('Not a file') + raise FileInvalid("Not a file") except TypeError: - raise FileInvalid('Not a file') + raise FileInvalid("Not a file") -@message('Not a directory', cls=DirInvalid) +@message("Not a directory", cls=DirInvalid) @truth def IsDir(v): """Verify the directory exists. @@ -568,7 +568,7 @@ def IsDir(v): raise DirInvalid("Not a directory") -@message('path does not exist', cls=PathInvalid) +@message("path does not exist", cls=PathInvalid) @truth def PathExists(v): """Verify the path exists, regardless of its type. @@ -649,22 +649,22 @@ def __call__(self, v): if self.min_included: if self.min is not None and not v >= self.min: raise RangeInvalid( - self.msg or 'value must be at least %s' % self.min + self.msg or "value must be at least %s" % self.min ) else: if self.min is not None and not v > self.min: raise RangeInvalid( - self.msg or 'value must be higher than %s' % self.min + self.msg or "value must be higher than %s" % self.min ) if self.max_included: if self.max is not None and not v <= self.max: raise RangeInvalid( - self.msg or 'value must be at most %s' % self.max + self.msg or "value must be at most %s" % self.max ) else: if self.max is not None and not v < self.max: raise RangeInvalid( - self.msg or 'value must be lower than %s' % self.max + self.msg or "value must be lower than %s" % self.max ) return v @@ -672,11 +672,11 @@ def __call__(self, v): # Objects that lack a partial ordering, e.g. None or strings will raise TypeError except TypeError: raise RangeInvalid( - self.msg or 'invalid value or type (must have a partial ordering)' + self.msg or "invalid value or type (must have a partial ordering)" ) def __repr__(self): - return 'Range(min=%r, max=%r, min_included=%r, max_included=%r, msg=%r)' % ( + return "Range(min=%r, max=%r, min_included=%r, max_included=%r, msg=%r)" % ( self.min, self.max, self.min_included, @@ -720,11 +720,11 @@ def __call__(self, v): # Objects that lack a partial ordering, e.g. None or strings will raise TypeError except TypeError: raise RangeInvalid( - self.msg or 'invalid value or type (must have a partial ordering)' + self.msg or "invalid value or type (must have a partial ordering)" ) def __repr__(self): - return 'Clamp(min=%s, max=%s)' % (self.min, self.max) + return "Clamp(min=%s, max=%s)" % (self.min, self.max) class Length(object): @@ -744,26 +744,26 @@ def __call__(self, v): try: if self.min is not None and len(v) < self.min: raise LengthInvalid( - self.msg or 'length of value must be at least %s' % self.min + self.msg or "length of value must be at least %s" % self.min ) if self.max is not None and len(v) > self.max: raise LengthInvalid( - self.msg or 'length of value must be at most %s' % self.max + self.msg or "length of value must be at most %s" % self.max ) return v # Objects that have no length e.g. None or strings will raise TypeError except TypeError: - raise RangeInvalid(self.msg or 'invalid value or type') + raise RangeInvalid(self.msg or "invalid value or type") def __repr__(self): - return 'Length(min=%s, max=%s)' % (self.min, self.max) + return "Length(min=%s, max=%s)" % (self.min, self.max) class Datetime(object): """Validate that the value matches the datetime format.""" - DEFAULT_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ' + DEFAULT_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" def __init__( self, format: typing.Optional[str] = None, msg: typing.Optional[str] = None @@ -776,30 +776,30 @@ def __call__(self, v): datetime.datetime.strptime(v, self.format) except (TypeError, ValueError): raise DatetimeInvalid( - self.msg or 'value does not match expected format %s' % self.format + self.msg or "value does not match expected format %s" % self.format ) return v def __repr__(self): - return 'Datetime(format=%s)' % self.format + return "Datetime(format=%s)" % self.format class Date(Datetime): """Validate that the value matches the date format.""" - DEFAULT_FORMAT = '%Y-%m-%d' + DEFAULT_FORMAT = "%Y-%m-%d" def __call__(self, v): try: datetime.datetime.strptime(v, self.format) except (TypeError, ValueError): raise DateInvalid( - self.msg or 'value does not match expected format %s' % self.format + self.msg or "value does not match expected format %s" % self.format ) return v def __repr__(self): - return 'Date(format=%s)' % self.format + return "Date(format=%s)" % self.format class In(object): @@ -818,12 +818,12 @@ def __call__(self, v): check = True if check: raise InInvalid( - self.msg or 'value must be one of {}'.format(sorted(self.container)) + self.msg or "value must be one of {}".format(sorted(self.container)) ) return v def __repr__(self): - return 'In(%s)' % (self.container,) + return "In(%s)" % (self.container,) class NotIn(object): @@ -842,12 +842,12 @@ def __call__(self, v): check = True if check: raise NotInInvalid( - self.msg or 'value must not be one of {}'.format(sorted(self.container)) + self.msg or "value must not be one of {}".format(sorted(self.container)) ) return v def __repr__(self): - return 'NotIn(%s)' % (self.container,) + return "NotIn(%s)" % (self.container,) class Contains(object): @@ -870,11 +870,11 @@ def __call__(self, v): except TypeError: check = True if check: - raise ContainsInvalid(self.msg or 'value is not allowed') + raise ContainsInvalid(self.msg or "value is not allowed") return v def __repr__(self): - return 'Contains(%s)' % (self.item,) + return "Contains(%s)" % (self.item,) class ExactSequence(object): @@ -913,7 +913,7 @@ def __call__(self, v): return v def __repr__(self): - return 'ExactSequence([%s])' % ", ".join(repr(v) for v in self.validators) + return "ExactSequence([%s])" % ", ".join(repr(v) for v in self.validators) class Unique(object): @@ -949,15 +949,15 @@ def __call__(self, v): try: set_v = set(v) except TypeError as e: - raise TypeInvalid(self.msg or 'contains unhashable elements: {0}'.format(e)) + raise TypeInvalid(self.msg or "contains unhashable elements: {0}".format(e)) if len(set_v) != len(v): seen = set() dupes = list(set(x for x in v if x in seen or seen.add(x))) - raise Invalid(self.msg or 'contains duplicate items: {0}'.format(dupes)) + raise Invalid(self.msg or "contains duplicate items: {0}".format(dupes)) return v def __repr__(self): - return 'Unique()' + return "Unique()" class Equal(object): @@ -984,12 +984,12 @@ def __call__(self, v): if v != self.target: raise Invalid( self.msg - or 'Values are not equal: value:{} != target:{}'.format(v, self.target) + or "Values are not equal: value:{} != target:{}".format(v, self.target) ) return v def __repr__(self): - return 'Equal({})'.format(self.target) + return "Equal({})".format(self.target) class Unordered(object): @@ -1019,12 +1019,12 @@ def __init__( def __call__(self, v): if not isinstance(v, (list, tuple)): - raise Invalid(self.msg or 'Value {} is not sequence!'.format(v)) + raise Invalid(self.msg or "Value {} is not sequence!".format(v)) if len(v) != len(self._schemas): raise Invalid( self.msg - or 'List lengths differ, value:{} != target:{}'.format( + or "List lengths differ, value:{} != target:{}".format( len(v), len(self._schemas) ) ) @@ -1051,7 +1051,7 @@ def __call__(self, v): el = missing[0] raise Invalid( self.msg - or 'Element #{} ({}) is not valid against any validator'.format( + or "Element #{} ({}) is not valid against any validator".format( el[0], el[1] ) ) @@ -1060,7 +1060,7 @@ def __call__(self, v): [ Invalid( self.msg - or 'Element #{} ({}) is not valid against any validator'.format( + or "Element #{} ({}) is not valid against any validator".format( el[0], el[1] ) ) @@ -1070,7 +1070,7 @@ def __call__(self, v): return v def __repr__(self): - return 'Unordered([{}])'.format(", ".join(repr(v) for v in self.validators)) + return "Unordered([{}])".format(", ".join(repr(v) for v in self.validators)) class Number(object): @@ -1133,7 +1133,7 @@ def __call__(self, v): return v def __repr__(self): - return 'Number(precision=%s, scale=%s, msg=%s)' % ( + return "Number(precision=%s, scale=%s, msg=%s)" % ( self.precision, self.scale, self.msg, @@ -1147,7 +1147,7 @@ def _get_precision_scale(self, number) -> typing.Tuple[int, int, Decimal]: try: decimal_num = Decimal(number) except InvalidOperation: - raise Invalid(self.msg or 'Value must be a number enclosed with string') + raise Invalid(self.msg or "Value must be a number enclosed with string") exp = decimal_num.as_tuple().exponent if isinstance(exp, int): @@ -1215,14 +1215,14 @@ def _exec(self, funcs, v, path=None): msg = self.msg if not msg: - msg = ', '.join(map(str, errors)) + msg = ", ".join(map(str, errors)) if passed_count > self.max_valid: raise TooManyValid(msg) raise NotEnoughValid(msg) def __repr__(self): - return 'SomeOf(min_valid=%s, validators=[%s], max_valid=%s, msg=%r)' % ( + return "SomeOf(min_valid=%s, validators=[%s], max_valid=%s, msg=%r)" % ( self.min_valid, ", ".join(repr(v) for v in self.validators), self.max_valid,