API reference
Validating objects
To validate an object against a schema one may use vtjson.validate()
. If validation fails this throws a vtjson.ValidationError
.
A suitable written schema can be used as a Python type annotation. vtjson.safe_cast()
verifies if a given object has a given type.
vtjson.make_type()
transforms a schema into a genuine Python type so that validation can be done using isinstance().
- validate(schema, obj, name='object', strict=True, subs={})
Validates the given object against the given schema.
- Parameters:
schema (
object
) – the given schemaobj (
object
) – the object to be validatedname (
str
) – common name for the object to be validated; used in non-validation messagesstrict (
bool
) – indicates whether or not the object being validated is allowed to have keys/entries which are not in the schemasubs (
Mapping
[str
,object
]) – a dictionary whose keys are labels and whose values are substitution schemas for schemas with those labels
- Raises:
ValidationError – exception thrown when the object does not validate; the exception message contains an explanation about what went wrong
SchemaError – exception thrown when the schema definition is found to contain an error
- Return type:
None
- safe_cast(schema, obj)
Validates the given object against the given schema and changes its type accordingly.
- Parameters:
schema (
Type
[TypeVar
(T
)]) – the given schemaobj (
Any
) – the object to be validated
- Return type:
TypeVar
(T
)- Returns:
the validated object with its type changed
- Raises:
ValidationError – exception thrown when the object does not validate; the exception message contains an explanation about what went wrong
SchemaError – exception thrown when the schema definition is found to contain an error
- make_type(schema, name=None, strict=True, debug=False, subs={})
Transforms a schema into a genuine Python type.
- Parameters:
schema (
object
) – the given schemaname (
str
|None
) – sets the __name__ attribute of the type; if it is not supplied then vtjson makes an educated guessstrict (
bool
) – indicates whether or not the object being validated is allowed to have keys/entries which are not in the schemadebug (
bool
) – print feedback on the console if validation failssubs (
Mapping
[str
,object
]) – a dictionary whose keys are labels and whose values are substitution schemas for schemas with those labels
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- Return type:
_validate_meta
- exception ValidationError
Raised if validation fails. The associated message explains what went wrong.
- exception SchemaError
Raised if a schema contains an error.
Built-in schemas
Some built-in schemas take arguments. If no arguments are given then the parentheses can be omitted. So email is equivalent to email(). Some built-ins have an optional name argument. This is used in non-validation messages.
- class regex(regex, name=None, fullmatch=True, flags=0)
Bases:
compiled_schema
This matches the strings which match the given pattern.
- Parameters:
regex (
str
) – the regular expression patternname (
str
|None
) – common name for the pattern that will be used in non-validation messagesfullmatch (
bool
) – indicates whether or not the full string should be matchedflags (
int
) – the flags argument used when invoking re.compile
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class glob(pattern, name=None)
Bases:
compiled_schema
Unix style filename matching. This is implemented using pathlib.PurePath().match().
- Parameters:
pattern (
str
) – the wild card pattern to matchname (
str
|None
) – common name for the pattern that will be used in non-validation messages
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class div(divisor, remainder=0, name=None)
Bases:
compiled_schema
This matches the integers x such that (x - remainder) % divisor == 0.
- Parameters:
divisor (
int
) – the divisorremainder (
int
) – the remainername (
str
|None
) – common name (e.g. even or odd) that will be used in non-validation messages
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class close_to(x, rel_tol=None, abs_tol=None)
Bases:
compiled_schema
This matches the real numbers that are close to x in the sense of math.isclose.
- Parameters:
rel_tol (
int
|float
|None
) – the maximal allowed relative deviationabs_tol (
int
|float
|None
) – the maximal allowed absolute deviation
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class email(**kw)
Bases:
compiled_schema
Checks if the object is a valid email address. This uses the package email_validator. The email schema accepts the same options as validate_email in loc. cit.
- Parameters:
kw (
Any
) – optional keyword arguments to be forwarded to email_validator.validate_email
- class ip_address(version=None)
Bases:
compiled_schema
Matches ip addresses of the specified version which can be 4, 6 or None.
- Parameters:
version (
Literal
[4
,6
,None
]) – the version of the ip protocol- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class url
Bases:
compiled_schema
Matches valid urls.
- class domain_name(ascii_only=True, resolve=False)
Bases:
compiled_schema
Checks if the object is a valid domain name.
- Parameters:
ascii_only (
bool
) – if False then allow IDNA domain namesresolve (
bool
) – if True check if the domain names resolves
- class date_time(format=None)
Bases:
compiled_schema
Without argument this represents an ISO 8601 date-time. The format argument represents a format string for strftime.
- Parameters:
format (
str
|None
) – format string for strftime
- class date
Bases:
compiled_schema
Matches an ISO 8601 date.
- class time
Bases:
compiled_schema
Matches an ISO 8601 time.
- class anything
Bases:
compiled_schema
Matchess anything.
- class nothing
Bases:
compiled_schema
Matches nothing.
- class float_
Bases:
compiled_schema
Schema that only matches floats. Not ints.
Modifiers
- class one_of(*args)
Bases:
compiled_schema
This represents a dictionary with exactly one key among a collection of keys.
- Parameters:
args (
object
) – a collection of keys
- class at_least_one_of(*args)
Bases:
compiled_schema
This represents a dictionary with a least one key among a collection of keys.
- Parameters:
args (
object
) – a collection of keys
- class at_most_one_of(*args)
Bases:
compiled_schema
This represents an dictionary with at most one key among a collection of keys.
- Parameters:
args (
object
) – a collection of keys
- class keys(*args)
Bases:
compiled_schema
This represents a dictionary containing all the keys in a collection of keys.
- Parameters:
args (
object
) – a collection of keys
- class interval(lb, ub, strict_lb=False, strict_ub=False)
Bases:
compiled_schema
This checks if lb <= object <= ub, provided the comparisons make sense.
- Parameters:
lb (
comparable
|EllipsisType
) – lower bound; … (ellipsis) means no lower boundub (
comparable
|EllipsisType
) – upper bound; … (ellipsis) means no upper boundstrict_lb (
bool
) – if True use a strict lower boundstrict_ub (
bool
) – if True use a strict upper bound
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class gt(lb)
Bases:
compiled_schema
This checks if object > lb.
- Parameters:
lb (
comparable
) – the strict lower bound- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class ge(lb)
Bases:
compiled_schema
This checks if object >= lb.
- Parameters:
lb (
comparable
) – the lower bound- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class lt(ub)
Bases:
compiled_schema
This checks if object < ub.
- Parameters:
ub (
comparable
) – the strict upper bound- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class le(ub)
Bases:
compiled_schema
This checks if object <= ub.
- Parameters:
ub (
comparable
) – the upper bound- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class size(lb, ub=None)
Bases:
compiled_schema
Matches the objects (which support len() such as strings or lists) whose length is in the interval [lb, ub].
- Parameters:
lb (
int
) – the lower bound for the lengthub (
int
|EllipsisType
|None
) – the upper bound for the length; … (ellipsis) means that there is no upper bound; None means lb==ub
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class fields(d)
Bases:
wrapper
,Generic
[StringKeyType
]d is a dictionary {“field1”: schema1, …}. This matches Python objects with attributes field1, field2, …, fieldN whose corresponding values should validate against schema1, schema2, …, schemaN respectively.
- Parameters:
d (
Mapping
[TypeVar
(StringKeyType
, bound=Union
[str
,optional_key
[str
]]),object
]) – a dictionary associating fields with schemas- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class magic(mime_type, name=None)
Bases:
compiled_schema
Checks if a buffer (for example a string or a byte array) has the given mime type. This is implemented using the python-magic package.
- Parameters:
mime_type (
str
) – the mime typename (
str
|None
) – common name to refer to this mime type
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- class filter(filter, schema, filter_name=None)
Bases:
wrapper
Applies filter to the object and validates the result with schema. If the callable throws an exception then validation fails.
- Parameters:
filter (
Callable
[[Any
],object
]) – the filter to apply to the objectschema (
object
) – the schema used for validation once the filter has been appliedfilter_name (
str
|None
) – common name to refer to the filter
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
Wrappers
Wrappers are schemas that contain references to other schemas.
- class union(*schemas)
Bases:
wrapper
An object matches the schema union(schema1, …, schemaN) if it matches one of the schemas schema1, …, schemaN.
- Parameters:
schemas (
object
) – collection of schemas, one of which should match
- class intersect(*schemas)
Bases:
wrapper
An object matches the schema intersect(schema1, …, schemaN) if it matches all the schemas schema1, …, schemaN.
- Parameters:
schemas (
object
) – collection of schemas, all of which should match
- class complement(schema)
Bases:
wrapper
An object matches the schema complement(schema) if it does not match schema.
- Parameters:
schema (
object
) – the schema that should not be matched
- class lax(schema)
Bases:
wrapper
An object matches the schema lax(schema) if it matches schema when validated with strict=False.
- Parameters:
schema (
object
) – schema that should be validated against with strict=False
- class strict(schema)
Bases:
wrapper
An object matches the schema strict(schema) if it matches schema when validated with strict=True.
- Parameters:
schema (
object
) – schema that should be validated against with strict=True
- class quote(schema)
Bases:
wrapper
An object matches the schema quote(schema) if it is equal to schema. For example the schema str matches strings but the schema quote(str) matches the object str.
- Parameters:
schema (
object
) – the schema to be quoted
- class set_name(schema, name, reason=False)
Bases:
wrapper
An object matches the schema set_name(schema, name) if it matches schema, but the name argument will be used in non-validation messages.
- Parameters:
schema (
object
) – the original schemaname (
str
) – name for use in non-validation messagesreason (
bool
) – if True then the original non-validation message will not be suppressed
- class protocol(schema, dict=False)
Bases:
wrapper
An object matches the schema protocol(schema, dict=False) if schema is a class (or class like object) and its fields are annotated with schemas which validate the corresponding fields in the object.
- Parameters:
schema (
object
) – a type annotated class (or class like object such as Protocol or TypedDict) serving as prototypedict (
bool
) – if True parse the object as a dict
- Raises:
SchemaError – exception thrown when the schema does not support type_hints
- class set_label(schema, *labels, debug=False)
Bases:
wrapper
An object matches the schema set_label(schema, label1, …, labelN, debug=False) if it matches schema, unless the schema is replaced by a different one via the subs argument to validate.
- Parameters:
schema (
object
) – the schema that will be labeledlabels (
str
) – labels that will be attached to the schemadebug (
bool
) – it True print a message on the console if the schema was changed via substitution
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
Conditional schemas
- class ifthen(if_schema, then_schema, else_schema=None)
Bases:
wrapper
If the object matches the if_schema then it should also match the then_schema. If the object does not match the if_schema then it should match the else_schema, if present.
- Parameters:
if_schema (
object
) – the if_schemathen_schema (
object
) – the then_schemaelse_schema (
object
|None
) – the else_schema
- class cond(*args)
Bases:
wrapper
Args is a list of tuples (if_schema, then_schema). An object is successively validated against if_schema1, if_schema2, … until a validation succeeds. When this happens the object should match the corresponding then_schema. If no if_schema succeeds then the object is considered to have been validated. If one sets if_schemaN equal to anything then this serves as a catch all.
- Parameters:
args (
tuple
[object
,object
]) – list of tuples pairing if_schemas with then_schemas- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
Type annotations integration
Type annotations as schemas
vtjson recognizes the following type annotations as schemas.
Annotated, Mapping[K, V] and subtypes, Container[T] and subtypes, tuple[…] and Tuple[…], Protocol, NamedTuple, NewType, TypedDict, Union and the | operator, Any.
For example dict[str, str] is translated internally into the schema {str: str}. This is explained further below.
Annotated
More general vtjson schemas can work along Python type annotations by using the typing.Annotated contruct. The most naive way to do this is via
Annotated[type_annotation, vtjson_schema, skip_first]
For example
Annotated[list[object], [int, str, float], skip_first]
A type checker such as mypy will only see the type annotation (list[object] in the example), whereas vtjson will only see the vtjson schema ([int, str, float] in the example). skip_first is a built-in short hand for Apply(skip_first=True) (see below) which directs vtjson to ignore the first argument of an Annotated schema.
In some use cases a vtjon schema will meaningfully refine a Python type or type annotation. In that case one should not use skip_first. For example:
Annotated[datetime, fields({"tzinfo": timezone.utc})]
defines a datetime object whose time zone is utc.
The built-in schemas already check that an object has the correct type. So for those one should use skip_first. For example:
Annotated[int, div(2), skip_first]
matches even integers.
If one wants to pre-compile a schema and still use it as a type annotation (assuming it is valid as such) then one can do:
schema = <schema definition> Schema = Annotated[schema, compile(schema), skip_first]
Supported type annotations
Note that Python imposes strong restrictions on what constitutes a valid type annotation but vtjson is much more lax about this. Enforcing the restrictions is left to the type checkers or the Python interpreter.
- TypedDict
A TypedDict type annotation is, roughly speaking, translated into a dict schema. E.g.
class Movie(TypedDict): title: str price: float
internally becomes
set_name({"title": str, "price": float}, "Movie", reason=True)
vtjson supports the total option to TypedDict as well as the Required and NotRequired annotations of fields, if they are compatible with the Python version being used.
- Protocol
A class implementing a protocol is translated into a
vtjson.fields
schema. E.g.class Movie(Protocol): title: str price: float
internally becomes
set_name(fields({"title": str, "price": float}), "Movie", reason=True)
- NamedTuple
A NamedTuple class is translated into an
vtjson.intersect
schema encompassing a tuple schema and avtjson.fields
schema. E.g.class Movie(NamedTuple): title: str price: float
internally becomes
set_name(intersect(tuple, fields({"title": str, "price": float})), "Movie", reason=True)
- Annotated
This has already been discussed in the section Annotated. It is translated into a suitable
vtjson.intersect
schema. The handling of Annotated schemas can be influenced byvtjson.Apply
objects.
- NewType
This is translated into a
vtjson.set_name
schema. E.g. NewType(‘Movie’, str) becomes set_name(str, ‘Movie’)
- tuple[…] and Tuple[…]
These are translated into the equivalent tuple schemas.
- Mapping[K, V] and subtypes
These validate those objects that are members of the origin type (a subclass of Mapping) and whose (key, value) pairs match (K, V).
- Container[T] and subtypes
These validate those objects that are members of the origin type (a subclass of Container) and whose elements match T.
- Union and the | operator
These are translated into
vtjson.union
.
- Literal
This is also translated into
vtjson.union
.
- Any
This is translated into
vtjson.anything
.
Apply objects
If the list of arguments of an Annotated schema includes
vtjson.Apply
objects then those modify the treatement of the arguments that come before them. We already encounteredvtjson.skip_first
which is a built-in alias for Apply(skip_first=True).Multiple
vtjson.Apply
objects are allowed. E.g. the following contrived schemaAnnotated[int, str, skip_first, float, skip_first]
is equivalent to float.
- class Apply(skip_first=None, name=None, labels=None)
Bases:
object
Modifies the treatement of the previous arguments in an Annotated schema.
- Parameters:
skip_first (
bool
|None
) – if True do not use the first argument (the Python type annotation) in an Annotated construct for validation because this is already covered by the other argumentsname (
str
|None
) – apply the correspondingvtjson.set_name
command to the previous argumentslabels (
Sequence
[str
] |None
) – apply the correspondingvtjson.set_label
command to the previous arguments
- vtjson.skip_first: vtjson.Apply = vtjson.Apply(skip_first=True)
Do not use the first argument (the Python type annotation) in an Annotated construct for validation (likely because it is already covered by the other arguments).
Schema format
A schema can be, in order of precedence:
An instance of the class
vtjson.compiled_schema
. The classvtjson.compiled_schema
defines a single abstract methodvtjson.compiled_schema.__validate__()
with similar semantics asvtjson.validate()
.A subclass of
vtjson.compiled_schema
with a no-argument constructor.An object having a __validate__() attribute with the same signature as
vtjson.compiled_schema.__validate__()
.An instance of the class
vtjson.wrapper
. The classvtjson.wrapper
defines a single abstract methodvtjson.wrapper.__compile__()
that should produce an instance ofvtjson.compiled_schema
.A Python type annotation such as list[str]. See Type annotations integration.
A Python type. In that case validation is done by checking membership. For compatibility with Python type annotations, the schema float matches both ints and floats. Use
vtjson.float_
if you want only floats.A callable. Validation is done by applying the callable to the object. If applying the callable throws an exception then the corresponding message will be part of the non-validation message.
An instance of Sequence that is not an instance of str (e.g a list or a tuple). Validation is done by first checking membership of the schema type, and then performing validation for each of the entries of the object being validated against the corresponding entries of the schema.
An instance of Mapping. Validation is done by first checking membership of the schema type, and then performing validation for each of the values of the object being validated against the corresponding values of the schema. Keys are themselves considered as schemas. E.g. {str: str} represents a dictionary whose keys and values are both strings. For a more elaborate discussion of validation of mappings see Validating against Mapping schemas.
A set. A set validates an object if the object is a set and the elements of the object are validated by an element of the schema.
An arbitrary Python object. Validation is done by checking equality of the schema and the object, except when the schema is float, in which case math.isclose is used. Below we call such an object a const schema.
- class compiled_schema
The result of compiling a schema. A
compiled_schema
is produced by the factory functionvtjson.compile()
.- __validate__(obj, name, strict, subs)
Validates the given object against the given schema.
- Parameters:
schema – the given schema
obj (
object
) – the object to be validatedname (
str
) – common name for the object to be validated; used in non-validation messagesstrict (
bool
) – indicates whether or not the object being validated is allowed to have keys/entries which are not in the schemasubs (
Mapping
[str
,object
]) – a dictionary whose keys are labels and whose values are substitution schemas for schemas with those labels
- Return type:
str
- Returns:
an empty string if validation succeeds; otherwise an explanation about what went wrong
- compile(schema)
Compiles a schema. Internally invokes
vtjson._compile()
.- Parameters:
schema (
object
) – the schema that should be compiled- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- Return type:
- _compile(schema, _deferred_compiles=None)
Compiles a schema.
- Parameters:
schema (
object
) – the schema that should be compiled_deferred_compiles (
_mapping
|None
) – an opaque data structure used for handling recursive schemas; it should be passed unmodifed to any internal invocations ofvtjson._compile()
orvtjson.wrapper.__compile__()
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- Return type:
- class wrapper
Base class for schemas that refer to other schemas.
Handling such schemas is somewhat delicate since vtjson allows them to be recursive.
- __compile__(_deferred_compiles=None)
Compiles a schema.
- Parameters:
_deferred_compiles (
_mapping
|None
) – an opaque data structure used for handling recursive schemas; it should be passed unmodifed to any internal invocations ofvtjson._compile()
orvtjson.wrapper.__compile__()
- Raises:
SchemaError – exception thrown when the schema definition is found to contain an error
- Return type:
Validating against Mapping schemas
For a Mapping schema containing only const keys (i.e. keys corresponding to a const schema) the interpretation is obvious. Below we discuss the validation of an object against a Mapping schema in the general case.
First we verify that the type of the object is a subtype of the type of the schema. If not then validation fails.
We verify that all non-optional const keys of the schema are also keys of the object. If this is not the case then validation fails.
Now we make a list of all the keys of the schema (both optional and non-optional). The result will be called the key list below.
The object will pass validation if all its keys pass validation. We next discuss how to validate a particular key of the object.
If none of the entries of the key list validate the given key and strict==True (the default) then the key fails validation. If on the other hand strict==False then the key passes.
Assuming the fate of the given key hasn’t been decided yet, we now match it against all entries of the key list. If it matches an entry and the corresponding value also validates then the key is validated. Otherwise we keep going through the key list.
If the entire key list is consumed then the key fails validation.
A consequence of this algorithm is that non-const keys are automatically optional. So applying the wrapper vtjson.optional_key()
to them is meaningless and has no effect.
- class optional_key(key, _optional=True)
Bases:
Generic
[K
]Make a key in a Mapping schema optional. In the common case that the key is a string, the same effect can be achieved by appending ?. If you absolutely positively need a non-optional string key that ends in ? you can quote the ? by preceding it with a backslash.
- Parameters:
key (
TypeVar
(K
)) – the key to be made optional_optional (
bool
) – if False create a mandatory key; this is normally for internal use only
Pre-compiling a schema
An object matches the schema compile(schema) if it matches schema. vtjson compiles a schema before using it for validation, so pre-compiling is not necessary. However for large schemas it may gain some of performance as it needs to be done only once. Compiling is an idempotent operation. It does nothing for an already compiled schema.