diff --git a/jsonschema/__init__.pyi b/jsonschema/__init__.pyi new file mode 100644 index 000000000..00ff5a061 --- /dev/null +++ b/jsonschema/__init__.pyi @@ -0,0 +1,24 @@ +from jsonschema._format import FormatChecker as FormatChecker +from jsonschema._format import draft3_format_checker as draft3_format_checker +from jsonschema._format import draft4_format_checker as draft4_format_checker +from jsonschema._format import draft6_format_checker as draft6_format_checker +from jsonschema._format import draft7_format_checker as draft7_format_checker +from jsonschema._format import \ + draft201909_format_checker as draft201909_format_checker +from jsonschema._format import \ + draft202012_format_checker as draft202012_format_checker +from jsonschema._types import TypeChecker as TypeChecker +from jsonschema.exceptions import ErrorTree as ErrorTree +from jsonschema.exceptions import FormatError as FormatError +from jsonschema.exceptions import RefResolutionError as RefResolutionError +from jsonschema.exceptions import SchemaError as SchemaError +from jsonschema.exceptions import ValidationError as ValidationError +from jsonschema.protocols import Validator as Validator +from jsonschema.validators import Draft3Validator as Draft3Validator +from jsonschema.validators import Draft4Validator as Draft4Validator +from jsonschema.validators import Draft6Validator as Draft6Validator +from jsonschema.validators import Draft7Validator as Draft7Validator +from jsonschema.validators import Draft201909Validator as Draft201909Validator +from jsonschema.validators import Draft202012Validator as Draft202012Validator +from jsonschema.validators import RefResolver as RefResolver +from jsonschema.validators import validate as validate diff --git a/jsonschema/_format.pyi b/jsonschema/_format.pyi new file mode 100644 index 000000000..061a30cb7 --- /dev/null +++ b/jsonschema/_format.pyi @@ -0,0 +1,50 @@ +from collections.abc import Callable, Iterable +from typing import Any, TypeVar, Union + +from typing_extensions import TypeAlias + +_F = TypeVar("_F", bound=Callable[..., Any]) +_RaisesType: TypeAlias = Union[type[Exception], tuple[type[Exception], ...]] + +class FormatChecker: + checkers: dict[str, tuple[Callable[[Any], bool], _RaisesType]] + + def __init__(self, formats: Iterable[str] | None = ...) -> None: ... + def checks(self, format: str, raises: _RaisesType = ...) -> Callable[[_F], _F]: ... + @classmethod + def cls_checks(cls, format: str, raises: _RaisesType = ...) -> Callable[[_F], _F]: ... + def check(self, instance: Any, format: str) -> None: ... + def conforms(self, instance: Any, format: str) -> bool: ... + +draft3_format_checker: FormatChecker +draft4_format_checker: FormatChecker +draft6_format_checker: FormatChecker +draft7_format_checker: FormatChecker +draft201909_format_checker: FormatChecker +draft202012_format_checker: FormatChecker + +def is_email(instance: object) -> bool: ... +def is_ipv4(instance: object) -> bool: ... +def is_ipv6(instance: object) -> bool: ... + +# is_host_name is only defined if fqdn is installed. +def is_host_name(instance: object) -> bool: ... +def is_idn_host_name(instance: object) -> bool: ... +def is_uri(instance: object) -> bool: ... +def is_uri_reference(instance: object) -> bool: ... +def is_iri(instance: object) -> bool: ... +def is_iri_reference(instance: object) -> bool: ... +def is_datetime(instance: object) -> bool: ... +def is_time(instance: object) -> bool: ... +def is_regex(instance: object) -> bool: ... +def is_date(instance: object) -> bool: ... +def is_draft3_time(instance: object) -> bool: ... +def is_css_color_code(instance: object) -> bool: ... +def is_css21_color(instance: object) -> bool: ... +def is_json_pointer(instance: object) -> bool: ... +def is_relative_json_pointer(instance: object) -> bool: ... +def is_uri_template(instance: object) -> bool: ... + +# is_duration is only defined if isoduration is installed. +def is_duration(instance: object) -> bool: ... +def is_uuid(instance: object) -> bool: ... diff --git a/jsonschema/_legacy_validators.pyi b/jsonschema/_legacy_validators.pyi new file mode 100644 index 000000000..783d3e5b3 --- /dev/null +++ b/jsonschema/_legacy_validators.pyi @@ -0,0 +1,16 @@ +from collections.abc import ItemsView +from typing import Any + +def ignore_ref_siblings(schema) -> list[tuple[str, Any]] | ItemsView[str, Any]: ... +def dependencies_draft3(validator, dependencies, instance, schema) -> None: ... +def dependencies_draft4_draft6_draft7(validator, dependencies, instance, schema) -> None: ... +def disallow_draft3(validator, disallow, instance, schema) -> None: ... +def extends_draft3(validator, extends, instance, schema) -> None: ... +def items_draft3_draft4(validator, items, instance, schema) -> None: ... +def items_draft6_draft7_draft201909(validator, items, instance, schema) -> None: ... +def minimum_draft3_draft4(validator, minimum, instance, schema) -> None: ... +def maximum_draft3_draft4(validator, maximum, instance, schema) -> None: ... +def properties_draft3(validator, properties, instance, schema) -> None: ... +def type_draft3(validator, types, instance, schema) -> None: ... +def contains_draft6_draft7(validator, contains, instance, schema) -> None: ... +def recursiveRef(validator, recursiveRef, instance, schema) -> None: ... diff --git a/jsonschema/_reflect.pyi b/jsonschema/_reflect.pyi new file mode 100644 index 000000000..a19c6f9d8 --- /dev/null +++ b/jsonschema/_reflect.pyi @@ -0,0 +1,7 @@ +class _NoModuleFound(Exception): ... +class InvalidName(ValueError): ... +class ModuleNotFound(InvalidName): ... +class ObjectNotFound(InvalidName): ... + +def reraise(exception, traceback) -> None: ... +def namedAny(name): ... diff --git a/jsonschema/_types.pyi b/jsonschema/_types.pyi new file mode 100644 index 000000000..2a3641d32 --- /dev/null +++ b/jsonschema/_types.pyi @@ -0,0 +1,24 @@ +from collections.abc import Callable, Iterable, Mapping + +def is_array(checker, instance) -> bool: ... +def is_bool(checker, instance) -> bool: ... +def is_integer(checker, instance) -> bool: ... +def is_null(checker, instance) -> bool: ... +def is_number(checker, instance) -> bool: ... +def is_object(checker, instance) -> bool: ... +def is_string(checker, instance) -> bool: ... +def is_any(checker, instance) -> bool: ... + +class TypeChecker: + def __init__(self, type_checkers: Mapping[str, Callable[[object], bool]] = ...) -> None: ... + def is_type(self, instance, type: str) -> bool: ... + def redefine(self, type: str, fn: Callable[..., bool]) -> TypeChecker: ... + def redefine_many(self, definitions=...) -> TypeChecker: ... + def remove(self, *types: Iterable[str]) -> TypeChecker: ... + +draft3_type_checker: TypeChecker +draft4_type_checker: TypeChecker +draft6_type_checker: TypeChecker +draft7_type_checker: TypeChecker +draft201909_type_checker: TypeChecker +draft202012_type_checker: TypeChecker diff --git a/jsonschema/_utils.pyi b/jsonschema/_utils.pyi new file mode 100644 index 000000000..b8adb9d68 --- /dev/null +++ b/jsonschema/_utils.pyi @@ -0,0 +1,34 @@ +from collections.abc import ( + Generator, + Iterable, + Iterator, + Mapping, + MutableMapping, + Sized, +) +from typing import Any + +from _typeshed import SupportsKeysAndGetItem + +class URIDict(MutableMapping[str, str]): + def normalize(self, uri: str) -> str: ... + store: dict[str, str] + def __init__(self, __m: SupportsKeysAndGetItem[str, str] | Iterable[tuple[str, str]], **kwargs: str) -> None: ... + def __getitem__(self, uri: str) -> str: ... + def __setitem__(self, uri: str, value: str) -> None: ... + def __delitem__(self, uri: str) -> None: ... + def __iter__(self) -> Iterator[str]: ... + def __len__(self) -> int: ... + +class Unset: ... + +def load_schema(name): ... +def format_as_index(container: str, indices) -> str: ... +def find_additional_properties(instance: Iterable[Any], schema: Mapping[Any, Any]) -> Generator[Any, None, None]: ... +def extras_msg(extras: Iterable[Any] | Sized) -> str: ... +def ensure_list(thing) -> list[Any]: ... +def equal(one, two) -> bool: ... +def unbool(element, true=..., false=...): ... +def uniq(container) -> bool: ... +def find_evaluated_item_indexes_by_schema(validator, instance, schema) -> list[Any]: ... +def find_evaluated_property_keys_by_schema(validator, instance, schema) -> list[Any]: ... diff --git a/jsonschema/_validators.pyi b/jsonschema/_validators.pyi new file mode 100644 index 000000000..f6daf1268 --- /dev/null +++ b/jsonschema/_validators.pyi @@ -0,0 +1,37 @@ +def patternProperties(validator, patternProperties, instance, schema) -> None: ... +def propertyNames(validator, propertyNames, instance, schema) -> None: ... +def additionalProperties(validator, aP, instance, schema) -> None: ... +def items(validator, items, instance, schema) -> None: ... +def additionalItems(validator, aI, instance, schema) -> None: ... +def const(validator, const, instance, schema) -> None: ... +def contains(validator, contains, instance, schema) -> None: ... +def exclusiveMinimum(validator, minimum, instance, schema) -> None: ... +def exclusiveMaximum(validator, maximum, instance, schema) -> None: ... +def minimum(validator, minimum, instance, schema) -> None: ... +def maximum(validator, maximum, instance, schema) -> None: ... +def multipleOf(validator, dB, instance, schema) -> None: ... +def minItems(validator, mI, instance, schema) -> None: ... +def maxItems(validator, mI, instance, schema) -> None: ... +def uniqueItems(validator, uI, instance, schema) -> None: ... +def pattern(validator, patrn, instance, schema) -> None: ... +def format(validator, format, instance, schema) -> None: ... +def minLength(validator, mL, instance, schema) -> None: ... +def maxLength(validator, mL, instance, schema) -> None: ... +def dependentRequired(validator, dependentRequired, instance, schema) -> None: ... +def dependentSchemas(validator, dependentSchemas, instance, schema) -> None: ... +def enum(validator, enums, instance, schema) -> None: ... +def ref(validator, ref, instance, schema) -> None: ... +def dynamicRef(validator, dynamicRef, instance, schema) -> None: ... +def type(validator, types, instance, schema) -> None: ... +def properties(validator, properties, instance, schema) -> None: ... +def required(validator, required, instance, schema) -> None: ... +def minProperties(validator, mP, instance, schema) -> None: ... +def maxProperties(validator, mP, instance, schema) -> None: ... +def allOf(validator, allOf, instance, schema) -> None: ... +def anyOf(validator, anyOf, instance, schema) -> None: ... +def oneOf(validator, oneOf, instance, schema) -> None: ... +def not_(validator, not_schema, instance, schema) -> None: ... +def if_(validator, if_schema, instance, schema) -> None: ... +def unevaluatedItems(validator, unevaluatedItems, instance, schema) -> None: ... +def unevaluatedProperties(validator, unevaluatedProperties, instance, schema) -> None: ... +def prefixItems(validator, prefixItems, instance, schema) -> None: ... diff --git a/jsonschema/cli.pyi b/jsonschema/cli.pyi new file mode 100644 index 000000000..85c3bd71d --- /dev/null +++ b/jsonschema/cli.pyi @@ -0,0 +1,32 @@ +from typing import Any + +class _CannotLoadFile(Exception): ... + +class _Outputter: + def __init__(self, formatter, stdout, stderr): ... + @classmethod + def from_arguments(cls, arguments, stdout, stderr): ... + def load(self, path): ... + def filenotfound_error(self, **kwargs) -> None: ... + def parsing_error(self, **kwargs) -> None: ... + def validation_error(self, **kwargs) -> None: ... + def validation_success(self, **kwargs) -> None: ... + +class _PrettyFormatter: + def filenotfound_error(self, path, exc_info): ... + def parsing_error(self, path, exc_info): ... + def validation_error(self, instance_path, error): ... + def validation_success(self, instance_path): ... + +class _PlainFormatter: + def __init__(self, error_format): ... + def filenotfound_error(self, path, exc_info): ... + def parsing_error(self, path, exc_info): ... + def validation_error(self, instance_path, error): ... + def validation_success(self, instance_path): ... + +parser: Any + +def parse_args(args): ... +def main(args=...) -> None: ... +def run(arguments, stdout=..., stderr=..., stdin=...): ... diff --git a/jsonschema/exceptions.pyi b/jsonschema/exceptions.pyi new file mode 100644 index 000000000..3e7da6c8f --- /dev/null +++ b/jsonschema/exceptions.pyi @@ -0,0 +1,89 @@ +from collections import deque +from collections.abc import Callable, Container, Iterable, Sequence +from typing import Any + +from _typeshed import Self, SupportsRichComparison +from typing_extensions import TypeAlias + +from jsonschema import _utils, protocols + +_RelevanceFuncType: TypeAlias = Callable[[ValidationError], SupportsRichComparison] + +WEAK_MATCHES: frozenset[str] +STRONG_MATCHES: frozenset[str] + +class _Error(Exception): + message: str + path: deque[str | int] + relative_path: deque[str | int] + schema_path: deque[str | int] + relative_schema_path: deque[str | int] + context: list[ValidationError] | None + cause: Exception | None + validator: protocols.Validator | None + validator_value: Any + instance: Any + schema: Any + parent: _Error | None + def __init__( + self, + message: str, + validator: _utils.Unset | None | protocols.Validator = ..., + path: Sequence[str | int] = ..., + cause: Any | None = ..., + context: Sequence[ValidationError] = ..., + validator_value=..., + instance: Any = ..., + schema: Any = ..., + schema_path: Sequence[str | int] = ..., + parent: _Error | None = ..., + ) -> None: ... + @classmethod + def create_from(cls: type[Self], other: _Error) -> Self: ... + @property + def absolute_path(self) -> Sequence[str | int]: ... + @property + def absolute_schema_path(self) -> Sequence[str | int]: ... + @property + def json_path(self) -> str: ... + # TODO: this type could be made more precise using TypedDict to + # enumerate the types of the members + def _contents(self) -> dict[str, Any]: ... + +class ValidationError(_Error): ... +class SchemaError(_Error): ... + +class RefResolutionError(Exception): + def __init__(self, cause: str) -> None: ... + +class UndefinedTypeCheck(Exception): + type: Any + def __init__(self, type) -> None: ... + +class UnknownType(Exception): + type: Any + instance: Any + schema: Any + def __init__(self, type, instance, schema) -> None: ... + +class FormatError(Exception): + message: Any + cause: Any + def __init__(self, message, cause: Any | None = ...) -> None: ... + +class ErrorTree: + errors: Any + def __init__(self, errors=...) -> None: ... + def __contains__(self, index): ... + def __getitem__(self, index): ... + def __setitem__(self, index, value) -> None: ... + def __iter__(self): ... + def __len__(self): ... + @property + def total_errors(self): ... + +def by_relevance(weak: Container[str] = ..., strong: Container[str] = ...) -> _RelevanceFuncType: ... + +relevance: _RelevanceFuncType + +def best_match(errors: Iterable[ValidationError], key: _RelevanceFuncType = ...): ... diff --git a/jsonschema/protocols.pyi b/jsonschema/protocols.pyi new file mode 100644 index 000000000..1a6ff086a --- /dev/null +++ b/jsonschema/protocols.pyi @@ -0,0 +1,23 @@ +from collections.abc import Iterator +from typing import Any, ClassVar, Protocol + +from jsonschema._format import FormatChecker +from jsonschema._types import TypeChecker +from jsonschema.exceptions import ValidationError +from jsonschema.validators import RefResolver + +class Validator(Protocol): + META_SCHEMA: ClassVar[dict[Any, Any]] + VALIDATORS: ClassVar[dict[Any, Any]] + TYPE_CHECKER: ClassVar[TypeChecker] + schema: dict[Any, Any] | bool + def __init__( + self, schema: dict[Any, Any] | bool, resolver: RefResolver | None = ..., format_checker: FormatChecker | None = ... + ) -> None: ... + @classmethod + def check_schema(cls, schema: dict[Any, Any]) -> None: ... + def is_type(self, instance: Any, type: str) -> bool: ... + def is_valid(self, instance: dict[Any, Any]) -> bool: ... + def iter_errors(self, instance: dict[Any, Any]) -> Iterator[ValidationError]: ... + def validate(self, instance: dict[Any, Any]) -> None: ... + def evolve(self, **kwargs) -> Validator: ... diff --git a/jsonschema/py.typed b/jsonschema/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/jsonschema/validators.pyi b/jsonschema/validators.pyi new file mode 100644 index 000000000..fd6287383 --- /dev/null +++ b/jsonschema/validators.pyi @@ -0,0 +1,85 @@ +from collections.abc import Callable, Generator, Iterable, Mapping +from typing import Any, ClassVar + +from _typeshed import SupportsKeysAndGetItem +from typing_extensions import TypeAlias + +from ._utils import URIDict + +_Schema: TypeAlias = Mapping[str, Any] + +# This class does not exist at runtime. Compatible classes are created at +# runtime by create(). +class _Validator: + VALIDATORS: ClassVar[dict[Any, Any]] + META_SCHEMA: ClassVar[dict[Any, Any]] + TYPE_CHECKER: Any + @staticmethod + def ID_OF(schema: _Schema) -> str: ... + schema: _Schema + resolver: Any + format_checker: Any + evolve: Any + def __init__(self, schema: _Schema, resolver: Any | None = ..., format_checker: Any | None = ...) -> None: ... + @classmethod + def check_schema(cls, schema: _Schema) -> None: ... + def iter_errors(self, instance, _schema: _Schema | None = ...) -> Generator[Any, None, None]: ... + def descend( + self, instance, schema: _Schema, path: Any | None = ..., schema_path: Any | None = ... + ) -> Generator[Any, None, None]: ... + def validate(self, *args, **kwargs) -> None: ... + def is_type(self, instance, type): ... + def is_valid(self, instance, _schema: _Schema | None = ...) -> bool: ... + +def validates(version: str) -> Callable[..., Any]: ... +def create( + meta_schema, validators=..., version: Any | None = ..., type_checker=..., id_of=..., applicable_validators=... +) -> type[_Validator]: ... +def extend(validator, validators=..., version: Any | None = ..., type_checker: Any | None = ...): ... + +# At runtime these are fields that are assigned the return values of create() calls. +class Draft3Validator(_Validator): ... +class Draft4Validator(_Validator): ... +class Draft6Validator(_Validator): ... +class Draft7Validator(_Validator): ... +class Draft201909Validator(_Validator): ... +class Draft202012Validator(_Validator): ... + +_Handler: TypeAlias = Callable[[str], Any] + +class RefResolver: + referrer: dict[str, Any] + cache_remote: Any + handlers: dict[str, _Handler] + store: URIDict + def __init__( + self, + base_uri: str, + referrer: dict[str, Any], + store: SupportsKeysAndGetItem[str, str] | Iterable[tuple[str, str]] = ..., + cache_remote: bool = ..., + handlers: SupportsKeysAndGetItem[str, _Handler] | Iterable[tuple[str, _Handler]] = ..., + urljoin_cache: Any | None = ..., + remote_cache: Any | None = ..., + ) -> None: ... + @classmethod + def from_schema(cls, schema: _Schema, id_of=..., *args, **kwargs): ... + def push_scope(self, scope) -> None: ... + def pop_scope(self) -> None: ... + @property + def resolution_scope(self): ... + @property + def base_uri(self): ... + def in_scope(self, scope) -> None: ... + def resolving(self, ref) -> None: ... + def resolve(self, ref): ... + def resolve_from_url(self, url): ... + def resolve_fragment(self, document, fragment): ... + def resolve_remote(self, uri): ... + +def validate(instance: object, schema: _Schema, cls: type[_Validator] | None = ..., *args: Any, **kwargs: Any) -> None: ... +def validator_for(schema: _Schema | bool, default=...): ... + + +_LATEST_VERSION: type[_Validator] +_VALIDATORS: dict[str, Any] diff --git a/pyproject.toml b/pyproject.toml index 115e20154..c330deb6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,3 +95,6 @@ add-ignore = [ "D412", # Trailing whitespace plz "D413", # No trailing whitespace plz ] + +[tool.setuptools.package-data] +jsonschema = ["py.typed", "*.pyi", "schemas/*.json", "schemas/*/*.json"]