1+ from __future__ import annotations
2+
13import sys
4+ from dataclasses import dataclass
25from functools import lru_cache
6+ from typing import TYPE_CHECKING
37
48from asdf .tagged import Tagged
59from asdf .util import get_class_name , uri_match
610
711from ._extension import ExtensionProxy
812
13+ if TYPE_CHECKING :
14+ from collections .abc import Iterable , Iterator , Mapping
15+ from typing import Any
16+
17+ from asdf .exceptions import ValidationError
18+ from asdf .extension import Validator
19+ from asdf .typing import TreeKey
20+
921
1022def _resolve_type (path ):
1123 """
@@ -317,32 +329,26 @@ def _get_cached_extension_manager(extensions):
317329
318330class ValidatorManager :
319331 """
320- Wraps a list of custom validators and indexes them by schema property .
332+ Wraps a list of custom validators and binds them to their associated schemas .
321333
322334 Parameters
323335 ----------
324336 validators : iterable of asdf.extension.Validator
325337 List of validators to manage.
326338 """
327339
328- def __init__ (self , validators ):
329- self ._validators = list (validators )
340+ def __init__ (self , validators : Iterable [Validator ]):
341+ self ._validators = {}
342+ for validator in validators :
343+ if validator .schema_property not in self ._validators :
344+ self ._validators [validator .schema_property ] = set ()
330345
331- self ._validators_by_schema_property = {}
332- for validator in self ._validators :
333- if validator .schema_property not in self ._validators_by_schema_property :
334- self ._validators_by_schema_property [validator .schema_property ] = set ()
335- self ._validators_by_schema_property [validator .schema_property ].add (validator )
346+ self ._validators [validator .schema_property ].add (validator )
336347
337- self ._jsonschema_validators_by_schema_property = {}
338- for schema_property in self ._validators_by_schema_property :
339- self ._jsonschema_validators_by_schema_property [schema_property ] = self ._get_jsonschema_validator (
340- schema_property ,
341- )
342-
343- def validate (self , schema_property , schema_property_value , node , schema ):
344- """
345- Validate an ASDF tree node against custom validators for a schema property.
348+ def validate (
349+ self , schema_property : str , schema_property_value : Any , node : Tagged , schema : Mapping [TreeKey , Any ]
350+ ) -> Iterator [ValidationError ]:
351+ """Validate an ASDF tree node against custom validators for a schema property.
346352
347353 Parameters
348354 ----------
@@ -360,27 +366,34 @@ def validate(self, schema_property, schema_property_value, node, schema):
360366 ------
361367 asdf.exceptions.ValidationError
362368 """
363- if schema_property in self ._validators_by_schema_property :
364- for validator in self ._validators_by_schema_property [schema_property ]:
365- if _validator_matches (validator , node ):
366- yield from validator .validate (schema_property_value , node , schema )
369+ for validator in self ._validators [schema_property ]:
370+ if _validator_matches (validator , node ):
371+ yield from validator .validate (schema_property_value , node , schema )
367372
368- def get_jsonschema_validators (self ):
369- """
370- Get a dictionary of validator methods suitable for use
371- with the jsonschema library.
373+ def get_jsonschema_validators (self ) -> dict [str , JsonSchemaValidators ]:
374+ """Get a dictionary mapping schema names to ``jsonschema``-compatible validator functions."""
375+ return {
376+ schema_property : JsonSchemaValidators (schema_property , frozenset (validators ))
377+ for schema_property , validators in self ._validators .items ()
378+ }
372379
373- Returns
374- -------
375- dict of str: callable
376- """
377- return dict (self ._jsonschema_validators_by_schema_property )
378380
379- def _get_jsonschema_validator (self , schema_property ):
380- def _validator (_ , schema_property_value , node , schema ):
381- return self .validate (schema_property , schema_property_value , node , schema )
381+ @dataclass (frozen = True , slots = True )
382+ class JsonSchemaValidators :
383+ """Callable that wraps a set of `Validator` objects to make them compatible with `jsonschema`.
384+
385+ Each validator is always passed `schema_property` as its first argument regardless of the actual input schema.
386+ """
387+
388+ schema_property : str
389+ validators : frozenset [Validator ]
382390
383- return _validator
391+ def __call__ (
392+ self , _schema_property : Any , schema_property_value : Any , node : Tagged , schema : Mapping [TreeKey , Any ]
393+ ) -> Iterator [ValidationError ]:
394+ for validator in self .validators :
395+ if _validator_matches (validator , node ):
396+ yield from validator .validate (schema_property_value , node , schema )
384397
385398
386399def _validator_matches (validator , node ):
0 commit comments