diff --git a/.gitignore b/.gitignore index 3c1e174a..9bd595e5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ src/plotman.egg-info .idea .tox coverage.xml +docs/build +docs/source/jsonschema.json +docs/source/openapi.yaml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..a27862d4 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,17 @@ +# https://docs.readthedocs.io/en/latest/config-file/v2.html +version: 2 + +formats: + - htmlzip + - epub + +build: + image: latest + +python: + version: 3.8 + install: + - method: pip + path: . + extra_requirements: + - docs diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..6247f7e2 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..6ea6ec2b --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,136 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +import os + + +# -- Path setup -------------------------------------------------------------- + +# 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. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = "plotman" +copyright = "2021, Eric Altendorf" +author = "Eric Altendorf" + +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get("READTHEDOCS", None) == "True" + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx-jsonschema", + "sphinxcontrib.redoc", + "sphinxcontrib.openapi", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +if not on_rtd: # only set the theme if we"re building docs locally + html_theme = "sphinx_rtd_theme" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + + +# -- Build stuff ------------------------------------------------------------- + +import collections +import pathlib +import sys + +import apispec +import apispec.ext.marshmallow +import desert +import yaml + +import plotman.configuration + + +schema_class = desert.schema_class(plotman.configuration.PlotmanConfig) + +spec = apispec.APISpec( + title="plotman Configuration", + version=str(plotman.configuration.expected_major_version), + openapi_version="3.0.2", + plugins=[apispec.ext.marshmallow.MarshmallowPlugin()], +) + +spec.components.schema( + component_id="plotman Configuration", + schema=schema_class, +) + +yaml.add_representer( + collections.OrderedDict, + lambda dumper, data: dumper.represent_dict( + getattr(data, "viewitems" if sys.version_info < (3,) else "items")() + ), + Dumper=yaml.SafeDumper, +) + +openapi_path = pathlib.Path(__file__).parent.joinpath("openapi.yaml") + +with open(openapi_path, "w") as f: + yaml.safe_dump(data=spec.to_dict(), stream=f) + +redoc = [ + { + "name": "plotman configuration", + "page": "api", + "spec": os.fspath(openapi_path), + "embed": True, + }, + # { + # 'name': 'Example API', + # 'page': 'example/index', + # 'spec': 'http://example.com/openapi.yml', + # 'opts': { + # 'lazy': False, + # 'nowarnings': False, + # 'nohostname': False, + # 'required-props-first': True, + # 'expand-responses': ["200", "201"], + # } + # }, +] + +import json + +import marshmallow_jsonschema + +json_schema = marshmallow_jsonschema.JSONSchema() +dumped_schema = json_schema.dump(schema_class()) +print(dumped_schema) +jsonschema_path = pathlib.Path(__file__).parent.joinpath("jsonschema.json") + +with open(jsonschema_path, "w") as f: + json.dump(obj=dumped_schema, fp=f, indent=4, skipkeys=True) diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst new file mode 100644 index 00000000..d3d35254 --- /dev/null +++ b/docs/source/configuration.rst @@ -0,0 +1,19 @@ +Configuration ++++++++++++++ + +redoc +===== + +`redoc `_ + + +openapi +======= + +.. openapi:: openapi.yaml + + +jsonschema +========== + +.. jsonschema:: jsonschema.json diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..3077b834 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,21 @@ +.. plotman documentation master file, created by + sphinx-quickstart on Sat Sep 11 14:48:13 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to plotman's documentation! +=================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + configuration.rst + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/setup.cfg b/setup.cfg index b43ad338..fe0bc055 100644 --- a/setup.cfg +++ b/setup.cfg @@ -60,8 +60,19 @@ coverage = coverage diff-cover dev = + %(docs)s + %(checks)s %(test)s isort +docs = + apispec[marshmallow] ~= 5.1 + marshmallow-jsonschema ~= 0.12.0 + sphinx ~= 4.1 + sphinx-jsonschema ~= 1.16 + # >= 1.0.0rc1 for https://github.com/readthedocs/sphinx_rtd_theme/issues/1115 + sphinx-rtd-theme >= 1.0.0rc1 + sphinxcontrib-openapi ~= 0.7.0 + sphinxcontrib-redoc ~= 1.6 test = %(coverage)s pytest diff --git a/src/plotman/configuration.py b/src/plotman/configuration.py index dff7d679..18f02802 100644 --- a/src/plotman/configuration.py +++ b/src/plotman/configuration.py @@ -57,8 +57,6 @@ def get_validated_configs( version = config_objects.get("version", (0,)) - expected_major_version = 2 - if version[0] != expected_major_version: message = textwrap.dedent( f"""\ @@ -433,6 +431,9 @@ class Commands: interactive: Interactive = attr.ib(factory=Interactive) +expected_major_version = 2 + + @attr.frozen class PlotmanConfig: directories: Directories