def test_error_messages_interface(): """ `errors.messages()` should return a list of Message instances. """ validator = Integer() value, error = validator.validate_or_error("abc") assert error.messages() == [Message(text="Must be a number.", code="type")]
def test_not(): validator = Not(Integer()) value, error = validator.validate_or_error("abc") assert value == "abc" assert error is None validator = Not(Integer()) value, error = validator.validate_or_error(5) assert value is None assert error == ValidationError(text="Must not match.", code="negated")
def test_union(): validator = Union(any_of=[Integer(), String()]) value, error = validator.validate_or_error("abc") assert value == "abc" assert error is None validator = Union(any_of=[Integer(), String()]) value, error = validator.validate_or_error(123) assert value == 123 assert error is None validator = Union(any_of=[Integer(), String()]) value, error = validator.validate_or_error(None) assert value is None assert error == ValidationError(text="May not be null.", code="null") validator = Union(any_of=[Integer(), String()]) value, error = validator.validate_or_error(True) assert value is None assert error == ValidationError(text="Did not match any valid type.", code="union") validator = Union(any_of=[Integer(allow_null=True), String()]) value, error = validator.validate_or_error(None) assert error is None assert value is None validator = Union(any_of=[Integer(), String()], allow_null=True) value, error = validator.validate_or_error(None) assert error is None assert value is None validator = Union(any_of=[Integer(maximum=1000), String()]) value, error = validator.validate_or_error(9999) assert value is None assert error == ValidationError(text="Must be less than or equal to 1000.", code="maximum") validator = Integer() | String() | Boolean() value, error = validator.validate_or_error(123) assert value == 123 validator = Integer() | (String() | Boolean()) value, error = validator.validate_or_error(123) assert value == 123
def test_errors_dict_interface(): """ `validated.errors` should present a dict-like interface. """ validator = Object(properties={"example": Integer()}) value, error = validator.validate_or_error({"example": "abc"}) assert dict(error) == {"example": "Must be a number."} validator = Object(properties={"example": Integer()}) value, error = validator.validate_or_error({"example": "abc"}) assert error["example"] == "Must be a number." validator = Object(additional_properties=Object( additional_properties=Integer())) value, error = validator.validate_or_error({"example": {"nested": "abc"}}) assert dict(error) == {"example": {"nested": "Must be a number."}} validator = Integer() value, error = validator.validate_or_error("abc") assert error[""] == "Must be a number." validator = Integer() value, error = validator.validate_or_error("abc") assert dict(error) == {"": "Must be a number."}
def test_one_of(): validator = OneOf([String(), Integer()]) value, error = validator.validate_or_error(123) assert value is 123 assert error is None validator = OneOf([String(allow_null=True), Integer()]) value, error = validator.validate_or_error(None) assert value is None assert error is None validator = OneOf([String(allow_null=True), Integer(allow_null=True)]) value, error = validator.validate_or_error(None) assert value is None assert error == ValidationError( text="Matched more than one type.", code="multiple_matches" ) validator = OneOf([String(), Integer()]) value, error = validator.validate_or_error(None) assert value is None assert error == ValidationError( text="Did not match any valid type.", code="no_match" )
def test_all_of(): validator = AllOf([Integer(multiple_of=5), Integer(multiple_of=3)]) value, error = validator.validate_or_error(3) assert value is None assert error == ValidationError(text="Must be a multiple of 5.", code="multiple_of") validator = AllOf([Integer(multiple_of=5), Integer(multiple_of=3)]) value, error = validator.validate_or_error(5) assert value is None assert error == ValidationError(text="Must be a multiple of 3.", code="multiple_of") validator = AllOf([Integer(multiple_of=5), Integer(multiple_of=3)]) value, error = validator.validate_or_error(15) assert value == 15 assert error is None
def from_json_schema_type(data: dict, type_string: str, allow_null: bool, definitions: SchemaDefinitions) -> Field: """ Build a typed field from a JSON schema object. """ if type_string == "number": kwargs = { "allow_null": allow_null, "minimum": data.get("minimum", None), "maximum": data.get("maximum", None), "exclusive_minimum": data.get("exclusiveMinimum", None), "exclusive_maximum": data.get("exclusiveMaximum", None), "multiple_of": data.get("multipleOf", None), "default": data.get("default", NO_DEFAULT), } return Float(**kwargs) elif type_string == "integer": kwargs = { "allow_null": allow_null, "minimum": data.get("minimum", None), "maximum": data.get("maximum", None), "exclusive_minimum": data.get("exclusiveMinimum", None), "exclusive_maximum": data.get("exclusiveMaximum", None), "multiple_of": data.get("multipleOf", None), "default": data.get("default", NO_DEFAULT), } return Integer(**kwargs) elif type_string == "string": min_length = data.get("minLength", 0) kwargs = { "allow_null": allow_null, "allow_blank": min_length == 0, "min_length": min_length if min_length > 1 else None, "max_length": data.get("maxLength", None), "format": data.get("format"), "pattern": data.get("pattern", None), "default": data.get("default", NO_DEFAULT), } return String(**kwargs) elif type_string == "boolean": kwargs = { "allow_null": allow_null, "default": data.get("default", NO_DEFAULT) } return Boolean(**kwargs) elif type_string == "array": items = data.get("items", None) if items is None: items_argument: typing.Union[None, Field, typing.List[Field]] = None elif isinstance(items, list): items_argument = [ from_json_schema(item, definitions=definitions) for item in items ] else: items_argument = from_json_schema(items, definitions=definitions) additional_items = data.get("additionalItems", None) if additional_items is None: additional_items_argument: typing.Union[bool, Field] = True elif isinstance(additional_items, bool): additional_items_argument = additional_items else: additional_items_argument = from_json_schema( additional_items, definitions=definitions) kwargs = { "allow_null": allow_null, "min_items": data.get("minItems", 0), "max_items": data.get("maxItems", None), "additional_items": additional_items_argument, "items": items_argument, "unique_items": data.get("uniqueItems", False), "default": data.get("default", NO_DEFAULT), } return Array(**kwargs) elif type_string == "object": properties = data.get("properties", None) if properties is None: properties_argument: typing.Optional[typing.Dict[str, Field]] = None else: properties_argument = { key: from_json_schema(value, definitions=definitions) for key, value in properties.items() } pattern_properties = data.get("patternProperties", None) if pattern_properties is None: pattern_properties_argument: typing.Optional[typing.Dict[ str, Field]] = (None) else: pattern_properties_argument = { key: from_json_schema(value, definitions=definitions) for key, value in pattern_properties.items() } additional_properties = data.get("additionalProperties", None) if additional_properties is None: additional_properties_argument: typing.Union[None, bool, Field] = (None) elif isinstance(additional_properties, bool): additional_properties_argument = additional_properties else: additional_properties_argument = from_json_schema( additional_properties, definitions=definitions) property_names = data.get("propertyNames", None) if property_names is None: property_names_argument: typing.Optional[Field] = None else: property_names_argument = from_json_schema(property_names, definitions=definitions) kwargs = { "allow_null": allow_null, "properties": properties_argument, "pattern_properties": pattern_properties_argument, "additional_properties": additional_properties_argument, "property_names": property_names_argument, "min_properties": data.get("minProperties", None), "max_properties": data.get("maxProperties", None), "required": data.get("required", None), "default": data.get("default", NO_DEFAULT), } return Object(**kwargs) assert False, f"Invalid argument type_string={type_string!r}" # pragma: no cover
JSONSchema = ( Object( properties={ "$ref": String(), "type": String() | Array(items=String()), "enum": Array(unique_items=True, min_items=1), "definitions": Object(additional_properties=Reference("JSONSchema", definitions=definitions)), # String "minLength": Integer(minimum=0), "maxLength": Integer(minimum=0), "pattern": String(format="regex"), "format": String(), # Numeric "minimum": Number(), "maximum": Number(), "exclusiveMinimum": Number(), "exclusiveMaximum": Number(),
def test_array(): validator = Array() value, error = validator.validate_or_error([]) assert value == [] validator = Array() value, error = validator.validate_or_error(None) assert error == ValidationError(text="May not be null.", code="null") validator = Array() value, error = validator.validate_or_error(123) assert error == ValidationError(text="Must be an array.", code="type") validator = Array(allow_null=True) value, error = validator.validate_or_error(None) assert value is None assert error is None validator = Array(min_items=1) value, error = validator.validate_or_error([]) assert error == ValidationError(text="Must not be empty.", code="empty") validator = Array(min_items=1) value, error = validator.validate_or_error([1]) assert value == [1] validator = Array(min_items=2) value, error = validator.validate_or_error([]) assert error == ValidationError(text="Must have at least 2 items.", code="min_items") validator = Array(min_items=2) value, error = validator.validate_or_error([1, 2]) assert value == [1, 2] validator = Array(max_items=2) value, error = validator.validate_or_error([]) assert value == [] validator = Array(max_items=2) value, error = validator.validate_or_error([1, 2, 3]) assert error == ValidationError(text="Must have no more than 2 items.", code="max_items") validator = Array(exact_items=2) value, error = validator.validate_or_error([1, 2]) assert value == [1, 2] validator = Array(exact_items=2) value, error = validator.validate_or_error([1, 2, 3]) assert error == ValidationError(text="Must have 2 items.", code="exact_items") validator = Array(items=Integer()) value, error = validator.validate_or_error(["1", 2, "3"]) assert value == [1, 2, 3] validator = Array(items=Integer()) value, error = validator.validate_or_error(["a", 2, "c"]) assert dict(error) == {0: "Must be a number.", 2: "Must be a number."} validator = Array(items=[String(), Integer()]) value, error = validator.validate_or_error(["a", "b", "c"]) assert error == ValidationError(text="Must have 2 items.", code="exact_items") validator = Array(items=[String(), Integer()]) value, error = validator.validate_or_error(["a", "123"]) assert value == ["a", 123] validator = Array(items=[String(), Integer()], additional_items=Integer()) value, error = validator.validate_or_error(["a", "123", "456"]) assert value == ["a", 123, 456] validator = Array(items=String(), unique_items=True) value, error = validator.validate_or_error(["a", "b"]) assert value == ["a", "b"] validator = Array(items=String(), unique_items=True) value, error = validator.validate_or_error(["a", "a"]) assert dict(error) == {1: "Items must be unique."} validator = Array(items=[String(), Integer(), Boolean()], min_items=1) value, error = validator.validate_or_error(["a"]) assert value == ["a"] validator = Array(items=[String(), Integer(), Boolean()], min_items=1) value, error = validator.validate_or_error(["a", "123"]) assert value == ["a", 123] validator = Array(items=[String(), Integer(), Boolean()], min_items=1) value, error = validator.validate_or_error([]) assert error == ValidationError(text="Must not be empty.", code="empty") validator = Array(items=[String(), Integer(), Boolean()], min_items=2) value, error = validator.validate_or_error([]) assert error == ValidationError(text="Must have at least 2 items.", code="min_items")
def test_object(): validator = Object() value, error = validator.validate_or_error({}) assert value == {} validator = Object() value, error = validator.validate_or_error(None) assert dict(error) == {"": "May not be null."} validator = Object() value, error = validator.validate_or_error(123) assert dict(error) == {"": "Must be an object."} validator = Object() value, error = validator.validate_or_error({1: 123}) assert dict(error) == {"": "All object keys must be strings."} validator = Object(allow_null=True) value, error = validator.validate_or_error(None) assert value is None assert error is None validator = Object(min_properties=1) value, error = validator.validate_or_error({}) assert dict(error) == {"": "Must not be empty."} validator = Object(min_properties=1) value, error = validator.validate_or_error({"a": 1}) assert value == {"a": 1} validator = Object(min_properties=2) value, error = validator.validate_or_error({}) assert dict(error) == {"": "Must have at least 2 properties."} validator = Object(min_properties=2) value, error = validator.validate_or_error({"a": 1, "b": 2}) assert value == {"a": 1, "b": 2} validator = Object(max_properties=2) value, error = validator.validate_or_error({}) assert value == {} validator = Object(max_properties=2) value, error = validator.validate_or_error({"a": 1, "b": 2, "c": 3}) assert dict(error) == {"": "Must have no more than 2 properties."} validator = Object(required=["example"]) value, error = validator.validate_or_error({"example": 123}) assert value == {"example": 123} validator = Object(required=["example"]) value, error = validator.validate_or_error({}) assert dict(error) == {"example": "This field is required."} validator = Object(properties={"example": Integer()}) value, error = validator.validate_or_error({"example": "123"}) assert value == {"example": 123} validator = Object(properties={"example": Integer()}) value, error = validator.validate_or_error({"example": "abc"}) assert dict(error) == {"example": "Must be a number."} validator = Object(pattern_properties={"^x-.*$": Integer()}) value, error = validator.validate_or_error({"x-example": "123"}) assert value == {"x-example": 123} validator = Object(pattern_properties={"^x-.*$": Integer()}) value, error = validator.validate_or_error({"x-example": "abc"}) assert dict(error) == {"x-example": "Must be a number."} validator = Object(properties={"example": Integer(default=0)}) value, error = validator.validate_or_error({"example": "123"}) assert value == {"example": 123} validator = Object(properties={"example": Integer(default=0)}) value, error = validator.validate_or_error({}) assert value == {"example": 0} validator = Object(additional_properties=False) value, error = validator.validate_or_error({"example": "123"}) assert dict(error) == {"example": "Invalid property name."} validator = Object(additional_properties=True) value, error = validator.validate_or_error({"example": "abc"}) assert value == {"example": "abc"} validator = Object(additional_properties=None) value, error = validator.validate_or_error({"example": "abc"}) assert value == {} validator = Object(properties=Integer()) value, error = validator.validate_or_error({"example": "123"}) assert value == {"example": 123} validator = Object(properties=Integer()) value, error = validator.validate_or_error({"example": "abc"}) assert dict(error) == {"example": "Must be a number."} validator = Object(properties={"example": Integer()}) value, error = validator.validate_or_error({"example": "123"}) assert value == {"example": 123} validator = Object(properties={"example": Integer()}) value, error = validator.validate_or_error({"example": "abc"}) assert dict(error) == {"example": "Must be a number."} validator = Object(additional_properties=Object( additional_properties=Integer())) value, error = validator.validate_or_error({"example": {"nested": "123"}}) assert value == {"example": {"nested": 123}} validator = Object(additional_properties=Object( additional_properties=Integer())) value, error = validator.validate_or_error({"example": {"nested": "abc"}}) assert dict(error) == {"example": {"nested": "Must be a number."}}
def test_integer(): validator = Integer() value, error = validator.validate_or_error(123) assert value == 123 validator = Integer() value, error = validator.validate_or_error("123") assert value == 123 validator = Integer() value, error = validator.validate_or_error(123.0) assert value == 123 validator = Integer() value, error = validator.validate_or_error("123.0") assert value == 123 validator = Integer() value, error = validator.validate_or_error(None) assert error == ValidationError(text="May not be null.", code="null") validator = Integer() value, error = validator.validate_or_error("abc") assert error == ValidationError(text="Must be a number.", code="type") validator = Integer() value, error = validator.validate_or_error(True) assert error == ValidationError(text="Must be a number.", code="type") validator = Integer() value, error = validator.validate_or_error(123.1) assert error == ValidationError(text="Must be an integer.", code="integer") validator = Integer() value, error = validator.validate_or_error(float("inf")) assert error == ValidationError(text="Must be an integer.", code="integer") validator = Integer() value, error = validator.validate_or_error(float("nan")) assert error == ValidationError(text="Must be an integer.", code="integer") validator = Integer() value, error = validator.validate_or_error("123", strict=True) assert error == ValidationError(text="Must be a number.", code="type") validator = Integer(allow_null=True) value, error = validator.validate_or_error(None) assert value is None assert error is None validator = Integer(allow_null=True) value, error = validator.validate_or_error("") assert value is None assert error is None validator = Integer(allow_null=True) value, error = validator.validate_or_error("", strict=True) assert error == ValidationError(text="Must be a number.", code="type") validator = Integer(maximum=10) value, error = validator.validate_or_error(100) assert error == ValidationError(text="Must be less than or equal to 10.", code="maximum") validator = Integer(maximum=10) value, error = validator.validate_or_error(10) assert value == 10 validator = Integer(minimum=3) value, error = validator.validate_or_error(1) assert error == ValidationError(text="Must be greater than or equal to 3.", code="minimum") validator = Integer(minimum=3) value, error = validator.validate_or_error(3) assert value == 3 validator = Integer(exclusive_maximum=10) value, error = validator.validate_or_error(10) assert error == ValidationError(text="Must be less than 10.", code="exclusive_maximum") validator = Integer(exclusive_minimum=3) value, error = validator.validate_or_error(3) assert error == ValidationError(text="Must be greater than 3.", code="exclusive_minimum") validator = Integer(multiple_of=10) value, error = validator.validate_or_error(5) assert error == ValidationError(text="Must be a multiple of 10.", code="multiple_of")
def test_validation_error_is_hashable(): validator = Integer() _, error = validator.validate_or_error("abc") hash(error)