jschon 0.11.1 documentation

# 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

- Documentation

- Package info

- Source code

### API Reference

#### Package API

##### Catalog

jschon.create_catalog(*versions, name='catalog')

  Create and return a `Catalog` instance, initialized with a meta-schema and keyword support for each of the specified JSON Schema versions.

  Parameters:

    - versions (str) – Any of `2019-09`, `2020-12`.

    - name (str) – A unique name for the `Catalog` instance.

  Raises:

    ValueError – If any of versions is unrecognized.

  Return type:

    Catalog

- `Catalog`

- `LocalSource`

- `RemoteSource`

##### JSON

- `JSON`

- `JSONCompatible`

##### JSON Patch

- `JSONPatch`

- `JSONPatchOperation`

##### JSON Pointer

- `JSONPointer`

- `RelativeJSONPointer`

##### JSON Schema

- `JSONSchema`

- `Result`

##### URI

- `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)

  classmethod get_catalog(name='catalog')
    Parameters:

      name (str)

    Return type:

      Catalog

  __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 cache

      - cacheid (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:

      - base_uri (URI | None) – a normalized, absolute URI - including scheme, without a fragment, and ending with `'/'` or None to match complete URIs

      - source (Source) – a `Source` object

    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 file

      - kwargs (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:

      Metaschema

  create_vocabulary(uri, *kwclasses)

    Create a `Vocabulary` object, which may be used by a `Metaschema` to provide keyword classes used in schema construction.

    Parameters:

      - uri (URI) – the URI identifying the vocabulary

      - kwclasses (Type[Keyword]) – the `Keyword` classes constituting the vocabulary

    Returns:

      the newly created `Vocabulary` instance

    Return type:

      Vocabulary

  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 using `create_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 valid

      - JSONSchemaError – if the metaschema is loaded from sources but no known core vocabulary is present in `"$vocabulary"`

    Return type:

      Metaschema

  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 disk

      - cacheid (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:

      JSONSchema

  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:

      Vocabulary

  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]

  name: str

    The unique name of this `Catalog` instance.

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

class jschon.catalog.RemoteSource(base_url, **kwargs)
  Parameters:

    - base_url (URI)

    - kwargs (Any)

  __call__(relative_path)
    Parameters:

      relative_path (str)

    Return type:

      None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]

  __init__(base_url, **kwargs)
    Parameters:

      - base_url (URI)

      - kwargs (Any)

    Return type:

      None

class jschon.catalog.Source(suffix=None)
  Parameters:

    suffix (str)

  __call__(relative_path)
    Parameters:

      relative_path (str)

    Return type:

      None | bool | int | float | str | Sequence[Any] | Mapping[str, Any]

  __init__(suffix=None)
    Parameters:

      suffix (str)

    Return type:

      None

##### jschon.exc

exception jschon.exc.CatalogError

  An error originating in the `catalog` module.

exception jschon.exc.JSONError

  An error originating in the `json` module.

exception jschon.exc.JSONPatchError

  An error originating in the `jsonpatch` module.

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 by `Keyword` 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.

exception jschon.exc.URIError

  An error originating in the `uri` module.

##### 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.

  Parameters:

    - value (JSONCompatible)

    - parent (JSON)

    - key (str)

    - itemclass (Type[JSON])

    - itemkwargs (Any)

  classmethod loadf(path, **kwargs)

    Deserialize a JSON file to a `JSON` instance.

    Parameters:

      - path (str | PathLike) – the path to the file

      - kwargs (Any) – keyword arguments to pass to the `JSON` (subclass) constructor

    Return type:

      JSON

  classmethod loadr(url, **kwargs)

    Deserialize a remote JSON resource to a `JSON` instance.

    Parameters:

      - url (str) – the URL of the resource

      - kwargs (Any) – keyword arguments to pass to the `JSON` (subclass) constructor

    Return type:

      JSON

  classmethod loads(value, **kwargs)

    Deserialize a JSON string to a `JSON` instance.

    Parameters:

      - value (str) – the JSON string

      - kwargs (Any) – keyword arguments to pass to the `JSON` (subclass) constructor

    Return type:

      JSON

  __bool__()

    Return bool(self).

    Return type:

      bool

  __delitem__(index)

    Delete self[index].

    Supported for JSON types `array` and `object`.

    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` and `string`.

    Parameters:

      other (JSON | int | float | str)

    Return type:

      bool

  __getitem__(index)

    Return self[index].

    Supported for JSON types `array` and `object`.

    Parameters:

      index (int | slice | str)

    Return type:

      JSON

  __gt__(other)

    Return self > other.

    Supported for JSON types `number` and `string`.

    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 by `JSON` 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` and `object`.

    Return type:

      Iterator

  __le__(other)

    Return self <= other.

    Supported for JSON types `number` and `string`.

    Parameters:

      other (JSON | int | float | str)

    Return type:

      bool

  __len__()

    Return len(self).

    Supported for JSON types `string`, `array` and `object`.

    Return type:

      int

  __lt__(other)

    Return self < other.

    Supported for JSON types `number` and `string`.

    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` and `object`.

    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 to `add()`, this method performs an in-place JSON Patch `add` 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 to `remove()`, this method performs an in-place JSON Patch `remove` 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 to `replace()`, this method performs an in-place JSON Patch `replace` 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]

  itemclass: Type[JSON]

    The `JSON` class type of child instances.

  itemkwargs: Dict[str, Any]

    Keyword arguments to the `itemclass` constructor.

  key: str | None

    The index of the instance within its parent.

  parent: JSON | None

    The containing JSON instance.

  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 a `JSONPatchOperation` 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:

    JSONPatchOperation

  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` and `replace` operations, the value to set at the target location. For `test`, the value to compare with the target.

      - from – The location from which to `move` or `copy`. An alias for from, which may be passed via kwargs.

      - from_ (str | JSONPointer | None)

      - kwargs (str | JSONPointer)

    Return type:

      JSONPatchOperation

  __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 new `JSONPointer` instance by copying the left-hand argument (a `JSONPointer` 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 a `JSONPointer` returns a new `JSONPointer` composed of the specified slice of the original’s keys.

  [1]

  An unescaped object key is the unmodified form of the key within its mapping. Keys appearing in an RFC 6901 JSON pointer string, on the other hand, are required by the syntax to have reserved characters escaped.

  [2]

  Object keys and array indices are uniformly represented as strings and referred to as keys in the JSONPointer class.

  Parameters:

    values (Union[str, Iterable[str]])

  Return type:

    JSONPointer

  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 with `URI` objects.

    Parameters:

      value (str) – a percent-encoded URI fragment

    Return type:

      JSONPointer

  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:

      JSONPointer

  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 a `Sequence`, evaluation by any non-empty `JSONPointer` will always fail.

    Parameters:

      document (Any) – any Python object

    Raises:

      JSONPointerReferenceError – if self references a non-existent location in document

    Return type:

      Any

  uri_fragment()

    Return a percent-encoded URI fragment representation of self.

    The returned string excludes the initial `'#'` of the fragment; this allows for sensible interoperation with `URI` objects.

    Return type:

      str

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:

    RelativeJSONPointer

  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:

      RelativeJSONPointer

  __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:

    - value (Union[bool, Mapping[str, JSONCompatible]])

    - catalog (Union[str, Catalog])

    - cacheid (Hashable)

    - uri (URI)

    - metaschema_uri (URI)

    - parent (JSON | None)

    - key (str | None)

  __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 this

      - metaschema_uri (URI) – the URI identifying the schema’s metaschema; a `"$schema"` keyword appearing in value will override this

      - parent (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.

    Parameters:

      - instance (JSON) – the JSON document to evaluate

      - result (Result) – the current result node; given by keywords when invoking this method recursively

    Return type:

      Result

  validate()

    Validate the schema against its metaschema.

    Return type:

      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.

  catalog: Catalog

    The catalog in which the schema is cached.

  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` or `JSONSchema` 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"`.

  property uri: URI | None

    The `URI` identifying the schema.

    Used as the key for caching the schema in the catalog.

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` or `verbose` – or any format registered with the `output_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.

    Parameters:

      - instance (JSON)

      - key (str)

    Return type:

      Result | None

  property absolute_uri: URI | None

    Return the absolute URI of the current schema node.

  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
  instance: JSON

    The instance under evaluation.

  key: str | None

    The index of the current schema node within its dynamic parent.

  parent: Result | None

    The parent result node.

  property passed: bool

    Return the assertion result for the schema node.

    In the standard JSON Schema vocabulary, this can only differ from `valid` for the `if` keyword: validity may be false (triggering `else`) while its assertion result is always true.

    For the root result node, `passed` will always equal `valid`.

  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 schema_node: JSON

    Return the current schema node.

  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:

      URI

  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.

    Parameters:

      base_uri (URI)

    Return type:

      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])

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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 of `JSONSchema`, 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 file

      - kwargs (Any) – additional keyword arguments to pass through to the `JSONSchema` constructor

      - default_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 internal `Keyword` 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)

  __init__(uri, *kwclasses)
    Parameters:

      - uri (URI)

      - kwclasses (Type[Keyword])

###### 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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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)

  evaluate(instance, result)
    Parameters:

      - instance (JSON)

      - result (Result)

    Return type:

      None

  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 a `bool`.

- Deserialize it from a JSON file or a JSON string using the `loadf()` or `loads()` 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:

1. 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.

2. 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 the `relative_path`

- `JSONPointer` and `RelativeJSONPointer` now have class attributes defining the exceptions that they use, which can be overidden in subclasses

- Cached 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 by `RelativeJSONPointerMalformedError` and `RelativeJSONPointerReferenceError`

Deprecations:

- Exception classes dropped from the top-level package API

- `jschon.exceptions` module renamed to `jschon.exc`

Documentation:

- Exception classes documented

- Custom keyword example refactored to raise exception in constructor

Miscellaneous:

- `JschonError` base exception class introduced

- `JSONPointerError` partitioned into `JSONPointerMalformedError`, `JSONPointerReferenceError`, `RelativeJSONPointerMalformedError` and `RelativeJSONPointerReferenceError`

#### 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 option

- `integer` is no longer considered a type for keyword evaluation restriction purposes

- Drop `Keyword.can_evaluate()` method

- Preload 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` decorator

- json-pointer format validator

- Annotation filtering for basic output format (#32)

- JSON `null`, `true`, `false` literals

- Relative JSON Pointer `+`/`-` array index adjustments

- Unknown keywords are collected as annotations

- Automatically create metaschemas as referenced by `"$schema"` on first access of the now-cached `JSONSchema.metaschema` property

- Automatically 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 to `Catalog.cache()`

- Rename `session` parameter to `cacheid` in many places

- Rename public functions in the `jsonpatch` module

- Rename `*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 explicitly

- Add `JSONCompatible` and `Result` classes to the top-level package API

- Remove 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 to `Catalog.get_schema()`

- `Catalog.create_metaschema()` and `Catalog.create_vocabulary()` return the created instance

- Rename `core_vocabulary` and `core_vocabulary_uri` parameters for `Metaschema.__init__()` and `Catalog.create_metaschema()` respectively to `default_core_vocabulary` and `default_core_vocabulary_uri`

- Improve kwarg-based construction of `RelativeJSONPointer`

- Rename `AnnotationKeyword` to `_AnnotationKeyword`

- Rename `vocabularies` parameter of `create_catalog()` to `versions`

- 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.py

- Support 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)