def wrapped(*args, **kwargs): request.validation_error = None if request.method in ('POST', 'PUT'): try: body = request.body.decode() if not body: raise ValueError('No JSON object could be decoded') data = json.loads(body) notario.validate(data, schema) except (Invalid, ValueError) as error: # TODO: It would be nice if we could have a sane default # here where we set the response body instead of requiring # a handler request.validation_error = error if handler: redirect_to_handler(error, handler) # a controller can say `handler=False` to signal they don't # want to delegate, not even to the fallback if handler is None: headers = {'Content-Type': 'application/json'} raise JSONValidationException(detail=error, headers=headers) return f(*args, **kwargs)
def test_all_objects_fail_non_callable(self): data = {'a': {'a': 1, 'b': 1, 'c': 1}} schema = ('a', recursive.AllObjects((types.string, 2))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> a -> 1 did not match 2' in error
def test_all_items_fail(self): def fail(value): raise AssertionError data = {'a': 'some string'} schema = ('a', chainable.AnyIn(types.boolean, fail)) with raises(Invalid) as exc: validate(data, schema) assert exc.value.args[0] == '-> a did not pass validation against callable: AnyIn'
def test_one_item_fails(self): data = {'a': 'some string'} schema = ('a', chainable.AllIn(types.string, types.boolean)) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> some string did not pass validation against callable: AllIn -> boolean' in error
def wrapped(*args, **kwargs): request.validation_error = None if request.method in ('POST', 'PUT'): try: body = request.body.decode() if not body: raise ValueError('No JSON object could be decoded') data = json.loads(body) notario.validate(data, schema) except (Invalid, ValueError) as error: # TODO: It would be nice if we could have a sane default # here where we set the response body instead of requiring # a handler request.validation_error = error if handler: redirect_to_handler(error, handler) # a controller can say `handler=False` to signal they don't # want to delegate, not even to the fallback if handler is None: headers = {'Content-Type': 'application/json'} raise JSONValidationException( detail=error, headers=headers ) return f(*args, **kwargs)
def test_all_items_fail_length(self): data = {'a': [{'a': 2}, {'b': {'a': 'b'}}]} schema = ('a', iterables.AllItems((types.string, 2))) with raises(SchemaError) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> b has less items in schema than in data' in error
def test_all_items_fail_length(self): data = {"a": [{"a": 2}, {"b": {"a": "b"}}]} schema = ("a", iterables.AllItems((types.string, 2))) with raises(SchemaError) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> b has less items in schema than in data" in error
def test_all_objects_fail_non_callable(self): data = {"a": {"a": 1, "b": 1, "c": 1}} schema = ("a", recursive.AllObjects((types.string, 2))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> a -> 1 did not match 2" in error
def test_nested_raises_nested_invalid(self): data = {'a': [{'a': ['a']}, {'b': 'c'}]} nested_schema = iterables.MultiIterable(('a', ['b']), ('b', 'c')) schema = ('a', iterables.AllItems(nested_schema)) with raises(Invalid) as exc: validate(data, schema) assert exc.value.reason == 'expected a list but got dict'
def test_nested_raises_nested_invalid(self): data = {"a": [{"a": ["a"]}, {"b": "c"}]} nested_schema = iterables.MultiIterable(("a", ["b"]), ("b", "c")) schema = ("a", iterables.AllItems(nested_schema)) with raises(Invalid) as exc: validate(data, schema) assert exc.value.reason == "expected a list but got dict"
def test_no_pollution_from_previous_traversing_all_items(self): data = {"a": {"a": 1, "b": 2}, "b": {"c": 1, "d": 2}, "c": ["e", 1, "f", 2]} schema = (("a", (("a", 1), ("b", 2))), ("b", (("c", 1), ("d", 2))), ("c", iterables.AllItems(types.string))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "not of type string" in error assert "-> c -> list[1] item did not pass validation against callable: string" in error
def test_any_objects_fail_non_callable(self): data = {"a": {"a": 1, "b": 4, "c": 3}} schema = ("a", recursive.AnyObject(("a", "a"))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a did not contain any valid objects against callable: AnyObject" in error
def test_all_objects_fail_length(self): data = {"a": {"a": 2, "b": {"a": "b"}}} schema = ("a", recursive.AllObjects((types.string, 2))) with raises(SchemaError) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> b has less items in schema than in data" in error
def test_all_objects_fail(self): data = {"a": {"a": 1, "b": "a string", "c": 3}} schema = ("a", recursive.AllObjects((types.string, types.integer))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> b -> a string did not pass validation against callable: integer" in error assert "not of type int" in error
def test_most_simple_validation(self): data = {'a': 'a'} schema = (('a', 'b')) with raises(Invalid) as exc: validate(data, schema) assert exc.value.args[0] == "-> a -> a did not match 'b'"
def test_multi_pair_non_nested_third_key(self): data = {'a': 'a', 'b':'b', 'c':'c', 'd':'d'} schema = (('a', 'a'), ('b', 'b'), ('f', 'c'), ('d', 'a')) with raises(Invalid) as exc: validate(data, schema) assert exc.value.args[0] == "-> c key did not match 'f'"
def test_nested_raises_nested_invalid(self): data = {"a": {"a": ["a"], "b": {}}} nested_schema = iterables.AllItems(types.string) schema = ("a", recursive.AllObjects((types.string, nested_schema))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "did not pass validation against callable: AllItems" in error
def test_any_item_with_dictionaries(self): data = {'a': [{'a': 1}, {'b': 2}]} schema = ('a', iterables.AnyItem(('c', 4))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> list[] did not contain any valid items matching ('c', 4)" in error
def test_multi_pair_non_nested_second(self): data = {'a': 'a', 'b':'b', 'c':'c', 'd':'d'} schema = (('a', 'a'), ('b', 'a'), ('c', 'c'), ('d', 'd')) with raises(Invalid) as exc: validate(data, schema) assert exc.value.args[0] == "-> b -> b did not match 'a'"
def test_top_level_cherry_pick_with_optionals_complains(self): data = {'b': 'b', 'optional': 1, 'garbage': 'yes'} schema = (('b', types.string), (optional('optional'), types.string)) with raises(Invalid) as exc: validate(data, schema, defined_keys=True) error = exc.value.args[0] assert '1 did not pass validation against callable: string' in error
def test_all_objects_fail(self): data = {'a': {'a': 1, 'b': 'a string', 'c': 3}} schema = ('a', recursive.AllObjects((types.string, types.integer))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> b -> a string did not pass validation against callable: integer' in error assert 'not of type int' in error
def test_any_items_fail_non_callable(self): data = {'a': [1, 2, 3, 4, 5]} schema = ('a', iterables.AnyItem('foo')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> list[] did not contain any valid items matching 'foo'" in error
def test_any_items_fail(self): data = {'a': [1, 2, 3, 4, 5]} schema = ('a', iterables.AnyItem(types.string)) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> list[] did not contain any valid items against callable: string' in error
def test_nested_raises_nested_invalid(self): data = {'a': {'a': ['a'], 'b': {}}} nested_schema = iterables.AllItems(types.string) schema = ('a', recursive.AllObjects((types.string, nested_schema))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert 'did not pass validation against callable: AllItems' in error
def test_all_items_fail_non_callable(self): data = {'a': [1, 2, '3', 4, 5]} schema = ('a', iterables.AllItems('foo')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> list[0] item did not match 'foo'" in error
def test_all_objects_fail_length(self): data = {'a': {'a': 2, 'b': {'a': 'b'}}} schema = ('a', recursive.AllObjects((types.string, 2))) with raises(SchemaError) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> b has less items in schema than in data' in error
def test_all_items_fail(self): data = {'a': [1, 2, '3', 4, 5]} schema = ('a', iterables.AllItems(types.integer)) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert 'not of type int' in error assert '-> a -> list[2] item did not pass validation against callable: integer' in error
def test_any_objects_fail_non_callable(self): data = {'a': {'a': 1, 'b': 4, 'c': 3}} schema = ('a', recursive.AnyObject(('a', 'a'))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a did not contain any valid objects against callable: AnyObject' in error
def test_fail_object(self): sschema = (1, 1) schema = ('a', Hybrid(validator, sschema)) data = {'a': {1: 2}} with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '1 -> 2 did not match 1' in error assert error.startswith('-> a -> 1')
def test_extra_unexpected_items(self): optional_schema = (optional(1), 1) schema = ('a', Hybrid(validator, optional_schema)) data = {'a': {'foo': 'bar'}} with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a did not match {}' in error assert exc.value.reason == 'unexpected extra items'
def test_key_is_empty_string(self): data = {'a': ''} schema = (('a', 'b')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> '' did not match 'b'" in error
def test_hybrid_delegates_when_dict_or_list(self): # send off to Recursive when isinstance(value, (dict, list)) data = {'a': ['a']} hybrid = Hybrid(types.string, iterables.AllItems('b')) schema = ('a', hybrid) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "list[0] item did not match 'b'" in error
def test_validate_only_one_item(self): data = {'a': {'b': 'b', 'c': 'c', 'd': 'd'}} schema = ('a', cherry_pick(('b', 'a'))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> b -> b did not match 'a'" in error
def test_simple_validation_against_empty_data(self): data = {} schema = (('a', 'b')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert 'top level has no data to validate against schema' in error
def test_key_fails_before_value(self): data = {'a': {'a': {'b': 'b'}}} schema = ('a', ('b', ('b', 'b'))) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> a key did not match 'b'" in error
def test_validate_only_one_item(self): data = {'b': 'b', 'c': 'c', 'd': 'd'} schema = ('d', 'a') with raises(Invalid) as exc: validate(data, schema, defined_keys=True) error = exc.value.args[0] assert "-> d -> d did not match 'a'" in error
def test_complain_about_non_alpha_optional_schema(self): data = {'a': 'a', 'b': 'b', 'c': 'c'} schema = ((optional('b') ,'b'), ('a', 'a'), ('c', 'c')) with raises(SchemaError) as exc: validate(data, schema) error = exc.value.args[0] assert "b schema item is not alphabetically ordered" in error
def test_multi_pair_non_nested_first(self): data = {'a': 'a', 'b':'b', 'c':'c', 'd':'d'} schema = (('a', 'b'), ('b', 'b'), ('c', 'c'), ('d', 'd')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> a did not match 'b'" in error
def test_multi_pair_non_nested_third_key(self): data = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'} schema = (('a', 'a'), ('b', 'b'), ('f', 'c'), ('d', 'a')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> c key did not match 'f'" in error
def test_most_simple_validation(self): data = {'a': 'a'} schema = (('a', 'b')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "-> a -> a did not match 'b'" in error
def test_complain_about_non_alpha_optional_schema(self): data = {'a': 'a', 'b': 'b', 'c': 'c'} schema = ((optional('b'), 'b'), ('a', 'a'), ('c', 'c')) with raises(SchemaError) as exc: validate(data, schema) error = exc.value.args[0] assert "b schema item is not alphabetically ordered" in error
def test_nested_can_raise_nested_invalid(self): data = {'a': {'a': 'b'}} data = {'a': [{'a': [1, 2]}, {'a': {}}]} nested_schema = ('a', iterables.AllItems(types.integer)) schema = ('a', iterables.AllItems(nested_schema)) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert 'did not pass validation against callable: integer' assert exc.value.reason == 'expected a list but got dict'
def test_all_items_fail(self): def fail(value): raise AssertionError data = {'a': 'some string'} schema = ('a', chainable.AnyIn(types.boolean, fail)) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert '-> a -> some string did not pass validation against callable: AnyIn' in error
def test_required_key_is_missing(self): data = {'a': 'a', 'c': 'c'} schema = (('a', 'a'), ('b', 'b'), ('c', 'c')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "key did not match schema" in error assert "required key in data is missing: b" in error
def test_required_key_is_missing(self): data = {'k1': 'v1', 'k3': 'v3'} schema = (('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')) with raises(Invalid) as exc: validate(data, schema) error = exc.value.args[0] assert "key did not match schema" in error assert "required key in data is missing: k2" in error