Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-sphinx-jsonschema for
openSUSE:Factory checked in at 2021-03-24 16:13:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sphinx-jsonschema (Old)
and /work/SRC/openSUSE:Factory/.python-sphinx-jsonschema.new.2401 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-sphinx-jsonschema"
Wed Mar 24 16:13:54 2021 rev:2 rq:880627 version:1.16.7
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-sphinx-jsonschema/python-sphinx-jsonschema.changes
2020-06-17 14:48:16.416559291 +0200
+++
/work/SRC/openSUSE:Factory/.python-sphinx-jsonschema.new.2401/python-sphinx-jsonschema.changes
2021-03-24 16:13:57.028001847 +0100
@@ -1,0 +2,30 @@
+Tue Mar 16 21:13:34 UTC 2021 - Matthias Fehring <[email protected]>
+
+- Update to 1.16.7:
+ * Fixed: Renders "null" default value as "None"
+- Changes from 1.16.6:
+ * Bug fixes
+- Changes from 1.16.5:
+ * Fixes auto reference without title
+- Changes from 1.16.4:
+ * Introduces the :lift_title: directive option suggested by ankostis.
+ * Fixed a bug in rendering the items attribute of the array type
+- Changes from 1.16.3:
+ * Fixed bugs rendering the default and examples keywords.
+- Changes from 1.16.2:
+ * Introduced the configuration entry jsonschema_options setting
+ default values for the directive options introduced in 1.16.
+ The options now can accept a parameter to explicitly turn the
+ option on or off.
+- Changes from 1.16.1:
+ * Bug fixes
+- Changes from 1.16:
+ * WouterTuinstra reimplemented support for dependencies and properly
+ this time. He also improved error handling and reporting and added
+ a couple of options improving the handling of references. The most
+ important additions are the directive options :lift_description:,
+ :lift_definitions:, :auto_target: and :auto_reference:. In addition
+ to all that he also implemented support for the if, then and else
+ keywords.
+
+-------------------------------------------------------------------
Old:
----
v1.15.tar.gz
New:
----
ab7262e105845c306604eef60803a76ec8ff955e.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-sphinx-jsonschema.spec ++++++
--- /var/tmp/diff_new_pack.HHLCuV/_old 2021-03-24 16:13:57.516002361 +0100
+++ /var/tmp/diff_new_pack.HHLCuV/_new 2021-03-24 16:13:57.520002366 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-sphinx-jsonschema
#
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,12 +18,13 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-sphinx-jsonschema
-Version: 1.15
+Version: 1.16.7
Release: 0
Summary: Sphinx extension to display JSON Schema
License: GPL-3.0-only
URL: https://github.com/lnoor/sphinx-jsonschema
-Source:
https://github.com/lnoor/sphinx-jsonschema/archive/v%{version}.tar.gz
+# Upstream has not released/tagged the current version and the tarball at
pypi.org is missing license and tests
+Source:
https://github.com/lnoor/sphinx-jsonschema/archive/ab7262e105845c306604eef60803a76ec8ff955e.tar.gz
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
@@ -45,7 +46,7 @@
Sphinx extension to display JSON Schema.
%prep
-%setup -q -n sphinx-jsonschema-%{version}
+%setup -q -n sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e
%build
%python_build
@@ -56,6 +57,7 @@
%check
# The tests don't actually properly execute
+# see upstream https://github.com/lnoor/sphinx-jsonschema/issues/56
#%%pytest
%files %{python_files}
++++++ v1.15.tar.gz -> ab7262e105845c306604eef60803a76ec8ff955e.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/README.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/README.rst
--- old/sphinx-jsonschema-1.15/README.rst 2020-04-27 21:24:51.000000000
+0200
+++ new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/README.rst
2021-01-09 18:30:40.000000000 +0100
@@ -1,5 +1,5 @@
.. sphinx-jsonschema README
- Copyright: (C) 2017, Leo Noordergraaf
+ Copyright: (C) 2017-2020, Leo Noordergraaf
=================
sphinx-jsonschema
@@ -9,6 +9,8 @@
authors to display a `JSON Schema <http://json-schema.org>`_ in their
documentation.
+A dockerized version can be found at: `Extended Sphinx
<https://hub.docker.com/r/lnoor/sphinx-extended>`_.
+
It arose out of a personal itch and implements what I needed.
Some features of JSON Schema are (not yet) implemented.
Also I can imagine that other display layouts are desired.
@@ -167,6 +169,38 @@
Changelog
=========
+Version 1.16.5-6
+----------------
+
+Bugfix version.
+
+Version 1.16.4
+--------------
+
+Introduces the ``:lift_title:`` directive option suggested by `ankostis
<https://github.com/ankostis>`_.
+Ankostis also provided an example on how to extend the formatter to handle
custom properties.
+
+Fixed a bug in rendering the ``items`` attribute of the ``array`` type
reported by nijel (https://github.com/nijel).
+
+Version 1.16.1-3
+----------------
+
+Fixed bugs rendering the ``default`` and ``examples`` keywords.
+
+Introduced the configuration entry ``jsonschema_options`` setting default
values for the directive options
+introduced in 1.16. The options now can accept a parameter to explicitly turn
the option on or off.
+
+Version 1.16
+------------
+
+`WouterTuinstra <https://github.com/WouterTuinstra>`_ reimplemented support
for ``dependencies`` and properly this time.
+He also improved error handling and reporting and added a couple of options
improving the handling of references.
+
+The most important additions are the directive options ``:lift_description:``,
``:lift_definitions:``,
+``:auto_target:`` and ``:auto_reference:``.
+
+In addition to all that he also implemented support for the ``if``, ``then``
and ``else`` keywords.
+
Version 1.15
------------
@@ -187,19 +221,19 @@
Version 1.10
------------
-Ivan Vysotskyy (https://github.com/ivysotskyi) contributed the idea to use an
array with
+`Ivan Vysotskyy <https://github.com/ivysotskyi>`_ contributed the idea to use
an array with
the ``description`` key resulting in the new ``$$description`` key.
Version 1.9
-----------
-Tom Walter (https://github.com/EvilPuppetMaster) contributed the ``example``
support.
+`Tom Walter <https://github.com/EvilPuppetMaster>`_ contributed the
``example`` support.
Version 1.4
-----------
-Chris Holdgraf (https://github.com/choldgraf) contributed Python3 and yaml
support.
+`Chris Holdgraf <https://github.com/choldgraf>`_ contributed Python3 and yaml
support.
Version 1.3
-----------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/conf.py
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/conf.py
--- old/sphinx-jsonschema-1.15/docs/conf.py 2020-04-27 21:24:51.000000000
+0200
+++ new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/conf.py
2021-01-09 18:30:40.000000000 +0100
@@ -52,7 +52,7 @@
# General information about the project.
project = u'Sphinx JSON Schema'
-copyright = u'2017-2020, Leo Noordergraaf'
+copyright = u'2017-2021, Leo Noordergraaf'
author = u'Leo Noordergraaf'
# The version info for the project you're documenting, acts as replacement for
@@ -60,9 +60,9 @@
# built documents.
#
# The short X.Y version.
-version = u'1.15'
+version = u'1.16'
# The full version, including alpha/beta/rc tags.
-release = u'1.15'
+release = u'1.16.7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/directive.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/directive.rst
--- old/sphinx-jsonschema-1.15/docs/directive.rst 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/directive.rst
2021-01-09 18:30:40.000000000 +0100
@@ -10,6 +10,8 @@
This means that you can write the schemas in either json or yaml notation
and they will be processed identically.
+Usage
+-----
To display a schema fetched from a website:
@@ -121,3 +123,254 @@
"type": "string"
}
}
+
+Options
+-------
+
+There a couple of options implemented in **sphinx-jsonschema** that control
the way a schema is rendered or processed.
+These options are:
+
+lift_title (default: True)
+ Uses the title to create a new section in your document and creates an
anchor you can refer to using jsonschema's
+ ``$ref`` or ReStructuredText's ``:ref:`` notation.
+ When `False` the title becomes part of the table rendered from the schema,
the table cannot be referenced and the
+ option ``:lift_description:`` is ignored.
+
+lift_description (default: False)
+ Places the description between the title and the table rendering the
schema.
+ This option is ignored when ``:lift_title:`` is `False`.
+
+lift_definitions (default: False)
+ Removed the items under the ``definitions`` key and renders each of them
separately as if they are top-level
+ schemas.
+
+auto_target (default: False)
+ Automatically generate values for the ``$$target`` key.
+ Especially useful in combination with ``:lift_definitions:``.
+
+auto_reference (default: False)
+ Automatically resolves references when possible.
+ Works well with ``:auto_target:`` and ``:lift_definitions:``.
+
+
+Lift Title
+++++++++++
+
+By default the schema's top level title is displayed above the table
containing the remainder of the schema.
+This title becomes a section that can be included in the table of contents and
the index.
+It is also used to resolve references to the schema from either other schemas
of from elsewhere in the documentation.
+
+This option mainly exists to suppress this behaviour.
+One place where this is desirable is when using jsonschema to validate and
document function parameters.
+See `issue 48 <https://github.com/lnoor/sphinx-jsonschema/issues/48>`_ for an
example.
+
+Lift Description
+++++++++++++++++
+
+Lifts the ``description`` from the table and places it between the title and
the table.
+You will need to have a title defined and the flag **\:lift_description:**
otherwise it will be included into
+the table:
+
+.. code-block::
+
+ .. jsonschema::
+ :lift_description:
+
+ {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "id": "http://example.com/schemas/example.json",
+ "title": "Example Separate Description",
+ "description": "This is just a tiny example of a schema rendered
by `sphinx-jsonschema <http://github.com/lnoor/sphinx-jsonschema>`_.\n\nWhereby
the description can shown as text outside the table, and you can still use
*reStructuredText* in a description.",
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 100,
+ "pattern": "^[A-Z]+$"
+ }
+
+which renders:
+
+.. jsonschema::
+ :lift_description:
+
+ {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "id": "http://example.com/schemas/example.json",
+ "title": "Example Separate Description",
+ "description": "This is just a tiny example of a schema rendered by
`sphinx-jsonschema <http://github.com/lnoor/sphinx-jsonschema>`_.\n\nWhereby
the description can shown as text outside the table, and you can still use
*reStructuredText* in a description.",
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 100,
+ "pattern": "^[A-Z]+$"
+ }
+
+Lift Definitions
+++++++++++++++++
+
+To separate the ``definitions`` from the table you will need to have the flag
**\:lift_definitions:** included.
+For each item inside the ``definitions`` it will make a new section with title
and a table of the items inside.
+It's advised to also use the **\:auto_reference:** flag to auto link ``$ref``
to a local ``definitions`` title.
+
+.. code-block:: rst
+
+ .. jsonschema::
+ :lift_definitions:
+
+ {
+ "title": "Example with definitions",
+ "definitions": {
+ "football_player": {
+ "type": "object",
+ "required": ["first_name", "last_name", "age"],
+ "properties": {
+ "first_name": {"type": "string"},
+ "last_name": {"type": "string"},
+ "age": {"type": "integer"}
+ }
+ },
+ "football_team": {
+ "type": "object",
+ "required": ["team", "league"],
+ "properties": {
+ "team": {"type": "string"},
+ "league": {"type": "string"},
+ "year_founded": {"type": "integer"}
+ }
+ }
+ }
+ }
+
+which renders:
+
+.. jsonschema::
+ :lift_definitions:
+
+ {
+ "title": "Example with definitions",
+ "definitions": {
+ "football_player": {
+ "type": "object",
+ "required": ["first_name", "last_name", "age"],
+ "properties": {
+ "first_name": {"type": "string"},
+ "last_name": {"type": "string"},
+ "age": {"type": "integer"}
+ }
+ },
+ "football_team": {
+ "type": "object",
+ "required": ["team", "league"],
+ "properties": {
+ "team": {"type": "string"},
+ "league": {"type": "string"},
+ "year_founded": {"type": "integer"}
+ }
+ }
+ }
+ }
+
+Auto Target and Reference
++++++++++++++++++++++++++
+
+With the **\:auto_target:** flag there will be a target created with filename
and optional pointer.
+When you would include auto target on multiple JSON schemas with identical
file names it will cause a conflict
+within your build only the last build target will be used by the references.
+This also applies if you would embed the schema directly into your
documentation; in that case the document name is used
+as the file name.
+
+With the **\:auto_reference:** flag there will be more logic applied to reduce
the amount of undefined label warnings.
+It will check if it is referencing to itself and if there would be a title to
link to,
+when there are titles in the same page that have an identical name it will
cause linking issues.
+If you didn't separate definitions from the schema the ``$ref`` will become a
text field without a linked reference.
+If the ``$ref`` would point to an other schema from the path it will extract
the filename it expected
+to be included into your documentation with **\:auto_target:**.
+
+Mainly the **\:auto_reference:** flag influences behavior of the existing
``$$target`` method and could potentially break links.
+
+| See below the schema whereby both options are included.
+ For each section it will create a target in this example filename of the
document as the schema is added as context and it's pointer if there would be
one.
+| :ref:`directive.rst` this link as raw text using reStructuredText format
would be: **\:ref:`directive.rst`**.
+| And for the definition :ref:`directive.rst#/definitions/person` the raw text
would be: **\:ref:`directive.rst#/definitions/person`**.
+
+.. code-block:: rst
+
+ .. jsonschema::
+ :lift_definitions:
+ :auto_reference:
+ :auto_target:
+
+ {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Example of Target & Reference",
+ "type": "object",
+ "properties": {
+ "person": { "$ref": "#/definitions/person" }
+ },
+ "definitions": {
+ "person": {
+ "type": "object",
+ "properties": {
+ "name": { "type": "string" },
+ "children": {
+ "type": "array",
+ "items": { "$ref": "#/definitions/person" },
+ "default": []
+ }
+ }
+ }
+ }
+ }
+
+which renders:
+
+.. jsonschema::
+ :lift_definitions:
+ :auto_reference:
+ :auto_target:
+
+ {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Example of Target & Reference",
+ "type": "object",
+ "properties": {
+ "person": { "$ref": "#/definitions/person" }
+ },
+ "definitions": {
+ "person": {
+ "type": "object",
+ "properties": {
+ "name": { "type": "string" },
+ "children": {
+ "type": "array",
+ "items": { "$ref": "#/definitions/person" },
+ "default": []
+ }
+ }
+ }
+ }
+ }
+
+Setting default values
+++++++++++++++++++++++
+When you want to use the options \:lift_definitions: \:lift_description,
\:auto_target
+and \:auto_reference in most schema renderings it is more convenient to set
them once
+for your whole project.
+
+The ``conf.py`` option **jsonschema_options** lets you do so.
+It takes a dict as value the boolean valued keys of which have the same name
as the options.
+
+So, in ``conf.py`` you can state:
+.. code-block:: py
+
+ jsonschema_options = {
+ 'lift_description': True,
+ 'aut_reference': True
+ }
+
+By default all four options are False.
+
+Overruling defaults
+^^^^^^^^^^^^^^^^^^^
+The default values for the options can be overruled by setting the directive
options.
+They accept an optional argument which can be one of the words ``On``,
``Off``, ``True``
+or ``False``. The default value for the argument is ``True``.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/extensions.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/extensions.rst
--- old/sphinx-jsonschema-1.15/docs/extensions.rst 1970-01-01
01:00:00.000000000 +0100
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/extensions.rst
2021-01-09 18:30:40.000000000 +0100
@@ -0,0 +1,38 @@
+Extending jsonschema
+====================
+
+I didn't create jsonschema with extensibility in mind.
+But I also never thought so many people would find it useful.
+
+Render custom keywords
+----------------------
+
+That being said `ankostis <https://github.com/ankostis>`_ needed a way to
render his own custom keywords.
+This is his solution, you need to append this code to your `conf.py` file.
+
+.. code-block:: python
+
+ ## PATCH `sphinx-jsonschema`
+ # to render the extra `units`` and ``tags`` schema properties
+ #
+ def _patched_sphinx_jsonschema_simpletype(self, schema):
+ """Render the *extra* ``units`` and ``tags`` schema properties for
every object."""
+ rows = _original_sphinx_jsonschema_simpletype(self, schema)
+
+ if "units" in schema:
+ units = schema["units"]
+ units = f"``{units}``"
+ rows.append(self._line(self._cell("units"), self._cell(units)))
+ del schema["units"]
+
+ if "tags" in schema:
+ tags = ", ".join(f"``{tag}``" for tag in schema["tags"])
+ rows.append(self._line(self._cell("tags"), self._cell(tags)))
+ del schema["tags"]
+
+ return rows
+
+ sjs_wide_format = importlib.import_module("sphinx-jsonschema.wide_format")
+ _original_sphinx_jsonschema_simpletype =
sjs_wide_format.WideFormat._simpletype # type: ignore
+ sjs_wide_format.WideFormat._simpletype =
_patched_sphinx_jsonschema_simpletype # type: ignore
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/index.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/index.rst
--- old/sphinx-jsonschema-1.15/docs/index.rst 2020-04-27 21:24:51.000000000
+0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/index.rst
2021-01-09 18:30:40.000000000 +0100
@@ -10,7 +10,7 @@
I only tested it for use with the `draft 4
<http://json-schema.org/specification-links.html#draft-4>`_ specification of
JSON Schema.
I was pleasantly surprised to find that the software is useful to others as
well.
-Therefore it made sense to document intended use.
+Therefore it made sense to document its intended use.
Contents
========
@@ -22,6 +22,7 @@
directive
schemakeywords
organization
+ extensions
Indices and tables
==================
@@ -33,6 +34,38 @@
Changelog
=========
+Version 1.16.5-6
+----------------
+
+Bugfix version.
+
+Version 1.16.4
+--------------
+
+Introduces the ``:lift_title:`` directive option suggested by `ankostis
<https://github.com/ankostis>`_.
+Ankostis also provided an example on how to extend the formatter to handle
custom properties.
+
+Fixed a bug in rendering the ``items`` attribute of the ``array`` type
reported by `nijel <https://github.com/nijel>`_.
+
+Version 1.16.1-3
+----------------
+
+Fixed bugs rendering the ``default`` and ``examples`` keywords.
+
+Introduced the configuration entry ``jsonschema_options`` setting default
values for the directive options
+introduced in 1.16. The options now can accept a parameter to explicitly turn
the option on or off.
+
+Version 1.16
+------------
+
+`WouterTuinstra <https://github.com/WouterTuinstra>`_ reimplemented support
for ``dependencies`` and properly this time.
+He also improved error handling and reporting and added a couple of options
improving the handling of references.
+
+The most important additions are the directive options ``:lift_description:``,
``:lift_definitions:``,
+``:auto_target:`` and ``:auto_reference:``.
+
+In addition to all that he also implemented support for the ``if``, ``then``
and ``else`` keywords.
+
Version 1.15
------------
@@ -46,23 +79,23 @@
Version 1.11
------------
-Solved a divergence of the standard reported by bbasic
(https://github.com/bbasics).
+Solved a divergence of the standard reported by `bbasic
<https://github.com/bbasics>`_.
Version 1.10
------------
-Ivan Vysotskyy (https://github.com/ivysotskyi) contributed the idea to use an
array with
+`Ivan Vysotskyy <https://github.com/ivysotskyi>`_ contributed the idea to use
an array with
the ``description`` key resulting in the new ``$$description`` key.
Version 1.9
-----------
-Tom Walter (https://github.com/EvilPuppetMaster) contributed the ``example``
support.
+`Tom Walter <https://github.com/EvilPuppetMaster>`_ contributed the
``example`` support.
Version 1.4
-----------
-Chris Holdgraf (https://github.com/choldgraf) contributed Python3 and yaml
support.
+`Chris Holdgraf <https://github.com/choldgraf>`_ contributed Python3 and yaml
support.
Version 1.3
-----------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/installation.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/installation.rst
--- old/sphinx-jsonschema-1.15/docs/installation.rst 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/installation.rst
2021-01-09 18:30:40.000000000 +0100
@@ -22,3 +22,11 @@
-----------
The source code for this extension can be found on `GitHub
<https://github.com/lnoor/sphinx-jsonschema>`_.
+
+Docker image
+------------
+
+A Docker image containing Sphinx and a number of extensions, including
sphinx-jsonschema, can be found
+at `Extended Sphinx <https://hub.docker.com/r/lnoor/sphinx-extended>`_.
+This Docker image is generated from the Dockerfile on `Github
<https://github.com/lnoor/docker-sphinx-extended>`_.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/organization.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/organization.rst
--- old/sphinx-jsonschema-1.15/docs/organization.rst 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/organization.rst
2021-01-09 18:30:40.000000000 +0100
@@ -4,9 +4,7 @@
As stated earlier, I needed this to manage and document rather large schemas.
I wanted to organize these schemas in such a way that the number of levels
-remained under control. Have a look at the documentation and schemas at the
-`Nextpertise API documentation <http://api.nextpertise.nl/documentation>`_ for
-an example.
+remained under control.
To achieve this I wanted the schemas to be able to reference other (reusable)
schemas
using the ``$ref`` keyword. These subschemas, should be documented somewhere
else but
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/docs/schemakeywords.rst
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/schemakeywords.rst
--- old/sphinx-jsonschema-1.15/docs/schemakeywords.rst 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/docs/schemakeywords.rst
2021-01-09 18:30:40.000000000 +0100
@@ -40,7 +40,7 @@
$$target
--------
-After some experimentation I concluded that I needed to extend JSON Schema
with a single key.
+After some experimentation I concluded that I needed to extend JSON Schema.
Most of the time sphinx-jsonschema just does the 'sensible' thing.
The ``$ref`` key in JSON Schema posed a problem.
@@ -129,7 +129,7 @@
The `$$target` is needed because **sphinx-jsonschema** does not resolve `$ref`
like
a validator using the `id` key etc. The value of `$$target` should match the
corresponding
-`$ref` value exactly. When the schema is referenced from mulitple locations
using different
+`$ref` value exactly. When the schema is referenced from multiple locations
using different
values for `$ref` then the value of `$$target` may be an array of strings
instead of a single
string.
@@ -220,7 +220,7 @@
.. sidebar:: Benefits
This method lets you arrange the schema parts to match the structure of
your documentation
- and also allows you to create mulitple copies of a schema in your
documentation.
+ and also allows you to create multiple copies of a schema in your
documentation.
.. jsonschema:: #/calls
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/setup.py
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/setup.py
--- old/sphinx-jsonschema-1.15/setup.py 2020-04-27 21:24:51.000000000 +0200
+++ new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/setup.py
2021-01-09 18:30:40.000000000 +0100
@@ -10,7 +10,7 @@
setup(
name='sphinx-jsonschema',
- version='1.15', # don't forget: must match __init__.py::setup() return
value
+ version='1.16.7', # don't forget: must match __init__.py::setup()
return value
description='Sphinx extension to display JSON Schema',
long_description=long_description,
@@ -29,7 +29,6 @@
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: OS Independent',
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Documentation',
'Topic :: Documentation :: Sphinx'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/sphinx-jsonschema/__init__.py
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/sphinx-jsonschema/__init__.py
--- old/sphinx-jsonschema-1.15/sphinx-jsonschema/__init__.py 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/sphinx-jsonschema/__init__.py
2021-01-09 18:30:40.000000000 +0100
@@ -16,74 +16,168 @@
import os.path
import json
from jsonpointer import resolve_pointer
+from traceback import format_exception, format_exception_only
import yaml
from collections import OrderedDict
-from docutils.parsers.rst import Directive
+from docutils import nodes, utils
+from docutils.parsers.rst import Directive, DirectiveError
+from docutils.parsers.rst import directives
+from docutils.utils import SystemMessagePropagation
+from docutils.utils.error_reporting import SafeString
from .wide_format import WideFormat
-# TODO find out if app is accessible in some other way
-_glob_app = None
+
+def flag(argument):
+ if argument is None:
+ return True
+
+ value = argument.lower().strip()
+ if value in ['on', 'true']:
+ return True
+ if value in ['off', 'false']:
+ return False
+ raise ValueError('"%s" unknown, choose from "On", "True", "Off" or
"False"' % argument)
class JsonSchema(Directive):
optional_arguments = 1
has_content = True
+ option_spec = {'lift_title': flag,
+ 'lift_description': flag,
+ 'lift_definitions': flag,
+ 'auto_reference': flag,
+ 'auto_target': flag,
+ 'timeout': float}
- def __init__(self, directive, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
- assert directive == 'jsonschema'
+ def run(self):
+ try:
+ schema, source, pointer = self.get_json_data()
+ format = WideFormat(self.state, self.lineno, source, self.options,
self.state.document.settings.env.app)
+ return format.run(schema, pointer)
+ except SystemMessagePropagation as detail:
+ return [detail.args[0]]
+ except DirectiveError as error:
+ raise self.directive_error(error.level, error.msg)
+ except Exception as error:
+ tb = error.__traceback__
+ # loop through all traceback points to only return the last
traceback
+ while tb.tb_next:
+ tb = tb.tb_next
- #breakpoint()
+ raise self.error(''.join(format_exception(type(error), error, tb,
chain=False)))
+
+ def get_json_data(self):
+ """
+ Get JSON data from the directive content, from an external
+ file, or from a URL reference.
+ """
+ if self.arguments:
+ filename, pointer = self._splitpointer(self.arguments[0])
+ else:
+ filename = None
+ pointer = ''
- self.options = options
- self.state = state
- self.lineno = lineno
- self.statemachine = state_machine
-
- if len(arguments) == 1:
- filename, pointer = self._splitpointer(arguments[0])
- if filename != '':
- self._load_external(filename)
- else:
- self._load_internal(content)
- if pointer:
- self.schema = resolve_pointer(self.schema, pointer)
+ if self.content:
+ schema, source = self.from_content(filename)
+ elif filename and filename.startswith('http'):
+ schema, source = self.from_url(filename)
+ elif filename:
+ schema, source = self.from_file(filename)
else:
- self._load_internal(content)
+ raise self.error('"%s" directive has no content or a reference to
an external file.'
+ % self.name)
- def run(self):
- format = WideFormat(self.state, self.lineno, _glob_app)
- return format.transform(self.schema)
+ try:
+ schema = self.ordered_load(schema)
+ except Exception as error:
+ error = self.state_machine.reporter.error(
+ '"%s" directive encountered a the following error while
parsing the data.\n %s'
+ % (self.name,
SafeString("".join(format_exception_only(type(error), error)))),
+ nodes.literal_block(schema, schema), line=self.lineno)
+ raise SystemMessagePropagation(error)
- def _load_external(self, file_or_url):
- if file_or_url.startswith('http'):
+ if pointer:
try:
- import requests
- except ImportError:
- self.error("JSONSCHEMA loading from http requires requests.
Try 'pip install requests'")
- text = requests.get(file_or_url)
- self.schema = self.ordered_load(text.content)
+ schema = resolve_pointer(schema, pointer)
+ except KeyError:
+ error = self.state_machine.reporter.error(
+ '"%s" directive encountered a KeyError when trying to
resolve the pointer'
+ ' in schema: %s' % (self.name, SafeString(pointer)),
+ nodes.literal_block(schema, schema), line=self.lineno)
+ raise SystemMessagePropagation(error)
+
+ return schema, source, pointer
+
+ def from_content(self, filename):
+ if filename:
+ error = self.state_machine.reporter.error(
+ '"%s" directive may not both specify an external file and'
+ ' have content.' % self.name,
+ nodes.literal_block(self.block_text, self.block_text),
+ line=self.lineno)
+ raise SystemMessagePropagation(error)
+
+ source = self.content.source(0)
+ data = '\n'.join(self.content)
+ return data, source
+
+ def from_url(self, url):
+ # To prevent loading on a not existing adress added timeout
+ timeout = self.options.get('timeout', 30)
+ if timeout < 0:
+ timeout = None
+
+ try:
+ import requests
+ except ImportError:
+ raise self.error('"%s" directive requires requests when loading
from http.'
+ ' Try "pip install requests".' % self.name)
+
+ try:
+ response = requests.get(url, timeout=timeout)
+ except requests.exceptions.RequestException as e:
+ raise self.error(u'"%s" directive recieved an "%s" when loading
from url: %s.'
+ % (self.name, type(e), url))
+
+ if response.status_code != 200:
+ # When making a connection to the url a status code will be
returned
+ # Normally a OK (200) response would we be returned all other
responses
+ # an error will be raised could be separated futher
+ raise self.error(u'"%s" directive received an "%s" when loading
from url: %s.'
+ % (self.name, response.reason, url))
+
+ # response content always binary converting with decode() no specific
format defined
+ data = response.content.decode()
+ return data, url
+
+ def from_file(self, filename):
+ document_source = os.path.dirname(self.state.document.current_source)
+ if not os.path.isabs(filename):
+ # file relative to the path of the current rst file
+ source = os.path.join(document_source, filename)
else:
- if not os.path.isabs(file_or_url):
- # file relative to the path of the current rst file
- dname =
os.path.dirname(self.statemachine.input_lines.source(0))
- file_or_url = os.path.join(dname, file_or_url)
- with open(file_or_url) as file:
- text = file.read()
- self.schema = self.ordered_load(text, yaml.SafeLoader)
-
- def _load_internal(self, text):
- if text is None or len(text) == 0:
- self.error("JSONSCHEMA requires either filename, http url or
inline content")
- self.schema = self.ordered_load('\n'.join(text), yaml.SafeLoader)
+ source = filename
+
+ try:
+ with open(source) as file:
+ data = file.read()
+ except IOError as error:
+ raise self.error(u'"%s" directive encountered an IOError while
loading file: %s\n%s'
+ % (self.name, source, error))
+
+ # Simplifing source path and to the document a new dependency
+ source = utils.relative_path(document_source, source)
+ self.state.document.settings.record_dependencies.add(source)
+
+ return data, source
def _splitpointer(self, path):
- val = path.split('#', 1)
+ val = path.rsplit('#', 1)
if len(val) == 1:
- val.append(None)
+ val.append('')
return val
-
- def ordered_load(self, text, Loader=yaml.Loader,
object_pairs_hook=OrderedDict):
+ def ordered_load(self, text, Loader=yaml.SafeLoader,
object_pairs_hook=OrderedDict):
"""Allows you to use `pyyaml` to load as OrderedDict.
Taken from https://stackoverflow.com/a/21912744/1927102
@@ -94,26 +188,22 @@
def construct_mapping(loader, node):
loader.flatten_mapping(node)
return object_pairs_hook(loader.construct_pairs(node))
+
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping)
+
+ text = text.replace('\\(', '\\\\(')
+ text = text.replace('\\)', '\\\\)')
try:
- text = text.replace('\\(', '\\\\(')
- text = text.replace('\\)', '\\\\)')
- try:
- result = yaml.load(text, OrderedLoader)
- except yaml.scanner.ScannerError:
- # will it load as plain json?
- result = json.loads(text, object_pairs_hook=object_pairs_hook)
- except Exception as e:
- print("exception: ",e)
- self.error(e)
- result = {}
+ result = yaml.load(text, OrderedLoader)
+ except yaml.scanner.ScannerError:
+ # will it load as plain json?
+ result = json.loads(text, object_pairs_hook=object_pairs_hook)
return result
def setup(app):
- global _glob_app
- _glob_app = app
app.add_directive('jsonschema', JsonSchema)
- return {'version': '1.15'}
+ app.add_config_value('jsonschema_options', {}, 'env')
+ return {'version': '1.16.7'}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/sphinx-jsonschema-1.15/sphinx-jsonschema/wide_format.py
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/sphinx-jsonschema/wide_format.py
--- old/sphinx-jsonschema-1.15/sphinx-jsonschema/wide_format.py 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/sphinx-jsonschema/wide_format.py
2021-01-09 18:30:40.000000000 +0100
@@ -6,12 +6,13 @@
In this layout for each nesting level the table is extended by
one or more columns.
- :copyright: Copyright 2017-2020, Leo Noordergraaf
+ :copyright: Copyright 2017-2021, Leo Noordergraaf
:licence: GPL v3, see LICENCE for details.
"""
from sys import version_info
-import string
+from copy import deepcopy
+from pathlib import Path
from docutils import statemachine
from docutils import nodes
from docutils.nodes import fully_normalize_name as normalize_name
@@ -26,7 +27,7 @@
KV_SIMPLE = [
'multipleOf', 'maximum', 'exclusiveMaximum', 'minimum',
'exclusiveMinimum', 'maxLength', 'minLength', 'pattern', 'default',
- 'format'
+ 'format', 'const'
]
KV_ARRAY = ['maxItems', 'minItems', 'uniqueItems']
@@ -37,66 +38,147 @@
SINGLEOBJECTS = ['not']
- def __init__(self, state, lineno, app):
+ CONDITIONAL = ["if", "then", "else"]
+
+ option_defaults = {
+ 'lift_title': True,
+ 'lift_description': False,
+ 'lift_definitions': False,
+ 'auto_target': False,
+ 'auto_reference': False
+ }
+
+ def __init__(self, state, lineno, source, options, app):
super(WideFormat, self).__init__()
self.app = app
self.trans = None
self.lineno = lineno
self.state = state
+ self.filename = self._get_filename(source)
self.nesting = 0
+ self.ref_titles = {}
+ self.target_pointer = '#'
- def transform(self, schema):
- body = self._dispatch(schema)
- cols, head, body = self._cover(schema, body)
- table = self.state.build_table((cols, head, body), self.lineno)
- return self._wrap_in_section(schema, table)
+ self.options = deepcopy(self.option_defaults)
+ self.options.update(app.config.jsonschema_options)
+ self.options.update(options)
+
+ def run(self, schema, pointer=''):
+ # To set the correct auto target for a nested definitions we need to
save
+ # the current pointer that may be used inside recursive run append on
+ before = self.target_pointer
+ self.target_pointer += pointer
+
+ result = []
+ target = self._target(schema, self.target_pointer)
+ section = self._section(schema)
+
+ table, definitions = self.transform(schema)
+
+ # restore to previous pointer
+ self.target_pointer = before
+
+ if target:
+ result.append(target)
+
+ if section:
+ section += table
+ section += definitions
+ result.append(section)
+ else:
+ if table:
+ result.append(table)
+ if definitions:
+ result.extend(definitions)
- def _dispatch(self, schema, label=None):
- # Main driver of the recursive schema traversal.
- rows = []
- self.nesting += 1
+ return result
- if 'type' in schema:
- # select processor for type
- if 'object' in schema['type']:
- rows = self._objecttype(schema)
- elif 'array' in schema['type']:
- rows = self._arraytype(schema)
-# else: # to fix: #31
-# rows = self._simpletype(schema)
+ def transform(self, schema):
+ body, definitions = self._dispatch(schema)
+ if len(body) > 0:
+ cols, head, body = self._cover(schema, body)
+ table = self.state.build_table((cols, head, body), self.lineno)
else:
- rows = self._objecttype(schema)
- self._check_description(schema, rows)
- rows.extend(self._simpletype(schema)) # to fix: #31
+ table = None
+ return table, definitions
- if '$ref' in schema:
- rows.append(self._line(self._cell(':ref:`' + schema['$ref'] +
'`')))
- del schema['$ref']
+ def _target(self, schema, pointer=''):
+ # Wrap section and table in a target (anchor) node so
+ # that it can be referenced from other sections.
+ labels = self.app.env.domaindata['std']['labels']
+ anonlabels = self.app.env.domaindata['std']['anonlabels']
+ docname = self.app.env.docname
- for k in self.COMBINATORS:
- # combinators belong at this level as alternative to type
- if k in schema:
- items = []
- for s in schema[k]:
- items.extend(self._dispatch(s, self._cell('-')))
- rows.extend(self._prepend(self._cell(k), items))
- del schema[k]
+ targets = []
- for k in self.SINGLEOBJECTS:
- # combinators belong at this level as alternative to type
- if k in schema:
- rows.extend(self._dispatch(schema[k], self._cell(k)))
- del schema[k]
+ if '$$target' in schema:
+ if not isinstance(schema['$$target'], list):
+ targets.append(schema['$$target'])
+ else:
+ targets.extend(schema['$$target'])
+ del schema['$$target']
- # definitions aren't really type equiv's but still best place for them
- rows.extend(self._objectproperties(schema, 'definitions'))
+ if self.options['auto_target']:
+ # When schema's multiple schema's are writen with content but
without a pointer
+ # you get multiple equal named targets, all $ref will link to the
last created schema
+ # The same applies if you would load files with equal name into
your documentation
+ if len(pointer) > 1:
+ targets.append(self.filename + pointer)
+ else:
+ targets.append(self.filename)
- if label is not None:
- # prepend label column if required
- rows = self._prepend(label, rows)
+ if targets:
+ targetnode = nodes.target()
+ anchorid = nodes.make_id((schema['title'] if 'title' in schema
else targets[0]))
+ targetnode['ids'].append(anchorid)
+ targetnode['names'].append(anchorid)
+ targetnode.line = self.lineno
- self.nesting -= 1
- return rows
+ for target in targets:
+ anchor = normalize_name(target)
+ anonlabels[anchor] = docname, targetnode['ids'][0]
+ labels[anchor] = docname, targetnode['ids'][0],
(schema['title'] if 'title' in schema else target)
+
+ return targetnode
+
+ return None
+
+ def _section(self, schema):
+ if 'title' in schema and self.options['lift_title']:
+ # Wrap the resulting table in a section giving it a caption and an
+ # entry in the table of contents.
+ # unable to use self.state.section() to make a section as style is
unknown
+ # all sections will be placed inside current section
+ section_node = nodes.section()
+ textnodes, title_messages =
self.state.inline_text(schema['title'], self.lineno)
+ titlenode = nodes.title(schema['title'], '', *textnodes)
+ name = normalize_name(titlenode.astext())
+ section_node['names'].append(name)
+ section_node += titlenode
+ section_node += title_messages
+ self.state.document.note_implicit_target(section_node,
section_node)
+
+ if self.nesting == 0:
+ self.ref_titles[self.nesting] = schema['title']
+
+ if self.options['lift_description']:
+ self._get_description(schema, section_node)
+
+ del schema['title']
+ return section_node
+
+ return None
+
+ def _get_description(self, schema, node):
+ if 'description' in schema:
+
self.state.nested_parse(self._convert_content(schema['description']),
self.lineno, node)
+ del schema['description']
+
+ if '$$description' in schema:
+ if isinstance(schema['$$description'], list):
+ schema['$$description'] = '\n'.join(schema['$$description'])
+
self.state.nested_parse(self._convert_content(schema['$$description']),
self.lineno, node)
+ del schema['$$description']
def _cover(self, schema, body):
# Patch up and finish the table.
@@ -104,9 +186,13 @@
# Outermost id becomes schema url
# NB: disregards interior id's
+ # to support both 'id' draft 4 only and '$id' from draft 6
if 'id' in schema:
body.insert(0, self._line(self._cell(schema['id'])))
del schema['id']
+ elif '$id' in schema:
+ body.insert(0, self._line(self._cell(schema['$id'])))
+ del schema['$id']
# patch up if necessary, all rows should be of equal length
nrcols = self._square(body)
@@ -120,51 +206,41 @@
# All columns have same width, to change alter the first element
return [1] * nrcols, head, body
- def _wrap_in_section(self, schema, table):
-
- result = list()
- if '$$target' in schema:
- # Wrap section and table in a target (anchor) node so
- # that it can be referenced from other sections.
- labels = self.app.env.domaindata['std']['labels']
- anonlabels = self.app.env.domaindata['std']['anonlabels']
- docname = self.app.env.docname
- targets = schema['$$target']
- if not isinstance(targets, list):
- targets = [targets]
+ def _dispatch(self, schema, label=None):
+ # Main driver of the recursive schema traversal.
+ rows = []
+ self.nesting += 1
- targetnode = nodes.target()
- for target in targets:
- anchor = normalize_name(target)
- targetnode['ids'].append(anchor)
- targetnode['names'].append(anchor)
- anonlabels[anchor] = docname, targetnode['ids'][0]
- labels[anchor] = docname, targetnode['ids'][0],
(schema['title'] if 'title' in schema else anchor)
- targetnode.line = self.lineno
- result.append(targetnode)
- del schema['$$target']
+ if 'definitions' in schema and self.options['lift_definitions']:
+ definitions = self._definitions(schema)
+ else:
+ definitions = None
- if 'title' in schema:
- # Wrap the resulting table in a section giving it a caption and an
- # entry in the table of contents.
- memo = self.state.memo
- mylevel = memo.section_level
- memo.section_level += 1
- section_node = nodes.section()
- textnodes, title_messages =
self.state.inline_text(schema['title'], self.lineno)
- titlenode = nodes.title(schema['title'], '', *textnodes)
- name = normalize_name(titlenode.astext())
- section_node['names'].append(name)
- section_node += titlenode
- section_node += title_messages
- self.state.document.note_implicit_target(section_node,
section_node)
- section_node += table
- memo.section_level = mylevel
- result.append(section_node)
- del schema['title']
+ if 'type' in schema:
+ # select processor for type
+ if 'object' in schema['type']:
+ rows = self._objecttype(schema)
+ elif 'array' in schema['type']:
+ rows = self._arraytype(schema)
else:
- result.append(table)
- return result
+ rows = self._objecttype(schema)
+ self._check_description(schema, rows)
+ rows.extend(self._simpletype(schema))
+
+ if '$ref' in schema:
+ rows.extend(self._reference(schema))
+
+ rows.extend(self._complexstructures(schema))
+
+ # definitions aren't really type equiv's but still best place for them
+ rows.extend(self._objectproperties(schema, 'definitions'))
+
+ if label is not None:
+ # prepend label column if required
+ rows = self._prepend(label, rows)
+
+ self.nesting -= 1
+ return rows, definitions
def _objecttype(self, schema):
# create description and type rows
@@ -177,16 +253,23 @@
return rows
def _arraytype(self, schema):
+ def oneline(label, item):
+ if isinstance(item, dict):
+ rows.extend(self._dispatch(item, label)[0])
+ else:
+ rows.append(self._line(label, self._cell(item)))
+
# create description and type rows
rows = self._simpletype(schema)
if 'items' in schema:
- # add items label
- rows.append(self._line(self._cell('items')))
- items = schema['items'] if type(schema['items']) == list else
[schema['items']]
- for item in items:
- label = self._cell('-')
- rows.extend(self._dispatch(item, label))
+ if type(schema['items']) == list:
+ rows.append(self._line(self._cell('items')))
+ for item in schema['items']:
+ label = self._cell('-')
+ oneline(label, item)
+ else:
+ oneline(self._cell('items'), schema['items'])
del schema['items']
rows.extend(self._bool_or_object(schema, 'additionalItems'))
@@ -196,7 +279,7 @@
def _simpletype(self, schema):
rows = []
- if 'title' in schema and self.nesting > 1:
+ if 'title' in schema and (not self.options['lift_title'] or
self.nesting > 1):
rows.append(self._line(self._cell('*' + schema['title'] + '*')))
del schema['title']
@@ -242,11 +325,76 @@
if prop in schema['required']:
bold = '**'
label = self._cell('- ' + bold + dispprop + bold)
- obj = schema[key][prop]
- rows.extend(self._dispatch(obj, label))
+
+ if isinstance(schema[key][prop], dict):
+ obj = schema[key][prop]
+ rows.extend(self._dispatch(obj, label)[0])
+ else:
+ rows.append(self._line(label,
self._cell(schema[key][prop])))
del schema[key]
return rows
+ def _definitions(self, schema):
+ target = {}
+ for name, item in schema['definitions'].items():
+ # add title by the name of the object if title not defined
+ if 'title' not in item:
+ item['title'] = name
+
+ target[name] = item['title']
+
+ # To automate $ref to definitions titles save a copy
+ # of the schema before continuing the recursive build
+ # so reference can be set with the correct title
+ if self.nesting in self.ref_titles:
+ self.ref_titles[self.nesting].update(target)
+ else:
+ self.ref_titles[self.nesting] = target
+
+
+ result = []
+ for name, item in schema['definitions'].items():
+ result.extend(self.run(item, '/definitions/' + name))
+
+ del schema['definitions']
+ return result
+
+ def _complexstructures(self, schema):
+ rows = []
+
+ for k in self.COMBINATORS:
+ # combinators belong at this level as alternative to type
+ if k in schema:
+ items = []
+ for s in schema[k]:
+ content = self._dispatch(s)[0]
+ if content:
+ items.extend(content)
+ if items:
+ rows.extend(self._prepend(self._cell(k), items))
+ del schema[k]
+
+ for k in self.SINGLEOBJECTS:
+ # combinators belong at this level as alternative to type
+ if k in schema:
+ rows.extend(self._dispatch(schema[k], self._cell(k))[0])
+ del schema[k]
+
+ if self.CONDITIONAL[0] in schema:
+ # only if 'if' in schema there would be a needs to go through if,
then & else
+ items = []
+ for k in self.CONDITIONAL:
+ if k in schema:
+ content = self._dispatch(schema[k])[0]
+ if content:
+ items.append(self._prepend(self._cell(k), content))
+ del schema[k]
+ if len(items) >= 2:
+ for item in items:
+ rows.extend(item)
+
+ return rows
+
def _dependencies(self, schema, key):
rows = []
@@ -261,12 +409,53 @@
self._line(
label,
self._cell(str_unicode(', '.join(obj)))))
- del schema[key]
else:
import pdb; pdb.set_trace()
- rows.extend(self._dispatch(obj, label))
+ rows.extend(self._dispatch(obj, label)[0])
+ del schema[key]
return rows
+ def _reference(self, schema):
+ if self.options['auto_reference'] and self.options['lift_title']:
+ # first check if references is to own schema
+ # when definitions is separated automated they will be linked to
the title
+ # otherwise it will only be a string
+ if schema['$ref'] == '#' or schema['$ref'] == '#/':
+ if self.ref_titles.get(0, False):
+ row = (self._line(self._cell('`' + self.ref_titles[0] +
'`_')))
+ else:
+ row = (self._line(self._cell(schema['$ref'])))
+ elif schema['$ref'].startswith("#/definitions/"):
+ reference = schema['$ref'][2:].split('/')
+ # removing definitions from list otherwise nesting level will
be to deep
+ reference = [v for v in reference if v != "definitions"]
+ target_name = reference[-1]
+ ref_length = len(reference)
+ # Check if there are definitions available to make a reference
+ if (self.ref_titles.get(ref_length, False) and
+ target_name in self.ref_titles[ref_length]):
+ ref_title = self.ref_titles[ref_length][target_name]
+ row = (self._line(self._cell('`' + ref_title + '`_')))
+ else:
+ row = (self._line(self._cell(schema['$ref'])))
+ elif schema['$ref'].startswith("#/"):
+ # Other references to own schema should not be defined as
:ref: only as string
+ row = (self._line(self._cell(schema['$ref'])))
+ elif schema['$ref'].startswith("http"):
+ row = (self._line(self._cell(schema['$ref'])))
+ elif "#/" in schema['$ref']:
+ row = (self._line(self._cell(':ref:`' +
self._get_filename(schema['$ref'], True) + '`')))
+ else:
+ row = (self._line(self._cell(':ref:`' +
self._get_filename(schema['$ref']) + '`')))
+ elif self.options['auto_reference'] and not self.options['lift_title']:
+ # when using reference without titles we need to reference to our
own targets
+ # if auto_target is False linking won't work
+ row = (self._line(self._cell(':ref:`' + self.filename +
schema['$ref'] + '`')))
+ else:
+ row = (self._line(self._cell(':ref:`' + schema['$ref'] + '`')))
+ del schema['$ref']
+ return [row]
+
def _bool_or_object(self, schema, key):
# for those attributes that accept either a boolean or a schema.
rows = []
@@ -276,7 +465,7 @@
rows.append(self._line(self._cell(key),
self._cell(schema[key])))
del schema[key]
else:
- rows.extend(self._dispatch(schema[key], self._cell(key)))
+ rows.extend(self._dispatch(schema[key], self._cell(key))[0])
del schema[key]
return rows
@@ -290,7 +479,10 @@
value = schema[k]
if k == 'pattern':
value = self._escape(value)
- rows.append(self._line(self._cell(k), self._cell(value)))
+ if k == 'default':
+ rows.extend(self._prepend(self._cell(k),
self._render_any_value(value)))
+ else:
+ rows.append(self._line(self._cell(k), self._cell(value)))
del schema[k]
return rows
@@ -322,8 +514,7 @@
def _examples(self, examples):
# Render examples as rows
rows = []
- for example in examples:
- rows.append(self._line(self._cell(example)))
+ rows.extend(self._render_any_value(examples))
rows = self._prepend(self._cell('examples'), rows)
return rows
@@ -339,6 +530,25 @@
rows.append(self._line(self._cell(schema['$$description'])))
del schema['$$description']
+ def _render_any_value(self, value):
+ # render a single value, an array of values or a dict with key/value
pairs
+ rows = []
+ if isinstance(value, list):
+ if len(value) == 0:
+ rows.append(self._line(self._cell('')))
+ else:
+ for v in value:
+ rows.extend(self._render_any_value(v))
+ elif isinstance(value, dict):
+ if len(value) == 0:
+ rows.append(self._line(self._cell('')))
+ else:
+ for k in value:
+ rows.extend(self._prepend(self._cell(k),
self._render_any_value(value[k])))
+ else:
+ rows.append(self._line(self._cell(value if value is not None else
"null")))
+ return rows
+
def _square(self, rows, nrcols=0):
# determine max. number of columns
if nrcols == 0:
@@ -388,9 +598,25 @@
# turn string into multiline array of views on lists
# required by table builder
- statemachine.ViewList(statemachine.string2lines(str_unicode(text)))
+ self._convert_content(text)
]
+ def _convert_content(self, text):
+ list_lines = statemachine.string2lines(str_unicode(text))
+ # Adding a source and line number to each line text warnings may
appear when writing if there are issues with a line
+ # if left None the warnings would be counted but don't appear in the
output then you don't know the source of it
+ items = [(self.state.document.current_source, self.lineno)] *
len(list_lines)
+
+ return statemachine.StringList(list_lines, items=items)
+
+ def _get_filename(self, path, include_pointer=False):
+ # gets from filepath or url the name of file
+ if '#/' in path:
+ path, pointer = path.rsplit('#/', 1)
+ if include_pointer:
+ return Path(path).name + '#/' + pointer
+ return Path(path).name
+
def _escape(self, text):
text = text.replace('\\', '\\\\')
text = text.replace('_', '\\_')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/sphinx-jsonschema-1.15/tests/test_overall.py
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/tests/test_overall.py
--- old/sphinx-jsonschema-1.15/tests/test_overall.py 2020-04-27
21:24:51.000000000 +0200
+++
new/sphinx-jsonschema-ab7262e105845c306604eef60803a76ec8ff955e/tests/test_overall.py
2021-01-09 18:30:40.000000000 +0100
@@ -11,12 +11,14 @@
@pytest.fixture
def wideformat():
- state = Body(RSTStateMachine(None, None))
- #state = Mock()
+ state = Body(RSTStateMachine([], None))
+ state.build_table = Mock()
lineno = 1
+ source = ''
+ options = {}
app = None
- return wide_format.WideFormat(state, lineno, app)
+ return wide_format.WideFormat(state, lineno, source, options, app)
def test_create(wideformat):
wf = wideformat
@@ -24,10 +26,14 @@
def test_string(wideformat):
schema = {
- '$id': 'somewhere',
- 'title': 'Just a String',
- 'description': 'just another boring string',
- 'type': 'string'
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "An example",
+ "id": "http://example.com/schemas/example.json",
+ "description": "This is just a tiny example of a schema rendered by
`sphinx-jsonschema <http://github.com/lnoor/sphinx-jsonschema>`_.\n\nYes that's
right you can use *reStructuredText* in a description.",
+ "type": "string",
+ "minLength": 10,
+ "maxLength": 100,
+ "pattern": "^[A-Z]+$"
}
result = wideformat.transform(schema)
- #wideformat.state.build_table.assert_called()
+ wideformat.state.build_table.assert_called()