digitalfabrik/integreat-cms

View on GitHub
docs/src/conf.py

Summary

Maintainability
A
0 mins
Test Coverage
"""
Configuration file for the Sphinx documentation builder.

This file only contains the options which deviate from the default values.
For a full list see the documentation: :doc:`sphinx:usage/configuration`
"""

# -- Path setup --------------------------------------------------------------

from __future__ import annotations

import contextlib
import importlib
import inspect
import os
import sys
from datetime import date
from typing import Final

from django import VERSION as django_version_tuple
from sphinx.application import Sphinx

from integreat_cms.core import settings

# Append project source directory to path environment variable
sys.path.append(os.path.abspath("../.."))
# Append sphinx source directory to path environment variable to allow documentation for this file
sys.path.append(os.path.abspath("."))
#: The path to the django settings module (see :doc:`sphinxcontrib-django:readme`)
django_settings: Final[str] = "integreat_cms.core.sphinx_settings"
#: The "major.minor" version of Django
django_version: Final[str] = f"{django_version_tuple[0]}.{django_version_tuple[1]}"

# -- Project information -----------------------------------------------------

#: The project name
project: Final[str] = "integreat-cms"
# pylint: disable=redefined-builtin
#: The copyright notice
copyright: Final[str] = f"{date.today().year} {settings.COMPANY}"
#: The project author
author: Final[str] = settings.COMPANY
#: GitHub username
github_username: Final[str] = "digitalfabrik"
#: GitHub repository name
github_repository: Final[str] = "integreat-cms"
#: GitHub URL
github_url: Final[str] = f"https://github.com/{github_username}/{github_repository}"
#: GitHub pages URL (target of gh-pages branch)
github_pages_url: Final[str] = (
    f"https://{github_username}.github.io/{github_repository}"
)
# GitHub URL of Django repository
django_github_url: Final[str] = (
    f"https://github.com/django/django/blob/stable/{django_version}.x"
)

#: The full version, including alpha/beta/rc tags
release = "2024.11.0"

# -- General configuration ---------------------------------------------------

#: All enabled sphinx extensions (see :ref:`sphinx-extensions`)
extensions: Final[list[str]] = [
    "sphinx.ext.autodoc",
    "sphinx.ext.extlinks",
    "sphinx.ext.githubpages",
    "sphinx.ext.intersphinx",
    "sphinx.ext.linkcode",
    "sphinxcontrib_django",
    "sphinx_rtd_theme",
    "sphinx_last_updated_by_git",
]
#: Enable cross-references to other documentations
intersphinx_mapping: Final[dict[str, tuple[str, str | None]]] = {
    "aiohttp": ("https://docs.aiohttp.org/en/stable/", None),
    "dateutil": ("https://dateutil.readthedocs.io/en/stable/", None),
    "geopy": ("https://geopy.readthedocs.io/en/stable/", None),
    "lxml": ("https://lxml.de/apidoc/", None),
    "python": (
        f"https://docs.python.org/{sys.version_info.major}.{sys.version_info.minor}/",
        None,
    ),
    "pytest": ("https://docs.pytest.org/en/latest/", None),
    "pytest-cov": ("https://pytest-cov.readthedocs.io/en/latest/", None),
    "pytest-django": ("https://pytest-django.readthedocs.io/en/latest/", None),
    "pytest-httpserver": ("https://pytest-httpserver.readthedocs.io/en/latest/", None),
    "pytest-xdist": ("https://pytest-xdist.readthedocs.io/en/latest/", None),
    "requests": ("https://requests.readthedocs.io/en/latest/", None),
    "requests-mock": ("https://requests-mock.readthedocs.io/en/latest/", None),
    "sphinx": ("https://www.sphinx-doc.org/en/master/", None),
    "sphinx-rtd-theme": (
        "https://sphinx-rtd-theme.readthedocs.io/en/latest/",
        None,
    ),
    "sphinxcontrib-django": (
        "https://sphinxcontrib-django.readthedocs.io/en/latest/",
        None,
    ),
    "sphinx-rtd-tutorial": (
        "https://sphinx-rtd-tutorial.readthedocs.io/en/latest/",
        None,
    ),
    "db_mutex": ("https://django-db-mutex.readthedocs.io/en/latest/", None),
    "django": (
        f"https://docs.djangoproject.com/en/{django_version}/",
        f"https://docs.djangoproject.com/en/{django_version}/_objects/",
    ),
    "django-debug-toolbar": (
        "https://django-debug-toolbar.readthedocs.io/en/latest/",
        None,
    ),
    "django-polymorphic": (
        "https://django-polymorphic.readthedocs.io/en/latest/",
        None,
    ),
    "django-treebeard": ("https://django-treebeard.readthedocs.io/en/latest/", None),
    "setuptools": ("https://setuptools.pypa.io/en/latest/", None),
    "twine": ("https://twine.readthedocs.io/en/latest/", None),
    "wsgi": ("https://wsgi.readthedocs.io/en/latest/", None),
    "xhtml2pdf": ("https://xhtml2pdf.readthedocs.io/en/latest/", None),
    "django-import-export": (
        "https://django-import-export.readthedocs.io/en/latest/",
        None,
    ),
}
#: The intersphinx request timeout in seconds
intersphinx_timeout: Final[int] = 5
#: This value controls whether the types of undocumented parameters and return values are documented
autodoc_typehints: Final[str] = "both"
#: The path for patched template files
templates_path: Final[list[str]] = ["templates"]
#: Markup to shorten external links (see :doc:`sphinx:usage/extensions/extlinks`)
extlinks: Final[dict[str, tuple[str, str]]] = {
    "github": (f"{github_url}/%s", "%s"),
    "github-issue": (f"{github_url}/issues/%s", "#%s"),
    "github-source": (f"{github_url}/blob/develop/%s", "%s"),
    "django-source": (f"{django_github_url}/%s", "%s"),
}
#: A string of reStructuredText that will be included at the end of every source file that is read. Used for substitutions.
rst_epilog: Final[
    str
] = f"""
.. |github-username| replace:: {github_username}
.. |github-repository| replace:: {github_repository}
.. |github-pages-url| replace:: {github_pages_url}
"""
#: Warn about all references where the target cannot be found
nitpicky: Final[bool] = False
#: A list of (type, target) tuples that should be ignored when :attr:`nitpicky` is ``True``
nitpick_ignore: list[tuple[str, str]] = [
    ("py:attr", "django.contrib.auth.models.Group.role"),
    ("py:attr", "django.contrib.auth.models.Group.user_set"),
    ("py:attr", "django.contrib.auth.models.Permission.user_set"),
    (
        "py:attr",
        "django.contrib.contenttypes.models.ContentType.polymorphic_cms.feedback_set+",
    ),
    ("py:attr", "linkcheck.models.Link.+"),
    ("py:attr", "linkcheck.models.Link.event_translation"),
    ("py:attr", "linkcheck.models.Link.event_translations"),
    ("py:attr", "linkcheck.models.Link.imprint_translation"),
    ("py:attr", "linkcheck.models.Link.page_translation"),
    ("py:attr", "linkcheck.models.Link.page_translations"),
    ("py:attr", "linkcheck.models.Link.poi_translation"),
    ("py:attr", "linkcheck.models.Link.poi_translations"),
    ("py:class", "_io.StringIO"),
    ("py:class", "argparse.ArgumentTypeError"),
    ("py:class", "builtins.AssertionError"),
    ("py:class", "builtins.int"),
    ("py:class", "builtins.int"),
    ("py:class", "django.contrib.admin.checks.ModelAdminChecks"),
    ("py:class", "django.contrib.admin.helpers.ActionForm"),
    ("py:class", "django.contrib.auth.base_user.BaseUserManager"),
    ("py:class", "django.contrib.auth.context_processors.PermWrapper"),
    ("py:class", "django.contrib.auth.forms.UsernameField"),
    ("py:class", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher"),
    ("py:class", "django.contrib.auth.tokens.PasswordResetTokenGenerator"),
    ("py:class", "django.core.handlers.WSGIHandler"),
    ("py:class", "django.core.mail.EmailMultiAlternatives"),
    ("py:class", "django.core.management.base.BaseCommand"),
    ("py:class", "django.core.management.base.CommandError"),
    ("py:class", "django.core.management.base.CommandParser"),
    ("py:class", "django.core.serializers.base.DeserializationError"),
    ("py:class", "django.core.serializers.base.DeserializedObject"),
    ("py:class", "django.core.serializers.base.ProgressBar"),
    ("py:class", "django.core.serializers.base.SerializationError"),
    ("py:class", "django.core.serializers.xml_serializer.Deserializer"),
    ("py:class", "django.core.serializers.xml_serializer.Serializer"),
    ("py:class", "django.db.models.base.ModelBase"),
    ("py:class", "django.forms.BaseInlineFormSet"),
    ("py:class", "django.forms.BaseModelFormSet"),
    ("py:class", "django.forms.formsets.POICategoryTranslationFormFormSet"),
    ("py:class", "django.forms.models.ModelChoiceIterator"),
    ("py:class", "django.forms.models.ModelFormMetaclass"),
    ("py:class", "django.forms.widgets.LanguageTreeNodeForm"),
    ("py:class", "django.forms.widgets.PageForm"),
    ("py:class", "django.test.client.AsyncClient"),
    ("py:class", "django.test.client.Client"),
    ("py:class", "django.utils.datastructures.MultiValueDict"),
    ("py:class", "django.utils.functional.Promise"),
    ("py:class", "django.utils.xmlutils.SimplerXMLGenerator"),
    ("py:class", "linkcheck.apps.LinkcheckConfig"),
    ("py:class", "linkcheck.Linklist"),
    ("py:class", "linkcheck.models.Link"),
    ("py:class", "linkcheck.models.Url"),
    ("py:class", "NoneType"),
    ("py:class", "lxml.html.Element"),
    ("py:class", "polymorphic.query.PolymorphicQuerySet"),
    ("py:class", "PolymorphicQuerySet"),
    ("py:class", "pytest_django.fixtures.SettingsWrapper"),
    ("py:class", "requests_mock.mocker.Mocker"),
    ("py:class", "webauthn.WebAuthnUser"),
    ("py:class", "xml.dom.minidom.Element"),
    ("py:class", "django.contrib.auth.context_processors.PermWrapper"),
    ("py:func", "django.contrib.sitemaps.Sitemap._urls"),
    ("py:func", "django.utils.text.capfirst"),
    # Wrong docstrings in the CPython source of collections.queue
    ("py:class", "-- reverse *IN PLACE*"),
    ("py:class", "integer -- return first index of value."),
    ("py:class", "integer -- return number of occurrences of value"),
    ("py:class", "-- insert object before index"),
    ("py:class", "-- remove first occurrence of value."),
    ("py:class", "-- size of D in memory, in bytes"),
    ("py:class", "-- return a reverse iterator over the deque"),
]
#: A list of prefixes that are ignored for sorting the Python module index
modindex_common_prefix: Final[list[str]] = ["integreat_cms"]

# -- Options for HTML output -------------------------------------------------

#: The theme to use for HTML and HTML Help pages.
html_theme: Final[str] = "sphinx_rtd_theme"
#: Do not show the project name, only the logo
html_theme_options: Final[dict[str, bool]] = {
    "logo_only": False,
    "collapse_navigation": False,
}
#: The logo shown in the menu bar
html_logo: Final[str] = (
    "../../integreat_cms/static/src/logos/integreat/integreat-logo-white.svg"
)
#: The favicon of the html doc files
html_favicon: Final[str] = (
    "../../integreat_cms/static/src/logos/integreat/integreat-icon.svg"
)
#: The url where the docs should be published (via gh-pages)
html_baseurl: Final[str] = github_pages_url
#: Do not include links to the documentation source (.rst files) in build
html_show_sourcelink: Final[bool] = False
#: Do not include a link to sphinx
html_show_sphinx: Final[bool] = False
#: Include last updated timestamp
html_last_updated_fmt: Final[str] = "%b %d, %Y"

# -- Source Code links to GitHub ---------------------------------------------


def linkcode_resolve(domain: str, info: dict) -> str | None:
    """
    This function adds source code links to all modules (see :mod:`sphinx:sphinx.ext.linkcode`).
    It links all classes and functions to their source files on GitHub including line numbers.

    :param domain: The programming language of the given object (e.g. ``py``, ``c``, ``cpp`` or ``javascript``)
    :param info: Information about the given object. For a python object, it has the keys ``module`` and ``fullname``.
    :return: The URL of the given module on GitHub
    """
    module_str = info["module"]
    if domain != "py" or not module_str:
        return None
    item = importlib.import_module(module_str)
    line_number_reference = ""
    for piece in info["fullname"].split("."):
        with contextlib.suppress(AttributeError, TypeError, IOError):
            item = getattr(item, piece)
            line_number_reference = f"#L{inspect.getsourcelines(item)[1]}"
            module_str = item.__module__
    module = importlib.import_module(module_str)
    module_path = module_str.replace(".", "/")
    filename = module.__file__.partition(module_path)[2] if module.__file__ else ""
    url = (
        django_github_url
        if module_str.startswith("django.")
        else f"{github_url}/blob/develop"
    )
    return f"{url}/{module_path}{filename}{line_number_reference}"


# -- Custom patches for autodoc ----------------------------------------------


def setup(app: Sphinx) -> None:
    """
    Connect to the ``django-configured`` event of :mod:`sphinxcontrib_django` to monkeypatch application.

    :param app: The Sphinx application object
    """
    # Add crossref type for links to the pytest documentation
    app.add_crossref_type(
        directivename="fixture",
        rolename="fixture",
        indextemplate="pair: %s; fixture",
    )