Skip to main content

Build multiple versions of your sphinx docs and merge them into one website.

Project description

sphinx-polyversion

Static Badge pypi PyPI - Python Version Github License PyPI - Downloads Poetry Ruff pre-commit Code style: black

Build multiple versions of your sphinx docs and merge them into one website.

  • Isolated builds using venv, virtualenv or poetry
  • git support
  • Build with sphinx-build or custom commands
  • Access and modify all versioning data inside conf.py
  • Concurrent builds
  • Override build configuration from commandline easily
  • Render templates to the root directory containing the docs for each version
  • Build from local working tree easily while mocking version data
  • Not a sphinx extension -> standalone tool
  • Configuration in a python script
  • Highly customizable and scriptable through OOP
  • Implement subclasses in your configuration script to add support for other VCS, Project/dependency management tools, build tools and whatever you require
  • IDE integration and autocompletion

Have a look at the roadmap to find out about upcoming features.

Installation

pip install sphinx-polyversion
poetry add --group docs sphinx-polyversion

Usage

Example

Setup your sphinx docs in docs/source/sphinx. Add a conf.py file with the following to set directory:

from sphinx_polyversion.api import load

load(globals())
# This adds the following to the global scope
# html_context = {
#     "revisions": [GitRef('main', ...), GitRef('v6.8.9', ...), ...],
#     "current": GitRef('v1.4.6', ...),
# }

# process the loaded version information as you wish
html_context["latest"] = max(html_context["revisions"]) # latest by date

# sphinx config
project = "foo"
# ...

Configure sphinx-polyversion in the file docs/poly.py.

from pathlib import Path

from sphinx_polyversion.api import apply_overrides
from sphinx_polyversion.driver import DefaultDriver
from sphinx_polyversion.git import Git, file_predicate
from sphinx_polyversion.pyvenv import Poetry
from sphinx_polyversion.sphinx import SphinxBuilder

#: Regex matching the branches to build docs for
BRANCH_REGEX = r".*"

#: Regex matching the tags to build docs for
TAG_REGEX = r".*"

#: Output dir relative to project root
OUTPUT_DIR = "docs/build"

#: Source directory
SOURCE_DIR = "docs/source"

#: Arguments to pass to `poetry install`
POETRY_ARGS = "--only sphinx --sync".split()

#: Arguments to pass to `sphinx-build`
SPHINX_ARGS = "-a -v".split()

#: Mock data used for building local version
MOCK_DATA = {
    "revisions": [
        GitRef("v1.8.0", "", "", GitRefType.TAG, datetime.fromtimestamp(0)),
        GitRef("v1.9.3", "", "", GitRefType.TAG, datetime.fromtimestamp(1)),
        GitRef("v1.10.5", "", "", GitRefType.TAG, datetime.fromtimestamp(2)),
        GitRef("master", "", "", GitRefType.BRANCH, datetime.fromtimestamp(3)),
        GitRef("dev", "", "", GitRefType.BRANCH, datetime.fromtimestamp(4)),
        GitRef("some-feature", "", "", GitRefType.BRANCH, datetime.fromtimestamp(5)),
    ],
    "current": GitRef("local", "", "", GitRefType.BRANCH, datetime.fromtimestamp(6)),
}
#: Whether to build using only local files and mock data
MOCK = False

#: Whether to run the builds in sequence or in parallel
SEQUENTIAL = False

# Load overrides read from commandline to global scope
apply_overrides(globals())
# Determine repository root directory
root = Git.root(Path(__file__).parent)

# Setup driver and run it
src = Path(SOURCE_DIR)
DefaultDriver(
    root,
    OUTPUT_DIR,
    vcs=Git(
        branch_regex=BRANCH_REGEX,
        tag_regex=TAG_REGEX,
        buffer_size=1 * 10**9,  # 1 GB
        predicate=file_predicate([src]), # exclude refs without source dir
    ),
    builder=SphinxBuilder(src / "sphinx", args=SPHINX_ARGS),
    env=Poetry.factory(args=POETRY_ARGS),
    template_dir=root / src / "templates",
    static_dir=root / src / "static",
    mock=MOCK_DATA,
).run(MOCK, SEQUENTIAL)

Build your docs by running

$ sphinx-polyversion docs/poly.py

Commandline Options

usage: sphinx-polyversion [-h] [-o [OVERRIDE [OVERRIDE...]]] [-v] [-l] [--sequential] conf [out]

Build multiple versions of your sphinx docs and merge them into one site.

positional arguments:
  conf                  Polyversion config file to load. This must be a python file that can be evaluated.
  out                   Output directory to build the merged docs to.

optional arguments:
  -h, --help            show this help message and exit
  -o [OVERRIDE [OVERRIDE ...]], --override [OVERRIDE [OVERRIDE ...]]
                        Override config options. Pass them as `key=value` pairs.
  -v, --verbosity       Increase output verbosity (decreases minimum log level). The default log level is ERROR.
  -l, --local, --mock   Build the local version of your docs.
  --sequential          Build the revisions sequentially.

How To Build Versions Differently

#: Mapping of revisions to changes in build parameters
BUILDER = {
    None: SphinxBuilder(Path("docs")),  # default
    "v1.5.7": SphinxBuilder(Path("docs/source")),
    "v2.0.0": CommandBuilder(
        Path("docs/source"),
        ["sphinx-autodoc", Placeholder.SOURCE_DIR, Placeholder.OUTPUT_DIR],
    ),
    "v2.4.0": CommandBuilder(
        Path("docs/source/sphinx"),
        ["sphinx-autodoc", Placeholder.SOURCE_DIR, Placeholder.OUTPUT_DIR],
    ),
}

#: Mapping of revisions to changes in environment parameters
ENVIRONMENT = {
    None: Poetry.factory(args="--sync".split()),  # first version
    "v1.5.7": Poetry.factory(args="--only sphinx --sync".split()),
    "v1.8.2": Poetry.factory(args="--only dev --sync".split(), env={"MY_VAR": "value"}),
    # use a pre-existing environment at the location ./.venv
    "v3.0.0": Pip.factory(venv=Path(".venv"), args="-e . -r requirements.txt".split()),
    # dynamically create an environment in the temporary build directory
    "v4.*.*": Pip.factory(venv=Path(".venv"), args="-e . -r requirements.txt".split(), creator=VenvWrapper(), temporary=True),
}

# ...

DefaultDriver(
    # ...
    builder=BUILDER,
    env=ENVIRONMENT,
    selector=partial(closest_tag, root),
    # ...
).run()

Data Passed to Sphinx

{"revisions": [GitRef(...), GitRef(...)], "current": GitRef(...)}

You can change the format by passing your own factory.

def data(driver: DefaultDriver, rev: GitRef, env: Environment):
    return {
      "tags": list(filter(lambda r: r.type_ == GitRefType.TAG, driver.targets)),
      "branches": list(filter(lambda r: r.type_ == GitRefType.BRANCH, driver.targets)),
      "current": rev,
    }

# ...

DefaultDriver(
    # ...
    data_factory=data,
    # ...
).run()

Contributing

Contributions of all kinds are welcome. That explicitely includes suggestions for enhancing the API, the architecture or the documentation of the project. PRs are greatly appreciated as well. But please make sure that your change is wanted by opening an issue about it first before you waste your time with a PR that isn't merged in the end.

By contributing you affirm the Developer Certificate of Origin and license your work under the terms of this repository.

New top-level modules must be added to docs/sphinx/api/sphinx_polyversion.rst.

License

MIT License
See the LICENSE file which should be located in this directory.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sphinx_polyversion-1.1.0.tar.gz (29.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sphinx_polyversion-1.1.0-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file sphinx_polyversion-1.1.0.tar.gz.

File metadata

  • Download URL: sphinx_polyversion-1.1.0.tar.gz
  • Upload date:
  • Size: 29.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.10.12 Linux/5.15.167.4-microsoft-standard-WSL2

File hashes

Hashes for sphinx_polyversion-1.1.0.tar.gz
Algorithm Hash digest
SHA256 794bf119c938c766c71cc22d95ab53a374e0bc710eb8b91afe0d98b92dbfa923
MD5 53f9084367db7575e1e6a285f8ab3019
BLAKE2b-256 6f0e6d4d257f6e97c40617aa8972576cbee3f6f20ebb976dc0230804334b2139

See more details on using hashes here.

File details

Details for the file sphinx_polyversion-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: sphinx_polyversion-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.10.12 Linux/5.15.167.4-microsoft-standard-WSL2

File hashes

Hashes for sphinx_polyversion-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4bac755ffdde98a65fe90fbfedc037ea22ec37ed6618c97b10723d4d64d19fc3
MD5 5884c71c31e47482fd974968ab21a3ad
BLAKE2b-256 cd8da78f9d979b52c51c81cae59eb3e656ed1ef9f2d9f1a8f4dd5fb54b644f63

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page