summaryrefslogtreecommitdiff
path: root/jsonschema/protocols.py
blob: 8589afe01fe0b4ecf67270bd1cc30781bd59dc11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
typing.Protocol classes for jsonschema interfaces.
"""

# for reference material on Protocols, see
#   https://www.python.org/dev/peps/pep-0544/

from typing import Any, ClassVar, Iterator, Optional, Union

try:
    from typing import Protocol, runtime_checkable
except ImportError:
    from typing_extensions import Protocol, runtime_checkable

from jsonschema._format import FormatChecker

from ._types import TypeChecker
from .exceptions import ValidationError
from .validators import RefResolver

# For code authors working on the validator protocol, these are the three
# use-cases which should be kept in mind:
#
# 1. As a protocol class, it can be used in type annotations to describe the
#    available methods and attributes of a validator
# 2. It is the source of autodoc for the validator documentation
# 3. It is runtime_checkable, meaning that it can be used in isinstance()
#    checks.
#
# Since protocols are not base classes, isinstance() checking is limited in
# its capabilities. See docs on runtime_checkable for detail


@runtime_checkable
class Validator(Protocol):
    """
    The protocol to which all validator classes should adhere.

    :argument schema: the schema that the validator object
        will validate with. It is assumed to be valid, and providing
        an invalid schema can lead to undefined behavior. See
        `Validator.check_schema` to validate a schema first.
    :argument resolver: an instance of `jsonschema.RefResolver` that will be
        used to resolve :validator:`$ref` properties (JSON references). If
        unprovided, one will be created.
    :argument format_checker: an instance of `jsonschema.FormatChecker`
        whose `jsonschema.FormatChecker.conforms` method will be called to
        check and see if instances conform to each :validator:`format`
        property present in the schema. If unprovided, no validation
        will be done for :validator:`format`. Certain formats require
        additional packages to be installed (ipv5, uri, color, date-time).
        The required packages can be found at the bottom of this page.
    """

    #: An object representing the validator's meta schema (the schema that
    #: describes valid schemas in the given version).
    META_SCHEMA: ClassVar[dict]

    #: A mapping of validator names (`str`\s) to functions
    #: that validate the validator property with that name. For more
    #: information see `creating-validators`.
    VALIDATORS: ClassVar[dict]

    #: A `jsonschema.TypeChecker` that will be used when validating
    #: :validator:`type` properties in JSON schemas.
    TYPE_CHECKER: ClassVar[TypeChecker]

    #: The schema that was passed in when initializing the object.
    schema: Union[dict, bool]

    def __init__(
        self,
        schema: Union[dict, bool],
        resolver: Optional[RefResolver] = None,
        format_checker: Optional[FormatChecker] = None,
    ) -> None:
        ...

    @classmethod
    def check_schema(cls, schema: dict) -> None:
        """
        Validate the given schema against the validator's `META_SCHEMA`.

        :raises: `jsonschema.exceptions.SchemaError` if the schema
            is invalid
        """

    def is_type(self, instance: Any, type: str) -> bool:
        """
        Check if the instance is of the given (JSON Schema) type.

        :type type: str
        :rtype: bool
        :raises: `jsonschema.exceptions.UnknownType` if ``type``
            is not a known type.
        """

    def is_valid(self, instance: dict) -> bool:
        """
        Check if the instance is valid under the current `schema`.

        :rtype: bool

        >>> schema = {"maxItems" : 2}
        >>> Draft3Validator(schema).is_valid([2, 3, 4])
        False
        """

    def iter_errors(self, instance: dict) -> Iterator[ValidationError]:
        r"""
        Lazily yield each of the validation errors in the given instance.

        :rtype: an `collections.abc.Iterable` of
            `jsonschema.exceptions.ValidationError`\s

        >>> schema = {
        ...     "type" : "array",
        ...     "items" : {"enum" : [1, 2, 3]},
        ...     "maxItems" : 2,
        ... }
        >>> v = Draft3Validator(schema)
        >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str):
        ...     print(error.message)
        4 is not one of [1, 2, 3]
        [2, 3, 4] is too long
        """

    def validate(self, instance: dict) -> None:
        """
        Check if the instance is valid under the current `schema`.

        :raises: `jsonschema.exceptions.ValidationError` if the
            instance is invalid

        >>> schema = {"maxItems" : 2}
        >>> Draft3Validator(schema).validate([2, 3, 4])
        Traceback (most recent call last):
            ...
        ValidationError: [2, 3, 4] is too long
        """

    def evolve(self, **kwargs) -> "Validator":
        """
        Create a new validator like this one, but with given changes.

        Preserves all other attributes, so can be used to e.g. create a
        validator with a different schema but with the same :validator:`$ref`
        resolution behavior.

        >>> validator = Draft202012Validator({})
        >>> validator.evolve(schema={"type": "number"})
        Draft202012Validator(schema={'type': 'number'}, format_checker=None)
        """