44from __future__ import annotations
55
66from collections import deque
7- from collections .abc import Mapping , Sequence
7+ from collections .abc import Iterable , Mapping , Sequence
88from functools import lru_cache
99from operator import methodcaller
1010from urllib .parse import unquote , urldefrag , urljoin , urlsplit
1515import reprlib
1616import warnings
1717
18+ from attrs import define , field , fields
1819from jsonschema_specifications import REGISTRY as SPECIFICATIONS
1920from referencing import Specification
2021from rpds import HashTrieMap
21- import attr
2222import referencing .jsonschema
2323
2424from jsonschema import (
2525 _format ,
2626 _legacy_validators ,
2727 _types ,
28+ _typing ,
2829 _utils ,
2930 _validators ,
3031 exceptions ,
@@ -102,24 +103,29 @@ def _validates(cls):
102103
103104
104105def create (
105- meta_schema ,
106- validators = (),
107- version = None ,
108- type_checker = _types .draft202012_type_checker ,
109- format_checker = _format .draft202012_format_checker ,
110- id_of = referencing .jsonschema .DRAFT202012 .id_of ,
111- applicable_validators = methodcaller ("items" ),
106+ meta_schema : referencing .jsonschema .ObjectSchema ,
107+ validators : (
108+ Mapping [str , _typing .SchemaKeywordValidator ]
109+ | Iterable [tuple [str , _typing .SchemaKeywordValidator ]]
110+ ) = (),
111+ version : str | None = None ,
112+ type_checker : _types .TypeChecker = _types .draft202012_type_checker ,
113+ format_checker : _format .FormatChecker = _format .draft202012_format_checker ,
114+ id_of : _typing .id_of = referencing .jsonschema .DRAFT202012 .id_of ,
115+ applicable_validators : _typing .ApplicableValidators = methodcaller (
116+ "items" ,
117+ ),
112118):
113119 """
114120 Create a new validator class.
115121
116122 Arguments:
117123
118- meta_schema (collections.abc.Mapping) :
124+ meta_schema:
119125
120126 the meta schema for the new validator class
121127
122- validators (collections.abc.Mapping) :
128+ validators:
123129
124130 a mapping from names to callables, where each callable will
125131 validate the schema property with the given name.
@@ -132,37 +138,42 @@ def create(
132138 3. the instance
133139 4. the schema
134140
135- version (str) :
141+ version:
136142
137143 an identifier for the version that this validator class will
138144 validate. If provided, the returned validator class will
139145 have its ``__name__`` set to include the version, and also
140146 will have `jsonschema.validators.validates` automatically
141147 called for the given version.
142148
143- type_checker (jsonschema.TypeChecker) :
149+ type_checker:
144150
145151 a type checker, used when applying the :kw:`type` keyword.
146152
147153 If unprovided, a `jsonschema.TypeChecker` will be created
148154 with a set of default types typical of JSON Schema drafts.
149155
150- format_checker (jsonschema.FormatChecker) :
156+ format_checker:
151157
152158 a format checker, used when applying the :kw:`format` keyword.
153159
154160 If unprovided, a `jsonschema.FormatChecker` will be created
155161 with a set of default formats typical of JSON Schema drafts.
156162
157- id_of (collections.abc.Callable) :
163+ id_of:
158164
159165 A function that given a schema, returns its ID.
160166
161- applicable_validators (collections.abc.Callable) :
167+ applicable_validators:
162168
163- A function that given a schema, returns the list of
164- applicable validators (validation keywords and callables)
169+ A function that, given a schema, returns the list of
170+ applicable schema keywords and associated values
165171 which will be used to validate the instance.
172+ This is mostly used to support pre-draft 7 versions of JSON Schema
173+ which specified behavior around ignoring keywords if they were
174+ siblings of a ``$ref`` keyword. If you're not attempting to
175+ implement similar behavior, you can typically ignore this argument
176+ and leave it at its default.
166177
167178 Returns:
168179
@@ -176,7 +187,7 @@ def create(
176187 default = Specification .OPAQUE ,
177188 )
178189
179- @attr . s
190+ @define
180191 class Validator :
181192
182193 VALIDATORS = dict (validators )
@@ -185,17 +196,17 @@ class Validator:
185196 FORMAT_CHECKER = format_checker_arg
186197 ID_OF = staticmethod (id_of )
187198
188- schema = attr . ib (repr = reprlib .repr )
189- _ref_resolver = attr . ib (default = None , repr = False , alias = "resolver" )
190- format_checker = attr . ib (default = None )
199+ schema : referencing . jsonschema . Schema = field (repr = reprlib .repr )
200+ _ref_resolver = field (default = None , repr = False , alias = "resolver" )
201+ format_checker : _format . FormatChecker | None = field (default = None )
191202 # TODO: include new meta-schemas added at runtime
192- _registry = attr . ib (
203+ _registry : referencing . jsonschema . SchemaRegistry = field (
193204 default = SPECIFICATIONS ,
194205 converter = SPECIFICATIONS .combine , # type: ignore[misc]
195206 kw_only = True ,
196207 repr = False ,
197208 )
198- _resolver = attr . ib (
209+ _resolver = field (
199210 alias = "_resolver" ,
200211 default = None ,
201212 kw_only = True ,
@@ -222,7 +233,7 @@ def evolve(self, **changes):
222233 schema = changes .setdefault ("schema" , self .schema )
223234 NewValidator = validator_for (schema , default = cls )
224235
225- for field in attr . fields (cls ):
236+ for field in fields (cls ): # noqa: F402
226237 if not field .init :
227238 continue
228239 attr_name = field .name
@@ -429,14 +440,14 @@ def is_valid(self, instance, _schema=None):
429440
430441 evolve_fields = [
431442 (field .name , field .alias )
432- for field in attr . fields (Validator )
443+ for field in fields (Validator )
433444 if field .init
434445 ]
435446
436447 if version is not None :
437448 safe = version .title ().replace (" " , "" ).replace ("-" , "" )
438449 Validator .__name__ = Validator .__qualname__ = f"{ safe } Validator"
439- Validator = validates (version )(Validator )
450+ Validator = validates (version )(Validator ) # type: ignore[misc]
440451
441452 return Validator
442453
0 commit comments