Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: python-jsonschema/jsonschema
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v4.14.0
Choose a base ref
...
head repository: python-jsonschema/jsonschema
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v4.15.0
Choose a head ref

Commits on Aug 23, 2022

  1. Copy the full SHA
    c227d64 View commit details
  2. Disable max line length in doc8.

    We'll slowly move to sentence-per-line.
    Julian committed Aug 23, 2022
    Copy the full SHA
    8214626 View commit details

Commits on Aug 28, 2022

  1. Remove backticks from section headings.

    Sphinx/intersphinx generates really weird or unreferenceable
    labels when these are here.
    Julian committed Aug 28, 2022
    Copy the full SHA
    6d39c4b View commit details
  2. Copy the full SHA
    6693f93 View commit details
  3. Don't skip tests while debugging.

    This will maybe get annoying if debugging many at once, but
    works better for specifically mentioning one test.
    Julian committed Aug 28, 2022
    Copy the full SHA
    167ac4b View commit details
  4. Fix $id in the presence of $ref on draft 6 and 7.

    In these drafts, not only did $ref cause other validator keywords
    to be ignored, it prevents $id from setting the resolution scope
    too.
    
    In draft 3 and 4 this is now half-fixed in the sense that the
    correct URI is now the one that will be retrieved, but the logic
    for finding subschemas by ID is still broken on these drafts.
    Julian committed Aug 28, 2022
    Copy the full SHA
    bf92aed View commit details
  5. Copy the full SHA
    9c79837 View commit details

Commits on Aug 29, 2022

  1. Copy the full SHA
    8e43f78 View commit details
  2. Copy the full SHA
    5fe9759 View commit details
  3. Of course the tweaked name doesn't work on macOS.

    Hopefully this works on both.
    Julian committed Aug 29, 2022
    Copy the full SHA
    4320a2c View commit details
  4. Copy the full SHA
    bde874d View commit details
  5. Copy the full SHA
    3f7f1e3 View commit details
  6. Another RTD-only failed ref.

    Julian committed Aug 29, 2022
    Copy the full SHA
    1ad00c8 View commit details
  7. Merge pull request #989 from python-jsonschema/api

    Enable dedicated API documentation page(s)
    Julian authored Aug 29, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    68fad03 View commit details
  8. Copy the full SHA
    cdc3a21 View commit details

Commits on Aug 30, 2022

  1. Copy the full SHA
    b9dbe5a View commit details
  2. Copy the full SHA
    a513c99 View commit details
  3. Copy the full SHA
    fd491f9 View commit details
  4. Remove the incorrect Optional from FormatChecker's formats annotation.

    See https://docs.python.org/3/library/typing.html#typing.Optional.
    
    This is meant to be used only if None is a specifically allowed value, where
    here it is not, it's an internal sentinel, not part of its public API, which
    only allows iterables.
    Julian committed Aug 30, 2022
    Copy the full SHA
    6d04fd7 View commit details
  5. Remove the doc page for references.

    All it does is include objects which now appear in the
    API reference.
    
    This section should (will) come back as some prose instead on
    the validation doc page.
    Julian committed Aug 30, 2022
    Copy the full SHA
    57b604e View commit details
  6. Make the link to Understanding JSON Schema more prominent.

    (And remove some ancient language from when it was a twinkle in
    someone's eye).
    Julian committed Aug 30, 2022
    Copy the full SHA
    ca96760 View commit details
  7. Copy the full SHA
    d67decc View commit details
  8. Spelling...

    Julian committed Aug 30, 2022
    Copy the full SHA
    792311d View commit details
  9. Copy the full SHA
    6533d32 View commit details
  10. Copy the full SHA
    8ce8250 View commit details

Commits on Aug 31, 2022

  1. Copy the full SHA
    420fc6b View commit details
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
v4.15.0
=======

* A specific API Reference page is now present in the documentation.
* ``$ref`` on earlier drafts (specifically draft 7 and 6) has been "fixed" to
follow the specified behavior when present alongside a sibling ``$id``.
Specifically the ID is now properly ignored, and references are resolved
against whatever resolution scope was previously relevant.

v4.14.0
=======

14 changes: 7 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
@@ -64,17 +64,17 @@ Features
--------

* Partial support for
`Draft 2020-12 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft202012Validator>`_ and
`Draft 2019-09 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft201909Validator>`_,
`Draft 2020-12 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft202012Validator>`_ and
`Draft 2019-09 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft201909Validator>`_,
except for ``dynamicRef`` / ``recursiveRef`` and ``$vocabulary`` (in-progress).
Full support for
`Draft 7 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft7Validator>`_,
`Draft 6 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft6Validator>`_,
`Draft 4 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft4Validator>`_
`Draft 7 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft7Validator>`_,
`Draft 6 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft6Validator>`_,
`Draft 4 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft4Validator>`_
and
`Draft 3 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft3Validator>`_
`Draft 3 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft3Validator>`_

* `Lazy validation <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.protocols.Validator.iter_errors>`_
* `Lazy validation <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/protocols/#jsonschema.protocols.Validator.iter_errors>`_
that can iteratively report *all* validation errors.

* `Programmatic querying <https://python-jsonschema.readthedocs.io/en/latest/errors/>`_
34 changes: 33 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from importlib import metadata
from pathlib import Path
import os
import re
import sys

ROOT = Path(__file__).parent.parent
PACKAGE_SRC = ROOT / "jsonschema"

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -25,6 +29,8 @@
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.viewcode",

"autoapi.extension",
"sphinx_autodoc_typehints",
"sphinx_json_schema_spec",
"sphinxcontrib.spelling",
@@ -72,7 +78,8 @@
default_role = "any"

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
pygments_style = "lovelace"
pygments_dark_style = "one-dark"

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
@@ -83,6 +90,7 @@

intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"ujs": ("https://json-schema.org/understanding-json-schema/", None),
}


@@ -252,3 +260,27 @@ def entire_domain(host):
# -- Options for sphinxcontrib-spelling -----------------------------------

spelling_word_list_filename = "spelling-wordlist.txt"

# -- Options for autoapi --------------------------------------------------

suppress_warnings = [
"autoapi.python_import_resolution",
"autoapi.toc_reference",
]
autoapi_root = "api"
autoapi_ignore = [
"*/_[a-z]*.py",
"*/__main__.py",
"*/benchmarks/*",
"*/cli.py",
"*/tests/*",
]
autoapi_options = [
"members",
"undoc-members",
"show-module-summary",
"imported-members",
]

autoapi_type = "python"
autoapi_dirs = [PACKAGE_SRC]
4 changes: 4 additions & 0 deletions docs/creating.rst
Original file line number Diff line number Diff line change
@@ -7,12 +7,16 @@ Creating or Extending Validator Classes
=======================================

.. autofunction:: create
:noindex:

.. autofunction:: extend
:noindex:

.. autofunction:: validator_for
:noindex:

.. autofunction:: validates
:noindex:


Creating Validation Errors
6 changes: 6 additions & 0 deletions docs/errors.rst
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ When an invalid instance is encountered, a `ValidationError` will be
raised or returned, depending on which method or function is used.

.. autoexception:: ValidationError
:noindex:

The information carried by an error roughly breaks down into:

@@ -123,6 +124,7 @@ In case an invalid schema itself is encountered, a `SchemaError` is
raised.

.. autoexception:: SchemaError
:noindex:

The same attributes are present as for `ValidationError`\s.

@@ -229,6 +231,7 @@ failed when validating a given instance, you may want to do so using
`jsonschema.exceptions.ErrorTree` objects.

.. autoclass:: jsonschema.exceptions.ErrorTree
:noindex:
:members:
:special-members:
:exclude-members: __dict__,__weakref__
@@ -361,9 +364,11 @@ to guess the most relevant error in a given bunch.


.. autofunction:: best_match
:noindex:


.. function:: relevance(validation_error)
:noindex:

A key function that sorts errors based on heuristic relevance.

@@ -403,3 +408,4 @@ to guess the most relevant error in a given bunch.


.. autofunction:: by_relevance
:noindex:
37 changes: 31 additions & 6 deletions docs/faq.rst
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
Frequently Asked Questions
==========================


My schema specifies format validation. Why do invalid instances seem valid?
---------------------------------------------------------------------------

@@ -74,12 +73,38 @@ implemented here, across any other implementation they encounter.
the object which implements format validation


How do I configure a base URI for ``$ref`` resolution using local files?
------------------------------------------------------------------------
Can jsonschema be used to validate YAML, TOML, etc.?
----------------------------------------------------

Like most JSON Schema implementations, `jsonschema` doesn't actually deal directly with JSON at all (other than in relation to the :kw:`$ref` keyword, elaborated on below).

In other words as far as this library is concerned, schemas and instances are simply runtime Python objects.
The JSON object ``{}`` is simply the Python `dict` ``{}``, and a JSON Schema like ``{"type": "object", {"properties": {}}}`` is really an assertion about particular Python objects and their keys.

.. note::

The :kw:`$ref` keyword is a single notable exception.

Specifically, in the case where `jsonschema` is asked to `resolve a remote reference <jsonschema.validators.RefResolver>`, it has no choice but to assume that the remote reference is serialized as JSON, and to deserialize it using the `json` module.

One cannot today therefore reference some remote piece of YAML and have it deserialized into Python objects by this library without doing some additional work.

In practice what this means for JSON-like formats like YAML and TOML is that indeed one can generally schematize and then validate them exactly as if they were JSON by simply first deserializing them using libraries like ``PyYAML`` or the like, and passing the resulting Python objects into functions within this library.

Beware however that there are cases where the behavior of the JSON Schema specification itself is only well-defined within the data model of JSON itself, and therefore only for Python objects that could have "in theory" come from JSON.
As an example, JSON supports only string-valued keys, whereas YAML supports additional types.
The JSON Schema specification does not deal with how to apply the :kw:`patternProperties` keyword to non-string properties.
The behavior of this library is therefore similarly not defined when presented with Python objects of this form, which could never have come from JSON.
In such cases one is recommended to first pre-process the data such that the resulting behavior is well-defined.
In the previous example, if the desired behavior is to transparently coerce numeric properties to strings, as Javascript might, then do the conversion explicitly before passing data to this library.


How do I configure a base URI for $ref resolution using local files?
--------------------------------------------------------------------

`jsonschema` supports loading schemas from the filesystem.

The most common mistake when configuring a :class:`~jsonschema.RefResolver`
The most common mistake when configuring a `jsonschema.validators.RefResolver`
to retrieve schemas from the local filesystem is to give it a base URI
which points to a directory, but forget to add a trailing slash.

@@ -187,8 +212,8 @@ be valid under the schema.)

See the above-linked document for more info on how this works,
but basically, it just extends the :kw:`properties` keyword on a
`jsonschema.Draft202012Validator` to then go ahead and update all the
defaults.
`jsonschema.validators.Draft202012Validator` to then go ahead and update
all the defaults.

.. note::

4 changes: 3 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.. module:: jsonschema
:noindex:

.. include:: ../README.rst


@@ -10,9 +12,9 @@ Contents

validate
errors
references
creating
faq
api/index


Indices and tables
13 changes: 0 additions & 13 deletions docs/references.rst

This file was deleted.

1 change: 1 addition & 0 deletions docs/requirements.in
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ file:.#egg=jsonschema
furo
lxml
sphinx
sphinx-autoapi
sphinx-autodoc-typehints
sphinx-json-schema-spec
sphinxcontrib-spelling
17 changes: 16 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -6,6 +6,8 @@
#
alabaster==0.7.12
# via sphinx
astroid==2.12.2
# via sphinx-autoapi
attrs==22.1.0
# via jsonschema
babel==2.10.3
@@ -25,9 +27,13 @@ idna==3.3
imagesize==1.4.1
# via sphinx
jinja2==3.1.2
# via sphinx
# via
# sphinx
# sphinx-autoapi
file:.#egg=jsonschema
# via -r docs/requirements.in
lazy-object-proxy==1.7.1
# via astroid
lxml==4.9.1
# via
# -r docs/requirements.in
@@ -48,6 +54,8 @@ pyrsistent==0.18.1
# via jsonschema
pytz==2022.2.1
# via babel
pyyaml==6.0
# via sphinx-autoapi
requests==2.28.1
# via sphinx
snowballstemmer==2.2.0
@@ -58,10 +66,13 @@ sphinx==5.1.1
# via
# -r docs/requirements.in
# furo
# sphinx-autoapi
# sphinx-autodoc-typehints
# sphinx-basic-ng
# sphinx-json-schema-spec
# sphinxcontrib-spelling
sphinx-autoapi==1.9.0
# via -r docs/requirements.in
sphinx-autodoc-typehints==1.19.2
# via -r docs/requirements.in
sphinx-basic-ng==0.0.1a12
@@ -82,5 +93,9 @@ sphinxcontrib-serializinghtml==1.1.5
# via sphinx
sphinxcontrib-spelling==7.6.0
# via -r docs/requirements.in
unidecode==1.3.4
# via sphinx-autoapi
urllib3==1.26.11
# via requests
wrapt==1.14.1
# via astroid
10 changes: 10 additions & 0 deletions docs/spelling-wordlist.txt
Original file line number Diff line number Diff line change
@@ -7,8 +7,13 @@ ValidationError
# 0th, sigh...
th
callables
# non-codeblocked cls from autoapi
cls
deque
dereferences
deserialize
deserialized
deserializing
filesystem
hostname
implementers
@@ -17,6 +22,7 @@ indices
ipv
iterable
iteratively
Javascript
jsonschema
majorly
metaschema
@@ -27,7 +33,11 @@ programmatically
recurses
regex
repr
runtime
sensical
subclassing
submodule
submodules
subschema
subschemas
subscopes
66 changes: 39 additions & 27 deletions docs/validate.rst
Original file line number Diff line number Diff line change
@@ -5,6 +5,12 @@ Schema Validation

.. currentmodule:: jsonschema

.. tip::

Most of the documentation for this package assumes you're familiar with the fundamentals of writing JSON schemas themselves, and focuses on how this library helps you validate with them in Python.

If you aren't already comfortable with writing schemas and need an introduction which teaches about JSON Schema the specification, you may find `Understanding JSON Schema <ujs:basics>` to be a good read!


The Basics
----------
@@ -13,27 +19,27 @@ The simplest way to validate an instance under a given schema is to use the
:func:`validate` function.

.. autofunction:: validate

.. [#] For information on creating JSON schemas to validate
your data, there is a good introduction to JSON Schema
fundamentals underway at `Understanding JSON Schema
<https://json-schema.org/understanding-json-schema/>`_
:noindex:

.. _validator-protocol:

The Validator Protocol
-----------------------

`jsonschema` defines a protocol that all validator classes should adhere
to.
`jsonschema` defines a `protocol <typing.Protocol>` that all validator classes adhere to.

.. hint::

If you are unfamiliar with protocols, either as a general notion or as specifically implemented by `typing.Protocol`, you can think of them as a set of attributes and methods that all objects satisfying the protocol have.

Here, in the context of `jsonschema`, the `Validator.iter_errors` method can be called on `jsonschema.validators.Draft202012Validator`, or `jsonschema.validators.Draft7Validator`, or indeed any validator class, as all of them have it, along with all of the other methods described below.

.. autoclass:: jsonschema.protocols.Validator
:noindex:
:members:

All of the `versioned validators <versioned-validators>` that are included with
`jsonschema` adhere to the protocol, and implementers of validator classes
that extend or complement the ones included should adhere to it as well. For
more information see `creating-validators`.
All of the `versioned validators <versioned-validators>` that are included with `jsonschema` adhere to the protocol, and any `extensions of these validators <jsonschema.validators.extend>` will as well.
For more information on `creating <jsonschema.validators.create>` or `extending <jsonschema.validators.extend>` validators see `creating-validators`.

Type Checking
-------------
@@ -54,6 +60,7 @@ versions.
:members:

.. autoexception:: jsonschema.exceptions.UndefinedTypeCheck
:noindex:

Raised when trying to remove a type check that is not known to this
TypeChecker, or when calling `jsonschema.TypeChecker.is_type`
@@ -109,28 +116,35 @@ existing `TypeChecker` or create a new one. You may then create a new


.. autoexception:: jsonschema.exceptions.UnknownType
:noindex:

.. _versioned-validators:

Versioned Validators
--------------------

`jsonschema` ships with validator classes for various versions of
the JSON Schema specification. For details on the methods and attributes
that each validator class provides see the `Validator` protocol,
which each included validator class implements.
`jsonschema` ships with validator classes for various versions of the JSON Schema specification.
For details on the methods and attributes that each validator class provides see the `Validator` protocol, which each included validator class implements.

Each of the below cover a specific release of the JSON Schema specification.

.. autoclass:: Draft202012Validator
:noindex:

.. autoclass:: Draft201909Validator
:noindex:

.. autoclass:: Draft7Validator
:noindex:

.. autoclass:: Draft6Validator
:noindex:

.. autoclass:: Draft4Validator
:noindex:

.. autoclass:: Draft3Validator
:noindex:


For example, if you wanted to validate a schema you created against the
@@ -158,11 +172,8 @@ Draft 2020-12 meta-schema, you could use:
Validating Formats
------------------

JSON Schema defines the :kw:`format` keyword which can be used to check
if primitive types (``string``\s, ``number``\s, ``boolean``\s) conform to
well-defined formats. By default, no validation is enforced, but optionally,
validation can be enabled by hooking in a format-checking object into an
`Validator`.
JSON Schema defines the :kw:`format` keyword which can be used to check if primitive types (``string``\s, ``number``\s, ``boolean``\s) conform to well-defined formats.
By default, no validation is enforced, but optionally, validation can be enabled by hooking in a format-checking object into a `Validator`.

.. doctest::

@@ -182,18 +193,14 @@ validation can be enabled by hooking in a format-checking object into an

.. attribute:: checkers

A mapping of currently known formats to tuple of functions that
validate them and errors that should be caught. New checkers can be
added and removed either per-instance or globally for all checkers
using the `FormatChecker.checks` or `FormatChecker.cls_checks`
decorators respectively.
A mapping of currently known formats to tuple of functions that validate them and errors that should be caught.
New checkers can be added and removed either per-instance or globally for all checkers using the `FormatChecker.checks` decorator.

.. classmethod:: cls_checks(format, raises=())

Register a decorated function as *globally* validating a new format.

Any instance created after this function is called will pick up the
supplied checker.
Any instance created after this function is called will pick up the supplied checker.

:argument str format: the format that the decorated function will check
:argument Exception raises: the exception(s) raised
@@ -202,8 +209,13 @@ validation can be enabled by hooking in a format-checking object into an
`jsonschema.exceptions.ValidationError.cause` attribute
of the resulting validation error.

.. deprecated:: v4.14.0

Use `FormatChecker.checks` on an instance instead.


.. autoexception:: FormatError
:noindex:
:members:


5 changes: 3 additions & 2 deletions jsonschema/__init__.py
Original file line number Diff line number Diff line change
@@ -4,8 +4,9 @@
The main functionality is provided by the validator classes for each of the
supported JSON Schema versions.
Most commonly, `validate` is the quickest way to simply validate a given
instance under a schema, and will create a validator for you.
Most commonly, `jsonschema.validators.validate` is the quickest way to simply
validate a given instance under a schema, and will create a validator
for you.
"""
import warnings

22 changes: 10 additions & 12 deletions jsonschema/_format.py
Original file line number Diff line number Diff line change
@@ -28,13 +28,12 @@ class FormatChecker:
`FormatChecker` objects always return ``True`` when asked about
formats that they do not know how to validate.
To check a custom format using a function that takes an instance and
returns a ``bool``, use the `FormatChecker.checks` or
`FormatChecker.cls_checks` decorators.
To add a check for a custom format use the `FormatChecker.checks`
decorator.
Arguments:
formats (~collections.abc.Iterable):
formats:
The known formats to validate. This argument can be used to
limit which formats will be used during validation.
@@ -45,11 +44,10 @@ class FormatChecker:
tuple[_FormatCheckCallable, _RaisesType],
] = {}

def __init__(self, formats: typing.Iterable[str] | None = None):
def __init__(self, formats: typing.Iterable[str] = None):
if formats is None:
self.checkers = self.checkers.copy()
else:
self.checkers = dict((k, self.checkers[k]) for k in formats)
formats = self.checkers.keys()
self.checkers = {k: self.checkers[k] for k in formats}

def __repr__(self):
return "<FormatChecker checkers={}>".format(sorted(self.checkers))
@@ -62,11 +60,11 @@ def checks(
Arguments:
format (str):
format:
The format that the decorated function will check.
raises (Exception):
raises:
The exception(s) raised by the decorated function when an
invalid instance is found.
@@ -117,7 +115,7 @@ def check(self, instance: object, format: str) -> None:
The instance to check
format (str):
format:
The format that instance should conform to
@@ -150,7 +148,7 @@ def conforms(self, instance: object, format: str) -> bool:
The instance to check
format (str):
format:
The format that instance should conform to
13 changes: 13 additions & 0 deletions jsonschema/_legacy_validators.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,19 @@
from jsonschema.exceptions import ValidationError


def id_of_ignore_ref(property="$id"):
def id_of(schema):
"""
Ignore an ``$id`` sibling of ``$ref`` if it is present.
Otherwise, return the ID of the given schema.
"""
if schema is True or schema is False or "$ref" in schema:
return ""
return schema.get(property, "")
return id_of


def ignore_ref_siblings(schema):
"""
Ignore siblings of ``$ref`` if it is present.
6 changes: 5 additions & 1 deletion jsonschema/_types.py
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ def is_any(checker, instance):
return True


@attr.s(frozen=True)
@attr.s(frozen=True, repr=False)
class TypeChecker:
"""
A :kw:`type` property checker.
@@ -89,6 +89,10 @@ class TypeChecker:
converter=_typed_pmap_converter,
)

def __repr__(self):
types = ", ".join(repr(k) for k in sorted(self._type_checkers))
return f"<{self.__class__.__name__} types={{{types}}}>"

def is_type(self, instance, type: str) -> bool:
"""
Check if the instance is of the appropriate type.
17 changes: 13 additions & 4 deletions jsonschema/protocols.py
Original file line number Diff line number Diff line change
@@ -31,7 +31,6 @@
import jsonschema

from jsonschema.exceptions import ValidationError
from jsonschema.validators import RefResolver

# For code authors working on the validator protocol, these are the three
# use-cases which should be kept in mind:
@@ -49,7 +48,7 @@
@runtime_checkable
class Validator(Protocol):
"""
The protocol to which all validator classes should adhere.
The protocol to which all validator classes adhere.
Arguments:
@@ -75,6 +74,11 @@ class Validator(Protocol):
against instances. Ensure you've installed `jsonschema` with
its `extra (optional) dependencies <index:extras>` when
invoking ``pip``.
.. deprecated:: v4.12.0
Subclassing validator classes now explicitly warns this is not part of
their public API.
"""

#: An object representing the validator's meta schema (the schema that
@@ -91,7 +95,7 @@ class Validator(Protocol):
TYPE_CHECKER: ClassVar[jsonschema.TypeChecker]

#: A `jsonschema.FormatChecker` that will be used when validating
#: :kw:`format` properties in JSON schemas.
#: :kw:`format` keywords in JSON schemas.
FORMAT_CHECKER: ClassVar[jsonschema.FormatChecker]

#: A function which given a schema returns its ID.
@@ -103,7 +107,7 @@ class Validator(Protocol):
def __init__(
self,
schema: Mapping | bool,
resolver: RefResolver | None = None,
resolver: jsonschema.RefResolver | None = None,
format_checker: jsonschema.FormatChecker | None = None,
) -> None:
...
@@ -172,6 +176,11 @@ def iter_errors(self, instance: Any) -> Iterable[ValidationError]:
... print(error.message)
4 is not one of [1, 2, 3]
[2, 3, 4] is too long
.. deprecated:: v4.0.0
Calling this function with a second schema argument is deprecated.
Use `Validator.evolve` instead.
"""

def validate(self, instance: Any) -> None:
2 changes: 1 addition & 1 deletion jsonschema/tests/_suite.py
Original file line number Diff line number Diff line change
@@ -191,7 +191,7 @@ def fn(this):

fn.__name__ = self.method_name
reason = skip(self)
if reason is None:
if reason is None or os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0":
return fn
elif os.environ.get("JSON_SCHEMA_EXPECTED_FAILURES", "0") != "0":
return unittest.expectedFailure(fn)
47 changes: 5 additions & 42 deletions jsonschema/tests/test_jsonschema_test_suite.py
Original file line number Diff line number Diff line change
@@ -156,7 +156,7 @@ def leap_second(test):
or missing_format(jsonschema.draft3_format_checker)(test)
or complex_email_validation(test)
or skip(
message=bug(371),
message=bug(),
subject="ref",
valid=False,
case_description=(
@@ -188,27 +188,27 @@ def leap_second(test):
case_description="Recursive references between schemas",
)(test)
or skip(
message=bug(371),
message=bug(),
subject="ref",
case_description=(
"Location-independent identifier with "
"base URI change in subschema"
),
)(test)
or skip(
message=bug(371),
message=bug(),
subject="ref",
case_description=(
"$ref prevents a sibling id from changing the base uri"
),
)(test)
or skip(
message=bug(371),
message=bug(),
subject="id",
description="match $ref to id",
)(test)
or skip(
message=bug(371),
message=bug(),
subject="id",
description="no match on enum or $ref to id",
)(test)
@@ -248,13 +248,6 @@ def leap_second(test):
subject="refRemote",
case_description="base URI change - change folder in subschema",
)(test)
or skip(
message=bug(371),
subject="ref",
case_description=(
"$ref prevents a sibling $id from changing the base uri"
),
)(test)
),
)

@@ -263,7 +256,6 @@ def leap_second(test):
DRAFT7.tests(),
DRAFT7.format_tests(),
DRAFT7.optional_tests_of(name="bignum"),
DRAFT7.optional_tests_of(name="content"),
DRAFT7.optional_tests_of(name="cross-draft"),
DRAFT7.optional_tests_of(name="float-overflow"),
DRAFT7.optional_tests_of(name="non-bmp-regex"),
@@ -280,13 +272,6 @@ def leap_second(test):
subject="refRemote",
case_description="base URI change - change folder in subschema",
)(test)
or skip(
message=bug(371),
subject="ref",
case_description=(
"$ref prevents a sibling $id from changing the base uri"
),
)(test)
or skip(
message=bug(),
subject="ref",
@@ -295,28 +280,6 @@ def leap_second(test):
"not just immediate parent"
),
)(test)
or skip(
message=bug(593),
subject="content",
valid=False,
case_description=(
"validation of string-encoded content based on media type"
),
)(test)
or skip(
message=bug(593),
subject="content",
valid=False,
case_description="validation of binary string-encoding",
)(test)
or skip(
message=bug(593),
subject="content",
valid=False,
case_description=(
"validation of binary-encoded media type documents"
),
)(test)
),
)

4 changes: 4 additions & 0 deletions jsonschema/tests/test_types.py
Original file line number Diff line number Diff line change
@@ -105,6 +105,10 @@ def raises_keyerror(checker, instance):

self.assertIs(context.exception, error)

def test_repr(self):
checker = TypeChecker({"foo": is_namedtuple, "bar": is_namedtuple})
self.assertEqual(repr(checker), "<TypeChecker types={'bar', 'foo'}>")


class TestCustomTypes(TestCase):
def test_simple_type_can_be_extended(self):
19 changes: 12 additions & 7 deletions jsonschema/validators.py
Original file line number Diff line number Diff line change
@@ -445,7 +445,7 @@ def extend(
type_checker=_types.draft3_type_checker,
format_checker=_format.draft3_format_checker,
version="draft3",
id_of=lambda schema: schema.get("id", ""),
id_of=_legacy_validators.id_of_ignore_ref(property="id"),
applicable_validators=_legacy_validators.ignore_ref_siblings,
)

@@ -482,7 +482,7 @@ def extend(
type_checker=_types.draft4_type_checker,
format_checker=_format.draft4_format_checker,
version="draft4",
id_of=lambda schema: schema.get("id", ""),
id_of=_legacy_validators.id_of_ignore_ref(property="id"),
applicable_validators=_legacy_validators.ignore_ref_siblings,
)

@@ -524,6 +524,7 @@ def extend(
type_checker=_types.draft6_type_checker,
format_checker=_format.draft6_format_checker,
version="draft6",
id_of=_legacy_validators.id_of_ignore_ref(),
applicable_validators=_legacy_validators.ignore_ref_siblings,
)

@@ -566,6 +567,7 @@ def extend(
type_checker=_types.draft7_type_checker,
format_checker=_format.draft7_format_checker,
version="draft7",
id_of=_legacy_validators.id_of_ignore_ref(),
applicable_validators=_legacy_validators.ignore_ref_siblings,
)

@@ -801,6 +803,8 @@ def base_uri(self):
def in_scope(self, scope):
"""
Temporarily enter the given scope for the duration of the context.
.. deprecated:: v4.0.0
"""
warnings.warn(
"jsonschema.RefResolver.in_scope is deprecated and will be "
@@ -1043,10 +1047,11 @@ def validate(instance, schema, cls=None, *args, **kwargs):
itself valid, since not doing so can lead to less obvious error
messages and fail in less obvious or consistent ways.
If you know you have a valid schema already, especially if you
intend to validate multiple instances with the same schema, you
likely would prefer using the `Validator.validate` method directly
on a specific validator (e.g. ``Draft7Validator.validate``).
If you know you have a valid schema already, especially
if you intend to validate multiple instances with
the same schema, you likely would prefer using the
`jsonschema.protocols.Validator.validate` method directly on a
specific validator (e.g. ``Draft20212Validator.validate``).
Arguments:
@@ -1059,7 +1064,7 @@ def validate(instance, schema, cls=None, *args, **kwargs):
The schema to validate with
cls (Validator):
cls (jsonschema.protocols.Validator):
The class that will be used to validate the instance.
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ commands = {envpython} -m sphinx -b spelling {toxinidir}/docs/ {envtmpdir}/build
deps = {[testenv:docs-dirhtml]deps}

[testenv:docs-style]
commands = doc8 {posargs} {toxinidir}/docs
commands = doc8 --max-line-length 1000 {posargs} {toxinidir}/docs
deps =
doc8
pygments