From 87adf3bb07b7d33ec28389486e915d9118ea740c Mon Sep 17 00:00:00 2001 From: Stavros Korokithakis Date: Wed, 5 Dec 2018 16:48:02 +0200 Subject: [PATCH] Add pre-commit config and blackify code --- .pre-commit-config.yaml | 15 + schema.py | 211 ++++++------- setup.cfg | 11 + setup.py | 6 +- test_schema.py | 671 +++++++++++++++++++++------------------- 5 files changed, 491 insertions(+), 423 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d81ebf8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: +- repo: https://github.com/ambv/black + rev: 18.9b0 + hooks: + - id: black + args: [--line-length=120] +- repo: git://github.com/doublify/pre-commit-isort + rev: v4.3.0 + hooks: + - id: isort +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.0.0 + hooks: + - id: flake8 + additional_dependencies: [flake8~=3.6.0] diff --git a/schema.py b/schema.py index 5d209e2..4ac90de 100644 --- a/schema.py +++ b/schema.py @@ -3,20 +3,29 @@ parsing, converted from JSON/YAML (or something else) to Python data-types.""" import re + try: from contextlib import ExitStack except ImportError: from contextlib2 import ExitStack -__version__ = '0.6.8' -__all__ = ['Schema', - 'And', 'Or', 'Regex', 'Optional', 'Use', 'Forbidden', 'Const', - 'SchemaError', - 'SchemaWrongKeyError', - 'SchemaMissingKeyError', - 'SchemaForbiddenKeyError', - 'SchemaUnexpectedTypeError', - 'SchemaOnlyOneAllowedError'] +__version__ = "0.6.8" +__all__ = [ + "Schema", + "And", + "Or", + "Regex", + "Optional", + "Use", + "Forbidden", + "Const", + "SchemaError", + "SchemaWrongKeyError", + "SchemaMissingKeyError", + "SchemaForbiddenKeyError", + "SchemaUnexpectedTypeError", + "SchemaOnlyOneAllowedError", +] class SchemaError(Exception): @@ -33,6 +42,7 @@ def code(self): Removes duplicates values in auto and error list. parameters. """ + def uniq(seq): """ Utility function that removes duplicate. @@ -41,39 +51,45 @@ def uniq(seq): seen_add = seen.add # This way removes duplicates while preserving the order. return [x for x in seq if x not in seen and not seen_add(x)] + data_set = uniq(i for i in self.autos if i is not None) error_list = uniq(i for i in self.errors if i is not None) if error_list: - return '\n'.join(error_list) - return '\n'.join(data_set) + return "\n".join(error_list) + return "\n".join(data_set) class SchemaWrongKeyError(SchemaError): """Error Should be raised when an unexpected key is detected within the data set being.""" + pass class SchemaMissingKeyError(SchemaError): """Error should be raised when a mandatory key is not found within the data set being validated""" + pass class SchemaOnlyOneAllowedError(SchemaError): """Error should be raised when an only_one Or key has multiple matching candidates""" + pass class SchemaForbiddenKeyError(SchemaError): """Error should be raised when a forbidden key is found within the data set being validated, and its value matches the value that was specified""" + pass class SchemaUnexpectedTypeError(SchemaError): """Error should be raised when a type mismatch is detected within the data set being validated.""" + pass @@ -84,17 +100,16 @@ class And(object): def __init__(self, *args, **kw): self._args = args - if not set(kw).issubset({'error', 'schema', 'ignore_extra_keys'}): - diff = {'error', 'schema', 'ignore_extra_keys'}.difference(kw) - raise TypeError('Unknown keyword arguments %r' % list(diff)) - self._error = kw.get('error') - self._ignore_extra_keys = kw.get('ignore_extra_keys', False) + if not set(kw).issubset({"error", "schema", "ignore_extra_keys"}): + diff = {"error", "schema", "ignore_extra_keys"}.difference(kw) + raise TypeError("Unknown keyword arguments %r" % list(diff)) + self._error = kw.get("error") + self._ignore_extra_keys = kw.get("ignore_extra_keys", False) # You can pass your inherited Schema class. - self._schema = kw.get('schema', Schema) + self._schema = kw.get("schema", Schema) def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, - ', '.join(repr(a) for a in self._args)) + return "%s(%s)" % (self.__class__.__name__, ", ".join(repr(a) for a in self._args)) def validate(self, data): """ @@ -103,9 +118,7 @@ def validate(self, data): :param data: to be validated with sub defined schemas. :return: returns validated data """ - for s in [self._schema(s, error=self._error, - ignore_extra_keys=self._ignore_extra_keys) - for s in self._args]: + for s in [self._schema(s, error=self._error, ignore_extra_keys=self._ignore_extra_keys) for s in self._args]: data = s.validate(data) return data @@ -115,7 +128,7 @@ class Or(And): fashion.""" def __init__(self, *args, **kwargs): - self.only_one = kwargs.pop('only_one', False) + self.only_one = kwargs.pop("only_one", False) self.match_count = 0 super(Or, self).__init__(*args, **kwargs) @@ -123,8 +136,7 @@ def reset(self): failed = self.match_count > 1 and self.only_one self.match_count = 0 if failed: - raise SchemaOnlyOneAllowedError(['There are multiple keys present ' + - 'from the %r condition' % self]) + raise SchemaOnlyOneAllowedError(["There are multiple keys present " + "from the %r condition" % self]) def validate(self, data): """ @@ -134,9 +146,7 @@ def validate(self, data): :return: return validated data if not validation """ autos, errors = [], [] - for s in [self._schema(s, error=self._error, - ignore_extra_keys=self._ignore_extra_keys) - for s in self._args]: + for s in [self._schema(s, error=self._error, ignore_extra_keys=self._ignore_extra_keys) for s in self._args]: try: validation = s.validate(data) self.match_count += 1 @@ -145,36 +155,44 @@ def validate(self, data): return validation except SchemaError as _x: autos, errors = _x.autos, _x.errors - raise SchemaError(['%r did not validate %r' % (self, data)] + autos, - [self._error.format(data) if self._error else None] + - errors) + raise SchemaError( + ["%r did not validate %r" % (self, data)] + autos, + [self._error.format(data) if self._error else None] + errors, + ) class Regex(object): """ Enables schema.py to validate string using regular expressions. """ + # Map all flags bits to a more readable description - NAMES = ['re.ASCII', 're.DEBUG', 're.VERBOSE', 're.UNICODE', 're.DOTALL', - 're.MULTILINE', 're.LOCALE', 're.IGNORECASE', 're.TEMPLATE'] + NAMES = [ + "re.ASCII", + "re.DEBUG", + "re.VERBOSE", + "re.UNICODE", + "re.DOTALL", + "re.MULTILINE", + "re.LOCALE", + "re.IGNORECASE", + "re.TEMPLATE", + ] def __init__(self, pattern_str, flags=0, error=None): self._pattern_str = pattern_str - flags_list = [Regex.NAMES[i] for i, f in # Name for each bit - enumerate('{0:09b}'.format(flags)) if f != '0'] + flags_list = [Regex.NAMES[i] for i, f in enumerate("{0:09b}".format(flags)) if f != "0"] # Name for each bit if flags_list: - self._flags_names = ', flags=' + '|'.join(flags_list) + self._flags_names = ", flags=" + "|".join(flags_list) else: - self._flags_names = '' + self._flags_names = "" self._pattern = re.compile(pattern_str, flags=flags) self._error = error def __repr__(self): - return '%s(%r%s)' % ( - self.__class__.__name__, self._pattern_str, self._flags_names - ) + return "%s(%r%s)" % (self.__class__.__name__, self._pattern_str, self._flags_names) def validate(self, data): """ @@ -188,9 +206,9 @@ def validate(self, data): if self._pattern.search(data): return data else: - raise SchemaError('%r does not match %r' % (self, data), e) + raise SchemaError("%r does not match %r" % (self, data), e) except TypeError: - raise SchemaError('%r is not string nor buffer' % data, e) + raise SchemaError("%r is not string nor buffer" % data, e) class Use(object): @@ -201,25 +219,21 @@ class Use(object): def __init__(self, callable_, error=None): if not callable(callable_): - raise TypeError('Expected a callable, not %r' % callable_) + raise TypeError("Expected a callable, not %r" % callable_) self._callable = callable_ self._error = error def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self._callable) + return "%s(%r)" % (self.__class__.__name__, self._callable) def validate(self, data): try: return self._callable(data) except SchemaError as x: - raise SchemaError([None] + x.autos, - [self._error.format(data) - if self._error else None] + x.errors) + raise SchemaError([None] + x.autos, [self._error.format(data) if self._error else None] + x.errors) except BaseException as x: f = _callable_str(self._callable) - raise SchemaError('%s(%r) raised %r' % (f, data, x), - self._error.format(data) - if self._error else None) + raise SchemaError("%s(%r) raised %r" % (f, data, x), self._error.format(data) if self._error else None) COMPARABLE, CALLABLE, VALIDATOR, TYPE, DICT, ITERABLE = range(6) @@ -233,7 +247,7 @@ def _priority(s): return DICT if issubclass(type(s), type): return TYPE - if hasattr(s, 'validate'): + if hasattr(s, "validate"): return VALIDATOR if callable(s): return CALLABLE @@ -253,7 +267,7 @@ def __init__(self, schema, error=None, ignore_extra_keys=False): self._ignore_extra_keys = ignore_extra_keys def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self._schema) + return "%s(%r)" % (self.__class__.__name__, self._schema) @staticmethod def _dict_key_priority(s): @@ -303,8 +317,7 @@ def validate(self, data): with exitstack: # Evaluate dictionaries last - data_items = sorted(data.items(), - key=lambda value: isinstance(value[1], dict)) + data_items = sorted(data.items(), key=lambda value: isinstance(value[1], dict)) for key, value in data_items: for skey in sorted_skeys: svalue = s[skey] @@ -329,8 +342,7 @@ def validate(self, data): skey.handler(nkey, data, e) else: try: - nvalue = Schema(svalue, error=e, - ignore_extra_keys=i).validate(value) + nvalue = Schema(svalue, error=e, ignore_extra_keys=i).validate(value) except SchemaError as x: k = "Key '%s' error:" % nkey raise SchemaError([k] + x.autos, [e] + x.errors) @@ -341,28 +353,19 @@ def validate(self, data): required = set(k for k in s if not self._is_optional_type(k)) if not required.issubset(coverage): missing_keys = required - coverage - s_missing_keys = \ - ', '.join(repr(k) for k in sorted(missing_keys, key=repr)) - raise \ - SchemaMissingKeyError( - 'Missing key%s: %s' % (_plural_s(missing_keys), s_missing_keys), - e) + s_missing_keys = ", ".join(repr(k) for k in sorted(missing_keys, key=repr)) + raise SchemaMissingKeyError("Missing key%s: %s" % (_plural_s(missing_keys), s_missing_keys), e) if not self._ignore_extra_keys and (len(new) != len(data)): wrong_keys = set(data.keys()) - set(new.keys()) - s_wrong_keys = \ - ', '.join(repr(k) for k in sorted(wrong_keys, key=repr)) - raise \ - SchemaWrongKeyError( - 'Wrong key%s %s in %r' % ( - _plural_s(wrong_keys), s_wrong_keys, data), - e.format(data) if e else None) + s_wrong_keys = ", ".join(repr(k) for k in sorted(wrong_keys, key=repr)) + raise SchemaWrongKeyError( + "Wrong key%s %s in %r" % (_plural_s(wrong_keys), s_wrong_keys, data), e.format(data) if e else None + ) # Apply default-having optionals that haven't been used: - defaults = set(k for k in s if type(k) is Optional and - hasattr(k, 'default')) - coverage + defaults = set(k for k in s if type(k) is Optional and hasattr(k, "default")) - coverage for default in defaults: - new[default.key] = default.default() if callable(default.default) \ - else default.default + new[default.key] = default.default() if callable(default.default) else default.default return new if flavor == TYPE: @@ -370,8 +373,8 @@ def validate(self, data): return data else: raise SchemaUnexpectedTypeError( - '%r should be instance of %r' % (data, s.__name__), - e.format(data) if e else None) + "%r should be instance of %r" % (data, s.__name__), e.format(data) if e else None + ) if flavor == VALIDATOR: try: return s.validate(data) @@ -379,8 +382,8 @@ def validate(self, data): raise SchemaError([None] + x.autos, [e] + x.errors) except BaseException as x: raise SchemaError( - '%r.validate(%r) raised %r' % (s, data, x), - self._error.format(data) if self._error else None) + "%r.validate(%r) raised %r" % (s, data, x), self._error.format(data) if self._error else None + ) if flavor == CALLABLE: f = _callable_str(s) try: @@ -389,15 +392,12 @@ def validate(self, data): except SchemaError as x: raise SchemaError([None] + x.autos, [e] + x.errors) except BaseException as x: - raise SchemaError( - '%s(%r) raised %r' % (f, data, x), - self._error.format(data) if self._error else None) - raise SchemaError('%s(%r) should evaluate to True' % (f, data), e) + raise SchemaError("%s(%r) raised %r" % (f, data, x), self._error.format(data) if self._error else None) + raise SchemaError("%s(%r) should evaluate to True" % (f, data), e) if s == data: return data else: - raise SchemaError('%r does not match %r' % (s, data), - e.format(data) if e else None) + raise SchemaError("%r does not match %r" % (s, data), e.format(data) if e else None) def json_schema(self, schema_id=None, is_main_schema=True): """Generate a draft-07 JSON schema dict representing the Schema. @@ -414,19 +414,13 @@ def json_schema(self, schema_id=None, is_main_schema=True): if flavor == TYPE: # Handle type - return {"type": { - int: "integer", - float: "number", - bool: "boolean" - }.get(s, "string")} + return {"type": {int: "integer", float: "number", bool: "boolean"}.get(s, "string")} elif flavor == ITERABLE and len(s) == 1: # Handle arrays of a single type or dict schema - return {"type": "array", - "items": Schema(s[0]).json_schema(is_main_schema=False)} + return {"type": "array", "items": Schema(s[0]).json_schema(is_main_schema=False)} elif isinstance(s, Or): # Handle Or values - values = [Schema(or_key).json_schema(is_main_schema=False) - for or_key in s._args] + values = [Schema(or_key).json_schema(is_main_schema=False) for or_key in s._args] any_of = [] for value in values: if value not in any_of: @@ -469,30 +463,29 @@ def json_schema(self, schema_id=None, is_main_schema=True): "type": "object", "properties": expanded_schema, "required": required_keys, - "additionalProperties": i + "additionalProperties": i, } if is_main_schema: - schema_dict.update({ - "id": schema_id, - "$schema": "http://json-schema.org/draft-07/schema#", - }) + schema_dict.update({"id": schema_id, "$schema": "http://json-schema.org/draft-07/schema#"}) return schema_dict class Optional(Schema): """Marker for an optional part of the validation Schema.""" + _MARKER = object() def __init__(self, *args, **kwargs): - default = kwargs.pop('default', self._MARKER) + default = kwargs.pop("default", self._MARKER) super(Optional, self).__init__(*args, **kwargs) if default is not self._MARKER: # See if I can come up with a static key to use for myself: if _priority(self._schema) != COMPARABLE: raise TypeError( - 'Optional keys with defaults must have simple, ' - 'predictable values, like literal strings or ints. ' - '"%r" is too complex.' % (self._schema,)) + "Optional keys with defaults must have simple, " + "predictable values, like literal strings or ints. " + '"%r" is too complex.' % (self._schema,) + ) self.default = default self.key = self._schema @@ -500,10 +493,11 @@ def __hash__(self): return hash(self._schema) def __eq__(self, other): - return (self.__class__ is other.__class__ and - getattr(self, 'default', self._MARKER) == - getattr(other, 'default', self._MARKER) and - self._schema == other._schema) + return ( + self.__class__ is other.__class__ + and getattr(self, "default", self._MARKER) == getattr(other, "default", self._MARKER) + and self._schema == other._schema + ) def reset(self): if hasattr(self._schema, "reset"): @@ -512,7 +506,7 @@ def reset(self): class Hook(Schema): def __init__(self, *args, **kwargs): - self.handler = kwargs.pop('handler', lambda *args: None) + self.handler = kwargs.pop("handler", lambda *args: None) super(Hook, self).__init__(*args, **kwargs) self.key = self._schema @@ -524,8 +518,7 @@ def __init__(self, *args, **kwargs): @staticmethod def _default_function(nkey, data, error): - raise SchemaForbiddenKeyError('Forbidden key encountered: %r in %r' % - (nkey, data), error) + raise SchemaForbiddenKeyError("Forbidden key encountered: %r in %r" % (nkey, data), error) class Const(Schema): @@ -535,7 +528,7 @@ def validate(self, data): def _callable_str(callable_): - if hasattr(callable_, '__name__'): + if hasattr(callable_, "__name__"): return callable_.__name__ return str(callable_) diff --git a/setup.cfg b/setup.cfg index b3b5808..6b2e3f5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,3 +3,14 @@ universal = 1 [semantic_release] version_variable = schema.py:__version__ + +[flake8] +exclude=wsgi.py,env/*,*/migrations/*,venv/*,local_settings.py,doc/*,webpush/*,*.html,setup.cfg +ignore=E501,W503 + +[isort] +include_trailing_comma = true +line_length = 120 +force_grid_wrap = 0 +multi_line_output = 3 +skip=migrations,node_modules diff --git a/setup.py b/setup.py index 9ede22e..9b9d914 100644 --- a/setup.py +++ b/setup.py @@ -22,9 +22,9 @@ license="MIT", keywords="schema json validation", url="https://github.com/keleshev/schema", - py_modules=['schema'], - long_description=codecs.open('README.rst', 'r', 'utf-8').read(), - install_requires=open('requirements.txt', 'r').read().split("\n"), + py_modules=["schema"], + long_description=codecs.open("README.rst", "r", "utf-8").read(), + install_requires=open("requirements.txt", "r").read().split("\n"), classifiers=[ "Development Status :: 3 - Alpha", "Topic :: Utilities", diff --git a/test_schema.py b/test_schema.py index caa57ad..7d11c3a 100644 --- a/test_schema.py +++ b/test_schema.py @@ -1,20 +1,32 @@ from __future__ import with_statement -from collections import defaultdict, namedtuple -from functools import partial -from operator import methodcaller + +import copy import os +import platform import re import sys -import copy -import platform -from mock import Mock - -from pytest import raises, mark +from collections import defaultdict, namedtuple +from functools import partial +from operator import methodcaller -from schema import (Schema, Use, And, Or, Regex, Optional, Const, - SchemaError, SchemaWrongKeyError, - SchemaMissingKeyError, SchemaUnexpectedTypeError, - SchemaForbiddenKeyError, Forbidden, Hook) +from mock import Mock +from pytest import mark, raises +from schema import ( + And, + Const, + Forbidden, + Hook, + Optional, + Or, + Regex, + Schema, + SchemaError, + SchemaForbiddenKeyError, + SchemaMissingKeyError, + SchemaUnexpectedTypeError, + SchemaWrongKeyError, + Use, +) if sys.version_info[0] == 3: basestring = str # Python 3 does not have basestring @@ -29,81 +41,90 @@ def ve(_): def se(_): - raise SchemaError('first auto', 'first error') + raise SchemaError("first auto", "first error") def test_schema(): assert Schema(1).validate(1) == 1 - with SE: Schema(1).validate(9) + with SE: + Schema(1).validate(9) assert Schema(int).validate(1) == 1 - with SE: Schema(int).validate('1') - assert Schema(Use(int)).validate('1') == 1 - with SE: Schema(int).validate(int) - with SE: Schema(int).validate(True) - with SE: Schema(int).validate(False) + with SE: + Schema(int).validate("1") + assert Schema(Use(int)).validate("1") == 1 + with SE: + Schema(int).validate(int) + with SE: + Schema(int).validate(True) + with SE: + Schema(int).validate(False) - assert Schema(str).validate('hai') == 'hai' - with SE: Schema(str).validate(1) - assert Schema(Use(str)).validate(1) == '1' + assert Schema(str).validate("hai") == "hai" + with SE: + Schema(str).validate(1) + assert Schema(Use(str)).validate(1) == "1" - assert Schema(list).validate(['a', 1]) == ['a', 1] - assert Schema(dict).validate({'a': 1}) == {'a': 1} - with SE: Schema(dict).validate(['a', 1]) + assert Schema(list).validate(["a", 1]) == ["a", 1] + assert Schema(dict).validate({"a": 1}) == {"a": 1} + with SE: + Schema(dict).validate(["a", 1]) assert Schema(lambda n: 0 < n < 5).validate(3) == 3 - with SE: Schema(lambda n: 0 < n < 5).validate(-1) + with SE: + Schema(lambda n: 0 < n < 5).validate(-1) def test_validate_file(): - assert Schema( - Use(open)).validate('LICENSE-MIT').read().startswith('Copyright') - with SE: Schema(Use(open)).validate('NON-EXISTENT') - assert Schema(os.path.exists).validate('.') == '.' - with SE: Schema(os.path.exists).validate('./non-existent/') - assert Schema(os.path.isfile).validate('LICENSE-MIT') == 'LICENSE-MIT' - with SE: Schema(os.path.isfile).validate('NON-EXISTENT') + assert Schema(Use(open)).validate("LICENSE-MIT").read().startswith("Copyright") + with SE: + Schema(Use(open)).validate("NON-EXISTENT") + assert Schema(os.path.exists).validate(".") == "." + with SE: + Schema(os.path.exists).validate("./non-existent/") + assert Schema(os.path.isfile).validate("LICENSE-MIT") == "LICENSE-MIT" + with SE: + Schema(os.path.isfile).validate("NON-EXISTENT") def test_and(): assert And(int, lambda n: 0 < n < 5).validate(3) == 3 - with SE: And(int, lambda n: 0 < n < 5).validate(3.33) + with SE: + And(int, lambda n: 0 < n < 5).validate(3.33) assert And(Use(int), lambda n: 0 < n < 5).validate(3.33) == 3 - with SE: And(Use(int), lambda n: 0 < n < 5).validate('3.33') + with SE: + And(Use(int), lambda n: 0 < n < 5).validate("3.33") def test_or(): assert Or(int, dict).validate(5) == 5 assert Or(int, dict).validate({}) == {} - with SE: Or(int, dict).validate('hai') + with SE: + Or(int, dict).validate("hai") assert Or(int).validate(4) - with SE: Or().validate(2) + with SE: + Or().validate(2) def test_or_only_one(): or_rule = Or("test1", "test2", only_one=True) - schema = Schema({ - or_rule: str, - Optional("sub_schema"): { - Optional(copy.deepcopy(or_rule)): str - } - }) + schema = Schema({or_rule: str, Optional("sub_schema"): {Optional(copy.deepcopy(or_rule)): str}}) assert schema.validate({"test1": "value"}) assert schema.validate({"test1": "value", "sub_schema": {"test2": "value"}}) assert schema.validate({"test2": "other_value"}) - with SE: schema.validate({"test1": "value", "test2": "other_value"}) with SE: - schema.validate({ - "test1": "value", - "sub_schema": {"test1": "value", "test2": "value"} - }) - with SE: schema.validate({"othertest": "value"}) + schema.validate({"test1": "value", "test2": "other_value"}) + with SE: + schema.validate({"test1": "value", "sub_schema": {"test1": "value", "test2": "value"}}) + with SE: + schema.validate({"othertest": "value"}) extra_keys_schema = Schema({or_rule: str}, ignore_extra_keys=True) assert extra_keys_schema.validate({"test1": "value", "other-key": "value"}) assert extra_keys_schema.validate({"test2": "other_value"}) - with SE: extra_keys_schema.validate({"test1": "value", "test2": "other_value"}) + with SE: + extra_keys_schema.validate({"test1": "value", "test2": "other_value"}) def test_test(): @@ -113,219 +134,219 @@ def unique_list(_list): def dict_keys(key, _list): return list(map(lambda d: d[key], _list)) - schema = ( - Schema( - Const( - And(Use(partial(dict_keys, "index")), unique_list)))) - data = [ - {"index": 1, "value": "foo"}, - {"index": 2, "value": "bar"}] + schema = Schema(Const(And(Use(partial(dict_keys, "index")), unique_list))) + data = [{"index": 1, "value": "foo"}, {"index": 2, "value": "bar"}] assert schema.validate(data) == data - bad_data = [ - {"index": 1, "value": "foo"}, - {"index": 1, "value": "bar"}] - with SE: schema.validate(bad_data) + bad_data = [{"index": 1, "value": "foo"}, {"index": 1, "value": "bar"}] + with SE: + schema.validate(bad_data) def test_regex(): # Simple case: validate string - assert Regex(r'foo').validate('afoot') == 'afoot' - with SE: Regex(r'bar').validate('afoot') + assert Regex(r"foo").validate("afoot") == "afoot" + with SE: + Regex(r"bar").validate("afoot") # More complex case: validate string - assert Regex(r'^[a-z]+$').validate('letters') == 'letters' + assert Regex(r"^[a-z]+$").validate("letters") == "letters" with SE: - Regex(r'^[a-z]+$').validate('letters + spaces') == 'letters + spaces' + Regex(r"^[a-z]+$").validate("letters + spaces") == "letters + spaces" # Validate dict key - assert (Schema({Regex(r'^foo'): str}) - .validate({'fookey': 'value'}) == {'fookey': 'value'}) - with SE: Schema({Regex(r'^foo'): str}).validate({'barkey': 'value'}) + assert Schema({Regex(r"^foo"): str}).validate({"fookey": "value"}) == {"fookey": "value"} + with SE: + Schema({Regex(r"^foo"): str}).validate({"barkey": "value"}) # Validate dict value - assert (Schema({str: Regex(r'^foo')}).validate({'key': 'foovalue'}) == - {'key': 'foovalue'}) - with SE: Schema({str: Regex(r'^foo')}).validate({'key': 'barvalue'}) + assert Schema({str: Regex(r"^foo")}).validate({"key": "foovalue"}) == {"key": "foovalue"} + with SE: + Schema({str: Regex(r"^foo")}).validate({"key": "barvalue"}) # Error if the value does not have a buffer interface - with SE: Regex(r'bar').validate(1) - with SE: Regex(r'bar').validate({}) - with SE: Regex(r'bar').validate([]) - with SE: Regex(r'bar').validate(None) + with SE: + Regex(r"bar").validate(1) + with SE: + Regex(r"bar").validate({}) + with SE: + Regex(r"bar").validate([]) + with SE: + Regex(r"bar").validate(None) # Validate that the pattern has a buffer interface - assert Regex(re.compile(r'foo')).validate('foo') == 'foo' - assert Regex(unicode('foo')).validate('foo') == 'foo' - with raises(TypeError): Regex(1).validate('bar') - with raises(TypeError): Regex({}).validate('bar') - with raises(TypeError): Regex([]).validate('bar') - with raises(TypeError): Regex(None).validate('bar') + assert Regex(re.compile(r"foo")).validate("foo") == "foo" + assert Regex(unicode("foo")).validate("foo") == "foo" + with raises(TypeError): + Regex(1).validate("bar") + with raises(TypeError): + Regex({}).validate("bar") + with raises(TypeError): + Regex([]).validate("bar") + with raises(TypeError): + Regex(None).validate("bar") def test_validate_list(): assert Schema([1, 0]).validate([1, 0, 1, 1]) == [1, 0, 1, 1] assert Schema([1, 0]).validate([]) == [] - with SE: Schema([1, 0]).validate(0) - with SE: Schema([1, 0]).validate([2]) + with SE: + Schema([1, 0]).validate(0) + with SE: + Schema([1, 0]).validate([2]) assert And([1, 0], lambda l: len(l) > 2).validate([0, 1, 0]) == [0, 1, 0] - with SE: And([1, 0], lambda l: len(l) > 2).validate([0, 1]) + with SE: + And([1, 0], lambda l: len(l) > 2).validate([0, 1]) def test_list_tuple_set_frozenset(): assert Schema([int]).validate([1, 2]) - with SE: Schema([int]).validate(['1', 2]) + with SE: + Schema([int]).validate(["1", 2]) assert Schema(set([int])).validate(set([1, 2])) == set([1, 2]) - with SE: Schema(set([int])).validate([1, 2]) # not a set - with SE: Schema(set([int])).validate(['1', 2]) + with SE: + Schema(set([int])).validate([1, 2]) # not a set + with SE: + Schema(set([int])).validate(["1", 2]) assert Schema(tuple([int])).validate(tuple([1, 2])) == tuple([1, 2]) - with SE: Schema(tuple([int])).validate([1, 2]) # not a set + with SE: + Schema(tuple([int])).validate([1, 2]) # not a set def test_strictly(): assert Schema(int).validate(1) == 1 - with SE: Schema(int).validate('1') + with SE: + Schema(int).validate("1") def test_dict(): - assert Schema({'key': 5}).validate({'key': 5}) == {'key': 5} - with SE: Schema({'key': 5}).validate({'key': 'x'}) - with SE: Schema({'key': 5}).validate(['key', 5]) - assert Schema({'key': int}).validate({'key': 5}) == {'key': 5} - assert Schema({'n': int, 'f': float}).validate( - {'n': 5, 'f': 3.14}) == {'n': 5, 'f': 3.14} - with SE: Schema({'n': int, 'f': float}).validate( - {'n': 3.14, 'f': 5}) + assert Schema({"key": 5}).validate({"key": 5}) == {"key": 5} + with SE: + Schema({"key": 5}).validate({"key": "x"}) + with SE: + Schema({"key": 5}).validate(["key", 5]) + assert Schema({"key": int}).validate({"key": 5}) == {"key": 5} + assert Schema({"n": int, "f": float}).validate({"n": 5, "f": 3.14}) == {"n": 5, "f": 3.14} + with SE: + Schema({"n": int, "f": float}).validate({"n": 3.14, "f": 5}) with SE: try: - Schema({}).validate({'abc': None, 1: None}) + Schema({}).validate({"abc": None, 1: None}) except SchemaWrongKeyError as e: assert e.args[0].startswith("Wrong keys 'abc', 1 in") raise with SE: try: - Schema({'key': 5}).validate({}) + Schema({"key": 5}).validate({}) except SchemaMissingKeyError as e: assert e.args[0] == "Missing key: 'key'" raise with SE: try: - Schema({'key': 5}).validate({'n': 5}) + Schema({"key": 5}).validate({"n": 5}) except SchemaMissingKeyError as e: assert e.args[0] == "Missing key: 'key'" raise with SE: try: - Schema({'key': 5, 'key2': 5}).validate({'n': 5}) + Schema({"key": 5, "key2": 5}).validate({"n": 5}) except SchemaMissingKeyError as e: assert e.args[0] == "Missing keys: 'key', 'key2'" raise with SE: try: - Schema({}).validate({'n': 5}) + Schema({}).validate({"n": 5}) except SchemaWrongKeyError as e: assert e.args[0] == "Wrong key 'n' in {'n': 5}" raise with SE: try: - Schema({'key': 5}).validate({'key': 5, 'bad': 5}) + Schema({"key": 5}).validate({"key": 5, "bad": 5}) except SchemaWrongKeyError as e: - assert e.args[0] in ["Wrong key 'bad' in {'key': 5, 'bad': 5}", - "Wrong key 'bad' in {'bad': 5, 'key': 5}"] + assert e.args[0] in ["Wrong key 'bad' in {'key': 5, 'bad': 5}", "Wrong key 'bad' in {'bad': 5, 'key': 5}"] raise with SE: try: - Schema({}).validate({'a': 5, 'b': 5}) + Schema({}).validate({"a": 5, "b": 5}) except SchemaError as e: - assert e.args[0] in ["Wrong keys 'a', 'b' in {'a': 5, 'b': 5}", - "Wrong keys 'a', 'b' in {'b': 5, 'a': 5}"] + assert e.args[0] in ["Wrong keys 'a', 'b' in {'a': 5, 'b': 5}", "Wrong keys 'a', 'b' in {'b': 5, 'a': 5}"] raise with SE: try: - Schema({int: int}).validate({'': ''}) + Schema({int: int}).validate({"": ""}) except SchemaUnexpectedTypeError as e: assert e.args[0] in ["'' should be instance of 'int'"] def test_dict_keys(): - assert Schema({str: int}).validate( - {'a': 1, 'b': 2}) == {'a': 1, 'b': 2} - with SE: Schema({str: int}).validate({1: 1, 'b': 2}) - assert Schema({Use(str): Use(int)}).validate( - {1: 3.14, 3.14: 1}) == {'1': 3, '3.14': 1} + assert Schema({str: int}).validate({"a": 1, "b": 2}) == {"a": 1, "b": 2} + with SE: + Schema({str: int}).validate({1: 1, "b": 2}) + assert Schema({Use(str): Use(int)}).validate({1: 3.14, 3.14: 1}) == {"1": 3, "3.14": 1} def test_ignore_extra_keys(): - assert Schema({'key': 5}, ignore_extra_keys=True).validate( - {'key': 5, 'bad': 4}) == {'key': 5} - assert Schema({'key': 5, 'dk': {'a': 'a'}}, ignore_extra_keys=True).validate( - {'key': 5, 'bad': 'b', 'dk': {'a': 'a', 'bad': 'b'}}) == \ - {'key': 5, 'dk': {'a': 'a'}} - assert Schema([{'key': 'v'}], ignore_extra_keys=True).validate( - [{'key': 'v', 'bad': 'bad'}]) == [{'key': 'v'}] - assert Schema([{'key': 'v'}], ignore_extra_keys=True).validate( - [{'key': 'v', 'bad': 'bad'}]) == [{'key': 'v'}] + assert Schema({"key": 5}, ignore_extra_keys=True).validate({"key": 5, "bad": 4}) == {"key": 5} + assert Schema({"key": 5, "dk": {"a": "a"}}, ignore_extra_keys=True).validate( + {"key": 5, "bad": "b", "dk": {"a": "a", "bad": "b"}} + ) == {"key": 5, "dk": {"a": "a"}} + assert Schema([{"key": "v"}], ignore_extra_keys=True).validate([{"key": "v", "bad": "bad"}]) == [{"key": "v"}] + assert Schema([{"key": "v"}], ignore_extra_keys=True).validate([{"key": "v", "bad": "bad"}]) == [{"key": "v"}] def test_ignore_extra_keys_validation_and_return_keys(): - assert Schema({'key': 5, object: object}, ignore_extra_keys=True).validate( - {'key': 5, 'bad': 4}) == {'key': 5, 'bad': 4} - assert Schema({'key': 5, 'dk': {'a': 'a', object: object}}, - ignore_extra_keys=True).validate( - {'key': 5, 'dk': {'a': 'a', 'bad': 'b'}}) == \ - {'key': 5, 'dk': {'a': 'a', 'bad': 'b'}} + assert Schema({"key": 5, object: object}, ignore_extra_keys=True).validate({"key": 5, "bad": 4}) == { + "key": 5, + "bad": 4, + } + assert Schema({"key": 5, "dk": {"a": "a", object: object}}, ignore_extra_keys=True).validate( + {"key": 5, "dk": {"a": "a", "bad": "b"}} + ) == {"key": 5, "dk": {"a": "a", "bad": "b"}} def test_dict_forbidden_keys(): with raises(SchemaForbiddenKeyError): - Schema({Forbidden('b'): object}).validate({'b': 'bye'}) + Schema({Forbidden("b"): object}).validate({"b": "bye"}) with raises(SchemaWrongKeyError): - Schema({Forbidden('b'): int}).validate({'b': 'bye'}) - assert (Schema({Forbidden('b'): int, - Optional('b'): object}).validate({'b': 'bye'}) == - {'b': 'bye'}) + Schema({Forbidden("b"): int}).validate({"b": "bye"}) + assert Schema({Forbidden("b"): int, Optional("b"): object}).validate({"b": "bye"}) == {"b": "bye"} with raises(SchemaForbiddenKeyError): - Schema({Forbidden('b'): object, Optional('b'): object}).validate({'b': 'bye'}) + Schema({Forbidden("b"): object, Optional("b"): object}).validate({"b": "bye"}) def test_dict_hook(): function_mock = Mock(return_value=None) - hook = Hook('b', handler=function_mock) + hook = Hook("b", handler=function_mock) - assert Schema({hook: str, - Optional('b'): object}).validate({'b': 'bye'}) == {'b': 'bye'} + assert Schema({hook: str, Optional("b"): object}).validate({"b": "bye"}) == {"b": "bye"} function_mock.assert_called_once() - assert Schema({hook: int, - Optional('b'): object}).validate({'b': 'bye'}) == {'b': 'bye'} + assert Schema({hook: int, Optional("b"): object}).validate({"b": "bye"}) == {"b": "bye"} function_mock.assert_called_once() - assert Schema({hook: str, 'b': object}).validate({'b': 'bye'}) == {'b': 'bye'} + assert Schema({hook: str, "b": object}).validate({"b": "bye"}) == {"b": "bye"} assert function_mock.call_count == 2 def test_dict_optional_keys(): - with SE: Schema({'a': 1, 'b': 2}).validate({'a': 1}) - assert Schema({'a': 1, Optional('b'): 2}).validate({'a': 1}) == {'a': 1} - assert Schema({'a': 1, Optional('b'): 2}).validate( - {'a': 1, 'b': 2}) == {'a': 1, 'b': 2} + with SE: + Schema({"a": 1, "b": 2}).validate({"a": 1}) + assert Schema({"a": 1, Optional("b"): 2}).validate({"a": 1}) == {"a": 1} + assert Schema({"a": 1, Optional("b"): 2}).validate({"a": 1, "b": 2}) == {"a": 1, "b": 2} # Make sure Optionals are favored over types: - assert Schema({basestring: 1, - Optional('b'): 2}).validate({'a': 1, 'b': 2}) == {'a': 1, 'b': 2} + assert Schema({basestring: 1, Optional("b"): 2}).validate({"a": 1, "b": 2}) == {"a": 1, "b": 2} # Make sure Optionals hash based on their key: - assert len({Optional('a'): 1, Optional('a'): 1, Optional('b'): 2}) == 2 + assert len({Optional("a"): 1, Optional("a"): 1, Optional("b"): 2}) == 2 def test_dict_optional_defaults(): # Optionals fill out their defaults: - assert Schema({Optional('a', default=1): 11, - Optional('b', default=2): 22}).validate({'a': 11}) == {'a': 11, 'b': 2} + assert Schema({Optional("a", default=1): 11, Optional("b", default=2): 22}).validate({"a": 11}) == {"a": 11, "b": 2} # Optionals take precedence over types. Here, the "a" is served by the # Optional: - assert Schema({Optional('a', default=1): 11, - basestring: 22}).validate({'b': 22}) == {'a': 1, 'b': 22} + assert Schema({Optional("a", default=1): 11, basestring: 22}).validate({"b": 22}) == {"a": 1, "b": 22} with raises(TypeError): Optional(And(str, Use(int)), default=7) @@ -333,7 +354,7 @@ def test_dict_optional_defaults(): def test_dict_subtypes(): d = defaultdict(int, key=1) - v = Schema({'key': 1}).validate(d) + v = Schema({"key": 1}).validate(d) assert v == d assert isinstance(v, defaultdict) # Please add tests for Counter and OrderedDict once support for Python2.6 @@ -342,231 +363,244 @@ def test_dict_subtypes(): def test_dict_key_error(): try: - Schema({'k': int}).validate({'k': 'x'}) + Schema({"k": int}).validate({"k": "x"}) except SchemaError as e: assert e.code == "Key 'k' error:\n'x' should be instance of 'int'" try: - Schema({'k': {'k2': int}}).validate({'k': {'k2': 'x'}}) + Schema({"k": {"k2": int}}).validate({"k": {"k2": "x"}}) except SchemaError as e: code = "Key 'k' error:\nKey 'k2' error:\n'x' should be instance of 'int'" assert e.code == code try: - Schema({'k': {'k2': int}}, error='k2 should be int').validate({'k': {'k2': 'x'}}) + Schema({"k": {"k2": int}}, error="k2 should be int").validate({"k": {"k2": "x"}}) except SchemaError as e: - assert e.code == 'k2 should be int' + assert e.code == "k2 should be int" def test_complex(): - s = Schema({'': And([Use(open)], lambda l: len(l)), - '': os.path.exists, - Optional('--count'): And(int, lambda n: 0 <= n <= 5)}) - data = s.validate({'': ['./LICENSE-MIT'], '': './'}) + s = Schema( + { + "": And([Use(open)], lambda l: len(l)), + "": os.path.exists, + Optional("--count"): And(int, lambda n: 0 <= n <= 5), + } + ) + data = s.validate({"": ["./LICENSE-MIT"], "": "./"}) assert len(data) == 2 - assert len(data['']) == 1 - assert data[''][0].read().startswith('Copyright') - assert data[''] == './' + assert len(data[""]) == 1 + assert data[""][0].read().startswith("Copyright") + assert data[""] == "./" def test_nice_errors(): try: - Schema(int, error='should be integer').validate('x') + Schema(int, error="should be integer").validate("x") except SchemaError as e: - assert e.errors == ['should be integer'] + assert e.errors == ["should be integer"] try: - Schema(Use(float), error='should be a number').validate('x') + Schema(Use(float), error="should be a number").validate("x") except SchemaError as e: - assert e.code == 'should be a number' + assert e.code == "should be a number" try: - Schema({Optional('i'): Use(int, error='should be a number')}).validate({'i': 'x'}) + Schema({Optional("i"): Use(int, error="should be a number")}).validate({"i": "x"}) except SchemaError as e: - assert e.code == 'should be a number' + assert e.code == "should be a number" def test_use_error_handling(): try: - Use(ve).validate('x') + Use(ve).validate("x") except SchemaError as e: assert e.autos == ["ve('x') raised ValueError()"] assert e.errors == [None] try: - Use(ve, error='should not raise').validate('x') + Use(ve, error="should not raise").validate("x") except SchemaError as e: assert e.autos == ["ve('x') raised ValueError()"] - assert e.errors == ['should not raise'] + assert e.errors == ["should not raise"] try: - Use(se).validate('x') + Use(se).validate("x") except SchemaError as e: - assert e.autos == [None, 'first auto'] - assert e.errors == [None, 'first error'] + assert e.autos == [None, "first auto"] + assert e.errors == [None, "first error"] try: - Use(se, error='second error').validate('x') + Use(se, error="second error").validate("x") except SchemaError as e: - assert e.autos == [None, 'first auto'] - assert e.errors == ['second error', 'first error'] + assert e.autos == [None, "first auto"] + assert e.errors == ["second error", "first error"] def test_or_error_handling(): try: - Or(ve).validate('x') + Or(ve).validate("x") except SchemaError as e: - assert e.autos[0].startswith('Or(') + assert e.autos[0].startswith("Or(") assert e.autos[0].endswith(") did not validate 'x'") assert e.autos[1] == "ve('x') raised ValueError()" assert len(e.autos) == 2 assert e.errors == [None, None] try: - Or(ve, error='should not raise').validate('x') + Or(ve, error="should not raise").validate("x") except SchemaError as e: - assert e.autos[0].startswith('Or(') + assert e.autos[0].startswith("Or(") assert e.autos[0].endswith(") did not validate 'x'") assert e.autos[1] == "ve('x') raised ValueError()" assert len(e.autos) == 2 - assert e.errors == ['should not raise', 'should not raise'] + assert e.errors == ["should not raise", "should not raise"] try: - Or('o').validate('x') + Or("o").validate("x") except SchemaError as e: - assert e.autos == ["Or('o') did not validate 'x'", - "'o' does not match 'x'"] + assert e.autos == ["Or('o') did not validate 'x'", "'o' does not match 'x'"] assert e.errors == [None, None] try: - Or('o', error='second error').validate('x') + Or("o", error="second error").validate("x") except SchemaError as e: - assert e.autos == ["Or('o') did not validate 'x'", - "'o' does not match 'x'"] - assert e.errors == ['second error', 'second error'] + assert e.autos == ["Or('o') did not validate 'x'", "'o' does not match 'x'"] + assert e.errors == ["second error", "second error"] def test_and_error_handling(): try: - And(ve).validate('x') + And(ve).validate("x") except SchemaError as e: assert e.autos == ["ve('x') raised ValueError()"] assert e.errors == [None] try: - And(ve, error='should not raise').validate('x') + And(ve, error="should not raise").validate("x") except SchemaError as e: assert e.autos == ["ve('x') raised ValueError()"] - assert e.errors == ['should not raise'] + assert e.errors == ["should not raise"] try: - And(str, se).validate('x') + And(str, se).validate("x") except SchemaError as e: - assert e.autos == [None, 'first auto'] - assert e.errors == [None, 'first error'] + assert e.autos == [None, "first auto"] + assert e.errors == [None, "first error"] try: - And(str, se, error='second error').validate('x') + And(str, se, error="second error").validate("x") except SchemaError as e: - assert e.autos == [None, 'first auto'] - assert e.errors == ['second error', 'first error'] + assert e.autos == [None, "first auto"] + assert e.errors == ["second error", "first error"] def test_schema_error_handling(): try: - Schema(Use(ve)).validate('x') + Schema(Use(ve)).validate("x") except SchemaError as e: assert e.autos == [None, "ve('x') raised ValueError()"] assert e.errors == [None, None] try: - Schema(Use(ve), error='should not raise').validate('x') + Schema(Use(ve), error="should not raise").validate("x") except SchemaError as e: assert e.autos == [None, "ve('x') raised ValueError()"] - assert e.errors == ['should not raise', None] + assert e.errors == ["should not raise", None] try: - Schema(Use(se)).validate('x') + Schema(Use(se)).validate("x") except SchemaError as e: - assert e.autos == [None, None, 'first auto'] - assert e.errors == [None, None, 'first error'] + assert e.autos == [None, None, "first auto"] + assert e.errors == [None, None, "first error"] try: - Schema(Use(se), error='second error').validate('x') + Schema(Use(se), error="second error").validate("x") except SchemaError as e: - assert e.autos == [None, None, 'first auto'] - assert e.errors == ['second error', None, 'first error'] + assert e.autos == [None, None, "first auto"] + assert e.errors == ["second error", None, "first error"] def test_use_json(): import json - gist_schema = Schema(And(Use(json.loads), # first convert from JSON - {Optional('description'): basestring, - 'public': bool, - 'files': {basestring: {'content': basestring}}})) - gist = '''{"description": "the description for this gist", + + gist_schema = Schema( + And( + Use(json.loads), # first convert from JSON + {Optional("description"): basestring, "public": bool, "files": {basestring: {"content": basestring}}}, + ) + ) + gist = """{"description": "the description for this gist", "public": true, "files": { "file1.txt": {"content": "String file contents"}, - "other.txt": {"content": "Another file contents"}}}''' + "other.txt": {"content": "Another file contents"}}}""" assert gist_schema.validate(gist) def test_error_reporting(): - s = Schema({'': [Use(open, error=' should be readable')], - '': And(os.path.exists, error=' should exist'), - '--count': Or(None, And(Use(int), lambda n: 0 < n < 5), - error='--count should be integer 0 < n < 5')}, - error='Error:') - s.validate({'': [], '': './', '--count': 3}) + s = Schema( + { + "": [Use(open, error=" should be readable")], + "": And(os.path.exists, error=" should exist"), + "--count": Or(None, And(Use(int), lambda n: 0 < n < 5), error="--count should be integer 0 < n < 5"), + }, + error="Error:", + ) + s.validate({"": [], "": "./", "--count": 3}) try: - s.validate({'': [], '': './', '--count': '10'}) + s.validate({"": [], "": "./", "--count": "10"}) except SchemaError as e: - assert e.code == 'Error:\n--count should be integer 0 < n < 5' + assert e.code == "Error:\n--count should be integer 0 < n < 5" try: - s.validate({'': [], '': './hai', '--count': '2'}) + s.validate({"": [], "": "./hai", "--count": "2"}) except SchemaError as e: - assert e.code == 'Error:\n should exist' + assert e.code == "Error:\n should exist" try: - s.validate({'': ['hai'], '': './', '--count': '2'}) + s.validate({"": ["hai"], "": "./", "--count": "2"}) except SchemaError as e: - assert e.code == 'Error:\n should be readable' + assert e.code == "Error:\n should be readable" def test_schema_repr(): # what about repr with `error`s? schema = Schema([Or(None, And(str, Use(float)))]) repr_ = "Schema([Or(None, And(, Use()))])" # in Python 3 repr contains , not - assert repr(schema).replace('class', 'type') == repr_ + assert repr(schema).replace("class", "type") == repr_ def test_validate_object(): schema = Schema({object: str}) - assert schema.validate({42: 'str'}) == {42: 'str'} - with SE: schema.validate({42: 777}) + assert schema.validate({42: "str"}) == {42: "str"} + with SE: + schema.validate({42: 777}) def test_issue_9_prioritized_key_comparison(): - validate = Schema({'key': 42, object: 42}).validate - assert validate({'key': 42, 777: 42}) == {'key': 42, 777: 42} + validate = Schema({"key": 42, object: 42}).validate + assert validate({"key": 42, 777: 42}) == {"key": 42, 777: 42} def test_issue_9_prioritized_key_comparison_in_dicts(): # http://stackoverflow.com/questions/14588098/docopt-schema-validation - s = Schema({'ID': Use(int, error='ID should be an int'), - 'FILE': Or(None, Use(open, error='FILE should be readable')), - Optional(str): object}) - data = {'ID': 10, 'FILE': None, 'other': 'other', 'other2': 'other2'} + s = Schema( + { + "ID": Use(int, error="ID should be an int"), + "FILE": Or(None, Use(open, error="FILE should be readable")), + Optional(str): object, + } + ) + data = {"ID": 10, "FILE": None, "other": "other", "other2": "other2"} assert s.validate(data) == data - data = {'ID': 10, 'FILE': None} + data = {"ID": 10, "FILE": None} assert s.validate(data) == data def test_missing_keys_exception_with_non_str_dict_keys(): - s = Schema({And(str, Use(str.lower), 'name'): And(str, len)}) - with SE: s.validate(dict()) + s = Schema({And(str, Use(str.lower), "name"): And(str, len)}) + with SE: + s.validate(dict()) with SE: try: - Schema({1: 'x'}).validate(dict()) + Schema({1: "x"}).validate(dict()) except SchemaMissingKeyError as e: assert e.args[0] == "Missing key: 1" raise # PyPy does have a __name__ attribute for its callables. -@mark.skipif(platform.python_implementation() == 'PyPy', - reason='Running on PyPy') +@mark.skipif(platform.python_implementation() == "PyPy", reason="Running on PyPy") def test_issue_56_cant_rely_on_callables_to_have_name(): - s = Schema(methodcaller('endswith', '.csv')) - assert s.validate('test.csv') == 'test.csv' + s = Schema(methodcaller("endswith", ".csv")) + assert s.validate("test.csv") == "test.csv" with SE: try: - s.validate('test.py') + s.validate("test.py") except SchemaError as e: assert "operator.methodcaller" in e.args[0] raise @@ -605,28 +639,29 @@ def test_optional_key_convert_failed_randomly_while_with_another_optional_object :return: """ import datetime - fmt = '%Y-%m-%d %H:%M:%S' + + fmt = "%Y-%m-%d %H:%M:%S" _datetime_validator = Or(None, Use(lambda i: datetime.datetime.strptime(i, fmt))) # FIXME given tests enough for i in range(1024): - s = Schema({ - Optional('created_at'): _datetime_validator, - Optional('updated_at'): _datetime_validator, - Optional('birth'): _datetime_validator, - Optional(basestring): object, - }) - data = { - 'created_at': '2015-10-10 00:00:00' - } + s = Schema( + { + Optional("created_at"): _datetime_validator, + Optional("updated_at"): _datetime_validator, + Optional("birth"): _datetime_validator, + Optional(basestring): object, + } + ) + data = {"created_at": "2015-10-10 00:00:00"} validated_data = s.validate(data) # is expected to be converted to a datetime instance, but fails randomly # (most of the time) - assert isinstance(validated_data['created_at'], datetime.datetime) + assert isinstance(validated_data["created_at"], datetime.datetime) # assert isinstance(validated_data['created_at'], basestring) def test_copy(): - s1 = SchemaError('a', None) + s1 = SchemaError("a", None) s2 = copy.deepcopy(s1) assert s1 is not s2 assert type(s1) is type(s2) @@ -642,10 +677,10 @@ class MySchema(Schema): def validate(self, data): return super(MySchema, self).validate(convert(data)) - s = {'k': int, 'd': {'k': int, 'l': [{'l': [int]}]}} - v = {'k': 1, 'd': {'k': 2, 'l': [{'l': [3, 4, 5]}]}} + s = {"k": int, "d": {"k": int, "l": [{"l": [int]}]}} + v = {"k": 1, "d": {"k": 2, "l": [{"l": [3, 4, 5]}]}} d = MySchema(s).validate(v) - assert d['k'] == 2 and d['d']['k'] == 3 and d['d']['l'][0]['l'] == [4, 5, 6] + assert d["k"] == 2 and d["d"]["k"] == 3 and d["d"]["l"][0]["l"] == [4, 5, 6] def test_json_schema(): @@ -656,15 +691,19 @@ def test_json_schema(): "properties": {"test": {"type": "string"}}, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", } def test_json_schema_types(): - s = Schema({Optional("test_str"): str, - Optional("test_int"): int, - Optional("test_float"): float, - Optional("test_bool"): bool}) + s = Schema( + { + Optional("test_str"): str, + Optional("test_int"): int, + Optional("test_float"): float, + Optional("test_bool"): bool, + } + ) assert s.json_schema("my-id") == { "$schema": "http://json-schema.org/draft-07/schema#", "id": "my-id", @@ -672,11 +711,11 @@ def test_json_schema_types(): "test_str": {"type": "string"}, "test_int": {"type": "integer"}, "test_float": {"type": "number"}, - "test_bool": {"type": "boolean"} + "test_bool": {"type": "boolean"}, }, "required": [], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -685,16 +724,17 @@ def test_json_schema_nested(): assert s.json_schema("my-id") == { "$schema": "http://json-schema.org/draft-07/schema#", "id": "my-id", - "properties": {"test": { - "type": "object", - "properties": {"other": {"type": "string"}}, - "additionalProperties": True, - "required": ["other"] - } - }, + "properties": { + "test": { + "type": "object", + "properties": {"other": {"type": "string"}}, + "additionalProperties": True, + "required": ["other"], + } + }, "required": ["test"], "additionalProperties": True, - "type": "object" + "type": "object", } @@ -703,16 +743,17 @@ def test_json_schema_nested_schema(): assert s.json_schema("my-id") == { "$schema": "http://json-schema.org/draft-07/schema#", "id": "my-id", - "properties": {"test": { - "type": "object", - "properties": {"other": {"type": "string"}}, - "additionalProperties": True, - "required": ["other"] - } - }, + "properties": { + "test": { + "type": "object", + "properties": {"other": {"type": "string"}}, + "additionalProperties": True, + "required": ["other"], + } + }, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -724,7 +765,7 @@ def test_json_schema_optional_key(): "properties": {"test": {"type": "string"}}, "required": [], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -733,16 +774,17 @@ def test_json_schema_optional_key_nested(): assert s.json_schema("my-id") == { "$schema": "http://json-schema.org/draft-07/schema#", "id": "my-id", - "properties": {"test": { - "type": "object", - "properties": {"other": {"type": "string"}}, - "additionalProperties": False, - "required": [] - } - }, + "properties": { + "test": { + "type": "object", + "properties": {"other": {"type": "string"}}, + "additionalProperties": False, + "required": [], + } + }, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -754,7 +796,7 @@ def test_json_schema_or_key(): "properties": {"test1": {"type": "string"}, "test2": {"type": "string"}}, "required": [], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -766,7 +808,7 @@ def test_json_schema_or_types(): "properties": {"test": {"anyOf": [{"type": "string"}, {"type": "integer"}]}}, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -779,7 +821,7 @@ def test_json_schema_and_types(): "properties": {"test": {}}, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -790,23 +832,30 @@ def test_json_schema_object_or_array_of_object(): assert s.json_schema("my-id") == { "$schema": "http://json-schema.org/draft-07/schema#", "id": "my-id", - "properties": {"test": {"anyOf": [{'additionalProperties': False, - 'properties': {'param1': {}, 'param2': {}}, - 'required': ['param1'], - 'type': 'object' - }, {"type": "array", - "items": {'additionalProperties': False, - 'properties': {'param1': {}, - 'param2': {}}, - 'required': ['param1'], - 'type': 'object'} - } - ] - } - }, + "properties": { + "test": { + "anyOf": [ + { + "additionalProperties": False, + "properties": {"param1": {}, "param2": {}}, + "required": ["param1"], + "type": "object", + }, + { + "type": "array", + "items": { + "additionalProperties": False, + "properties": {"param1": {}, "param2": {}}, + "required": ["param1"], + "type": "object", + }, + }, + ] + } + }, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", } @@ -818,7 +867,7 @@ def test_json_schema_forbidden_key_ignored(): "properties": {"test": {"type": "string"}}, "required": ["test"], "additionalProperties": False, - "type": "object" + "type": "object", }