Documentation (Sphinx)
To generate this documentation, we use the Python documentation generator Sphinx (see Using Sphinx).
The generation process is divided into two stages:
sphinx-apidoc is a tool which scans the whole source code of our application in the
integreat_cmsdirectory and generates.rstfiles out of the Python docstrings. These files are then placed in thedocs/src/ref-extdirectory.sphinx-build generates the html documentation out of the
.rstfiles located in the sphinx directory. It merges the static.rstfiles directly in thesphinxdirectory together with the files generated in step 1 indocs/src/ref-extand the simplified.rstfiles indocs/src/ref.
Developer Tools
Generate this documentation with tools/make_docs.sh:
./tools/make_docs.sh [--clean]
Apart from the two steps above, this tool also performs the additional tasks:
Patch the footer template which allows custom URLs in the copyright notice.
Move the translation file to make sure the documentation doesn’t get partially translated.
Modify the autogenerated
.rstfiles to improve the readability by removing module paths in headings.Patch the autogenerated
~integreat_cms.cms.rstfile to make sure decorated functions are included in the documentation.Copy all
.rstfiles indocs/src/ref-extto the directorydocs/src/refand remove all undocumented and inherited members from the simplified version.Patch the breadcrumbs template which allows links from the simple view to the extended view and vice versa
Remove all temporary build files when running in CircleCI context to exclude them from the contents hosted on GitHub Pages.
If the --clean parameter is provided, the script will clean all temporary documentation files in the docs/src/ref/
and docs/src/ref-ext/ directories as well as the compiled html output in docs/dist. Existing outdated documentation
files can cause the generation script to fail if e.g. source files were added or deleted.
Docstrings
Please add docstrings in the sphinx format (see Writing docstrings):
"""
[Summary]
:param [ParamName]: [ParamDescription], defaults to [DefaultParamVal]
...
:return: [ReturnDescription]
:raises [ErrorType]: [ErrorDescription]
...
"""
Hint
In the model documentation, the parameters are not required, because they are automatically derived from the model field type.
Whenever you want to document module/class attributes which are not parameters (i.e. because they are not passed to the
__init__()-function or contain static values), use inline comments:
#: Description of attribute
attribute = "value of this attribute"
See the configuration files settings and conf or constants for examples.
Cross-referencing
Whenever you want to reference another module, class or function inside a static documentation page or within a docstring, use the according MOVED: Domains and have a look at Cross-referencing Python objects.
Example:
:class:`~integreat_cms.cms.models.regions.region.Region` becomes Region
Many other python projects also use Sphinx for their documentation. Whenever you use e.g. a library function or want
to reference external classes or documentation pages, you can do this with intersphinx.
All available documentations are listed in the dict intersphinx_mapping.
If you want to reference another documentation which is not yet listed, just add it to this dict. After that, you can
reference them with the normal directives plus the key specified in the intersphinx_mapping dict.
Example:
:doc:`python:howto/regex becomes Regular Expression HOWTO
Note
If the cross-referenced documentation uses custom text roles,
the usage of these custom roles will only work after these roles have been registered in an extension’s setup()
(see sphinx.application.Sphinx).
Hint
If you don’t know which references to the external documentation are possible, you can use the tool sphobjinv:
sphobjinv suggest -u https://docs.python.org/3.9/objects.inv "regex"
Remote inventory found.
:std:doc:`howto/regex`
:std:label:`regex-howto`
Substitutions
Whenever you use GitHub-specific strings, please use Substitutions:
|github-username|becomes digitalfabrik|github-repository|becomes integreat-cms|github-pages-url|becomes https://digitalfabrik.github.io/integreat-cms
If you want to provide new substitutions, add them to rst_epilog.
GitHub Pages
The CircleCI job deploy-documentation uses the GitHub user DigitalfabrikMember to
push all changes to the documentation on the develop branch to our repository’s gh-pages branch.
This branch is then automatically deployed to https://digitalfabrik.github.io/integreat-cms.
External Links
Whenever you use multiple external links to the same website, consider defining a shortcut in extlinks.
Currently, the following shortcuts exists:
:github:, e.g.:github:`issues`is rendered to issues:github-issue:, e.g.:github-issue:`1928`is rendered to #1928:github-source:, e.g.:github-source:`setup.py`is rendered to setup.py:django-source:, e.g.:django-source:`django/shortcuts.py`is rendered to django/shortcuts.py
Extensions
We use the following sphinx extensions:
sphinx.ext.autodocallows to use directives likeautomodulein.rstfiles to automatically import the modules and pull in documentation from docstrings in a semi-automatic way.sphinx.ext.extlinksallows to use shortcuts to external links defined inextlinks.sphinx.ext.githubpagescreates a.nojekyllfile on generated HTML directory to publish the document on GitHub Pages.sphinx.ext.intersphinxallows to reference other project’s documentations.sphinx.ext.linkcodeadds external links to the source code of documented modules, seelinkcode_resolve().sphinxcontrib_djangoadds improvements to the docstrings of Django models and forms.sphinx_rtd_theme is the theme we use for our documentation: Read the Docs Sphinx Theme
sphinx_last_updated_by_git determines the “last updated” date on the generated html documentation by the modification date of the source files in git.
Configuration
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: Configuration
- conf.autodoc_typehints: Final[str] = 'both'[source]
This value controls whether the types of undocumented parameters and return values are documented
- conf.django_settings: Final[str] = 'integreat_cms.core.sphinx_settings'[source]
The path to the django settings module (see sphinxcontrib-django)
- conf.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'][source]
All enabled sphinx extensions (see Extensions)
[ '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', ]
- conf.extlinks: Final[dict[str, tuple[str, str]]] = {'django-source': ('https://github.com/django/django/blob/stable/4.2.x/%s', '%s'), 'github': ('https://github.com/digitalfabrik/integreat-cms/%s', '%s'), 'github-issue': ('https://github.com/digitalfabrik/integreat-cms/issues/%s', '#%s'), 'github-source': ('https://github.com/digitalfabrik/integreat-cms/blob/develop/%s', '%s')}[source]
Markup to shorten external links (see sphinx.ext.extlinks – Markup to shorten external links)
{ 'django-source': ( 'https://github.com/django/django/blob/stable/4.2.x/%s', '%s', ), 'github': ('https://github.com/digitalfabrik/integreat-cms/%s', '%s'), 'github-issue': ( 'https://github.com/digitalfabrik/integreat-cms/issues/%s', '#%s', ), 'github-source': ( 'https://github.com/digitalfabrik/integreat-cms/blob/develop/%s', '%s', ), }
- conf.github_pages_url: Final[str] = 'https://digitalfabrik.github.io/integreat-cms'[source]
GitHub pages URL (target of gh-pages branch)
- conf.html_baseurl: Final[str] = 'https://digitalfabrik.github.io/integreat-cms'[source]
The url where the docs should be published (via gh-pages)
- conf.html_favicon: Final[str] = '../../integreat_cms/static/src/logos/integreat/integreat-icon.svg'[source]
The favicon of the html doc files
- conf.html_logo: Final[str] = '../../integreat_cms/static/src/logos/integreat/integreat-logo-white.svg'[source]
The logo shown in the menu bar
- conf.html_show_sourcelink: Final[bool] = False[source]
Do not include links to the documentation source (.rst files) in build
- conf.html_theme: Final[str] = 'sphinx_rtd_theme'[source]
The theme to use for HTML and HTML Help pages.
- conf.html_theme_options: Final[dict[str, bool]] = {'collapse_navigation': False, 'logo_only': False}[source]
Do not show the project name, only the logo
{'collapse_navigation': False, 'logo_only': False}
- conf.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), 'db_mutex': ('https://django-db-mutex.readthedocs.io/en/latest/', None), 'django': ('https://docs.djangoproject.com/en/4.2/', 'https://docs.djangoproject.com/en/4.2/_objects/'), 'django-debug-toolbar': ('https://django-debug-toolbar.readthedocs.io/en/latest/', None), 'django-import-export': ('https://django-import-export.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), 'geopy': ('https://geopy.readthedocs.io/en/stable/', None), 'lxml': ('https://lxml.de/apidoc/', 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), 'python': ('https://docs.python.org/3.11/', None), 'requests': ('https://requests.readthedocs.io/en/latest/', None), 'requests-mock': ('https://requests-mock.readthedocs.io/en/latest/', None), 'setuptools': ('https://setuptools.pypa.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), 'sphinx-rtd-tutorial': ('https://sphinx-rtd-tutorial.readthedocs.io/en/latest/', None), 'sphinxcontrib-django': ('https://sphinxcontrib-django.readthedocs.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)}[source]
Enable cross-references to other documentations
{ 'aiohttp': ('https://docs.aiohttp.org/en/stable/', None), 'dateutil': ('https://dateutil.readthedocs.io/en/stable/', None), 'db_mutex': ('https://django-db-mutex.readthedocs.io/en/latest/', None), 'django': ( 'https://docs.djangoproject.com/en/4.2/', 'https://docs.djangoproject.com/en/4.2/_objects/', ), 'django-debug-toolbar': ( 'https://django-debug-toolbar.readthedocs.io/en/latest/', None, ), 'django-import-export': ( 'https://django-import-export.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, ), 'geopy': ('https://geopy.readthedocs.io/en/stable/', None), 'lxml': ('https://lxml.de/apidoc/', 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), 'python': ('https://docs.python.org/3.11/', None), 'requests': ('https://requests.readthedocs.io/en/latest/', None), 'requests-mock': ('https://requests-mock.readthedocs.io/en/latest/', None), 'setuptools': ('https://setuptools.pypa.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, ), 'sphinx-rtd-tutorial': ( 'https://sphinx-rtd-tutorial.readthedocs.io/en/latest/', None, ), 'sphinxcontrib-django': ( 'https://sphinxcontrib-django.readthedocs.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), }
- conf.linkcode_resolve(domain: str, info: dict) str | None[source]
This function adds source code links to all modules (see
sphinx.ext.linkcode). It links all classes and functions to their source files on GitHub including line numbers.
- conf.modindex_common_prefix: Final[list[str]] = ['integreat_cms'][source]
A list of prefixes that are ignored for sorting the Python module index
['integreat_cms']
- conf.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'), ('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')][source]
A list of (type, target) tuples that should be ignored when
nitpickyisTrue[ ('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'), ('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'), ]
- conf.nitpicky: Final[bool] = False[source]
Warn about all references where the target cannot be found
- conf.rst_epilog: Final[str] = '\n.. |github-username| replace:: digitalfabrik\n.. |github-repository| replace:: integreat-cms\n.. |github-pages-url| replace:: https://digitalfabrik.github.io/integreat-cms\n'[source]
A string of reStructuredText that will be included at the end of every source file that is read. Used for substitutions.
- conf.setup(app: Sphinx) None[source]
Connect to the
django-configuredevent ofsphinxcontrib_djangoto monkeypatch application.- Parameters:
app (Sphinx) – The Sphinx application object
- Return type:
None