Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
validators.py1411 linesDownload Raw Back to jsonschema
1"""2Creation and extension of validators, with implementations for existing drafts.3"""4from __future__ import annotations5 6from collections import deque7from collections.abc import Iterable, Mapping, Sequence8from functools import lru_cache9from operator import methodcaller10from typing import TYPE_CHECKING11from urllib.parse import unquote, urldefrag, urljoin, urlsplit12from warnings import warn13import contextlib14import json15import reprlib16import warnings17 18from attrs import define, field, fields19from jsonschema_specifications import REGISTRY as SPECIFICATIONS20from rpds import HashTrieMap21import referencing.exceptions22import referencing.jsonschema23 24from jsonschema import (25    _format,26    _keywords,27    _legacy_keywords,28    _types,29    _typing,30    _utils,31    exceptions,32)33 34if TYPE_CHECKING:35    from jsonschema.protocols import Validator36 37_UNSET = _utils.Unset()38 39_VALIDATORS: dict[str, Validator] = {}40_META_SCHEMAS = _utils.URIDict()41 42 43def __getattr__(name):44    if name == "ErrorTree":45        warnings.warn(46            "Importing ErrorTree from jsonschema.validators is deprecated. "47            "Instead import it from jsonschema.exceptions.",48            DeprecationWarning,49            stacklevel=2,50        )51        from jsonschema.exceptions import ErrorTree52        return ErrorTree53    elif name == "validators":54        warnings.warn(55            "Accessing jsonschema.validators.validators is deprecated. "56            "Use jsonschema.validators.validator_for with a given schema.",57            DeprecationWarning,58            stacklevel=2,59        )60        return _VALIDATORS61    elif name == "meta_schemas":62        warnings.warn(63            "Accessing jsonschema.validators.meta_schemas is deprecated. "64            "Use jsonschema.validators.validator_for with a given schema.",65            DeprecationWarning,66            stacklevel=2,67        )68        return _META_SCHEMAS69    elif name == "RefResolver":70        warnings.warn(71            _RefResolver._DEPRECATION_MESSAGE,72            DeprecationWarning,73            stacklevel=2,74        )75        return _RefResolver76    raise AttributeError(f"module {__name__} has no attribute {name}")77 78 79def validates(version):80    """81    Register the decorated validator for a ``version`` of the specification.82 83    Registered validators and their meta schemas will be considered when84    parsing :kw:`$schema` keywords' URIs.85 86    Arguments:87 88        version (str):89 90            An identifier to use as the version's name91 92    Returns:93 94        collections.abc.Callable:95 96            a class decorator to decorate the validator with the version97 98    """99 100    def _validates(cls):101        _VALIDATORS[version] = cls102        meta_schema_id = cls.ID_OF(cls.META_SCHEMA)103        _META_SCHEMAS[meta_schema_id] = cls104        return cls105    return _validates106 107 108def _warn_for_remote_retrieve(uri: str):109    from urllib.request import Request, urlopen110    headers = {"User-Agent": "python-jsonschema (deprecated $ref resolution)"}111    request = Request(uri, headers=headers)  # noqa: S310112    with urlopen(request) as response:  # noqa: S310113        warnings.warn(114            "Automatically retrieving remote references can be a security "115            "vulnerability and is discouraged by the JSON Schema "116            "specifications. Relying on this behavior is deprecated "117            "and will shortly become an error. If you are sure you want to "118            "remotely retrieve your reference and that it is safe to do so, "119            "you can find instructions for doing so via referencing.Registry "120            "in the referencing documentation "121            "(https://referencing.readthedocs.org).",122            DeprecationWarning,123            stacklevel=9,  # Ha ha ha ha magic numbers :/124        )125        return referencing.Resource.from_contents(126            json.load(response),127            default_specification=referencing.jsonschema.DRAFT202012,128        )129 130 131_REMOTE_WARNING_REGISTRY = SPECIFICATIONS.combine(132    referencing.Registry(retrieve=_warn_for_remote_retrieve),  # type: ignore[call-arg]133)134 135 136def create(137    meta_schema: referencing.jsonschema.ObjectSchema,138    validators: (139        Mapping[str, _typing.SchemaKeywordValidator]140        | Iterable[tuple[str, _typing.SchemaKeywordValidator]]141    ) = (),142    version: str | None = None,143    type_checker: _types.TypeChecker = _types.draft202012_type_checker,144    format_checker: _format.FormatChecker = _format.draft202012_format_checker,145    id_of: _typing.id_of = referencing.jsonschema.DRAFT202012.id_of,146    applicable_validators: _typing.ApplicableValidators = methodcaller(147        "items",148    ),149) -> type[Validator]:150    """151    Create a new validator class.152 153    Arguments:154 155        meta_schema:156 157            the meta schema for the new validator class158 159        validators:160 161            a mapping from names to callables, where each callable will162            validate the schema property with the given name.163 164            Each callable should take 4 arguments:165 166                1. a validator instance,167                2. the value of the property being validated within the168                   instance169                3. the instance170                4. the schema171 172        version:173 174            an identifier for the version that this validator class will175            validate. If provided, the returned validator class will176            have its ``__name__`` set to include the version, and also177            will have `jsonschema.validators.validates` automatically178            called for the given version.179 180        type_checker:181 182            a type checker, used when applying the :kw:`type` keyword.183 184            If unprovided, a `jsonschema.TypeChecker` will be created185            with a set of default types typical of JSON Schema drafts.186 187        format_checker:188 189            a format checker, used when applying the :kw:`format` keyword.190 191            If unprovided, a `jsonschema.FormatChecker` will be created192            with a set of default formats typical of JSON Schema drafts.193 194        id_of:195 196            A function that given a schema, returns its ID.197 198        applicable_validators:199 200            A function that, given a schema, returns the list of201            applicable schema keywords and associated values202            which will be used to validate the instance.203            This is mostly used to support pre-draft 7 versions of JSON Schema204            which specified behavior around ignoring keywords if they were205            siblings of a ``$ref`` keyword. If you're not attempting to206            implement similar behavior, you can typically ignore this argument207            and leave it at its default.208 209    Returns:210 211        a new `jsonschema.protocols.Validator` class212 213    """214    # preemptively don't shadow the `Validator.format_checker` local215    format_checker_arg = format_checker216 217    specification = referencing.jsonschema.specification_with(218        dialect_id=id_of(meta_schema) or "urn:unknown-dialect",219        default=referencing.Specification.OPAQUE,220    )221 222    @define223    class Validator:224 225        VALIDATORS = dict(validators)  # noqa: RUF012226        META_SCHEMA = dict(meta_schema)  # noqa: RUF012227        TYPE_CHECKER = type_checker228        FORMAT_CHECKER = format_checker_arg229        ID_OF = staticmethod(id_of)230 231        _APPLICABLE_VALIDATORS = applicable_validators232        _validators = field(init=False, repr=False, eq=False)233 234        schema: referencing.jsonschema.Schema = field(repr=reprlib.repr)235        _ref_resolver = field(default=None, repr=False, alias="resolver")236        format_checker: _format.FormatChecker | None = field(default=None)237        # TODO: include new meta-schemas added at runtime238        _registry: referencing.jsonschema.SchemaRegistry = field(239            default=_REMOTE_WARNING_REGISTRY,240            kw_only=True,241            repr=False,242        )243        _resolver = field(244            alias="_resolver",245            default=None,246            kw_only=True,247            repr=False,248        )249 250        def __init_subclass__(cls):251            warnings.warn(252                (253                    "Subclassing validator classes is not intended to "254                    "be part of their public API. A future version "255                    "will make doing so an error, as the behavior of "256                    "subclasses isn't guaranteed to stay the same "257                    "between releases of jsonschema. Instead, prefer "258                    "composition of validators, wrapping them in an object "259                    "owned entirely by the downstream library."260                ),261                DeprecationWarning,262                stacklevel=2,263            )264 265            def evolve(self, **changes):266                cls = self.__class__267                schema = changes.setdefault("schema", self.schema)268                NewValidator = validator_for(schema, default=cls)269 270                for field in fields(cls):  # noqa: F402271                    if not field.init:272                        continue273                    attr_name = field.name274                    init_name = field.alias275                    if init_name not in changes:276                        changes[init_name] = getattr(self, attr_name)277 278                return NewValidator(**changes)279 280            cls.evolve = evolve281 282        def __attrs_post_init__(self):283            if self._resolver is None:284                registry = self._registry285                if registry is not _REMOTE_WARNING_REGISTRY:286                    registry = SPECIFICATIONS.combine(registry)287                resource = specification.create_resource(self.schema)288                self._resolver = registry.resolver_with_root(resource)289 290            if self.schema is True or self.schema is False:291                self._validators = []292            else:293                self._validators = [294                    (self.VALIDATORS[k], k, v)295                    for k, v in applicable_validators(self.schema)296                    if k in self.VALIDATORS297                ]298 299            # REMOVEME: Legacy ref resolution state management.300            push_scope = getattr(self._ref_resolver, "push_scope", None)301            if push_scope is not None:302                id = id_of(self.schema)303                if id is not None:304                    push_scope(id)305 306        @classmethod307        def check_schema(cls, schema, format_checker=_UNSET):308            Validator = validator_for(cls.META_SCHEMA, default=cls)309            if format_checker is _UNSET:310                format_checker = Validator.FORMAT_CHECKER311            validator = Validator(312                schema=cls.META_SCHEMA,313                format_checker=format_checker,314            )315            for error in validator.iter_errors(schema):316                raise exceptions.SchemaError.create_from(error)317 318        @property319        def resolver(self):320            warnings.warn(321                (322                    f"Accessing {self.__class__.__name__}.resolver is "323                    "deprecated as of v4.18.0, in favor of the "324                    "https://github.com/python-jsonschema/referencing "325                    "library, which provides more compliant referencing "326                    "behavior as well as more flexible APIs for "327                    "customization."328                ),329                DeprecationWarning,330                stacklevel=2,331            )332            if self._ref_resolver is None:333                self._ref_resolver = _RefResolver.from_schema(334                    self.schema,335                    id_of=id_of,336                )337            return self._ref_resolver338 339        def evolve(self, **changes):340            schema = changes.setdefault("schema", self.schema)341            NewValidator = validator_for(schema, default=self.__class__)342 343            for (attr_name, init_name) in evolve_fields:344                if init_name not in changes:345                    changes[init_name] = getattr(self, attr_name)346 347            return NewValidator(**changes)348 349        def iter_errors(self, instance, _schema=None):350            if _schema is not None:351                warnings.warn(352                    (353                        "Passing a schema to Validator.iter_errors "354                        "is deprecated and will be removed in a future "355                        "release. Call validator.evolve(schema=new_schema)."356                        "iter_errors(...) instead."357                    ),358                    DeprecationWarning,359                    stacklevel=2,360                )361                validators = [362                    (self.VALIDATORS[k], k, v)363                    for k, v in applicable_validators(_schema)364                    if k in self.VALIDATORS365                ]366            else:367                _schema, validators = self.schema, self._validators368 369            if _schema is True:370                return371            elif _schema is False:372                yield exceptions.ValidationError(373                    f"False schema does not allow {instance!r}",374                    validator=None,375                    validator_value=None,376                    instance=instance,377                    schema=_schema,378                )379                return380 381            for validator, k, v in validators:382                errors = validator(self, v, instance, _schema) or ()383                for error in errors:384                    # set details if not already set by the called fn385                    error._set(386                        validator=k,387                        validator_value=v,388                        instance=instance,389                        schema=_schema,390                        type_checker=self.TYPE_CHECKER,391                    )392                    if k not in {"if", "$ref"}:393                        error.schema_path.appendleft(k)394                    yield error395 396        def descend(397            self,398            instance,399            schema,400            path=None,401            schema_path=None,402            resolver=None,403        ):404            if schema is True:405                return406            elif schema is False:407                yield exceptions.ValidationError(408                    f"False schema does not allow {instance!r}",409                    validator=None,410                    validator_value=None,411                    instance=instance,412                    schema=schema,413                )414                return415 416            if self._ref_resolver is not None:417                evolved = self.evolve(schema=schema)418            else:419                if resolver is None:420                    resolver = self._resolver.in_subresource(421                        specification.create_resource(schema),422                    )423                evolved = self.evolve(schema=schema, _resolver=resolver)424 425            for k, v in applicable_validators(schema):426                validator = evolved.VALIDATORS.get(k)427                if validator is None:428                    continue429 430                errors = validator(evolved, v, instance, schema) or ()431                for error in errors:432                    # set details if not already set by the called fn433                    error._set(434                        validator=k,435                        validator_value=v,436                        instance=instance,437                        schema=schema,438                        type_checker=evolved.TYPE_CHECKER,439                    )440                    if k not in {"if", "$ref"}:441                        error.schema_path.appendleft(k)442                    if path is not None:443                        error.path.appendleft(path)444                    if schema_path is not None:445                        error.schema_path.appendleft(schema_path)446                    yield error447 448        def validate(self, *args, **kwargs):449            for error in self.iter_errors(*args, **kwargs):450                raise error451 452        def is_type(self, instance, type):453            try:454                return self.TYPE_CHECKER.is_type(instance, type)455            except exceptions.UndefinedTypeCheck:456                exc = exceptions.UnknownType(type, instance, self.schema)457                raise exc from None458 459        def _validate_reference(self, ref, instance):460            if self._ref_resolver is None:461                try:462                    resolved = self._resolver.lookup(ref)463                except referencing.exceptions.Unresolvable as err:464                    raise exceptions._WrappedReferencingError(err) from err465 466                return self.descend(467                    instance,468                    resolved.contents,469                    resolver=resolved.resolver,470                )471            else:472                resolve = getattr(self._ref_resolver, "resolve", None)473                if resolve is None:474                    with self._ref_resolver.resolving(ref) as resolved:475                        return self.descend(instance, resolved)476                else:477                    scope, resolved = resolve(ref)478                    self._ref_resolver.push_scope(scope)479 480                    try:481                        return list(self.descend(instance, resolved))482                    finally:483                        self._ref_resolver.pop_scope()484 485        def is_valid(self, instance, _schema=None):486            if _schema is not None:487                warnings.warn(488                    (489                        "Passing a schema to Validator.is_valid is deprecated "490                        "and will be removed in a future release. Call "491                        "validator.evolve(schema=new_schema).is_valid(...) "492                        "instead."493                    ),494                    DeprecationWarning,495                    stacklevel=2,496                )497                self = self.evolve(schema=_schema)498 499            error = next(self.iter_errors(instance), None)500            return error is None501 502    evolve_fields = [503        (field.name, field.alias)504        for field in fields(Validator)505        if field.init506    ]507 508    if version is not None:509        safe = version.title().replace(" ", "").replace("-", "")510        Validator.__name__ = Validator.__qualname__ = f"{safe}Validator"511        Validator = validates(version)(Validator)  # type: ignore[misc]512 513    return Validator  # type: ignore[return-value]514 515 516def extend(517    validator,518    validators=(),519    version=None,520    type_checker=None,521    format_checker=None,522):523    """524    Create a new validator class by extending an existing one.525 526    Arguments:527 528        validator (jsonschema.protocols.Validator):529 530            an existing validator class531 532        validators (collections.abc.Mapping):533 534            a mapping of new validator callables to extend with, whose535            structure is as in `create`.536 537            .. note::538 539                Any validator callables with the same name as an540                existing one will (silently) replace the old validator541                callable entirely, effectively overriding any validation542                done in the "parent" validator class.543 544                If you wish to instead extend the behavior of a parent's545                validator callable, delegate and call it directly in546                the new validator function by retrieving it using547                ``OldValidator.VALIDATORS["validation_keyword_name"]``.548 549        version (str):550 551            a version for the new validator class552 553        type_checker (jsonschema.TypeChecker):554 555            a type checker, used when applying the :kw:`type` keyword.556 557            If unprovided, the type checker of the extended558            `jsonschema.protocols.Validator` will be carried along.559 560        format_checker (jsonschema.FormatChecker):561 562            a format checker, used when applying the :kw:`format` keyword.563 564            If unprovided, the format checker of the extended565            `jsonschema.protocols.Validator` will be carried along.566 567    Returns:568 569        a new `jsonschema.protocols.Validator` class extending the one570        provided571 572    .. note:: Meta Schemas573 574        The new validator class will have its parent's meta schema.575 576        If you wish to change or extend the meta schema in the new577        validator class, modify ``META_SCHEMA`` directly on the returned578        class. Note that no implicit copying is done, so a copy should579        likely be made before modifying it, in order to not affect the580        old validator.581 582    """583    all_validators = dict(validator.VALIDATORS)584    all_validators.update(validators)585 586    if type_checker is None:587        type_checker = validator.TYPE_CHECKER588    if format_checker is None:589        format_checker = validator.FORMAT_CHECKER590    return create(591        meta_schema=validator.META_SCHEMA,592        validators=all_validators,593        version=version,594        type_checker=type_checker,595        format_checker=format_checker,596        id_of=validator.ID_OF,597        applicable_validators=validator._APPLICABLE_VALIDATORS,598    )599 600 601Draft3Validator = create(602    meta_schema=SPECIFICATIONS.contents(603        "http://json-schema.org/draft-03/schema#",604    ),605    validators={606        "$ref": _keywords.ref,607        "additionalItems": _legacy_keywords.additionalItems,608        "additionalProperties": _keywords.additionalProperties,609        "dependencies": _legacy_keywords.dependencies_draft3,610        "disallow": _legacy_keywords.disallow_draft3,611        "divisibleBy": _keywords.multipleOf,612        "enum": _keywords.enum,613        "extends": _legacy_keywords.extends_draft3,614        "format": _keywords.format,615        "items": _legacy_keywords.items_draft3_draft4,616        "maxItems": _keywords.maxItems,617        "maxLength": _keywords.maxLength,618        "maximum": _legacy_keywords.maximum_draft3_draft4,619        "minItems": _keywords.minItems,620        "minLength": _keywords.minLength,621        "minimum": _legacy_keywords.minimum_draft3_draft4,622        "pattern": _keywords.pattern,623        "patternProperties": _keywords.patternProperties,624        "properties": _legacy_keywords.properties_draft3,625        "type": _legacy_keywords.type_draft3,626        "uniqueItems": _keywords.uniqueItems,627    },628    type_checker=_types.draft3_type_checker,629    format_checker=_format.draft3_format_checker,630    version="draft3",631    id_of=referencing.jsonschema.DRAFT3.id_of,632    applicable_validators=_legacy_keywords.ignore_ref_siblings,633)634 635Draft4Validator = create(636    meta_schema=SPECIFICATIONS.contents(637        "http://json-schema.org/draft-04/schema#",638    ),639    validators={640        "$ref": _keywords.ref,641        "additionalItems": _legacy_keywords.additionalItems,642        "additionalProperties": _keywords.additionalProperties,643        "allOf": _keywords.allOf,644        "anyOf": _keywords.anyOf,645        "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7,646        "enum": _keywords.enum,647        "format": _keywords.format,648        "items": _legacy_keywords.items_draft3_draft4,649        "maxItems": _keywords.maxItems,650        "maxLength": _keywords.maxLength,651        "maxProperties": _keywords.maxProperties,652        "maximum": _legacy_keywords.maximum_draft3_draft4,653        "minItems": _keywords.minItems,654        "minLength": _keywords.minLength,655        "minProperties": _keywords.minProperties,656        "minimum": _legacy_keywords.minimum_draft3_draft4,657        "multipleOf": _keywords.multipleOf,658        "not": _keywords.not_,659        "oneOf": _keywords.oneOf,660        "pattern": _keywords.pattern,661        "patternProperties": _keywords.patternProperties,662        "properties": _keywords.properties,663        "required": _keywords.required,664        "type": _keywords.type,665        "uniqueItems": _keywords.uniqueItems,666    },667    type_checker=_types.draft4_type_checker,668    format_checker=_format.draft4_format_checker,669    version="draft4",670    id_of=referencing.jsonschema.DRAFT4.id_of,671    applicable_validators=_legacy_keywords.ignore_ref_siblings,672)673 674Draft6Validator = create(675    meta_schema=SPECIFICATIONS.contents(676        "http://json-schema.org/draft-06/schema#",677    ),678    validators={679        "$ref": _keywords.ref,680        "additionalItems": _legacy_keywords.additionalItems,681        "additionalProperties": _keywords.additionalProperties,682        "allOf": _keywords.allOf,683        "anyOf": _keywords.anyOf,684        "const": _keywords.const,685        "contains": _legacy_keywords.contains_draft6_draft7,686        "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7,687        "enum": _keywords.enum,688        "exclusiveMaximum": _keywords.exclusiveMaximum,689        "exclusiveMinimum": _keywords.exclusiveMinimum,690        "format": _keywords.format,691        "items": _legacy_keywords.items_draft6_draft7_draft201909,692        "maxItems": _keywords.maxItems,693        "maxLength": _keywords.maxLength,694        "maxProperties": _keywords.maxProperties,695        "maximum": _keywords.maximum,696        "minItems": _keywords.minItems,697        "minLength": _keywords.minLength,698        "minProperties": _keywords.minProperties,699        "minimum": _keywords.minimum,700        "multipleOf": _keywords.multipleOf,701        "not": _keywords.not_,702        "oneOf": _keywords.oneOf,703        "pattern": _keywords.pattern,704        "patternProperties": _keywords.patternProperties,705        "properties": _keywords.properties,706        "propertyNames": _keywords.propertyNames,707        "required": _keywords.required,708        "type": _keywords.type,709        "uniqueItems": _keywords.uniqueItems,710    },711    type_checker=_types.draft6_type_checker,712    format_checker=_format.draft6_format_checker,713    version="draft6",714    id_of=referencing.jsonschema.DRAFT6.id_of,715    applicable_validators=_legacy_keywords.ignore_ref_siblings,716)717 718Draft7Validator = create(719    meta_schema=SPECIFICATIONS.contents(720        "http://json-schema.org/draft-07/schema#",721    ),722    validators={723        "$ref": _keywords.ref,724        "additionalItems": _legacy_keywords.additionalItems,725        "additionalProperties": _keywords.additionalProperties,726        "allOf": _keywords.allOf,727        "anyOf": _keywords.anyOf,728        "const": _keywords.const,729        "contains": _legacy_keywords.contains_draft6_draft7,730        "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7,731        "enum": _keywords.enum,732        "exclusiveMaximum": _keywords.exclusiveMaximum,733        "exclusiveMinimum": _keywords.exclusiveMinimum,734        "format": _keywords.format,735        "if": _keywords.if_,736        "items": _legacy_keywords.items_draft6_draft7_draft201909,737        "maxItems": _keywords.maxItems,738        "maxLength": _keywords.maxLength,739        "maxProperties": _keywords.maxProperties,740        "maximum": _keywords.maximum,741        "minItems": _keywords.minItems,742        "minLength": _keywords.minLength,743        "minProperties": _keywords.minProperties,744        "minimum": _keywords.minimum,745        "multipleOf": _keywords.multipleOf,746        "not": _keywords.not_,747        "oneOf": _keywords.oneOf,748        "pattern": _keywords.pattern,749        "patternProperties": _keywords.patternProperties,750        "properties": _keywords.properties,751        "propertyNames": _keywords.propertyNames,752        "required": _keywords.required,753        "type": _keywords.type,754        "uniqueItems": _keywords.uniqueItems,755    },756    type_checker=_types.draft7_type_checker,757    format_checker=_format.draft7_format_checker,758    version="draft7",759    id_of=referencing.jsonschema.DRAFT7.id_of,760    applicable_validators=_legacy_keywords.ignore_ref_siblings,761)762 763Draft201909Validator = create(764    meta_schema=SPECIFICATIONS.contents(765        "https://json-schema.org/draft/2019-09/schema",766    ),767    validators={768        "$recursiveRef": _legacy_keywords.recursiveRef,769        "$ref": _keywords.ref,770        "additionalItems": _legacy_keywords.additionalItems,771        "additionalProperties": _keywords.additionalProperties,772        "allOf": _keywords.allOf,773        "anyOf": _keywords.anyOf,774        "const": _keywords.const,775        "contains": _keywords.contains,776        "dependentRequired": _keywords.dependentRequired,777        "dependentSchemas": _keywords.dependentSchemas,778        "enum": _keywords.enum,779        "exclusiveMaximum": _keywords.exclusiveMaximum,780        "exclusiveMinimum": _keywords.exclusiveMinimum,781        "format": _keywords.format,782        "if": _keywords.if_,783        "items": _legacy_keywords.items_draft6_draft7_draft201909,784        "maxItems": _keywords.maxItems,785        "maxLength": _keywords.maxLength,786        "maxProperties": _keywords.maxProperties,787        "maximum": _keywords.maximum,788        "minItems": _keywords.minItems,789        "minLength": _keywords.minLength,790        "minProperties": _keywords.minProperties,791        "minimum": _keywords.minimum,792        "multipleOf": _keywords.multipleOf,793        "not": _keywords.not_,794        "oneOf": _keywords.oneOf,795        "pattern": _keywords.pattern,796        "patternProperties": _keywords.patternProperties,797        "properties": _keywords.properties,798        "propertyNames": _keywords.propertyNames,799        "required": _keywords.required,800        "type": _keywords.type,801        "unevaluatedItems": _legacy_keywords.unevaluatedItems_draft2019,802        "unevaluatedProperties": (803            _legacy_keywords.unevaluatedProperties_draft2019804        ),805        "uniqueItems": _keywords.uniqueItems,806    },807    type_checker=_types.draft201909_type_checker,808    format_checker=_format.draft201909_format_checker,809    version="draft2019-09",810)811 812Draft202012Validator = create(813    meta_schema=SPECIFICATIONS.contents(814        "https://json-schema.org/draft/2020-12/schema",815    ),816    validators={817        "$dynamicRef": _keywords.dynamicRef,818        "$ref": _keywords.ref,819        "additionalProperties": _keywords.additionalProperties,820        "allOf": _keywords.allOf,821        "anyOf": _keywords.anyOf,822        "const": _keywords.const,823        "contains": _keywords.contains,824        "dependentRequired": _keywords.dependentRequired,825        "dependentSchemas": _keywords.dependentSchemas,826        "enum": _keywords.enum,827        "exclusiveMaximum": _keywords.exclusiveMaximum,828        "exclusiveMinimum": _keywords.exclusiveMinimum,829        "format": _keywords.format,830        "if": _keywords.if_,831        "items": _keywords.items,832        "maxItems": _keywords.maxItems,833        "maxLength": _keywords.maxLength,834        "maxProperties": _keywords.maxProperties,835        "maximum": _keywords.maximum,836        "minItems": _keywords.minItems,837        "minLength": _keywords.minLength,838        "minProperties": _keywords.minProperties,839        "minimum": _keywords.minimum,840        "multipleOf": _keywords.multipleOf,841        "not": _keywords.not_,842        "oneOf": _keywords.oneOf,843        "pattern": _keywords.pattern,844        "patternProperties": _keywords.patternProperties,845        "prefixItems": _keywords.prefixItems,846        "properties": _keywords.properties,847        "propertyNames": _keywords.propertyNames,848        "required": _keywords.required,849        "type": _keywords.type,850        "unevaluatedItems": _keywords.unevaluatedItems,851        "unevaluatedProperties": _keywords.unevaluatedProperties,852        "uniqueItems": _keywords.uniqueItems,853    },854    type_checker=_types.draft202012_type_checker,855    format_checker=_format.draft202012_format_checker,856    version="draft2020-12",857)858 859_LATEST_VERSION: type[Validator] = Draft202012Validator860 861 862class _RefResolver:863    """864    Resolve JSON References.865 866    Arguments:867 868        base_uri (str):869 870            The URI of the referring document871 872        referrer:873 874            The actual referring document875 876        store (dict):877 878            A mapping from URIs to documents to cache879 880        cache_remote (bool):881 882            Whether remote refs should be cached after first resolution883 884        handlers (dict):885 886            A mapping from URI schemes to functions that should be used887            to retrieve them888 889        urljoin_cache (:func:`functools.lru_cache`):890 891            A cache that will be used for caching the results of joining892            the resolution scope to subscopes.893 894        remote_cache (:func:`functools.lru_cache`):895 896            A cache that will be used for caching the results of897            resolved remote URLs.898 899    Attributes:900 901        cache_remote (bool):902 903            Whether remote refs should be cached after first resolution904 905    .. deprecated:: v4.18.0906 907        ``RefResolver`` has been deprecated in favor of `referencing`.908 909    """910 911    _DEPRECATION_MESSAGE = (912        "jsonschema.RefResolver is deprecated as of v4.18.0, in favor of the "913        "https://github.com/python-jsonschema/referencing library, which "914        "provides more compliant referencing behavior as well as more "915        "flexible APIs for customization. A future release will remove "916        "RefResolver. Please file a feature request (on referencing) if you "917        "are missing an API for the kind of customization you need."918    )919 920    def __init__(921        self,922        base_uri,923        referrer,924        store=HashTrieMap(),925        cache_remote=True,926        handlers=(),927        urljoin_cache=None,928        remote_cache=None,929    ):930        if urljoin_cache is None:931            urljoin_cache = lru_cache(1024)(urljoin)932        if remote_cache is None:933            remote_cache = lru_cache(1024)(self.resolve_from_url)934 935        self.referrer = referrer936        self.cache_remote = cache_remote937        self.handlers = dict(handlers)938 939        self._scopes_stack = [base_uri]940 941        self.store = _utils.URIDict(942            (uri, each.contents) for uri, each in SPECIFICATIONS.items()943        )944        self.store.update(945            (id, each.META_SCHEMA) for id, each in _META_SCHEMAS.items()946        )947        self.store.update(store)948        self.store.update(949            (schema["$id"], schema)950            for schema in store.values()951            if isinstance(schema, Mapping) and "$id" in schema952        )953        self.store[base_uri] = referrer954 955        self._urljoin_cache = urljoin_cache956        self._remote_cache = remote_cache957 958    @classmethod959    def from_schema(  # noqa: D417960        cls,961        schema,962        id_of=referencing.jsonschema.DRAFT202012.id_of,963        *args,964        **kwargs,965    ):966        """967        Construct a resolver from a JSON schema object.968 969        Arguments:970 971            schema:972 973                the referring schema974 975        Returns:976 977            `_RefResolver`978 979        """980        return cls(base_uri=id_of(schema) or "", referrer=schema, *args, **kwargs)  # noqa: B026, E501981 982    def push_scope(self, scope):983        """984        Enter a given sub-scope.985 986        Treats further dereferences as being performed underneath the987        given scope.988        """989        self._scopes_stack.append(990            self._urljoin_cache(self.resolution_scope, scope),991        )992 993    def pop_scope(self):994        """995        Exit the most recent entered scope.996 997        Treats further dereferences as being performed underneath the998        original scope.999 1000        Don't call this method more times than `push_scope` has been1001        called.1002        """1003        try:1004            self._scopes_stack.pop()1005        except IndexError:1006            raise exceptions._RefResolutionError(1007                "Failed to pop the scope from an empty stack. "1008                "`pop_scope()` should only be called once for every "1009                "`push_scope()`",1010            ) from None1011 1012    @property1013    def resolution_scope(self):1014        """1015        Retrieve the current resolution scope.1016        """1017        return self._scopes_stack[-1]1018 1019    @property1020    def base_uri(self):1021        """1022        Retrieve the current base URI, not including any fragment.1023        """1024        uri, _ = urldefrag(self.resolution_scope)1025        return uri1026 1027    @contextlib.contextmanager1028    def in_scope(self, scope):1029        """1030        Temporarily enter the given scope for the duration of the context.1031 1032        .. deprecated:: v4.0.01033        """1034        warnings.warn(1035            "jsonschema.RefResolver.in_scope is deprecated and will be "1036            "removed in a future release.",1037            DeprecationWarning,1038            stacklevel=3,1039        )1040        self.push_scope(scope)1041        try:1042            yield1043        finally:1044            self.pop_scope()1045 1046    @contextlib.contextmanager1047    def resolving(self, ref):1048        """1049        Resolve the given ``ref`` and enter its resolution scope.1050 1051        Exits the scope on exit of this context manager.1052 1053        Arguments:1054 1055            ref (str):1056 1057                The reference to resolve1058 1059        """1060        url, resolved = self.resolve(ref)1061        self.push_scope(url)1062        try:1063            yield resolved1064        finally:1065            self.pop_scope()1066 1067    def _find_in_referrer(self, key):1068        return self._get_subschemas_cache()[key]1069 1070    @lru_cache  # noqa: B0191071    def _get_subschemas_cache(self):1072        cache = {key: [] for key in _SUBSCHEMAS_KEYWORDS}1073        for keyword, subschema in _search_schema(1074            self.referrer, _match_subschema_keywords,1075        ):1076            cache[keyword].append(subschema)1077        return cache1078 1079    @lru_cache  # noqa: B0191080    def _find_in_subschemas(self, url):1081        subschemas = self._get_subschemas_cache()["$id"]1082        if not subschemas:1083            return None1084        uri, fragment = urldefrag(url)1085        for subschema in subschemas:1086            id = subschema["$id"]1087            if not isinstance(id, str):1088                continue1089            target_uri = self._urljoin_cache(self.resolution_scope, id)1090            if target_uri.rstrip("/") == uri.rstrip("/"):1091                if fragment:1092                    subschema = self.resolve_fragment(subschema, fragment)1093                self.store[url] = subschema1094                return url, subschema1095        return None1096 1097    def resolve(self, ref):1098        """1099        Resolve the given reference.1100        """1101        url = self._urljoin_cache(self.resolution_scope, ref).rstrip("/")1102 1103        match = self._find_in_subschemas(url)1104        if match is not None:1105            return match1106 1107        return url, self._remote_cache(url)1108 1109    def resolve_from_url(self, url):1110        """1111        Resolve the given URL.1112        """1113        url, fragment = urldefrag(url)1114        if not url:1115            url = self.base_uri1116 1117        try:1118            document = self.store[url]1119        except KeyError:1120            try:1121                document = self.resolve_remote(url)1122            except Exception as exc:1123                raise exceptions._RefResolutionError(exc) from exc1124 1125        return self.resolve_fragment(document, fragment)1126 1127    def resolve_fragment(self, document, fragment):1128        """1129        Resolve a ``fragment`` within the referenced ``document``.1130 1131        Arguments:1132 1133            document:1134 1135                The referent document1136 1137            fragment (str):1138 1139                a URI fragment to resolve within it1140 1141        """1142        fragment = fragment.lstrip("/")1143 1144        if not fragment:1145            return document1146 1147        if document is self.referrer:1148            find = self._find_in_referrer1149        else:1150 1151            def find(key):1152                yield from _search_schema(document, _match_keyword(key))1153 1154        for keyword in ["$anchor", "$dynamicAnchor"]:1155            for subschema in find(keyword):1156                if fragment == subschema[keyword]:1157                    return subschema1158        for keyword in ["id", "$id"]:1159            for subschema in find(keyword):1160                if "#" + fragment == subschema[keyword]:1161                    return subschema1162 1163        # Resolve via path1164        parts = unquote(fragment).split("/") if fragment else []1165        for part in parts:1166            part = part.replace("~1", "/").replace("~0", "~")1167 1168            if isinstance(document, Sequence):1169                try:  # noqa: SIM1051170                    part = int(part)1171                except ValueError:1172                    pass1173            try:1174                document = document[part]1175            except (TypeError, LookupError) as err:1176                raise exceptions._RefResolutionError(1177                    f"Unresolvable JSON pointer: {fragment!r}",1178                ) from err1179 1180        return document1181 1182    def resolve_remote(self, uri):1183        """1184        Resolve a remote ``uri``.1185 1186        If called directly, does not check the store first, but after1187        retrieving the document at the specified URI it will be saved in1188        the store if :attr:`cache_remote` is True.1189 1190        .. note::1191 1192            If the requests_ library is present, ``jsonschema`` will use it to1193            request the remote ``uri``, so that the correct encoding is1194            detected and used.1195 1196            If it isn't, or if the scheme of the ``uri`` is not ``http`` or1197            ``https``, UTF-8 is assumed.1198 1199        Arguments:1200 

Showing the first 1,200 of 1411 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai