1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
"""
Improve the docstrings of Django apps.
For example:
* List all model and form fields as parameters
(see:mod:`~sphinxcontrib_django.docstrings.classes`)
* Improve field representations in the documentation
(see :mod:`~sphinxcontrib_django.docstrings.attributes`)
* Add information about autogenerated methods
(see :mod:`~sphinxcontrib_django.docstrings.methods`)
* Improve the appearance of static iterable data
(see :mod:`~sphinxcontrib_django.docstrings.data`)
* Fix the intersphinx mappings to the Django documentation
(see :mod:`~sphinxcontrib_django.docstrings.patches`)
"""
from __future__ import annotations
import importlib
import os
from typing import TYPE_CHECKING
import django
from sphinx.errors import ConfigError
from .. import __version__
from .attributes import improve_attribute_docstring
from .classes import improve_class_docstring
from .config import CHOICES_LIMIT, EXCLUDE_MEMBERS, INCLUDE_MEMBERS
from .data import improve_data_docstring
from .methods import improve_method_docstring
if TYPE_CHECKING:
from sphinx.application import Sphinx
from sphinx.config import Config
from sphinx.ext.autodoc import Options
def setup(app: Sphinx) -> dict:
"""
Allow this package to be used as Sphinx extension.
This is also called from the top-level :meth:`~sphinxcontrib_django.setup`.
It connects to the sphinx events :event:`autodoc-skip-member` and
:event:`autodoc-process-docstring`.
Additionally, the sphinx config value ``django_settings`` is added via
:meth:`~sphinx.application.Sphinx.add_config_value` and
:meth:`~sphinxcontrib_django.docstrings.setup_django` is called on the
:event:`config-inited` event.
:param app: The Sphinx application object
"""
from .patches import patch_django_for_autodoc
# When running, make sure Django doesn't execute querysets
# Fix module paths for intersphinx mappings
patch_django_for_autodoc()
# Register custom event which can be emitted after Django has been set up
app.add_event("django-configured")
# Set default to environment variable to enable backwards compatibility
app.add_config_value(
"django_settings", os.environ.get("DJANGO_SETTINGS_MODULE"), True
)
# Django models tables names configuration.
# Set default of django_show_db_tables to False
app.add_config_value("django_show_db_tables", False, True)
# Set default of django_show_db_tables_abstract to False
app.add_config_value("django_show_db_tables_abstract", False, True)
# Integer amount of model field choices to show
app.add_config_value("django_choices_to_show", CHOICES_LIMIT, True)
# Setup Django after config is initialized
app.connect("config-inited", setup_django)
# Load sphinx.ext.autodoc extension before registering events
app.setup_extension("sphinx.ext.autodoc")
# Generate docstrings for Django model fields
# Register the docstring processor with sphinx
app.connect("autodoc-process-docstring", improve_docstring)
# influence skip rules
app.connect("autodoc-skip-member", autodoc_skip)
return {
"version:": __version__,
"parallel_read_safe": True,
"parallel_write_safe": True,
}
def setup_django(app: Sphinx, config: Config) -> None:
"""
This function calls :func:`django.setup` so it doesn't have to be done in the app's
``conf.py``.
Called on the :event:`config-inited` event.
:param app: The Sphinx application object
:param config: The Sphinx configuration
:raises ~sphinx.errors.ConfigError: If setting ``django_settings`` is not set correctly
"""
if not config.django_settings:
raise ConfigError(
"Please specify your Django settings in the configuration 'django_settings'"
" in your conf.py"
)
try:
importlib.import_module(config.django_settings)
except ModuleNotFoundError as e:
raise ConfigError(
"The module you specified in the configuration 'django_settings' in your"
" conf.py cannot be imported. Make sure the module path is correct and the"
" source directory is added to sys.path."
) from e
os.environ["DJANGO_SETTINGS_MODULE"] = config.django_settings
django.setup()
# Emit event to allow code which depends on Django to run
app.emit("django-configured")
def autodoc_skip(
app: Sphinx, what: str, name: str, obj: object, options: Options, lines: list[str]
) -> bool | None:
"""
Hook to tell autodoc to include or exclude certain fields (see :event:`autodoc-skip-member`).
Sadly, it doesn't give a reference to the parent object,
so only the ``name`` can be used for referencing.
:param app: The Sphinx application object
:param what: The parent type, ``class`` or ``module``
:param name: The name of the child method/attribute.
:param obj: The child value (e.g. a method, dict, or module reference)
:param options: The current autodoc settings.
"""
if name in EXCLUDE_MEMBERS:
return True
if name in INCLUDE_MEMBERS:
return False
return None
def improve_docstring(
app: Sphinx, what: str, name: str, obj: object, options: Options, lines: list[str]
) -> list[str]:
"""
Hook to improve the autodoc docstrings for Django models
(see :event:`autodoc-process-docstring`).
:param what: The type of the object which the docstring belongs to (one of ``module``,
``class``, ``exception``, ``function``, ``method`` and ``attribute``)
:param name: The fully qualified name of the object
:param obj: The documented object
:param options: The options given to the directive: an object with attributes
``inherited_members``, ``undoc_members``, ``show_inheritance`` and ``noindex``
that are ``True`` if the flag option of same name was given to the auto
directive
:param lines: A list of strings – the lines of the processed docstring – that the event
handler can modify in place to change what Sphinx puts into the output.
:return: The modified list of lines
"""
if what == "class":
improve_class_docstring(app, obj, lines)
elif what == "attribute":
improve_attribute_docstring(app, obj, name, lines)
elif what == "method":
improve_method_docstring(name, lines)
elif what == "data":
improve_data_docstring(obj, lines)
# Return the extended docstring
return lines
|