jschon
A JSON toolkit for Python developers.
Features
JSON Schema validator implementation (drafts 2019-09, 2020-12)
Schema compilation and indexing
$ref loading from local and remote sources
Support for custom keywords, vocabularies and meta-schemas
Support for format validation
JSON class implementing the JSON data model
JSON Pointer (RFC 6901)
JSON Patch (RFC 6902)
Relative JSON Pointer (draft)
Installation
pip install jschon
For remote $ref support, the requests library is required. It may be installed with:
pip install jschon[requests]
Basic usage
Create a JSON schema:
from jschon import create_catalog, JSON, JSONSchema
create_catalog('2020-12')
demo_schema = JSONSchema({
"$id": "https://example.com/demo",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "array",
"items": {
"anyOf": [
{
"type": "string",
"description": "Cool! We got a string here!"
},
{
"type": "integer",
"description": "Hey! We got an integer here!"
}
]
}
})
Validate JSON data:
result = demo_schema.evaluate(
JSON([12, "Monkeys"])
)
Generate JSON Schema-conformant output:
>>> result.output('basic')
{
"valid": True,
"annotations": [
{
"instanceLocation": "",
"keywordLocation": "/items",
"absoluteKeywordLocation": "https://example.com/demo#/items",
"annotation": True
},
{
"instanceLocation": "/0",
"keywordLocation": "/items/anyOf/1/description",
"absoluteKeywordLocation": "https://example.com/demo#/items/anyOf/1/description",
"annotation": "Hey! We got an integer here!"
},
{
"instanceLocation": "/1",
"keywordLocation": "/items/anyOf/0/description",
"absoluteKeywordLocation": "https://example.com/demo#/items/anyOf/0/description",
"annotation": "Cool! We got a string here!"
}
]
}
Links
API Reference
Package API
Catalog
JSON
JSON Patch
JSON Pointer
JSON Schema
URI
Module Reference
jschon.catalog
- class jschon.catalog.Catalog(name='catalog')
The
Catalog
acts as a schema cache, enabling schemas and subschemas to be indexed, re-used, and cross-referenced by URI.- Parameters:
name (str)
- __init__(name='catalog')
Initialize a
Catalog
instance.- Parameters:
name (str) – a unique name for this
Catalog
instance- Return type:
None
- add_schema(uri, schema, *, cacheid='default')
Add a (sub)schema to a cache.
Note that this method is called automatically during schema construction.
- Parameters:
uri (URI) – the URI identifying the (sub)schema
schema (JSONSchema) – the
JSONSchema
instance to cachecacheid (Hashable) – schema cache identifier
- Return type:
None
- add_uri_source(base_uri, source)
Register a source for loading URI-identified JSON resources.
A base URI of
None
registers a default source that handles any URI that does not match any registered base URI string.- Parameters:
- Raises:
CatalogError – if base_uri is invalid
- Return type:
None
- cache(cacheid=None)
Context manager for a schema cache.
Example usage:
with catalog.cache() as cacheid: schema = JSONSchema(..., cacheid=cacheid)
The cache and its contents are popped from the catalog upon exiting the
with
block.- Parameters:
cacheid (Hashable)
- Return type:
ContextManager[Hashable, bool | None]
- create_metaschema(uri, default_core_vocabulary_uri=None, *default_vocabulary_uris, **kwargs)
Create, cache and validate a
Metaschema
.- Parameters:
uri (URI) – the URI identifying the metaschema
default_core_vocabulary_uri (URI) – the URI identifying the metaschema’s core
Vocabulary
, used in the absence of a"$vocabulary"
keyword in the metaschema JSON file, or if a known core vocabulary is not present under"$vocabulary"
default_vocabulary_uris (URI) – default
Vocabulary
URIs, used in the absence of a"$vocabulary"
keyword in the metaschema JSON filekwargs (Any) – additional keyword arguments to pass through to the
JSONSchema
constructor
- Returns:
the newly created
Metaschema
instance- Raises:
CatalogError – if the metaschema is not valid
- Return type:
- create_vocabulary(uri, *kwclasses)
Create a
Vocabulary
object, which may be used by aMetaschema
to provide keyword classes used in schema construction.- Parameters:
- Returns:
the newly created
Vocabulary
instance- Return type:
- del_schema(uri, *, cacheid='default')
Remove a (sub)schema from a cache.
- Parameters:
uri (URI) – the URI identifying the (sub)schema
cacheid (Hashable) – schema cache identifier
- Return type:
None
- enable_formats(*format_attr)
Enable validation of the specified format attributes.
These may include formats defined in
jschon.formats
and elsewhere.- Parameters:
format_attr (str)
- Return type:
None
- get_metaschema(uri)
Get a metaschema identified by uri from the
'__meta__'
cache, or load it from configured sources if not already cached.Note that metaschemas that do not declare a known core vocabulary in
"$vocabulary"
must first be created usingcreate_metaschema()
.- Parameters:
uri (URI) – the URI identifying the metaschema
- Raises:
CatalogError – if the object referenced by uri is not a
Metaschema
, or if it is not validJSONSchemaError – if the metaschema is loaded from sources but no known core vocabulary is present in
"$vocabulary"
- Return type:
- get_schema(uri, *, metaschema_uri=None, cacheid='default')
Get a (sub)schema identified by uri from a cache, or load it from disk if not already cached.
- Parameters:
uri (URI) – the URI identifying the (sub)schema
metaschema_uri (URI) – passed to the
JSONSchema
constructor when loading a new instance from diskcacheid (Hashable) – schema cache identifier
- Raises:
CatalogError – if a schema cannot be found for uri, or if the object referenced by uri is not a
JSONSchema
- Return type:
- get_vocabulary(uri)
Get a
Vocabulary
by its uri.- Parameters:
uri (URI) – the URI identifying the vocabulary
- Raises:
CatalogError – if uri is not a recognized vocabulary URI
- Return type:
- is_format_enabled(format_attr)
Return True if validation is enabled for format_attr, False otherwise.
- Return type:
bool
- load_json(uri)
Load a JSON-compatible object from the source for uri.
If there are multiple candidate base URIs for uri, the most specific match (i.e. the longest one) is selected.
- Parameters:
uri (URI) – a normalized, absolute URI - including scheme, without a fragment
- Raises:
CatalogError – if uri is invalid, a source is not available for uri, or if a loading error occurs
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- class jschon.catalog.LocalSource(base_dir, **kwargs)
- Parameters:
base_dir (Union[str, PathLike])
kwargs (Any)
- __call__(relative_path)
- Parameters:
relative_path (str)
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- __init__(base_dir, **kwargs)
- Parameters:
base_dir (str | PathLike)
kwargs (Any)
- Return type:
None
jschon.exc
- exception jschon.exc.JSONPointerError
An error originating in the
jsonpointer
module.
- exception jschon.exc.JSONPointerMalformedError
Raised for an invalid
JSONPointer
constructor argument.
- exception jschon.exc.JSONPointerReferenceError
Raised when a
JSONPointer
evaluates a non-existent location in a document.
- exception jschon.exc.JSONSchemaError
Raised when an error occurs during construction of a
JSONSchema
object. May be raised byKeyword
initializers and reference resolution methods.
- exception jschon.exc.JschonError
Generic error class.
- exception jschon.exc.RelativeJSONPointerMalformedError
Raised for an invalid
RelativeJSONPointer
constructor argument.
- exception jschon.exc.RelativeJSONPointerReferenceError
Raised when a
RelativeJSONPointer
evaluates a non-existent location in a document.
jschon.formats
- jschon.formats.validate_json_pointer(value)
- Parameters:
value (str)
- Return type:
None
jschon.json
- class jschon.json.JSON(value, *, parent=None, key=None, itemclass=None, **itemkwargs)
An implementation of the JSON data model.
- __bool__()
Return bool(self).
- Return type:
bool
- __delitem__(index)
Delete self[index].
Supported for JSON types
array
andobject
.- Parameters:
index (int | str)
- Return type:
None
- __eq__(other)
Return self == other.
- Parameters:
other (JSON | None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
bool
- __ge__(other)
Return self >= other.
Supported for JSON types
number
andstring
.- Parameters:
other (JSON | int | float | str)
- Return type:
bool
- __getitem__(index)
Return self[index].
Supported for JSON types
array
andobject
.- Parameters:
index (int | slice | str)
- Return type:
- __gt__(other)
Return self > other.
Supported for JSON types
number
andstring
.- Parameters:
other (JSON | int | float | str)
- Return type:
bool
- __init__(value, *, parent=None, key=None, itemclass=None, **itemkwargs)
Initialize a
JSON
instance from the given JSON-compatible value.The parent, key, itemclass and itemkwargs parameters should typically only be used in the construction of compound
JSON
documents byJSON
subclasses.- Parameters:
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]) – a JSON-compatible Python object
parent (JSON) – the parent node of the instance
key (str) – the index of the instance within its parent
itemclass (Type[JSON]) – the
JSON
subclass used to instantiate child nodes of arrays and objects (default:JSON
)itemkwargs (Any) – keyword arguments to pass to the itemclass constructor
- __iter__()
Return iter(self).
Supported for JSON types
array
andobject
.- Return type:
Iterator
- __le__(other)
Return self <= other.
Supported for JSON types
number
andstring
.- Parameters:
other (JSON | int | float | str)
- Return type:
bool
- __len__()
Return len(self).
Supported for JSON types
string
,array
andobject
.- Return type:
int
- __lt__(other)
Return self < other.
Supported for JSON types
number
andstring
.- Parameters:
other (JSON | int | float | str)
- Return type:
bool
- __repr__()
Return repr(self).
- Return type:
str
- __setitem__(index, obj)
Set self[index] to obj.
Supported for JSON types
array
andobject
.- Parameters:
index (int | str)
obj (JSON | None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- __str__()
Return str(self).
- Return type:
str
- add(path, obj)
Add obj at path relative to self.
The
JSON
equivalent toadd()
, this method performs an in-place JSON Patchadd
operation on self.If path is empty, the value of self is replaced by obj.
Experimental.
- Parameters:
path (str | JSONPointer)
obj (JSON | None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- copy(from_, to)
Not yet implemented; experimental.
- Parameters:
from_ (str | JSONPointer)
to (str | JSONPointer)
- Return type:
None
- dumpf(path)
Serialize the instance data to a JSON file.
- Parameters:
path (str | PathLike) – the path to the file
- Return type:
None
- dumps()
Serialize the instance data to a JSON string.
- Return type:
str
- insert(index, obj)
Insert obj before index.
Supported for JSON type
array
.- Parameters:
index (int)
obj (JSON | None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- move(from_, to)
Not yet implemented; experimental.
- Parameters:
from_ (str | JSONPointer)
to (str | JSONPointer)
- Return type:
None
- remove(path)
Remove the instance at path relative to self.
The
JSON
equivalent toremove()
, this method performs an in-place JSON Patchremove
operation on self.If path is empty, the value of self is set to None.
Experimental.
- Parameters:
path (str | JSONPointer)
- Return type:
None
- replace(path, obj)
Set obj at path relative to self.
The
JSON
equivalent toreplace()
, this method performs an in-place JSON Patchreplace
operation on self.If path is empty, the value of self is replaced by obj.
Experimental.
- Parameters:
path (str | JSONPointer)
obj (JSON | None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- test(path, obj)
Not yet implemented; experimental.
- Parameters:
path (str | JSONPointer)
obj (JSON | None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- data: None | bool | int | float | str | List[JSON] | Dict[str, JSON]
The instance data.
JSON type
data type
null
None
boolean
bool
number
int | float
string
str
array
list[JSON]
object
dict[str, JSON]
- key: str | None
The index of the instance within its parent.
- property path: JSONPointer
Return the path to the instance from the document root.
- type: str
The JSON type of the instance. One of
null
,boolean
,number
,string
,array
,object
.
- property value: None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
Return the instance data as a JSON-compatible Python object.
- jschon.json.JSONCompatible
Type hint for a JSON-compatible Python object.
alias of
None
|bool
|int
|float
|str
|Sequence
[Any
] |Mapping
[str
,Any
]
- jschon.json.false = False
Use to represent the JSON false value literally in Python code.
- jschon.json.null = None
Use to represent the JSON null value literally in Python code.
- jschon.json.true = True
Use to represent the JSON true value literally in Python code.
jschon.jsonpatch
- class jschon.jsonpatch.JSONPatch(*operations)
RFC 6902-conformant JSON Patch implementation.
- Parameters:
operations (Union[JSONPatchOperation, Mapping[str, JSONCompatible]])
- __delitem__(index)
Delete self[index].
- Parameters:
index (int)
- Return type:
None
- __eq__(other)
Return self == other.
- Parameters:
other (JSONPatch | Iterable[JSONPatchOperation | Mapping[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]]])
- Return type:
bool
- __getitem__(index: int) JSONPatchOperation
- __getitem__(index: slice) JSONPatch
Return self[index].
- __init__(*operations)
Initialize a
JSONPatch
instance from the given operations, each of which may be aJSONPatchOperation
or a JSON patch operation-conformant dictionary.- Parameters:
operations (JSONPatchOperation | Mapping[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]])
- Return type:
None
- __len__()
Return len(self).
- Return type:
int
- __repr__()
Return repr(self).
- Return type:
str
- __setitem__(index, operation)
Set self[index] to operation.
- Parameters:
index (int)
operation (JSONPatchOperation | Mapping[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]])
- Return type:
None
- aslist()
Return self as a list of operation dicts.
- Return type:
List[Dict[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]]]
- evaluate(document)
Return the result of sequentially applying all patch operations to document, as a new document. document itself is not modified.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- insert(index, operation)
Insert operation before index.
- Parameters:
index (int)
operation (JSONPatchOperation | Mapping[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]])
- Return type:
None
- class jschon.jsonpatch.JSONPatchOperation(*, op, path, value=None, from_=None, **kwargs)
RFC 6902-conformant JSON patch operation object.
- Parameters:
op (PatchOp)
path (Union[str, JSONPointer])
value (JSONCompatible)
from_ (Optional[Union[str, JSONPointer]])
kwargs (Union[str, JSONPointer])
- Return type:
- static __new__(cls, *, op, path, value=None, from_=None, **kwargs)
Create and return a new
JSONPatchOperation
instance.- Parameters:
op (PatchOp) – The operation to perform. One of
add
,remove
,replace
,move
,copy
,test
.path (str | JSONPointer) – A JSON pointer to the target location.
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]) – For
add
andreplace
operations, the value to set at the target location. Fortest
, the value to compare with the target.from – The location from which to
move
orcopy
. An alias for from, which may be passed via kwargs.from_ (str | JSONPointer | None)
kwargs (str | JSONPointer)
- Return type:
- __eq__(other)
Return self == other.
- Parameters:
other (JSONPatchOperation | Mapping[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]])
- Return type:
bool
- __repr__()
Return repr(self).
- Return type:
str
- apply(document)
Apply the patch operation to document and return the resultant document.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- asdict()
Return self as a dict.
- Return type:
Dict[str, None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]]
- class jschon.jsonpatch.PatchOp(*values)
- __new__(value)
- __repr__()
- Return type:
str
- ADD = 'add'
- COPY = 'copy'
- MOVE = 'move'
- REMOVE = 'remove'
- REPLACE = 'replace'
- TEST = 'test'
- jschon.jsonpatch.add(document, path, value)
Add value to document at path.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
path (JSONPointer)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- jschon.jsonpatch.copy(document, path, from_)
Copy the value at from_ in document to path.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
path (JSONPointer)
from_ (JSONPointer)
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- jschon.jsonpatch.move(document, path, from_)
Move the value at from_ in document to path.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
path (JSONPointer)
from_ (JSONPointer)
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- jschon.jsonpatch.remove(document, path)
Remove the value at path in document.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
path (JSONPointer)
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- jschon.jsonpatch.replace(document, path, value)
Replace the value at path in document with value.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
path (JSONPointer)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- jschon.jsonpatch.test(document, path, value)
Test whether the value at path in document is equal to value.
- Parameters:
document (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
path (JSONPointer)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
jschon.jsonpointer
- class jschon.jsonpointer.JSONPointer(*values)
RFC 6901-conformant JSON Pointer implementation.
A JSON pointer is a string representing a reference to some value within a JSON document. It consists of a series of reference tokens each prefixed by
"/"
, each token in turn being the (escaped) JSON object key or the JSON array index at the next node down the path to the referenced value. The empty string""
represents a reference to an entire JSON document.A
JSONPointer
instance is an immutable sequence of the unescaped JSON object keys [1] and/or array indices [2] that comprise the path to a referenced value within a JSON document.A
JSONPointer
instance is constructed by the concatenation of any number of arguments, each of which can be one of:a string conforming to the RFC 6901 syntax
an iterable of unescaped keys (which may itself be a
JSONPointer
instance)
Two
JSONPointer
instances compare equal if their key sequences are identical.The
/
operator provides a convenient syntax for extending a JSON pointer. It produces a newJSONPointer
instance by copying the left-hand argument (aJSONPointer
instance) and appending the right-hand argument (an unescaped key, or an iterable of unescaped keys).Taking an index into a
JSONPointer
returns the unescaped key at that position. Taking a slice into aJSONPointer
returns a newJSONPointer
composed of the specified slice of the original’s keys.- Parameters:
values (Union[str, Iterable[str]])
- Return type:
- malformed_exc
Exception raised when the input is not a valid JSON Pointer.
alias of
JSONPointerMalformedError
- reference_exc
Exception raised when the JSON Pointer cannot be resolved against a document.
alias of
JSONPointerReferenceError
- classmethod parse_uri_fragment(value)
Return a new
JSONPointer
constructed from the RFC 6901 string obtained by decoding value.value must exclude the initial
'#'
of the fragment; this allows for sensible interoperation withURI
objects.- Parameters:
value (str) – a percent-encoded URI fragment
- Return type:
- static __new__(cls, *values)
Create and return a new
JSONPointer
instance, constructed by the concatenation of the given values.- Parameters:
values (str | Iterable[str]) – each value may either be an RFC 6901 string, or an iterable of unescaped keys
- Raises:
JSONPointerMalformedError – if a string argument does not conform to the RFC 6901 syntax
- Return type:
- static escape(key)
Return the escaped form of a JSON object key / array index, suitable for use in an RFC 6901 JSON pointer string.
- Parameters:
key (str) – an unescaped key
- Return type:
str
- static unescape(token)
Return the unescaped form of a reference token appearing in an RFC 6901 JSON pointer string
- Parameters:
token (str) – an RFC 6901 reference token
- Return type:
str
- __eq__(other)
Return self == other.
- Parameters:
other (JSONPointer)
- Return type:
bool
- __getitem__(index: int) str
- __getitem__(index: slice) JSONPointer
Return self[index].
- __hash__()
Return hash(self).
- Return type:
int
- __le__(other)
Return self <= other.
Test whether self is a prefix of other, that is, self == other[:len(self)].
- Parameters:
other (JSONPointer)
- Return type:
bool
- __len__()
Return len(self).
- Return type:
int
- __lt__(other)
Return self < other.
Test whether self is a proper prefix of other, that is, self <= other and self != other.
- Parameters:
other (JSONPointer)
- Return type:
bool
- __repr__()
Return repr(self).
- Return type:
str
- __str__()
Return str(self).
- Return type:
str
- __truediv__(suffix: str) JSONPointer
- __truediv__(suffix: Iterable[str]) JSONPointer
Return self / suffix.
- evaluate(document)
Return the value within document at the location referenced by self.
document may be of any type, though if neither a
Mapping
nor aSequence
, evaluation by any non-emptyJSONPointer
will always fail.- Parameters:
document (Any) – any Python object
- Raises:
JSONPointerReferenceError – if self references a non-existent location in document
- Return type:
Any
- class jschon.jsonpointer.RelativeJSONPointer(value=None, /, *, up=0, over=0, ref=JSONPointer(''))
- Parameters:
value (str)
up (int)
over (int)
ref (Union[JSONPointer, Literal['#']])
- Return type:
- malformed_exc
Exception raised when the input is not a valid Relative JSON Pointer.
alias of
RelativeJSONPointerMalformedError
- reference_exc
Exception raised when the Relative JSON Pointer cannot be resolved against a document.
alias of
RelativeJSONPointerReferenceError
- static __new__(cls, value=None, /, *, up=0, over=0, ref=JSONPointer(''))
Create and return a new
RelativeJSONPointer
instance.- Parameters:
value (str) – a relative JSON pointer-conformant string; if value is given, keyword args are ignored
up (int) – the number of levels up from the current referenced JSON node from which to evaluate ref
over (int) – the integer value used to adjust the array index after applying up, which is only valid if that location is an array item; a value of 0, which is not allowed by the grammar, is treated as if there is no adjustment.
ref (JSONPointer | Literal['#']) – a
JSONPointer
instance, or the literal'#'
- Raises:
RelativeJSONPointerMalformedError – for any invalid arguments
- Return type:
- __eq__(other)
Return self == other.
- Parameters:
other (RelativeJSONPointer)
- Return type:
bool
- __hash__()
Return hash(self).
- Return type:
int
- __repr__()
Return repr(self).
- Return type:
str
- __str__()
Return str(self).
- Return type:
str
- evaluate(document)
Return the value within document at the location referenced by self.
document must be an instance of
JSON
, as evaluation relies on parent and sibling links provided by that class.- Parameters:
document (JSON) – a
JSON
instance representing the document- Raises:
RelativeJSONPointerReferenceError – if self references a non-existent location in document
- Return type:
Union[int, str, JSON]
jschon.jsonschema
- class jschon.jsonschema.JSONSchema(value, *, catalog='catalog', cacheid='default', uri=None, metaschema_uri=None, parent=None, key=None)
JSON schema document model.
- Parameters:
- __init__(value, *, catalog='catalog', cacheid='default', uri=None, metaschema_uri=None, parent=None, key=None)
Initialize a
JSONSchema
instance from the given schema-compatible value.- Parameters:
value (Union[bool, Mapping[str, JSONCompatible]]) – a schema-compatible Python object
catalog (Union[str, Catalog]) – catalog instance or catalog name
cacheid (Hashable) – schema cache identifier
uri (URI) – the URI identifying the schema; an
"$id"
keyword appearing in value will override thismetaschema_uri (URI) – the URI identifying the schema’s metaschema; a
"$schema"
keyword appearing in value will override thisparent (JSON) – the parent node of the schema; used internally when creating a subschema
key (str) – the index of the schema within its parent; used internally when creating a subschema
- evaluate(instance, result=None)
Evaluate a JSON document and return the evaluation result.
- property base_uri: URI | None
The schema’s base
URI
.The base URI is obtained by searching up the schema tree for a schema URI, and removing any fragment.
- cacheid: Hashable
Schema cache identifier.
- property canonical_uri: URI | None
The absolute location of the (sub)schema.
This is not necessarily an ‘absolute URI’, as it may contain a fragment.
- data: bool | Dict[str, JSON]
The schema data.
JSON type
data type
boolean
bool
object
dict[str, JSON]
- property document_rootschema: JSONSchema
The
JSONSchema
at the root of the entire document.If no ancestor schemas contain
"$id"
, this is the same as self.resource_rootschema. If this schema has no self.parentschema, this method returns self.
- key: str | None
The index of the schema within its parent.
- keywords: Dict[str, Keyword]
A dictionary of the schema’s
Keyword
objects, indexed by keyword name.
- property metaschema: Metaschema
The schema’s
Metaschema
.
- property metaschema_uri: URI | None
The
URI
identifying the schema’s metaschema.If not defined on this (sub)schema, the metaschema URI is determined by the parent schema.
- parent: JSON | None
The containing
JSON
orJSONSchema
node.
- property parentschema: JSONSchema | None
The containing
JSONSchema
instance.Note that this is not necessarily the same as self.parent.
- property resource_rootschema: JSONSchema
The
JSONSchema
at the root of the containing resource.This is the nearest ancestor (including self) containing
"$id"
, or if none exist, it is the same as self.document_rootschema.
- type: str
The JSON type of the schema. One of
"boolean"
,"object"
.
- class jschon.jsonschema.Result(schema, instance, *, parent=None, key=None)
The result of evaluating a JSON document node against a JSON schema node.
The root of a
Result
tree represents a complete document evaluation result.- Parameters:
schema (JSONSchema)
instance (JSON)
parent (Result)
key (str)
- __call__(instance, key, schema=None, *, cls=None)
Yield a subresult for the evaluation of instance. Descend down the evaluation path by key, into schema if given, or within self.schema otherwise.
Extension keywords may provide a custom
Result
class via cls, which is applied to all nodes within the yielded subtree.- Parameters:
instance (JSON)
key (str)
schema (JSONSchema)
cls (Type[Result])
- Return type:
ContextManager[Result, bool | None]
- __init__(schema, instance, *, parent=None, key=None)
- Parameters:
schema (JSONSchema)
instance (JSON)
parent (Result)
key (str)
- Return type:
None
- annotate(value)
Annotate the result.
- Parameters:
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- collect_annotations(instance=None, key=None)
Return an iterator over annotations produced in this subtree, optionally filtered by instance and/or keyword.
- Parameters:
instance (JSON)
key (str)
- Return type:
Iterator[None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]]
- collect_errors(instance=None, key=None)
Return an iterator over errors produced in this subtree, optionally filtered by instance and/or keyword.
- Parameters:
instance (JSON)
key (str)
- Return type:
Iterator[None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]]
- discard()
Indicate that the result should be ignored and discarded.
- Return type:
None
- fail(error=None)
Mark the result as invalid, optionally with an error.
- Parameters:
error (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
None
- noassert()
Indicate that evaluation passes regardless of validity.
- Return type:
None
- output(format, **kwargs)
Return the evaluation result in the specified format.
- Parameters:
format (str) – One of the standard JSON Schema output formats –
flag
,basic
,detailed
orverbose
– or any format registered with theoutput_formatter()
decorator.kwargs (Any) – Keyword arguments to pass to the output formatter.
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- pass_()
Mark the result as valid.
A result is initially valid, so this should only need to be called by a keyword when it must reverse a failure.
- Return type:
None
- refschema(schema)
Set the referenced schema for a by-reference keyword.
This ensures that
absolute_uri
returns the URI of the referenced schema rather than the referencing keyword.- Parameters:
schema (JSONSchema)
- Return type:
None
- sibling(instance, key)
Return a sibling schema node’s evaluation result for instance.
- annotation: None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
The annotation value of the result.
- children: Dict[Tuple[str, JSONPointer], Result]
Subresults of the current result node, indexed by schema key and instance path.
- error: None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
The error value of the result.
- property globals: Dict
- key: str | None
The index of the current schema node within its dynamic parent.
- property passed: bool
Return the assertion result for the schema node.
In the standard JSON Schema vocabulary, this can only differ from
valid
for theif
keyword: validity may be false (triggeringelse
) while its assertion result is always true.
- path: JSONPointer
The dynamic evaluation path to the current schema node.
- relpath: JSONPointer
The path to the current schema node relative to the evaluating (sub)schema.
- schema: JSONSchema
The evaluating (sub)schema.
- property valid: bool
Return the validity of the instance against the schema.
jschon.output
- jschon.output.create_output(result, format, **kwargs)
- Parameters:
result (Result)
format (str)
kwargs (Any)
- Return type:
None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]
- jschon.output.output_formatter(format)
A decorator for a JSON Schema output formatting function.
- Parameters:
format (str) – A string identifying the output format.
- jschon.output.OutputFormatter
Call signature for a function decorated with
output_formatter()
.The function must take a
Result
object as its first argument.alias of
Callable
[[…],None
|bool
|int
|float
|str
|Sequence
[Any
] |Mapping
[str
,Any
]]
jschon.uri
- class jschon.uri.URI(value)
- Parameters:
value (str)
- __init__(value)
- Parameters:
value (str)
- Return type:
None
- copy(scheme=True, authority=True, path=True, query=True, fragment=True)
Produce a new URI composed of the specified components of self.
True => use existing
False/None => remove
Otherwise => replace
- Return type:
- has_absolute_base()
- Return type:
bool
- is_absolute()
- Return type:
bool
- resolve(base_uri)
Produce a new URI by resolving self against the given base URI.
- validate(require_scheme=False, require_normalized=False, allow_fragment=True, allow_non_empty_fragment=True)
Validate self.
- Raises:
URIError – if self fails validation
- Parameters:
require_scheme (bool)
require_normalized (bool)
allow_fragment (bool)
allow_non_empty_fragment (bool)
- Return type:
None
- property authority: str
- property fragment: str
- property path: str
- property query: str
- property scheme: str
jschon.utils
- jschon.utils.json_dumpf(obj, path)
Serialize a JSON-compatible Python object to a JSON file.
- Parameters:
obj (Any)
path (str | PathLike)
- Return type:
None
- jschon.utils.json_dumps(obj)
Serialize a JSON-compatible Python object to a JSON string.
- Parameters:
obj (Any)
- Return type:
str
- jschon.utils.json_loadf(path)
Deserialize a JSON file, returning a JSON-compatible Python object.
- Parameters:
path (str | PathLike)
- Return type:
Any
- jschon.utils.json_loadr(url)
Fetch and deserialize a remote JSON resource, returning a JSON-compatible Python object.
- Parameters:
url (str)
- Return type:
Any
- jschon.utils.json_loads(value)
Deserialize a JSON string, returning a JSON-compatible Python object.
- Parameters:
value (str)
- Return type:
Any
- jschon.utils.tuplify(value)
- Parameters:
value (Any)
- Return type:
Tuple
jschon.vocabulary
- class jschon.vocabulary.ArrayOfSubschemas
A
Keyword
class mixin that sets up an array of subschemas for a keyword.- classmethod jsonify(parentschema, key, value)
- Parameters:
parentschema (JSONSchema)
key (str)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
JSON | None
- class jschon.vocabulary.Keyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- depends_on: Tuple[str, ...] = ()
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('null', 'boolean', 'number', 'string', 'array', 'object')
The types of instance that the keyword can evaluate.
- key: str = Ellipsis
The keyword name as it appears in a schema object.
- static: bool = False
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.Metaschema(catalog, value, default_core_vocabulary=None, *default_vocabularies, **kwargs)
A metaschema declares the set of vocabularies that are available to any schema which references it, and provides any such schema with its
Keyword
classes.Metaschema
is itself a subclass ofJSONSchema
, and may be used to validate any referencing schema.- Parameters:
catalog (Catalog)
value (Mapping[str, JSONCompatible])
default_core_vocabulary (Vocabulary)
default_vocabularies (Vocabulary)
kwargs (Any)
- __init__(catalog, value, default_core_vocabulary=None, *default_vocabularies, **kwargs)
Initialize a
Metaschema
instance from the given schema-compatible value.- Parameters:
catalog (Catalog) – catalog instance
value (Mapping[str, JSONCompatible]) – a schema-compatible Python object
default_core_vocabulary (Vocabulary) – the metaschema’s core
Vocabulary
, used in the absence of a"$vocabulary"
keyword in the metaschema JSON file, or if a known core vocabulary is not present under"$vocabulary"
default_vocabulary – default
Vocabulary
instances, used in the absence of a"$vocabulary"
keyword in the metaschema JSON filekwargs (Any) – additional keyword arguments to pass through to the
JSONSchema
constructordefault_vocabularies (Vocabulary)
- Raises:
JSONSchemaError – if no core vocabulary can be determined
CatalogError – if the created metaschema is not valid
- get_kwclass(key)
Return the
Keyword
class this metaschema uses for the given key. If the key is not recognized, a subclass of an internalKeyword
subclass that treats the keyword as a simple annotation is automatically created, associated with the key, and returned.- Parameters:
key (str)
- Return type:
Type[Keyword]
- class jschon.vocabulary.ObjectOfSubschemas
A
Keyword
class mixin that sets up property-based subschemas for a keyword.- classmethod jsonify(parentschema, key, value)
- Parameters:
parentschema (JSONSchema)
key (str)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
JSON | None
- class jschon.vocabulary.Subschema
A
Keyword
class mixin that sets up a subschema for a keyword.- classmethod jsonify(parentschema, key, value)
- Parameters:
parentschema (JSONSchema)
key (str)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
JSON | None
- class jschon.vocabulary.SubschemaMixin
- classmethod jsonify(parentschema, key, value)
- Parameters:
parentschema (JSONSchema)
key (str)
value (None | bool | int | float | str | Sequence[Any] | Mapping[str, Any])
- Return type:
JSON | None
- class jschon.vocabulary.Vocabulary(uri, *kwclasses)
A vocabulary declares a set of keywords that may be used in the evaluation of JSON documents, and provides a runtime implementation (in the form of a
Keyword
class) for each of those keywords.- Parameters:
uri (URI)
kwclasses (KeywordClass)
jschon.vocabulary.annotation
- class jschon.vocabulary.annotation.ContentEncodingKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('string',)
The types of instance that the keyword can evaluate.
- key: str = 'contentEncoding'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.ContentMediaTypeKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('string',)
The types of instance that the keyword can evaluate.
- key: str = 'contentMediaType'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.ContentSchemaKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('contentMediaType',)
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('string',)
The types of instance that the keyword can evaluate.
- key: str = 'contentSchema'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.DefaultKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'default'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.DeprecatedKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'deprecated'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.DescriptionKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'description'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.ExamplesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'examples'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.ReadOnlyKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'readOnly'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.TitleKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'title'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.annotation.WriteOnlyKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'writeOnly'
The keyword name as it appears in a schema object.
jschon.vocabulary.applicator
- class jschon.vocabulary.applicator.AdditionalPropertiesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('properties', 'patternProperties')
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'additionalProperties'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.AllOfKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'allOf'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.AnyOfKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'anyOf'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.ContainsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'contains'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.DependentSchemasKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'dependentSchemas'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.ElseKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('if',)
Keywords that must be evaluated before this keyword can be evaluated.
- key: str = 'else'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.IfKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'if'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.ItemsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('prefixItems',)
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'items'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.NotKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'not'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.OneOfKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'oneOf'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.PatternPropertiesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'patternProperties'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.PrefixItemsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'prefixItems'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.PropertiesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'properties'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.PropertyNamesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'propertyNames'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.ThenKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('if',)
Keywords that must be evaluated before this keyword can be evaluated.
- key: str = 'then'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.UnevaluatedItemsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('prefixItems', 'items', 'contains', 'if', 'then', 'else', 'allOf', 'anyOf', 'oneOf', 'not')
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'unevaluatedItems'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.applicator.UnevaluatedPropertiesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('properties', 'patternProperties', 'additionalProperties', 'if', 'then', 'else', 'dependentSchemas', 'allOf', 'anyOf', 'oneOf', 'not')
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'unevaluatedProperties'
The keyword name as it appears in a schema object.
jschon.vocabulary.core
- class jschon.vocabulary.core.AnchorKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- key: str = '$anchor'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.core.CommentKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = '$comment'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.core.DefsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = '$defs'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.core.DynamicAnchorKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- key: str = '$dynamicAnchor'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.core.DynamicRefKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- resolve()
- Return type:
None
- key: str = '$dynamicRef'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.core.IdKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- key: str = '$id'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.core.RefKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- resolve()
- Return type:
None
- key: str = '$ref'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.core.SchemaKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- key: str = '$schema'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.core.VocabularyKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (Mapping[str, bool])
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (Mapping[str, bool])
- key: str = '$vocabulary'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
jschon.vocabulary.format
- class jschon.vocabulary.format.FormatKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- key: str = 'format'
The keyword name as it appears in a schema object.
- jschon.vocabulary.format.format_validator(format_attr, *, instance_types=('string',))
A decorator for a format validation function.
The decorator only registers a function as a format validator. Assertion behaviour must be enabled in a catalog using
enable_formats()
.- Parameters:
format_attr (str) – The format attribute that the decorated function validates.
instance_types (Tuple[str, ...]) – The set of instance types validated by this format.
- jschon.vocabulary.format.FormatValidator
Call signature for a function decorated with
format_validator()
.The function validates a JSON-compatible Python object (typically, a string) and raises a
ValueError
if the object is invalid per the applicable format specification.alias of
Callable
[[None
|bool
|int
|float
|str
|Sequence
[Any
] |Mapping
[str
,Any
]],None
]
jschon.vocabulary.legacy
- class jschon.vocabulary.legacy.AdditionalItemsKeyword_2019_09(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('items',)
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'additionalItems'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.legacy.ItemsKeyword_2019_09(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'items'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.legacy.RecursiveAnchorKeyword_2019_09(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = '$recursiveAnchor'
The keyword name as it appears in a schema object.
- static: bool = True
static = True (equivalent to instance_types = ()) indicates that the keyword does not ever evaluate any instance.
- class jschon.vocabulary.legacy.RecursiveRefKeyword_2019_09(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- resolve()
- Return type:
None
- key: str = '$recursiveRef'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.legacy.UnevaluatedItemsKeyword_2019_09(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('items', 'additionalItems', 'if', 'then', 'else', 'allOf', 'anyOf', 'oneOf', 'not')
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'unevaluatedItems'
The keyword name as it appears in a schema object.
jschon.vocabulary.validation
- class jschon.vocabulary.validation.ConstKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'const'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.DependentRequiredKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'dependentRequired'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.EnumKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'enum'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.ExclusiveMaximumKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('number',)
The types of instance that the keyword can evaluate.
- key: str = 'exclusiveMaximum'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.ExclusiveMinimumKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('number',)
The types of instance that the keyword can evaluate.
- key: str = 'exclusiveMinimum'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MaxContainsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('contains',)
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'maxContains'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MaxItemsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'maxItems'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MaxLengthKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('string',)
The types of instance that the keyword can evaluate.
- key: str = 'maxLength'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MaxPropertiesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'maxProperties'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MaximumKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('number',)
The types of instance that the keyword can evaluate.
- key: str = 'maximum'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MinContainsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- depends_on: Tuple[str, ...] = ('contains', 'maxContains')
Keywords that must be evaluated before this keyword can be evaluated.
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'minContains'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MinItemsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'minItems'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MinLengthKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('string',)
The types of instance that the keyword can evaluate.
- key: str = 'minLength'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MinPropertiesKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'minProperties'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MinimumKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('number',)
The types of instance that the keyword can evaluate.
- key: str = 'minimum'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.MultipleOfKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('number',)
The types of instance that the keyword can evaluate.
- key: str = 'multipleOf'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.PatternKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- __init__(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (str)
- instance_types: Tuple[str, ...] = ('string',)
The types of instance that the keyword can evaluate.
- key: str = 'pattern'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.RequiredKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('object',)
The types of instance that the keyword can evaluate.
- key: str = 'required'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.TypeKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- key: str = 'type'
The keyword name as it appears in a schema object.
- class jschon.vocabulary.validation.UniqueItemsKeyword(parentschema, value)
- Parameters:
parentschema (JSONSchema)
value (JSONCompatible)
- instance_types: Tuple[str, ...] = ('array',)
The types of instance that the keyword can evaluate.
- key: str = 'uniqueItems'
The keyword name as it appears in a schema object.
Examples
Extending JSON Schema
In this example, we define a custom keyword – "enumRef"
– that provides
us with the capability to validate JSON string instances against enumerations
(which may consist of many thousands of terms) that we have obtained and cached
from remote terminology services.
First, we create a vocabulary that describes the syntax of our new keyword.
This is a JSON meta-schema that we’ll save to data/enumRef-vocabulary.json
:
{
"title": "A meta-schema describing the syntax of a vocabulary that supports remote enumerations",
"$id": "https://example.com/enumRef/enumRef-vocabulary",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": {
"https://example.com/enumRef": true
},
"$dynamicAnchor": "meta",
"type": ["object", "boolean"],
"properties": {
"enumRef": {
"type": "string",
"format": "uri-reference"
}
}
}
Next, we create an extension to the JSON Schema 2020-12 meta-schema that
includes our new vocabulary. We’ll save this to data/enumRef-metaschema.json
:
{
"title": "An extension to the JSON Schema 2020-12 meta-schema, incorporating a vocabulary that supports remote enumerations",
"$id": "https://example.com/enumRef/enumRef-metaschema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": {
"https://json-schema.org/draft/2020-12/vocab/core": true,
"https://json-schema.org/draft/2020-12/vocab/applicator": true,
"https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
"https://json-schema.org/draft/2020-12/vocab/validation": true,
"https://json-schema.org/draft/2020-12/vocab/meta-data": true,
"https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
"https://json-schema.org/draft/2020-12/vocab/content": true,
"https://example.com/enumRef": true
},
"$dynamicAnchor": "meta",
"type": ["object", "boolean"],
"allOf": [
{"$ref": "https://json-schema.org/draft/2020-12/meta/core"},
{"$ref": "https://json-schema.org/draft/2020-12/meta/applicator"},
{"$ref": "https://json-schema.org/draft/2020-12/meta/unevaluated"},
{"$ref": "https://json-schema.org/draft/2020-12/meta/validation"},
{"$ref": "https://json-schema.org/draft/2020-12/meta/meta-data"},
{"$ref": "https://json-schema.org/draft/2020-12/meta/format-annotation"},
{"$ref": "https://json-schema.org/draft/2020-12/meta/content"},
{"$ref": "https://example.com/enumRef/enumRef-vocabulary"}
]
}
Finally, we implement the "enumRef"
keyword by defining an
EnumRefKeyword
class. The following script includes an example
implementation using a simple local cache, a few lines of boilerplate code
to compile the meta-schema and vocabulary definition files, and an example
schema that we use to evaluate both valid and invalid sample JSON instances:
import pathlib
import pprint
from jschon import create_catalog, URI, JSON, JSONSchema, JSONSchemaError, LocalSource
from jschon.jsonschema import Result
from jschon.vocabulary import Keyword
data_dir = pathlib.Path(__file__).parent / 'data'
# cache of enumeration values obtained from remote terminology services
remote_enum_cache = {
"https://example.com/remote-enum-colours": [
"red",
"orange",
"yellow",
"green",
"blue",
"indigo",
"violet",
]
}
# define a class that implements the "enumRef" keyword
class EnumRefKeyword(Keyword):
key = "enumRef"
# ignore non-string instances
instance_types = "string",
def __init__(self, parentschema: JSONSchema, value: str):
super().__init__(parentschema, value)
# raise an exception during schema construction if a reference is invalid
if value not in remote_enum_cache:
raise JSONSchemaError(f"Unknown remote enumeration {value}")
def evaluate(self, instance: JSON, result: Result) -> None:
# the keyword's value is a reference to a remote enumeration
enum_ref = self.json.value
# evaluate the current JSON instance node against the enumeration
if instance.data in remote_enum_cache.get(enum_ref):
# (optionally) on success, annotate the result
result.annotate(enum_ref)
else:
# on failure, mark the result as failed, with an (optional) error message
result.fail(f"The instance is not a member of the {enum_ref} enumeration")
# initialize the catalog, with JSON Schema 2020-12 vocabulary support
catalog = create_catalog('2020-12')
# add a local source for loading the enumRef meta-schema and vocabulary
# definition files
catalog.add_uri_source(
URI("https://example.com/enumRef/"),
LocalSource(data_dir, suffix='.json'),
)
# implement the enumRef vocabulary using the EnumRefKeyword class
catalog.create_vocabulary(
URI("https://example.com/enumRef"),
EnumRefKeyword,
)
# create a schema for validating that a string is a member of a remote enumeration
schema = JSONSchema({
"$schema": "https://example.com/enumRef/enumRef-metaschema",
"$id": "https://example.com/remote-enum-test-schema",
"type": "string",
"enumRef": "https://example.com/remote-enum-colours",
})
# validate the schema against its meta-schema
schema_validity = schema.validate()
print(f'Schema validity check: {schema_validity.valid}')
# declare a valid JSON instance
valid_json = JSON("green")
# declare an invalid JSON instance
invalid_json = JSON("purple")
# evaluate the valid instance
valid_result = schema.evaluate(valid_json)
# evaluate the invalid instance
invalid_result = schema.evaluate(invalid_json)
# print output for the valid case
print(f'Valid JSON result: {valid_result.valid}')
print('Valid JSON detailed output:')
pprint.pp(valid_result.output('detailed'))
# print output for the invalid case
print(f'Invalid JSON result: {invalid_result.valid}')
print('Invalid JSON detailed output:')
pprint.pp(invalid_result.output('detailed'))
The script produces the following output:
Schema validity check: True
Valid JSON result: True
Valid JSON detailed output:
{'valid': True,
'instanceLocation': '',
'keywordLocation': '',
'absoluteKeywordLocation': 'https://example.com/remote-enum-test-schema#',
'annotations': [{'instanceLocation': '',
'keywordLocation': '/type',
'absoluteKeywordLocation': 'https://example.com/remote-enum-test-schema#/type'},
{'instanceLocation': '',
'keywordLocation': '/enumRef',
'absoluteKeywordLocation': 'https://example.com/remote-enum-test-schema#/enumRef',
'annotation': 'https://example.com/remote-enum-colours'}]}
Invalid JSON result: False
Invalid JSON detailed output:
{'valid': False,
'instanceLocation': '',
'keywordLocation': '',
'absoluteKeywordLocation': 'https://example.com/remote-enum-test-schema#',
'errors': [{'instanceLocation': '',
'keywordLocation': '/enumRef',
'absoluteKeywordLocation': 'https://example.com/remote-enum-test-schema#/enumRef',
'error': 'The instance is not a member of the '
'https://example.com/remote-enum-colours enumeration'}]}
File-based schemas
Suppose that we’ve created several JSON schema files that we’d like to use
to validate organization data. For this example, our schemas and our data are
stored in a data
directory, relative to the location of the Python scripts
that follow.
The primary schema is an org schema, stored in data/org-schema.json
:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/org-schema",
"type": "object",
"properties": {
"people": {
"type": "array",
"items": {
"$ref": "https://example.com/person-schema"
}
}
}
}
The org schema references a person schema, stored in data/person-schema.json
:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/person-schema",
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
We’re going to use the org schema to validate our org data, which can be
found in data/org-data.json
:
{
"people": [
{"name": "Alice"},
{"name": "Bob"}
]
}
There are several different ways to ensure that all our schemas are loaded and available as needed.
The first way is to load all of our schemas up front. In this case, when
the "$ref"
keyword is encountered in the org schema, the target (person)
schema is found already cached in the catalog.
import pathlib
from jschon import create_catalog, JSON, JSONSchema
data_dir = pathlib.Path(__file__).parent / 'data'
catalog = create_catalog('2020-12')
person_schema = JSONSchema.loadf(data_dir / 'person-schema.json')
org_schema = JSONSchema.loadf(data_dir / 'org-schema.json')
org_data = JSON.loadf(data_dir / 'org-data.json')
result = org_schema.evaluate(org_data)
print(result.output('flag'))
Note that, when using this approach, the schemas must be loaded in
"$ref"
dependency order.
Another way is to set up a base URI-to-directory mapping on the catalog.
In this case, when the "$ref"
keyword is encountered in the org schema,
the catalog knows where to find the person schema on disk, and loads it on
the fly.
import pathlib
from jschon import create_catalog, JSON, JSONSchema, URI, LocalSource
data_dir = pathlib.Path(__file__).parent / 'data'
catalog = create_catalog('2020-12')
catalog.add_uri_source(URI('https://example.com/'), LocalSource(data_dir, suffix='.json'))
org_schema = JSONSchema.loadf(data_dir / 'org-schema.json')
org_data = JSON.loadf(data_dir / 'org-data.json')
result = org_schema.evaluate(org_data)
print(result.output('flag'))
Finally, yet another way is again to set up a base URI-to-directory mapping on the catalog, but this time we retrieve our primary schema from the catalog rather than loading it explicitly.
import pathlib
from jschon import create_catalog, JSON, URI, LocalSource
data_dir = pathlib.Path(__file__).parent / 'data'
catalog = create_catalog('2020-12')
catalog.add_uri_source(URI('https://example.com/'), LocalSource(data_dir, suffix='.json'))
org_schema = catalog.get_schema(URI('https://example.com/org-schema'))
org_data = JSON.loadf(data_dir / 'org-data.json')
result = org_schema.evaluate(org_data)
print(result.output('flag'))
This last approach is well-suited to schema re-use, in which JSON document evaluations are done independently with knowledge only of a schema’s URI. The schema is loaded and compiled the first time it is retrieved; thereafter, it is simply read from the cache.
Format validation
In this example we register and enable validators for the ipv4
and ipv6
formats.
import ipaddress
import pprint
from jschon import JSON, JSONSchema, create_catalog
from jschon.vocabulary.format import format_validator
# register an 'ipv4' format validator
@format_validator('ipv4')
def validate_ipv4(value: str) -> None:
if isinstance(value, str):
ipaddress.IPv4Address(value) # raises ValueError for an invalid IPv4 address
# register an 'ipv6' format validator
@format_validator('ipv6')
def validate_ipv6(value: str) -> None:
if isinstance(value, str):
ipaddress.IPv6Address(value) # raises ValueError for an invalid IPv6 address
# initialize the catalog, with JSON Schema 2020-12 vocabulary support
catalog = create_catalog('2020-12')
# enable validation with the 'ipv4' and 'ipv6' format validators
catalog.enable_formats('ipv4', 'ipv6')
# create a schema for validating an array of IP addresses
schema = JSONSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schema",
"type": "array",
"items": {
"type": "string",
"anyOf": [
{"format": "ipv4"},
{"format": "ipv6"}
]
}
})
# evaluate a valid array
valid_result = schema.evaluate(JSON(['127.0.0.1', '::1']))
# evaluate an invalid array
invalid_result = schema.evaluate(JSON(['127.0.1', '::1']))
# print output for the valid case
print('Valid case output:')
pprint.pp(valid_result.output('basic'))
# print output for the invalid case
print('Invalid case output:')
pprint.pp(invalid_result.output('basic'))
The script produces the following output:
Valid case output:
{'valid': True,
'annotations': [{'instanceLocation': '',
'keywordLocation': '/items',
'absoluteKeywordLocation': 'https://example.com/schema#/items',
'annotation': True},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf/0/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/0/format',
'annotation': 'ipv4'},
{'instanceLocation': '/1',
'keywordLocation': '/items/anyOf/1/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/1/format',
'annotation': 'ipv6'}]}
Invalid case output:
{'valid': False,
'errors': [{'instanceLocation': '',
'keywordLocation': '/items',
'absoluteKeywordLocation': 'https://example.com/schema#/items',
'error': [0]},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf',
'error': 'The instance must be valid against at least one '
'subschema'},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf/0/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/0/format',
'error': 'The instance is invalid against the "ipv4" format: '
"Expected 4 octets in '127.0.1'"},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf/1/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/1/format',
'error': 'The instance is invalid against the "ipv6" format: At '
"least 3 parts expected in '127.0.1'"}]}
Recursive schema extension
The following script implements the recursive schema extension example, described in the JSON Schema 2020-12 core specification.
import pprint
from jschon import create_catalog, JSON, JSONSchema
# create a catalog with support for JSON Schema version 2020-12
create_catalog('2020-12')
# define an extensible tree schema
tree_schema = JSONSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/tree",
"$dynamicAnchor": "node",
"type": "object",
"properties": {
"data": True,
"children": {
"type": "array",
"items": {
"$dynamicRef": "#node"
}
}
}
})
# define a strict-tree schema, which guards against misspelled properties
strict_tree_schema = JSONSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/strict-tree",
"$dynamicAnchor": "node",
"$ref": "tree",
"unevaluatedProperties": False
})
# declare a JSON instance with a misspelled field
tree_json = JSON({
"children": [{"daat": 1}]
})
# evaluate the JSON instance with the tree schema
tree_result = tree_schema.evaluate(tree_json)
# evaluate the JSON instance with the strict-tree schema
strict_tree_result = strict_tree_schema.evaluate(tree_json)
# print output for the tree case
print('Tree schema verbose output:')
pprint.pp(tree_result.output('verbose'))
# print output for the strict-tree case
print('Strict tree schema verbose output:')
pprint.pp(strict_tree_result.output('verbose'))
The script produces the output shown below. The 'verbose'
output
format reflects the complete dynamic evaluation path through a schema
and any referenced schemas.
Tree schema verbose output:
{'valid': True,
'instanceLocation': '',
'keywordLocation': '',
'absoluteKeywordLocation': 'https://example.com/tree#',
'annotations': [{'valid': True,
'instanceLocation': '',
'keywordLocation': '/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': True,
'instanceLocation': '',
'keywordLocation': '/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'annotation': ['children'],
'annotations': [{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/properties/children',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children',
'annotations': [{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/properties/children/type',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/type'},
{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/properties/children/items',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/items',
'annotation': True,
'annotations': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/properties/children/items/$dynamicRef',
'absoluteKeywordLocation': 'https://example.com/tree',
'annotations': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/properties/children/items/$dynamicRef/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/properties/children/items/$dynamicRef/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'annotation': []}]}]}]}]}]}
Strict tree schema verbose output:
{'valid': False,
'instanceLocation': '',
'keywordLocation': '',
'absoluteKeywordLocation': 'https://example.com/strict-tree#',
'errors': [{'valid': False,
'instanceLocation': '',
'keywordLocation': '/$ref',
'absoluteKeywordLocation': 'https://example.com/tree',
'errors': [{'valid': True,
'instanceLocation': '',
'keywordLocation': '/$ref/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': False,
'instanceLocation': '',
'keywordLocation': '/$ref/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'error': "Properties ['children'] are invalid",
'errors': [{'valid': False,
'instanceLocation': '/children',
'keywordLocation': '/$ref/properties/children',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children',
'errors': [{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/$ref/properties/children/type',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/type'},
{'valid': False,
'instanceLocation': '/children',
'keywordLocation': '/$ref/properties/children/items',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/items',
'error': [0],
'errors': [{'valid': False,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef',
'absoluteKeywordLocation': 'https://example.com/strict-tree',
'errors': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/$ref',
'absoluteKeywordLocation': 'https://example.com/tree',
'annotations': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/$ref/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/$ref/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'annotation': []}]},
{'valid': False,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/unevaluatedProperties',
'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
'error': ['daat']}]}]}]}]}]},
{'valid': False,
'instanceLocation': '',
'keywordLocation': '/unevaluatedProperties',
'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
'error': ['children']}]}
Tutorial
JSON
The JSON
class is an implementation of the JSON data model.
It is used to represent a JSON document that may be evaluated by a JSON schema.
The JSONSchema
class is itself a subclass of
JSON
.
A JSON
instance may be constructed from any JSON-compatible
Python object. Let’s take a look at a few simple examples, printing the JSON type
of each. We begin by importing the JSON
class:
>>> from jschon import JSON
>>> JSON("Hello, World!").type
'string'
>>> JSON(3.14159).type
'number'
>>> JSON(None).type
'null'
>>> JSON(("a", "b", "c")).type
'array'
Instances with the JSON types "array"
and "object"
are constructed
recursively. Here we create an array and an object:
>>> arr = JSON([1, 2, 3])
>>> obj = JSON({"foo": True, "bar": False})
Nested JSON
instances may be accessed using square-bracket
notation:
>>> arr[1]
JSON(2)
>>> obj["foo"]
JSON(True)
JSON
implements the Sequence
and Mapping
interfaces for instances with the JSON types "array"
and "object"
, respectively:
>>> [item for item in arr]
[JSON(1), JSON(2), JSON(3)]
>>> {key: val for key, val in obj.items()}
{'foo': JSON(True), 'bar': JSON(False)}
JSON
instances have several attributes, in addition to the
type
attribute seen above. These can be useful when
working with complex JSON structures. Consider the following example:
>>> document = JSON({
... "1a": {
... "2a": "foo",
... "2b": "bar"
... },
... "1b": [
... {"3a": "baz"},
... {"3b": "quux"}
... ]
... })
A leaf node’s data
attribute holds the value from which
it was constructed:
>>> document["1a"]["2a"].data
'foo'
The path
property returns a JSONPointer
instance representing the path to the node from the document root:
>>> document["1b"][0]["3a"].path
JSONPointer('/1b/0/3a')
The parent
attribute gives the containing instance:
>>> document["1a"]["2b"].parent
JSON({'2a': 'foo', '2b': 'bar'})
The key
is the index of the node within its parent:
>>> document["1b"][1]["3b"].key
'3b'
Notice that, although an array item’s sequential index is an integer, its
key
is a string. This makes it interoperable with
JSONPointer
:
>>> document["1b"][1].key
'1'
An "object"
node’s data
is a dict[str, JSON]
:
>>> document["1a"].data
{'2a': JSON('foo'), '2b': JSON('bar')}
An "array"
node’s data
is a list[JSON]
:
>>> document["1b"].data
[JSON({'3a': 'baz'}), JSON({'3b': 'quux'})]
The value
property returns the instance data as a
JSON-compatible Python object:
>>> document["1b"].value
[{'3a': 'baz'}, {'3b': 'quux'}]
Equality testing strictly follows the JSON data model. So, whereas the following two Python lists compare equal:
>>> [False, True] == [0, 1]
True
The JSON
equivalents are not equal, because the arrays’
items have different JSON types:
>>> JSON([False, True]) == JSON([0, 1])
False
A JSON
instance may be compared with any Python object.
Internally, the non-JSON
object is coerced to its JSON
equivalent before performing the comparison. Notice that tuples and lists are
considered structurally equivalent:
>>> (7, 11) == JSON([7, 11])
True
JSON
also implements the <
, <=
, >=
and >
inequality operators, which may be used for numeric or string comparisons:
>>> JSON(3) < 3.01
True
jschon is not a JSON encoder/decoder. However, the JSON
class supports both serialization and deserialization of JSON documents, via the
Python standard library’s json
module.
Serializing a JSON
instance is simply a matter of getting
its string representation:
>>> str(JSON({"xyz": (None, False, True)}))
'{"xyz": [null, false, true]}'
JSON
instances can be deserialized from JSON files and JSON
strings using the loadf()
and loads()
class methods, respectively:
>>> JSON.loadf('/path/to/file.json')
JSON(...)
>>> JSON.loads('{"1": "spam", "2": "eggs"}')
JSON({'1': 'spam', '2': 'eggs'})
JSON Pointer
The JSONPointer
class is an implementation of the
RFC 6901 JSON Pointer specification. In jschon, JSONPointer
is commonly used to represent paths to nodes within JSON
and JSONSchema
documents, and to extract nodes from
those documents. But JSONPointer
is designed to work
with any JSON-compatible Python object – including, for example, native dict
and list
objects.
Let’s see how JSONPointer
works. We begin with an import:
>>> from jschon import JSON, JSONPointer
Now, consider the following example. This JSON
instance describes
how characters in JSON object keys must be escaped in order to form reference tokens
within an RFC 6901 JSON pointer string:
>>> escape_rule = JSON([
... {"~": "~0"},
... {"/": "~1"}
... ])
Nodes within this instance can be referenced in the usual way, as described in the JSON guide:
>>> escape_rule[1]["/"]
JSON('~1')
If we look at the path
property of this node, we see
that the string representation of the JSON pointer includes the escaped form of
the "/"
key:
>>> escape_rule[1]["/"].path
JSONPointer('/1/~1')
Now let’s get that path into a variable and inspect it a little more closely:
>>> slash_path = escape_rule[1]["/"].path
A JSONPointer
is a Sequence[str]
, with each
item in the sequence being the unescaped object key or array index at the next
node down the path to the referenced value:
>>> [key for key in slash_path]
['1', '/']
You can create a list
or tuple
of keys directly from a
JSONPointer
instance:
>>> tuple(slash_path)
('1', '/')
Notice that the array index is represented as a string, too. In fact, it
matches the key
attribute on the corresponding
JSON
node:
>>> escape_rule[1].key
'1'
To extract the referenced object from a JSON document, we use the
evaluate()
method:
>>> slash_path.evaluate(escape_rule)
JSON('~1')
So far, we’ve seen how to work with the JSONPointer
instance that appears as the path
of a JSON
node. Now let’s look at how to construct a JSONPointer
.
Consider the following example document:
>>> doc = {"a": {"b": {"c": {"d": "😎"}}}}
The obvious way to make a JSONPointer
that points
to the leaf node in this example would be:
>>> JSONPointer('/a/b/c/d')
JSONPointer('/a/b/c/d')
Then, as we’d expect:
>>> JSONPointer('/a/b/c/d').evaluate(doc)
'😎'
But here are a few alternative ways to create the same JSON pointer:
>>> JSONPointer(['a', 'b', 'c', 'd'])
JSONPointer('/a/b/c/d')
>>> JSONPointer(['a'], '/b/c', ['d'])
JSONPointer('/a/b/c/d')
>>> JSONPointer('/a/b', JSONPointer('/c/d'))
JSONPointer('/a/b/c/d')
As you can see, the JSONPointer
constructor accepts
– and concatenates – any number of arguments. Each argument can be either:
an RFC 6901 JSON pointer string (with reserved characters escaped); or
an iterable of unescaped keys or array indices – which may itself be a
JSONPointer
instance.
A special case is the JSONPointer
constructed without
any args:
>>> JSONPointer()
JSONPointer('')
This represents a reference to an entire document:
>>> JSONPointer().evaluate(doc)
{'a': {'b': {'c': {'d': '😎'}}}}
The /
operator provides a convenient way to extend a JSONPointer
:
>>> JSONPointer() / 'a' / ('b', 'c', 'd')
JSONPointer('/a/b/c/d')
>>> JSONPointer('/a/b') / JSONPointer('/c/d')
JSONPointer('/a/b/c/d')
It works by copying the left-hand operand (a JSONPointer
instance) and appending the right-hand operand (an unescaped key, or an iterable
of unescaped keys). Note that JSONPointer
is immutable,
so each invocation of /
produces a new JSONPointer
instance.
As a Sequence
, JSONPointer
supports getting
a key by its index:
>>> JSONPointer('/a/b/c/d')[-4]
'a'
And taking a slice into a JSONPointer
returns a new
JSONPointer
instance composed of the specified slice
of the original’s keys:
>>> JSONPointer('/a/b/c/d')[1:-1]
JSONPointer('/b/c')
JSON Schema
The JSONSchema
class represents a compiled JSON
schema document. Once instantiated, a JSONSchema
object contains all the structural information and executable code it requires
for evaluating JSON
instances, and it may be re-used any
number of times for such evaluation. References to other schemas are resolved
during construction, guaranteeing further that any referenced schemas are also
fully loaded, compiled and ready for use and re-use.
JSONSchema
is a specialization of the JSON
class, and provides all the capabilities of its ancestor, as described in the
JSON guide. Only its JSON type is limited – to one of "object"
and
"boolean"
– in accordance with the JSON Schema specification. As we might
expect, JSONSchema
introduces several new properties
and behaviours, which we’ll explore in the following sections.
Initializing the catalog
Before we can begin creating and working with schemas, we must set up a catalog. For the examples shown on the remainder of this page, we’ll use the following:
>>> from jschon import create_catalog
>>> catalog = create_catalog('2020-12')
Creating a schema
There are several different ways to instantiate a JSONSchema
:
Create it directly from a schema-compatible Python object such as a
dict
or abool
.Deserialize it from a JSON file or a JSON string using the
loadf()
orloads()
class method.Retrieve it from the
Catalog
by providing a schema URI, which maps to a schema file on disk.
But first, let’s import the classes that we’ll be using:
>>> from jschon import JSONSchema, URI
Creating a schema from a Python object
A JSONSchema
object can be created directly from
any schema-compatible Python object, such as a dict
or a bool
.
For boolean schemas and empty schemas, it’s as simple as:
>>> true_schema = JSONSchema(True)
>>> false_schema = JSONSchema(False)
>>> empty_schema = JSONSchema({})
Creating a JSONSchema
object from any non-empty
Mapping
, however, requires that we specify a meta-schema. Here’s a
very basic example of a schema that simply ensures that a JSON value represents
an integer:
>>> int_schema = JSONSchema({
... "type": "integer"
... }, metaschema_uri=URI("https://json-schema.org/draft/2020-12/schema"))
The metaschema_uri parameter resolves to a Metaschema
object, which provides the new JSONSchema
instance
with Keyword
classes for each of its keywords. The
meta-schema URI may be parameterized, as above, or it may be provided using the
"$schema"
keyword:
>>> int_schema = JSONSchema({
... "type": "integer",
... "$schema": "https://json-schema.org/draft/2020-12/schema"
... })
If both are provided, the "$schema"
keyword takes precedence:
>>> int_schema = JSONSchema({
... "type": "integer",
... "$schema": "https://json-schema.org/draft/2020-12/schema"
... }, metaschema_uri=URI("https://json-schema.org/draft/2019-09/schema"))
>>> int_schema.metaschema_uri
URI('https://json-schema.org/draft/2020-12/schema')
An identifying URI is automatically generated for every root schema:
>>> int_schema.uri
URI('urn:uuid:f3adf4a3-c03d-4f30-9072-5bc7b8e9f078')
The schema URI is used as the key for caching the schema in the catalog, and
is required for resolving references to itself and to any subschemas it may
contain. If the schema is intended to be referenced from other schemas in the
catalog, then a URI should be provided explicitly. This may either be passed via
the uri parameter to the constructor, or declared in the schema document itself
using the "$id"
keyword. If both are provided, the "$id"
keyword takes
precedence:
>>> int_schema = JSONSchema({
... "type": "integer",
... "$schema": "https://json-schema.org/draft/2020-12/schema",
... "$id": "https://example.com/the-real-id"
... }, uri="https://example.com/not-the-real-id")
>>> int_schema.uri
URI('https://example.com/the-real-id')
Deserializing a schema from a JSON text document
Suppose that we have a string containing a JSON schema, such as the following, which validates a numeric JSON value:
>>> schema_text = '''{
... "$schema": "https://json-schema.org/draft/2020-12/schema",
... "$id": "https://example.com/num-schema",
... "type": "number"
... }'''
We can deserialize this JSON text into a new JSONSchema
instance using the loads()
class method:
>>> num_schema = JSONSchema.loads(schema_text)
If the schema is stored in a JSON text file, we can deserialize directly from
the file by providing the file path to the loadf()
class
method:
>>> num_schema = JSONSchema.loadf('/path/to/num-schema.json')
The argument to loadf()
may be a plain str
, or
any PathLike
object; for example:
>>> import pathlib
>>> schema_path = pathlib.Path(__file__).parent / 'num-schema.json'
>>> num_schema = JSONSchema.loadf(schema_path)
Both loads()
and loadf()
accept
keyword arguments that are passed through to the JSONSchema
constructor, in case we need to parameterize the meta-schema URI, the schema URI, or
any other JSONSchema
constructor argument:
>>> num_schema = JSONSchema.loads(schema_text, metaschema_uri=URI("https://json-schema.org/draft/2020-12/schema"))
>>> num_schema = JSONSchema.loadf(schema_path, uri=URI("https://example.com/num-schema"))
Retrieving a schema from the catalog
Finally, a JSONSchema
object may be instantiated implicitly,
when retrieving it by URI from the Catalog
. If the schema is not
already cached, it is loaded from disk and compiled on the fly. This approach requires
the catalog to be configured with an appropriate base URI-to-directory mapping. For
more information, see Reference loading.
The Catalog
The role of the Catalog
in jschon is twofold:
It acts as a schema cache, enabling schemas and subschemas to be indexed, re-used, and cross-referenced by URI – allowing for the definition of multiple, cooperative schemas that work together to evaluate
JSON
documents.It provides the infrastructure required for constructing
JSONSchema
objects. This can include meta-schemas, vocabularies and keyword implementations, format validators, and URI-to-directory mappings enabling URI-identified schemas to be located on disk.
A Catalog
object is typically created and configured
at startup:
>>> from jschon import create_catalog
>>> catalog = create_catalog('2020-12')
The create_catalog()
function accepts a variable argument list
indicating which versions of the JSON Schema vocabularies to support. For example,
the following initialization call will enable your application to work with both
2019-09 and 2020-12 schemas:
>>> catalog = create_catalog('2019-09', '2020-12')
If your application requires distinct Catalog
instances with different configurations, then your setup might look something
like this:
>>> catalog_1 = create_catalog('2019-09', name='Catalog 1')
>>> catalog_2 = create_catalog('2020-12', name='Catalog 2')
The relevant Catalog
instance - or name - can be
specified when creating new JSONSchema
objects:
>>> from jschon import JSONSchema
>>> schema_1 = JSONSchema({"type": "object", ...}, catalog=catalog_1)
>>> schema_2 = JSONSchema.loadf('/path/to/schema.json', catalog='Catalog 2')
Reference loading
Schema references can be resolved to files on disk, by configuring a local directory source for a given base URI:
>>> from jschon import create_catalog, LocalSource, URI
>>> catalog = create_catalog('2020-12')
>>> catalog.add_uri_source(
... URI("https://example.com/schemas/"),
... LocalSource('/path/to/schemas/', suffix='.json')
... )
Now, the "$ref"
in the following schema resolves to the local file
/path/to/schemas/my/schema.json
:
{
"$ref": "https://example.com/schemas/my/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
We can also retrieve JSONSchema
objects by URI
directly from the catalog:
>>> my_schema = catalog.get_schema(URI("https://example.com/schemas/my/schema"))
See File-based schemas for further examples of loading schemas from disk.
Format validation
By default, formats are not validated in jschon. Any occurrence of the format
keyword simply produces an annotation consisting of the keyword’s value, called
the format attribute.
Format validators can be registered using the format_validator()
decorator. Format attributes must, however, be explicitly enabled for validation
in the catalog, in order to use any registered format validator. This can be done
using enable_formats()
.
For a working example, see Format validation.
Running the tests
jschon is tested using the JSON Schema Test Suite (excluding optional and format tests), along with custom unit tests that make use of the Hypothesis testing library.
To run the tests, install jschon in editable mode, including testing dependencies:
pip install -e git+https://github.com/marksparkza/jschon.git#egg=jschon[test]
Then, cd
to the jschon source directory (pip show jschon
will give you
the location), and type tox
.
Note that a complete test run requires all of the supported Python versions (3.8, 3.9, 3.10, 3.11) to be installed on your system.
For detailed information on testing options, and to see which optional and format tests are supported, see Contributing.
Contributing
Please create an issue for any feature request, question, suggestion or bug report.
PRs are welcome for minor fixes, doc typos and clarifications, added test coverage, and to address updates or omissions from supported specifications.
PRs involving complex changes to jschon modules are unlikely to be merged while the development status of the library is alpha (v0.x). There are currently no plans for a v1.0 release. For advanced use cases, and in the spirit of open source software development, you are encouraged to fork and republish the library under any name of your choosing.
jschon was originally created to solve a JSON translation problem using JSON Schema and Python. It is intended to provide a starting point for building JSON-related tools, extensions and applications.
Development
The project uses git submodules to incorporate the JSON Schema Test Suite, as well as supported branches of the JSON Schema Specification repository which provides the meta-schema and vocabulary definition files.
Run the following command in your local copy of jschon to check out all the submodule files:
git submodule update --init --recursive
Create and activate a Python virtual environment, and install the project in editable mode along with development dependencies:
pip install -e .[dev]
Testing
To run the jschon tests, type:
pytest
A default test run includes all unit tests and JSON Schema Test Suite versions 2019-09 and 2020-12. Optional and format tests are excluded. To customize running of the test suite, jschon provides the following pytest command line options:
--testsuite-version={2019-09,2020-12,next}
JSON Schema version to test. The option may be repeated
to test multiple versions. (default: {2019-09,2020-12})
--testsuite-optionals
Include optional tests.
--testsuite-formats Include format tests.
--testsuite-file=TESTSUITE_FILE
Run only this file from the JSON Schema Test Suite.
Given as a path relative to the version directory in the
test suite, e.g. 'properties.json' or
'optional/bignum.json'. The option may be repeated to
run multiple files. Using this option causes
--testsuite-optionals and --testsuite-formats to be
ignored.
--testsuite-description=TESTSUITE_DESCRIPTION
Run only test groups and tests whose descriptions
contain the given substring. Matching is case
insensitive. The option may be repeated to match
alternative substrings.
--testsuite-generate-status
Run all possible tests from all supported versions and
update the tests/suite_status.json file. If a failed
test is already in tests/suite_status.json, its status
and reason are left as is. Otherwise, all optional and
format tests that fail are given an 'xfail' with the
reason being 'optional' or 'format', respectively, while
other failures from the 'next' version are given an
'xfail' status with a None (JSON null) reason, which
should be set manually to an appropriate string. All
other options are ignored when this option is passed.
NOTE: the tests/suite_status.json is updated IN PLACE,
overwriting the current contents.
The above options are printed under the section JSON Schema Test Suite in the output of:
pytest --help
Expected failures and skipped tests
Many optional, format, and draft-next test cases are expected to fail, as recorded in
tests/suite_status.json.
A status of xfail
indicates an optional feature or format that is not currently supported.
A status of skip
indicates a bug in the test that makes it impossible to pass.
Tests set to xfail
will produce an xpass
result if they begin to pass.
Updating xfail
and skip
test outcomes
The --testsuite-generate-status
can be used to rewrite tests/suite_status.json
based on the current pass/fail status. If a failing test is already present in the
status JSON file, it is left as-is to preserve any custom reasons or statuses.
Otherwise, it is added to the file as an xfail
status. Tests in the file that
now pass will be removed.
This option causes all other options to be ignored, and always runs all versions of all tests, including the optional and format tests.
Running the tests through tox
To run the tests against all supported versions of python (which must be available on your system), type:
tox
To pass arguments through to pytest
, use --
to indicate the end of the tox
arguments:
tox -e py310 -- --capture=tee-sys --testsuite-version=next
Documentation
The jschon documentation is written in reStructuredText.
To build the docs locally, install sphinx and co:
pip install -e .[doc]
In the docs
directory, type:
make html
The HTML pages are written to docs/_build/html/
.
Changelog
v0.11.1 (2023-10-22)
Features:
Allow adding a source with a base URI of
None
to match full URIs as therelative_path
JSONPointer
andRelativeJSONPointer
now have class attributes defining the exceptions that they use, which can be overidden in subclassesCached properties for accessing document and resource root schemas from subschemas
Documentation:
Update project description and contributing guidelines
Miscellaneous:
Test infrastructure for maintaining a detailed status report of the pass/skip/fail status of all tests in the JSON Schema Test Suite
v0.11.0 (2023-06-03)
Breaking changes:
RelativeJSONPointerError
superseded byRelativeJSONPointerMalformedError
andRelativeJSONPointerReferenceError
Deprecations:
Exception classes dropped from the top-level package API
jschon.exceptions
module renamed tojschon.exc
Documentation:
Exception classes documented
Custom keyword example refactored to raise exception in constructor
Miscellaneous:
JschonError
base exception class introducedJSONPointerError
partitioned intoJSONPointerMalformedError
,JSONPointerReferenceError
,RelativeJSONPointerMalformedError
andRelativeJSONPointerReferenceError
v0.10.3 (2023-05-21)
Bug Fixes:
Non-scalar annotation values are now fully unwrapped from the JSON class
Documentation:
Spell ‘meta-schema’ consistently in tutorials and examples
v0.10.2 (2023-04-20)
Experimental:
“$id” no longer allows empty fragments in draft-next
Bug Fixes:
“$id” allows non-normalized URI references
“$id” allows empty fragments in 2019-09 and 2020-12
Miscellaneous:
Set default (2019-09, 2020-12) for
--testsuite-version
pytest optioninteger
is no longer considered a type for keyword evaluation restriction purposesDrop
Keyword.can_evaluate()
methodPreload rather than implicit-load standard meta-schemas
v0.10.1 (2023-04-11)
Miscellaneous:
Rename submodules json-schema-spec-2019-09 and json-schema-spec-2020-12 to json-schema-2019-09 and json-schema-2020-12, respectively (run
git submodule init
to update local git config)LocalSource now includes the filename in the CatalogError when the file is not found
v0.10.0 (2023-04-01)
Features:
@format_validator
decoratorjson-pointer format validator
Annotation filtering for basic output format (#32)
JSON
null
,true
,false
literalsRelative JSON Pointer
+
/-
array index adjustmentsUnknown keywords are collected as annotations
Automatically create metaschemas as referenced by
"$schema"
on first access of the now-cachedJSONSchema.metaschema
propertyAutomatically detect the core vocabulary in metaschemas, but allow specifying a default to use when none is detectable
Experimental:
Catalog support for the next JSON Schema draft
hierarchical output format
In-place JSON Patch add, remove and replace operations on
JSON
class
Breaking changes:
Catalog.add_format_validators()
superseded by@format_validator
/Catalog.enable_formats()
Rename
Catalog.session()
context manager toCatalog.cache()
Rename
session
parameter tocacheid
in many placesRename public functions in the
jsonpatch
moduleRename
*Applicator*
keyword class mixins to*Subschema*
Bug Fixes:
“$dynamicRef” works with non-plain-name fragment URIs
Fixed remote anchor ref resolution
Documentation:
Rename User Guide to Tutorial
Restructure the API docs index page
Miscellaneous:
@output_formatter
decorator now identifies output formats explicitlyAdd
JSONCompatible
andResult
classes to the top-level package APIRemove implicit fall-through to looking up a schema in the __meta__ cache if not found in the parameterized cache, in
Catalog.get_schema()
(#40)Added
Catalog.get_metaschema()
, analogous toCatalog.get_schema()
Catalog.create_metaschema()
andCatalog.create_vocabulary()
return the created instanceRename
core_vocabulary
andcore_vocabulary_uri
parameters forMetaschema.__init__()
andCatalog.create_metaschema()
respectively todefault_core_vocabulary
anddefault_core_vocabulary_uri
Improve kwarg-based construction of
RelativeJSONPointer
Rename
AnnotationKeyword
to_AnnotationKeyword
Rename
vocabularies
parameter ofcreate_catalog()
toversions
Allow passthrough of arguments to pytest when invoking tox
Add pytest command line options
--testsuite-file
and--testsuite-description
Python 3.11 is now tested (no changes were required to support it)
Pinned
hypothesis<6.0.4
to avoid python/cpython#102126 in Python 3.10.10 and 3.11.2
v0.9.0 (2022-08-14)
Features:
JSON array/object mutation
JSON serialization to string/file
JSON deserialization from remote location
Breaking changes:
Rename Scope to Result
Remove JSON support for decimal.Decimal (#31)
Rename Keyword.types to Keyword.instance_types
Rename Keyword.depends to Keyword.depends_on
Move translation vocabulary implementation to its own repo (jschon-translation)
Miscellaneous:
Allow any JSON-compatible value to be set as an error on a Result node
Array/object applicator keywords – additionalProperties, unevaluatedProperties, propertyNames, additionalItems, items, prefixItems, unevaluatedItems – now produce an error array of failing child indices
Register output formatters with a decorator
Remove JSON type checks for unsupported usage
Append (rather than replace) the suffix when resolving a LocalSource filepath
Flatten dict of subresults on Result node
Provide a useful __str__ method for Result node
v0.8.5 (2022-05-10)
Features:
Added JSONPointer prefix test operators (#29)
v0.8.4 (2022-02-03)
Miscellaneous:
Add PEP-561 py.typed marker to signal to type checkers that this library has usable type annotations.
v0.8.3 (2022-01-31)
Miscellaneous:
Include translation vocabulary definition files in the distribution.
v0.8.1 (2022-01-30)
Miscellaneous:
The requests dependency for remote $refs is now an optional install.
v0.8.0 (2022-01-29)
Features:
Added support for remote schema references and, more generally, ‘sources’ for loading URI-identified JSON resources
Added a JSON Patch implementation
Added a Relative JSON Pointer implementation
Added experimental support for a JSON translation vocabulary
Breaking changes:
Replaced the Catalog.add_directory method with the more general Catalog.add_uri_source
Bug fixes:
Fixed error messaging for the “required” keyword
Eliminated extraneous error messages from “additionalProperties” and “items” by reverting to the Draft 7 approach for applying these keywords (#17)
Miscellaneous:
Implemented a Catalog instance registry, replacing the default instance approach
Moved JSON Schema vocabulary initialization from the Catalog class to the create_catalog function
Replaced the AnyJSONCompatible type variable with a JSONCompatible type alias
Removed isinstance type checks that would only fail if type hints were disregarded
Removed printing of JSON instance values for “enum” and “const” error messages
Decorated several JSON and JSONSchema properties with @cached_property
Constrained the Keyword.types and Keyword.depends class attributes to allow tuples only
Removed unused code supporting instantiation of JSON arrays/objects from collections of JSON class instances
Changed type hints for JSON inequality operators to indicate that they are supported only for strings and numbers
Removed unnecessary type coercion in JSON inequality operators
Generalized Keyword class mixins to support custom subschema construction by custom applicator keywords
Added a required positional arg instance to the Scope constructor
Removed the path, instpath and relpath Scope constructor args
Added a cls keyword arg to Scope.__call__ supporting custom Scope classes
Generalized output formatting, to support custom output formats by extensions
Added a globals property to the root of the Scope tree, for arbitrary evaluation state
Added a Keyword.static class attribute, obviating the need to override can_evaluate
v0.7.3 (2021-10-24)
Documentation:
Added example of extending JSON Schema with a custom keyword, vocab and meta-schema
Various improvements to wording and structuring of docs
Miscellaneous:
The default param of create_catalog() now defaults to True
Allow “$id” and “$schema” to be omitted from meta-schema documents
Renamed JSON.value to JSON.data; JSON.value now returns the instance data as a JSON-compatible Python object (#18)
Switched to reStructuredText across the board - top-level
*.rst
files are now included in the docs and in the published package
v0.7.2 (2021-08-28)
Bug fixes:
Fixed “absoluteKeywordLocation” output for “$ref”, “$dynamicRef” and “$recursiveRef” nodes (#15)
Documentation:
Restructured examples; example outputs are now verified by unit tests
Added examples of loading schemas from files
v0.7.1 (2021-08-08)
Breaking changes:
Renamed Catalogue to Catalog
v0.7.0 (2021-08-08)
Features:
Top-level catalogue initialization function
Session id-based schema caching
Breaking changes:
Removed the Catalogue.create_default_catalogue method
Documentation:
Added sections on getting started and running the tests
Improved JSONSchema and Catalogue usage docs
v0.6.0 (2021-06-10)
Features:
Detailed and verbose output format options
Breaking changes:
JSONSchema.validate() now returns a Scope result object
Bug fixes:
Fixed the instance location (shown in output) for object keys evaluated by “propertyNames”
Miscellaneous:
Failing schema nodes no longer have error messages, and are excluded from basic output
A Scope.passed property indicates a scope’s assertion result, while Scope.valid indicates its validation result (these can only differ for an “if” keyword subscope)
Improved the API (used by keywords) and internal structure of the Scope class
Dropped the Annotation and Error classes
v0.5.0 (2021-06-01)
Features:
An output method on Scope, providing output formatting
Breaking changes:
Dropped the Evaluator class
Miscellaneous:
Moved Metaschema, Vocabulary and Keyword into the vocabulary subpackage
v0.4.0 (2021-05-21)
Bug fixes:
Fixed error and annotation collection for array items (#8)
Miscellaneous:
Improved and better encapsulated the Scope class’s internal logic
Added
doc
dependencies to setup.pySupport testing with Python 3.10
v0.3.0 (2021-05-15)
Features:
Evaluator class providing output formatting
Multiple Catalogue instances now supported; with an optional default catalogue
Bug fixes:
Fixed percent-encoding of the URI fragment form of JSON pointers
Documentation:
Created user guides and API reference documentation; published to Read the Docs
Miscellaneous:
Improvements to base URI-directory mapping and file loading in the Catalogue
Tweaks to annotation and error collection in the Scope class affecting output generation
Auto-generated schema URIs are now formatted as
'urn:uuid:<uuid>'
v0.2.0 (2021-04-18)
Features:
Class methods for constructing JSON instances from JSON strings/files
Bug fixes:
Fixed unevaluatedItems-contains interaction
Miscellaneous:
Top-level package API defined in
__init.py__
Improved handling of floats in JSON constructor input
Removed mod operator from JSON class
Added development setup (
pip install -e .[dev]
)Added JSON class usage info to the README
v0.1.1 (2021-04-06)
Bug fixes:
Fixed $dynamicRef resolution (#3)
v0.1.0 (2021-03-31)
Features:
JSON class implementing the JSON data model
JSON Pointer implementation
JSON Schema implementation, supporting drafts 2019-09 and 2020-12 of the specification
Catalogue for managing (meta)schemas, vocabularies and format validators
URI class (wraps rfc3986.URIReference)