From 8e43f784bea88ee1a7344036f90808b49dc26e53 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Fri, 29 Jul 2022 12:22:35 +0300 Subject: [PATCH 1/6] Experiment with autoapi for generating explicit API documentation. Ref: #590 --- docs/conf.py | 30 ++++++++++++++++++++++++++++++ docs/creating.rst | 4 ++++ docs/errors.rst | 6 ++++++ docs/index.rst | 3 +++ docs/references.rst | 2 ++ docs/requirements.in | 1 + docs/requirements.txt | 17 ++++++++++++++++- docs/spelling-wordlist.txt | 4 ++++ docs/validate.rst | 12 +++++++++++- jsonschema/protocols.py | 3 +-- 10 files changed, 78 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index d4199181a..b8214532a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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", @@ -252,3 +258,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] diff --git a/docs/creating.rst b/docs/creating.rst index 810293f95..8405f3483 100644 --- a/docs/creating.rst +++ b/docs/creating.rst @@ -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 diff --git a/docs/errors.rst b/docs/errors.rst index f3d3fd0a1..7cfb502bf 100644 --- a/docs/errors.rst +++ b/docs/errors.rst @@ -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: diff --git a/docs/index.rst b/docs/index.rst index fc37113b7..707bceaeb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,6 @@ .. module:: jsonschema + :noindex: + .. include:: ../README.rst @@ -13,6 +15,7 @@ Contents references creating faq + api/index Indices and tables diff --git a/docs/references.rst b/docs/references.rst index 9f242994a..e83e4431c 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -6,8 +6,10 @@ Resolving JSON References .. currentmodule:: jsonschema .. autoclass:: RefResolver + :noindex: :members: .. autoexception:: RefResolutionError + :noindex: A JSON reference failed to resolve. diff --git a/docs/requirements.in b/docs/requirements.in index f9ee77e7e..83e52e58e 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -2,6 +2,7 @@ file:.#egg=jsonschema furo lxml sphinx +sphinx-autoapi sphinx-autodoc-typehints sphinx-json-schema-spec sphinxcontrib-spelling diff --git a/docs/requirements.txt b/docs/requirements.txt index f28c7d813..9f2c04f11 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -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 diff --git a/docs/spelling-wordlist.txt b/docs/spelling-wordlist.txt index 198c2be55..1f16b4055 100644 --- a/docs/spelling-wordlist.txt +++ b/docs/spelling-wordlist.txt @@ -7,6 +7,8 @@ ValidationError # 0th, sigh... th callables +# non-codeblocked cls from autoapi +cls deque dereferences deserialize @@ -33,6 +35,8 @@ regex repr runtime sensical +submodule +submodules subschema subschemas subscopes diff --git a/docs/validate.rst b/docs/validate.rst index a343b3051..97039e2de 100644 --- a/docs/validate.rst +++ b/docs/validate.rst @@ -13,6 +13,7 @@ The simplest way to validate an instance under a given schema is to use the :func:`validate` function. .. autofunction:: validate + :noindex: .. [#] For information on creating JSON schemas to validate your data, there is a good introduction to JSON Schema @@ -28,6 +29,7 @@ The Validator Protocol to. .. autoclass:: jsonschema.protocols.Validator + :noindex: :members: All of the `versioned validators ` that are included with @@ -54,6 +56,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,6 +112,7 @@ existing `TypeChecker` or create a new one. You may then create a new .. autoexception:: jsonschema.exceptions.UnknownType + :noindex: .. _versioned-validators: @@ -121,16 +125,22 @@ that each validator class provides see the `Validator` protocol, which each included validator class implements. .. 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 @@ -181,7 +191,6 @@ validation can be enabled by hooking in a format-checking object into an :exclude-members: cls_checks .. 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 @@ -204,6 +213,7 @@ validation can be enabled by hooking in a format-checking object into an .. autoexception:: FormatError + :noindex: :members: diff --git a/jsonschema/protocols.py b/jsonschema/protocols.py index f851a5501..a8406164e 100644 --- a/jsonschema/protocols.py +++ b/jsonschema/protocols.py @@ -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: @@ -103,7 +102,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: ... From 5fe9759e50b40074bbdad0a7280e8fd3ff6a692e Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Fri, 19 Aug 2022 12:36:55 +0300 Subject: [PATCH 2/6] Fix some ambiguous API refs which only fail on Sphinx+Linux :/ --- jsonschema/validators.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/jsonschema/validators.py b/jsonschema/validators.py index 2dde10a21..af3d2f76f 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -1045,10 +1045,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.Validator.validate` method directly on a specific + validator (e.g. ``Draft20212Validator.validate``). Arguments: @@ -1061,7 +1062,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. From 4320a2cb4f0117ddd4d987e8f3d0a60e4e81da21 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Fri, 19 Aug 2022 13:14:22 +0300 Subject: [PATCH 3/6] Of course the tweaked name doesn't work on macOS. Hopefully this works on both. --- jsonschema/validators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsonschema/validators.py b/jsonschema/validators.py index af3d2f76f..cb460474c 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -1048,8 +1048,8 @@ def validate(instance, schema, cls=None, *args, **kwargs): 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.Validator.validate` method directly on a specific - validator (e.g. ``Draft20212Validator.validate``). + `jsonschema.protocols.Validator.validate` method directly on a + specific validator (e.g. ``Draft20212Validator.validate``). Arguments: From bde874d31c8aa2db5123f11ac919742ba7b1d741 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Fri, 19 Aug 2022 18:48:07 +0300 Subject: [PATCH 4/6] Wouldn't be complete without refs which fail now only in ReadTheDocs. :/ --- docs/faq.rst | 6 +++--- jsonschema/__init__.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 8eb9adf65..ec34f7151 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -104,7 +104,7 @@ 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. @@ -212,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:: diff --git a/jsonschema/__init__.py b/jsonschema/__init__.py index 75f294696..7e3b91e74 100644 --- a/jsonschema/__init__.py +++ b/jsonschema/__init__.py @@ -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 From 3f7f1e34e359e290a2e636d111436d6c44d25930 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Fri, 26 Aug 2022 12:29:06 +0300 Subject: [PATCH 5/6] And now yet again some new failures... --- docs/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.rst b/docs/faq.rst index ec34f7151..51a7d2fc2 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -85,7 +85,7 @@ The JSON object ``{}`` is simply the Python `dict` ``{}``, and a JSON Schema lik The :kw:`$ref` keyword is a single notable exception. - Specifically, in the case where `jsonschema` is asked to `resolve a remote reference `, it has no choice but to assume that the remote reference is serialized as JSON, and to deserialize it using the `json` module. + Specifically, in the case where `jsonschema` is asked to `resolve a remote reference `, 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. From 1ad00c8b84d8316860580aa04c98a3a687d6edd9 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Sun, 28 Aug 2022 11:19:24 +0300 Subject: [PATCH 6/6] Another RTD-only failed ref. --- docs/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.rst b/docs/faq.rst index 51a7d2fc2..4dc1c5b61 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -85,7 +85,7 @@ The JSON object ``{}`` is simply the Python `dict` ``{}``, and a JSON Schema lik The :kw:`$ref` keyword is a single notable exception. - Specifically, in the case where `jsonschema` is asked to `resolve a remote reference `, it has no choice but to assume that the remote reference is serialized as JSON, and to deserialize it using the `json` module. + Specifically, in the case where `jsonschema` is asked to `resolve a remote reference `, 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.