def test_url(): validator = String(format="url") for item in [ "http://www.python.org", "https://www.python.org", "http://www.python007.org", "http://42.com", "http://python.org", "http://python.org/intro", "https://python.org/intro/firstlesson/", "http://www.google.com" ]: value, error = validator.validate_or_error(item) assert value == urllib.parse.urlparse(item) validator = String(format="url") for item in [ "www.python.org", "www.python42.org", "42.com", "python.org" "inside.python.org", "python.org/intro", "python.org/intro/firstlesson/" ]: value, error = validator.validate_or_error(item) assert value == urllib.parse.urlparse("http://" + item) validator = String(format="url") for item in ["python@sas", "pythonv7", ".com"]: value, error = validator.validate_or_error(item) assert error == ValidationError(text="Must be valid URL format.", code="format")
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_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_uuid(): validator = String(format="uuid") value, error = validator.validate_or_error( "93e19019-c7a6-45fe-8936-f6f4d550f35f") assert value == uuid.UUID("93e19019-c7a6-45fe-8936-f6f4d550f35f") validator = String(format="uuid") value, error = validator.validate_or_error( "1245a678-1234-1234-1234-123412341234") assert error == ValidationError(text="Must be valid UUID format.", code="format")
def test_email(): validator = String(format="email") for item in [ "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**", "[email protected]", "*****@*****.**", "*****@*****.**", "*****@*****.**" ]: value, error = validator.validate_or_error(item) assert value == item validator = String(format="email") for item in [ "info@python", "python@python", "python@[email protected]", "@python.org" ]: value, error = validator.validate_or_error(item) assert error == ValidationError(text="Must be valid Email format.", code="format")
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
"pattern", "patternProperties", "properties", "propertyNames", "required", "type", "uniqueItems", } definitions = SchemaDefinitions() 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":
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_string(): validator = String() validated = validator.validate_or_error("abc") assert validated assert validated.value == "abc" assert validated.error is None validator = String() value, error = validator.validate_or_error("") assert error == ValidationError(text="Must not be blank.", code="blank") validator = String() value, error = validator.validate_or_error(None) assert error == ValidationError(text="May not be null.", code="null") validator = String() value, error = validator.validate_or_error(123) assert error == ValidationError(text="Must be a string.", code="type") validator = String(max_length=10) value, error = validator.validate_or_error("abc" * 10) assert error == ValidationError( text="Must have no more than 10 characters.", code="max_length") validator = String(min_length=3) value, error = validator.validate_or_error("a") assert error == ValidationError(text="Must have at least 3 characters.", code="min_length") validator = String(allow_blank=False) value, error = validator.validate_or_error("") assert error == ValidationError(text="Must not be blank.", code="blank") validator = String(allow_blank=True) value, error = validator.validate_or_error("") assert value == "" validator = String(allow_blank=True) value, error = validator.validate_or_error(None) assert value == "" validator = String(allow_null=True) value, error = validator.validate_or_error(None) assert value is None assert error is None validator = String(allow_null=True) value, error = validator.validate_or_error("") assert value is None assert error is None validator = String(allow_null=True) value, error = validator.validate_or_error(" ") assert value is None assert error is None validator = String(pattern="^[abc]*$") value, error = validator.validate_or_error("cba") assert value == "cba" validator = String(pattern="^[abc]*$") value, error = validator.validate_or_error("cbxa") assert error == ValidationError(text="Must match the pattern /^[abc]*$/.", code="pattern") validator = String() value, error = validator.validate_or_error(" ") assert error == ValidationError(text="Must not be blank.", code="blank") validator = String() value, error = validator.validate_or_error(" test ") assert value == "test" validator = String(trim_whitespace=False) value, error = validator.validate_or_error(" ") assert value == " " validator = String(trim_whitespace=False) value, error = validator.validate_or_error(" test ") assert value == " test "
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) == {1: "All object keys must be strings."} validator = Object(property_names=String(min_length=3)) value, error = validator.validate_or_error({"a": 123}) assert dict(error) == {"a": "Invalid property name."} 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."}}