diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..9797093
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,5 @@
+# Each line is a file pattern followed by one or more owners.
+
+# These owners will be the default owners for everything in the repo.
+# Unless a later match takes precedence, they will be requested for review when someone opens a pull request.
+* @timobrembeck
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 0000000..111a009
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,43 @@
+---
+name: "Bug report \U0001F41B"
+about: "Create a report to help us improve"
+labels: "bug"
+
+---
+
+### Describe the Bug
+
+
+
+
+### Minimal Example to Reproduce
+
+
+
+### Expected Behavior
+
+
+
+### Actual Behavior
+
+
+
+### Additional Information
+
+
+
+ Traceback
+
+ ```
+ ```
+
+
+
+
+### System Information
+
+
+OS version:
+Python version:
+Sphinx version:
+sphinxcontrib_django version:
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 0000000..77e2e2a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,23 @@
+---
+name: "Feature request \U0001F4A1"
+about: "Suggest an idea for this project"
+labels: "feature request"
+
+---
+
+### Motivation
+
+
+
+
+### Proposed Solution
+
+
+
+### Alternatives
+
+
+
+### Additional Context
+
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..4fa69a1
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,15 @@
+### Short description
+
+
+
+### Proposed changes
+
+
+-
+-
+
+
+### Resolved issues
+
+
+Fixes: #
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..be006de
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,13 @@
+# Keep GitHub Actions up to date with GitHub's Dependabot...
+# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ groups:
+ github-actions:
+ patterns:
+ - "*" # Group all Actions updates into a single larger pull request
+ schedule:
+ interval: weekly
diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml
index adde2f5..fa09f64 100644
--- a/.github/workflows/deployment.yml
+++ b/.github/workflows/deployment.yml
@@ -18,8 +18,8 @@ jobs:
needs: has
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
- name: Install dependencies
run: pip install build twine
- name: Build a binary wheel and a source tarball
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index 52876b4..6d538f9 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -4,23 +4,11 @@ jobs:
black:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-python@v2
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
- uses: psf/black@stable
- isort:
+ ruff:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-python@v2
- - uses: jamescurtin/isort-action@master
- with:
- configuration: --check-only
- flake8:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-python@v2
- - name: Install dependencies
- run: pip install flake8 flake8-pyproject
- - name: Run flake8
- run: flake8 .
+ - uses: actions/checkout@v4
+ - uses: chartboost/ruff-action@v1
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index fc4f1c2..0a96194 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -5,14 +5,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
- django-version: ["django~=3.2", "django~=4.0", "django~=4.1"]
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
+ django-version: ["django~=3.2", "django~=4.2", "django~=5.0"]
optional-dependencies: ["optional-deps", "no-optional-deps"]
exclude:
- - python-version: "3.7"
- django-version: "django~=4.0"
- - python-version: "3.7"
- django-version: "django~=4.1"
+ - python-version: "3.8"
+ django-version: "django~=5.0"
+ - python-version: "3.9"
+ django-version: "django~=5.0"
env:
OS: ubuntu-latest
PYTHON: ${{ matrix.python-version }}
@@ -34,6 +34,8 @@ jobs:
run: coverage run
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
env_vars: OS,PYTHON,DJANGO
name: codecov-umbrella
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 92ef5e3..5721d5f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,13 +3,8 @@ repos:
rev: 23.1.0
hooks:
- id: black
- - repo: https://github.com/PyCQA/isort
- rev: 5.12.0
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.0.291
hooks:
- - id: isort
- - repo: https://github.com/pycqa/flake8
- rev: 6.0.0
- hooks:
- - id: flake8
- additional_dependencies:
- - flake8-pyproject
+ - id: ruff
+ args: [--fix, --exit-non-zero-on-fix]
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index cf5f062..6e9fc9e 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -5,6 +5,12 @@
# Required
version: 2
+# Set the OS, Python version and other tools you might need
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.11"
+
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
diff --git a/AUTHORS b/AUTHORS
index 53a9043..b8b0d86 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,4 +4,4 @@ Original authors:
Maintainer since 2020:
-* Timo Ludwig (@timoludwig)
+* Timo Brembeck (@timobrembeck)
diff --git a/CHANGES.rst b/CHANGES.rst
index b8db4b3..b5613d1 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,10 +1,44 @@
Changelog
=========
+Unreleased
+----------
+
+* Add support for Python 3.12
+
+
+Version 2.5 (2023-09-26)
+------------------------
+
+* Drop support for sphinx < 3.4.0
+* [ `#45 `_ ] Fix rendering of inheritance diagrams
+* Drop support for Python 3.7
+
+
+Version 2.4 (2023-07-02)
+------------------------
+
+* [ `#39 `_ ] Fix table names of abstract models (`@insspb `__)
+* [ `#41 `_ ] Fix rendering of iterable choices (`@insspb `__)
+
+
+Version 2.3 (2023-04-12)
+------------------------
+
+* Add support for Django 4.2
+* Drop support for Django 4.0
+
+
+Version 2.2 (2023-03-01)
+------------------------
+
+* [ `#35 `_ ] Fix interference with other ``autodoc-skip-member`` signal handlers
+
+
Version 2.1 (2023-03-01)
------------------------
-* [ `#32 `_ ] Fix rendering of nested directives in model parameter documentation
+* [ `#32 `_ ] Fix rendering of nested directives in model parameter documentation
Version 2.0 (2023-01-02)
diff --git a/README.rst b/README.rst
index 488937c..b7b200a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,25 +1,25 @@
-.. image:: https://github.com/edoburu/sphinxcontrib-django/workflows/Tests/badge.svg
+.. image:: https://github.com/sphinx-doc/sphinxcontrib-django/workflows/Tests/badge.svg
:alt: GitHub Workflow Status
- :target: https://github.com/edoburu/sphinxcontrib-django/actions?query=workflow%3ATests
+ :target: https://github.com/sphinx-doc/sphinxcontrib-django/actions?query=workflow%3ATests
.. image:: https://img.shields.io/pypi/v/sphinxcontrib-django.svg
:alt: PyPi
:target: https://pypi.org/project/sphinxcontrib-django/
-.. image:: https://codecov.io/gh/edoburu/sphinxcontrib-django/branch/main/graph/badge.svg
+.. image:: https://codecov.io/gh/sphinx-doc/sphinxcontrib-django/branch/main/graph/badge.svg
:alt: Code coverage
- :target: https://codecov.io/gh/edoburu/sphinxcontrib-django
+ :target: https://codecov.io/gh/sphinx-doc/sphinxcontrib-django
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:alt: Black Code Style
:target: https://github.com/psf/black
-.. image:: https://img.shields.io/github/license/edoburu/sphinxcontrib-django
+.. image:: https://img.shields.io/github/license/sphinx-doc/sphinxcontrib-django
:alt: GitHub license
- :target: https://github.com/edoburu/sphinxcontrib-django/blob/main/LICENSE
+ :target: https://github.com/sphinx-doc/sphinxcontrib-django/blob/main/LICENSE
.. image:: https://readthedocs.org/projects/sphinxcontrib-django/badge/?version=latest
:alt: Documentation Status
:target: https://sphinxcontrib-django.readthedocs.io/en/latest/?badge=latest
|
-.. image:: https://raw.githubusercontent.com/edoburu/sphinxcontrib-django/main/docs/images/django-sphinx-logo-blue.png
+.. image:: https://raw.githubusercontent.com/sphinx-doc/sphinxcontrib-django/main/docs/images/django-sphinx-logo-blue.png
:width: 500
:alt: logo
:target: https://pypi.org/project/sphinxcontrib-django/
@@ -80,8 +80,16 @@ Optionally, you can include the table names of your models in their docstrings w
.. code-block:: python
# Include the database table names of Django models
- django_show_db_tables = True
+ django_show_db_tables = True # Boolean, default: False
+ # Add abstract database tables names (only takes effect if django_show_db_tables is True)
+ django_show_db_tables_abstract = True # Boolean, default: False
+Optionally, you can extend amount of displayed choices in model fields with them:
+
+.. code-block:: python
+
+ # Integer amount of model field choices to show, default 10
+ django_choices_to_show = 10
Advanced Usage
--------------
diff --git a/docs/conf.py b/docs/conf.py
index 807df08..57e350f 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -9,8 +9,8 @@
# -- Project information -----------------------------------------------------
project = "sphinxcontrib-django"
-copyright = "2021"
-author = "Timo Ludwig"
+copyright = "2023"
+author = "Timo Brembeck"
# The full version, including alpha/beta/rc tags
release = __version__
@@ -31,6 +31,9 @@
# Warn about all references where the target cannot be found
nitpicky = True
+# A list of (type, target) tuples that should be ignored when :attr:`nitpicky` is ``True``
+nitpick_ignore = [("py:class", "sphinx.ext.autodoc.Options")]
+
# Add any paths that contain templates here, relative to this directory.
templates_path = ["templates"]
@@ -45,7 +48,7 @@
html_theme = "sphinx_rtd_theme"
# The logos shown in the menu bar
html_logo = "images/django-sphinx-logo-white.png"
-# The facivon of the html doc files
+# The favicon of the html doc files
html_favicon = "images/favicon.svg"
# Do not include links to the documentation source (.rst files) in build
html_show_sourcelink = False
diff --git a/pyproject.toml b/pyproject.toml
index 972d776..73bcbd5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,44 +5,47 @@
[project]
authors = [
{ name = "Diederik van der Boor", email = "opensource@edoburu.nl" },
- { name = "Timo Ludwig", email = "ti.ludwig@web.de" }
+ { name = "Timo Brembeck", email = "opensource@timo.brembeck.email" },
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Django :: 3.2",
- "Framework :: Django :: 4.0",
- "Framework :: Django :: 4.1",
+ "Framework :: Django :: 4.2",
+ "Framework :: Django :: 5.0",
"Framework :: Django",
"Framework :: Sphinx :: Extension",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Libraries :: Python Modules",
]
- dependencies = ["Django>=2.2", "Sphinx>=0.5", "pprintpp"]
+ dependencies = ["Django>=3.2", "Sphinx>=3.4.0", "pprintpp"]
description = "Improve the Sphinx autodoc for Django classes."
dynamic = ["version"]
keywords = ["django", "docstrings", "extension", "sphinx"]
license = { text = "Apache2 2.0 License" }
+ maintainers = [
+ { name = "Timo Brembeck", email = "opensource@timo.brembeck.email" },
+ ]
name = "sphinxcontrib-django"
readme = "README.rst"
- requires-python = ">=3.7"
+ requires-python = ">=3.8"
[project.urls]
- "Bug Tracker" = "https://github.com/edoburu/sphinxcontrib-django/issues"
+ "Bug Tracker" = "https://github.com/sphinx-doc/sphinxcontrib-django/issues"
"Documentation" = "https://sphinxcontrib-django.readthedocs.io/"
- "Release Notes" = "https://github.com/edoburu/sphinxcontrib-django/blob/main/CHANGES.rst"
- "Source Code" = "https://github.com/edoburu/sphinxcontrib-django"
+ "Release Notes" = "https://github.com/sphinx-doc/sphinxcontrib-django/blob/main/CHANGES.rst"
+ "Source Code" = "https://github.com/sphinx-doc/sphinxcontrib-django"
[project.optional-dependencies]
dev = ["pre-commit"]
@@ -68,24 +71,28 @@
command_line = "-m pytest"
source = ["sphinxcontrib_django"]
+[tool.coverage.report]
+ exclude_lines = [
+ "pragma: no cover",
+ "if TYPE_CHECKING:",
+ ]
+
[tool.pytest.ini_options]
addopts = "-ra -vv --color=yes"
minversion = "6.0"
testpaths = ["tests"]
-[tool.flake8]
- ignore = [
- "D1", # Missing docstrings
- "E203", # whitespace before ':' in slice (incompatible with black)
- "E731", # Allow lambdas
- "F405", # name undefined due to star imports
- "W503", # line break before binary operator (incompatible with black)
- ]
- max-line-length = 99
-
-[tool.isort]
- known_first_party = "sphinxcontrib_django"
- # Approach Black compatibility (just run black after isort)
- include_trailing_comma = true
- line_length = 88
- multi_line_output = 3
+[tool.ruff]
+ select = [
+ "F",
+ "E",
+ "W",
+ "I",
+ # "D",
+ "RET",
+ "SIM",
+ ]
+ ignore = [
+ "D1", # Missing docstrings
+ ]
+ line-length = 99
diff --git a/sphinxcontrib_django/__init__.py b/sphinxcontrib_django/__init__.py
index 62ad31b..192121e 100644
--- a/sphinxcontrib_django/__init__.py
+++ b/sphinxcontrib_django/__init__.py
@@ -1,12 +1,20 @@
"""
This is a sphinx extension which improves the documentation of Django apps.
"""
-__version__ = "2.1"
+
+from __future__ import annotations
+
+__version__ = "2.5"
+
+from typing import TYPE_CHECKING
from . import docstrings, roles
+if TYPE_CHECKING:
+ import sphinx
+
-def setup(app):
+def setup(app: sphinx.application.Sphinx) -> dict:
"""
Allow this module to be used as sphinx extension.
@@ -14,7 +22,6 @@ def setup(app):
:mod:`~sphinxcontrib_django.roles` which can also be imported separately.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
"""
docstrings.setup(app)
roles.setup(app)
diff --git a/sphinxcontrib_django/docstrings/__init__.py b/sphinxcontrib_django/docstrings/__init__.py
index ff172de..c561b0e 100644
--- a/sphinxcontrib_django/docstrings/__init__.py
+++ b/sphinxcontrib_django/docstrings/__init__.py
@@ -14,8 +14,12 @@
* 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
@@ -23,12 +27,15 @@
from .. import __version__
from .attributes import improve_attribute_docstring
from .classes import improve_class_docstring
-from .config import EXCLUDE_MEMBERS, INCLUDE_MEMBERS
+from .config import CHOICES_LIMIT, EXCLUDE_MEMBERS, INCLUDE_MEMBERS
from .data import improve_data_docstring
from .methods import improve_method_docstring
+if TYPE_CHECKING:
+ import sphinx
+
-def setup(app):
+def setup(app: sphinx.application.Sphinx) -> dict:
"""
Allow this package to be used as Sphinx extension.
@@ -43,7 +50,6 @@ def setup(app):
:event:`config-inited` event.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
"""
from .patches import patch_django_for_autodoc
@@ -59,8 +65,13 @@ def setup(app):
"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)
@@ -81,7 +92,7 @@ def setup(app):
}
-def setup_django(app, config):
+def setup_django(app: sphinx.application.Sphinx, config: sphinx.config.Config) -> None:
"""
This function calls :func:`django.setup` so it doesn't have to be done in the app's
``conf.py``.
@@ -89,10 +100,8 @@ def setup_django(app, config):
Called on the :event:`config-inited` event.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
:param config: The Sphinx configuration
- :type config: ~sphinx.config.Config
:raises ~sphinx.errors.ConfigError: If setting ``django_settings`` is not set correctly
"""
@@ -107,7 +116,7 @@ def setup_django(app, config):
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 directoy is added to sys.path."
+ " source directory is added to sys.path."
) from e
os.environ["DJANGO_SETTINGS_MODULE"] = config.django_settings
django.setup()
@@ -116,7 +125,14 @@ def setup_django(app, config):
app.emit("django-configured")
-def autodoc_skip(app, what, name, obj, skip, options):
+def autodoc_skip(
+ app: sphinx.application.Sphinx,
+ what: str,
+ name: str,
+ obj: object,
+ options: sphinx.ext.autodoc.Options,
+ lines: list[str],
+) -> bool | None:
"""
Hook to tell autodoc to include or exclude certain fields (see :event:`autodoc-skip-member`).
@@ -124,19 +140,10 @@ def autodoc_skip(app, what, name, obj, skip, options):
so only the ``name`` can be used for referencing.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
-
:param what: The parent type, ``class`` or ``module``
- :type what: str
-
:param name: The name of the child method/attribute.
- :type name: str
-
:param obj: The child value (e.g. a method, dict, or module reference)
- :type obj: object
-
:param options: The current autodoc settings.
- :type options: dict
"""
if name in EXCLUDE_MEMBERS:
return True
@@ -144,41 +151,37 @@ def autodoc_skip(app, what, name, obj, skip, options):
if name in INCLUDE_MEMBERS:
return False
- return skip
+ return None
-def improve_docstring(app, what, name, obj, options, lines):
+def improve_docstring(
+ app: sphinx.application.Sphinx,
+ what: str,
+ name: str,
+ obj: object,
+ options: sphinx.ext.autodoc.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``)
- :type what: str
-
:param name: The fully qualified name of the object
- :type name: str
-
:param obj: The documented object
- :type obj: 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
- :type options: object
-
: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.
- :type lines: list [ str ]
-
:return: The modified list of lines
- :rtype: list [ str ]
"""
if what == "class":
improve_class_docstring(app, obj, lines)
elif what == "attribute":
- improve_attribute_docstring(obj, name, lines)
+ improve_attribute_docstring(app, obj, name, lines)
elif what == "method":
improve_method_docstring(name, lines)
elif what == "data":
diff --git a/sphinxcontrib_django/docstrings/attributes.py b/sphinxcontrib_django/docstrings/attributes.py
index 1fb4104..86c36bd 100644
--- a/sphinxcontrib_django/docstrings/attributes.py
+++ b/sphinxcontrib_django/docstrings/attributes.py
@@ -1,6 +1,9 @@
"""
This module contains all functions which are used to improve the documentation of attributes.
"""
+
+from __future__ import annotations
+
from django.db import models
from django.db.models.fields import related_descriptors
from django.db.models.fields.files import FileDescriptor
@@ -9,7 +12,6 @@
from django.utils.module_loading import import_string
from sphinx.util.docstrings import prepare_docstring
-from .config import CHOICES_LIMIT
from .field_utils import get_field_type, get_field_verbose_name
FIELD_DESCRIPTORS = (FileDescriptor, related_descriptors.ForwardManyToOneDescriptor)
@@ -23,12 +25,15 @@
PhoneNumberDescriptor = None
-def improve_attribute_docstring(attribute, name, lines):
+def improve_attribute_docstring(app, attribute, name, lines):
"""
Improve the documentation of various model fields.
This improves the navigation between related objects.
+ :param app: The Sphinx application object
+ :type app: ~sphinx.application.Sphinx
+
:param attribute: The instance of the object to document
:type attribute: object
@@ -56,21 +61,21 @@ def improve_attribute_docstring(attribute, name, lines):
f"Internal field, use :class:`~{cls_path}.{field.name}` instead."
)
else:
- lines.extend(get_field_details(field))
+ lines.extend(get_field_details(app, field))
elif isinstance(attribute, FIELD_DESCRIPTORS):
# Display a reasonable output for forward descriptors (foreign key and one to one fields).
- lines.extend(get_field_details(attribute.field))
+ lines.extend(get_field_details(app, attribute.field))
elif isinstance(attribute, related_descriptors.ManyToManyDescriptor):
# Check this case first since ManyToManyDescriptor inherits from ReverseManyToOneDescriptor
# This descriptor is used for both forward and reverse relationships
if attribute.reverse:
- lines.extend(get_field_details(attribute.rel))
+ lines.extend(get_field_details(app, attribute.rel))
else:
- lines.extend(get_field_details(attribute.field))
+ lines.extend(get_field_details(app, attribute.field))
elif isinstance(attribute, related_descriptors.ReverseManyToOneDescriptor):
- lines.extend(get_field_details(attribute.rel))
+ lines.extend(get_field_details(app, attribute.rel))
elif isinstance(attribute, related_descriptors.ReverseOneToOneDescriptor):
- lines.extend(get_field_details(attribute.related))
+ lines.extend(get_field_details(app, attribute.related))
elif isinstance(attribute, (models.Manager, ManagerDescriptor)):
# Somehow the 'objects' manager doesn't pass through the docstrings.
module, model_name, field_name = name.rsplit(".", 2)
@@ -92,17 +97,22 @@ def improve_attribute_docstring(attribute, name, lines):
lines.extend(docstring_lines[:-1])
-def get_field_details(field):
+def get_field_details(app, field):
"""
This function returns the detail docstring of a model field.
It includes the field type and the verbose name of the field.
+ :param app: The Sphinx application object
+ :type app: ~sphinx.application.Sphinx
+
:param field: The field
:type field: ~django.db.models.Field
:return: The field details as list of strings
:rtype: list [ str ]
"""
+ choices_limit = app.config.django_choices_to_show
+
field_details = [
f"Type: {get_field_type(field)}",
"",
@@ -111,13 +121,16 @@ def get_field_details(field):
if hasattr(field, "choices") and field.choices:
field_details.extend(["", "Choices:", ""])
field_details.extend(
- [f"* ``{key}``" for key, value in field.choices[:CHOICES_LIMIT]]
+ [
+ f"* ``{key}``" if key != "" else "* ``''`` (Empty string)"
+ for key, value in field.choices[:choices_limit]
+ ]
)
# Check if list has been truncated
- if len(field.choices) > CHOICES_LIMIT:
+ if len(field.choices) > choices_limit:
# If only one element has been truncated, just list it as well
- if len(field.choices) == CHOICES_LIMIT + 1:
+ if len(field.choices) == choices_limit + 1:
field_details.append(f"* ``{field.choices[-1][0]}``")
else:
- field_details.append(f"* and {len(field.choices) - CHOICES_LIMIT} more")
+ field_details.append(f"* and {len(field.choices) - choices_limit} more")
return field_details
diff --git a/sphinxcontrib_django/docstrings/classes.py b/sphinxcontrib_django/docstrings/classes.py
index 7489244..0dc5003 100644
--- a/sphinxcontrib_django/docstrings/classes.py
+++ b/sphinxcontrib_django/docstrings/classes.py
@@ -2,25 +2,30 @@
This module contains all functions which are used to improve the documentation of classes.
"""
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
from django import forms
from django.db import models
from sphinx.pycode import ModuleAnalyzer
from .field_utils import get_field_type, get_field_verbose_name
+if TYPE_CHECKING:
+ import django
+ import sphinx
+
-def improve_class_docstring(app, cls, lines):
+def improve_class_docstring(
+ app: sphinx.application.Sphinx, cls: type, lines: list[str]
+) -> None:
"""
Improve the documentation of a class if it's a Django model or form
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
-
:param cls: The instance of the class to document
- :type cls: object
-
:param lines: The docstring lines
- :type lines: list [ str ]
"""
if issubclass(cls, models.Model):
improve_model_docstring(app, cls, lines)
@@ -28,26 +33,22 @@ def improve_class_docstring(app, cls, lines):
improve_form_docstring(cls, lines)
-def improve_model_docstring(app, model, lines):
+def improve_model_docstring(
+ app: sphinx.application.Sphinx, model: django.db.models.Model, lines: list[str]
+) -> None:
"""
Improve the documentation of a Django :class:`~django.db.models.Model` subclass.
This adds all model fields as parameters to the ``__init__()`` method.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
-
:param model: The instance of the model to document
- :type model: ~django.db.models.Model
-
:param lines: The docstring lines
- :type lines: list [ str ]
"""
# Add database table name
if app.config.django_show_db_tables:
- lines.insert(0, "")
- lines.insert(0, f"**Database table:** ``{model._meta.db_table}``")
+ add_db_table_name(app, model, lines)
# Get predefined params to exclude them from the automatically inserted params
param_offset = len(":param ")
@@ -113,21 +114,38 @@ def improve_model_docstring(app, model, lines):
and "sphinx.ext.graphviz" in app.extensions
and not any("inheritance-diagram::" in line for line in lines)
):
- lines.append(".. inheritance-diagram::") # pragma: no cover
+ lines.append("")
+ lines.append(f".. inheritance-diagram:: {model.__module__}.{model.__name__}")
+ lines.append("")
-def add_model_parameters(fields, lines, field_docs):
+def add_db_table_name(
+ app: sphinx.application.Sphinx, model: django.db.models.Model, lines: list[str]
+) -> None:
+ """
+ Format and add table name by extension configuration.
+
+ :param app: The Sphinx application object
+ :param model: The instance of the model to document
+ :param lines: The docstring lines
+ """
+ if model._meta.abstract and not app.config.django_show_db_tables_abstract:
+ return
+
+ table_name = None if model._meta.abstract else model._meta.db_table
+ lines.insert(0, "")
+ lines.insert(0, f"**Database table:** ``{table_name}``")
+
+
+def add_model_parameters(
+ fields: list[django.db.models.Field], lines: list[str], field_docs: dict
+) -> None:
"""
Add the given fields as model parameter with the ``:param:`` directive
:param fields: The list of fields
- :type fields: list [ ~django.db.models.Field ]
-
:param lines: The list of current docstring lines
- :type lines: list [ str ]
-
:param field_docs: The attribute docstrings of the model
- :type field_docs: dict
"""
for field in fields:
# Add docstrings if they are found
@@ -145,16 +163,13 @@ def add_model_parameters(fields, lines, field_docs):
lines.append(f":type {field.name}: {get_field_type(field, include_role=False)}")
-def improve_form_docstring(form, lines):
+def improve_form_docstring(form: django.forms.Form, lines: list[str]) -> None:
"""
Improve the documentation of a Django :class:`~django.forms.Form` class.
This highlights the available fields in the form.
:param form: The form object
- :type form: ~django.forms.Form
-
:param lines: The list of existing docstring lines
- :type lines: list [ str ]
"""
lines.append("**Form fields:**")
lines.append("")
diff --git a/sphinxcontrib_django/docstrings/config.py b/sphinxcontrib_django/docstrings/config.py
index 9ebcb5d..1f65e95 100644
--- a/sphinxcontrib_django/docstrings/config.py
+++ b/sphinxcontrib_django/docstrings/config.py
@@ -2,6 +2,7 @@
This module contains configuration of the members which should in-/excluded in sphinx
(see :event:`autodoc-skip-member`)
"""
+
#: Ensure that the __init__ method gets documented (also see :confval:`autoclass_content` setting)
INCLUDE_MEMBERS = {"__init__"}
@@ -22,5 +23,6 @@
"polymorphic_super_sub_accessors_replaced",
}
-#: How many choices should be shown for model fields
+#: How many choices should be shown for model fields by default,
+#: used as default for ``django_choices_to_show`` option
CHOICES_LIMIT = 10
diff --git a/sphinxcontrib_django/docstrings/field_utils.py b/sphinxcontrib_django/docstrings/field_utils.py
index bb732e2..77eee22 100644
--- a/sphinxcontrib_django/docstrings/field_utils.py
+++ b/sphinxcontrib_django/docstrings/field_utils.py
@@ -3,24 +3,27 @@
:mod:`~sphinxcontrib_django.docstrings.attributes` and
:mod:`~sphinxcontrib_django.docstrings.classes` modules.
"""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
from django.apps import apps
from django.contrib import contenttypes
from django.db import models
from django.utils.encoding import force_str
+if TYPE_CHECKING:
+ import django
-def get_field_type(field, include_role=True):
+
+def get_field_type(field: django.db.models.Field, include_role: bool = True) -> str:
"""
Get the type of a field including the correct intersphinx mappings.
:param field: The field
- :type field: ~django.db.models.Field
-
:param include_directive: Whether or not the role :any:`py:class` should be included
- :type include_directive: bool
-
:return: The type of the field
- :rtype: str
"""
if isinstance(field, models.fields.related.RelatedField):
to = field.remote_field.model
@@ -31,23 +34,22 @@ def get_field_type(field, include_role=True):
f":class:`~{type(field).__module__}.{type(field).__name__}` to"
f" :class:`~{to.__module__}.{to.__name__}`"
)
- elif isinstance(field, models.fields.reverse_related.ForeignObjectRel):
+ if isinstance(field, models.fields.reverse_related.ForeignObjectRel):
to = field.remote_field.model
return (
"Reverse"
f" :class:`~{type(field.remote_field).__module__}.{type(field.remote_field).__name__}`"
f" from :class:`~{to.__module__}.{to.__name__}`"
)
- else:
- if include_role:
- # For the docstrings of attributes, the :class: role is required
- return f":class:`~{type(field).__module__}.{type(field).__name__}`"
- else:
- # For the :param: role in class docstrings, the :class: role is not required
- return f"~{type(field).__module__}.{type(field).__name__}"
+ if include_role:
+ # For the docstrings of attributes, the :class: role is required
+ return f":class:`~{type(field).__module__}.{type(field).__name__}`"
+ # For the :param: role in class docstrings, the :class: role is not required
+ return f"~{type(field).__module__}.{type(field).__name__}"
-def get_field_verbose_name(field):
+
+def get_field_verbose_name(field: django.db.models.Field) -> str:
"""
Get the verbose name of the field.
If the field has a ``help_text``, it is also included.
@@ -56,7 +58,6 @@ def get_field_verbose_name(field):
For reverse related fields, the originating field is linked.
:param field: The field
- :type field: ~django.db.models.Field
"""
help_text = ""
# Check whether the field is a reverse related field
@@ -138,18 +139,15 @@ def get_field_verbose_name(field):
return verbose_name
-def get_model_from_string(field, model_string):
+def get_model_from_string(
+ field: django.db.models.Field, model_string: str
+) -> type[django.db.models.Model]:
"""
Get a model class from a string
:param field: The field
- :type field: ~django.db.models.Field
-
:param model_string: The string label of the model
- :type model_string: str
-
:return: The class of the model
- :rtype: type
"""
if "." in model_string:
model = apps.get_model(model_string)
diff --git a/sphinxcontrib_django/docstrings/methods.py b/sphinxcontrib_django/docstrings/methods.py
index c5973f2..771ab6c 100644
--- a/sphinxcontrib_django/docstrings/methods.py
+++ b/sphinxcontrib_django/docstrings/methods.py
@@ -1,6 +1,7 @@
"""
This module contains all functions which are used to improve the documentation of methods.
"""
+
import re
RE_GET_FOO_DISPLAY = re.compile(r"\.get_(?P[a-zA-Z0-9_]+)_display$")
diff --git a/sphinxcontrib_django/docstrings/patches.py b/sphinxcontrib_django/docstrings/patches.py
index d3c91c2..2597b80 100644
--- a/sphinxcontrib_django/docstrings/patches.py
+++ b/sphinxcontrib_django/docstrings/patches.py
@@ -1,6 +1,9 @@
"""
This module contains patches for Django to improve its interaction with Sphinx.
"""
+
+import contextlib
+
from django import apps, forms, test
from django.db import models
@@ -84,10 +87,8 @@ def patch_django_for_autodoc():
for parent_module_str, django_modules in DJANGO_MODULE_PATHS.items():
for django_module in django_modules:
for module_class in map(django_module.__dict__.get, django_module.__all__):
- try:
+ with contextlib.suppress(AttributeError):
module_class.__module__ = parent_module_str
- except AttributeError:
- pass
# Fix module path of model manager
models.manager.Manager.__module__ = "django.db.models"
diff --git a/sphinxcontrib_django/roles.py b/sphinxcontrib_django/roles.py
index f80a696..8f66d12 100644
--- a/sphinxcontrib_django/roles.py
+++ b/sphinxcontrib_django/roles.py
@@ -21,16 +21,23 @@
"sphinxcontrib_django.roles",
]
"""
+
+from __future__ import annotations
+
import logging
+from typing import TYPE_CHECKING
from sphinx.errors import ExtensionError
from . import __version__
+if TYPE_CHECKING:
+ import sphinx
+
logger = logging.getLogger(__name__)
-def setup(app):
+def setup(app: sphinx.application.Sphinx) -> dict:
"""
Allow this module to be used as Sphinx extension.
@@ -39,7 +46,6 @@ def setup(app):
It adds cross-reference types via :meth:`~sphinx.application.Sphinx.add_crossref_type`.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
"""
# Load sphinx.ext.intersphinx extension
app.setup_extension("sphinx.ext.intersphinx")
@@ -65,7 +71,9 @@ def setup(app):
}
-def add_default_intersphinx_mappings(app, config):
+def add_default_intersphinx_mappings(
+ app: sphinx.application.Sphinx, config: sphinx.config.Config
+) -> None:
"""
This function provides a default intersphinx mapping to the documentations of Python, Django
and Sphinx if ``intersphinx_mapping`` is not given in ``conf.py``.
@@ -73,10 +81,7 @@ def add_default_intersphinx_mappings(app, config):
Called on the :event:`config-inited` event.
:param app: The Sphinx application object
- :type app: ~sphinx.application.Sphinx
-
:param config: The Sphinx configuration
- :type config: ~sphinx.config.Config
"""
DEFAULT_INTERSPHINX_MAPPING = {
"python": ("https://docs.python.org/", None),
@@ -87,4 +92,5 @@ def add_default_intersphinx_mappings(app, config):
),
}
if not config.intersphinx_mapping:
- config.intersphinx_mapping = DEFAULT_INTERSPHINX_MAPPING
+ # TYPING: type hints are missing `.intersphinx_mapping` attribute.
+ config.intersphinx_mapping = DEFAULT_INTERSPHINX_MAPPING # type: ignore[attr-defined ]
diff --git a/tests/conftest.py b/tests/conftest.py
index c8cc794..3ab43f0 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -3,6 +3,7 @@
https://github.com/sphinx-doc/sphinx/issues/7008), so this setup was created using the given code
snippets and the existing test cases for the autodoc extension.
"""
+
from unittest.mock import Mock
import pytest
@@ -43,8 +44,7 @@ def setup_app_with_different_config(app_params, make_app):
def setup_app_with_different_config(**confoverrides):
args, kwargs = app_params
kwargs["confoverrides"] = confoverrides
- _app = make_app(*args, **kwargs)
- return _app
+ return make_app(*args, **kwargs)
return setup_app_with_different_config
@@ -54,7 +54,7 @@ def do_autodoc():
"""
This function simulates the autodoc functionality.
- Taken from https://github.com/sphinx-doc/sphinx/blob/d635d94eebbca0ebb1a5402aa07ed58c0464c6d3/tests/test_ext_autodoc.py#L33-L45 # noqa: E501
+ Taken from https://github.com/sphinx-doc/sphinx/blob/d635d94eebbca0ebb1a5402aa07ed58c0464c6d3/tests/test_ext_autodoc.py#L33-L45
"""
def do_autodoc(app, objtype, name, options=None):
diff --git a/tests/roots/test-docstrings/conf.py b/tests/roots/test-docstrings/conf.py
index fcd54cd..e4e6cf8 100644
--- a/tests/roots/test-docstrings/conf.py
+++ b/tests/roots/test-docstrings/conf.py
@@ -5,7 +5,11 @@
sys.path.insert(0, os.path.abspath("."))
project = "sphinx dummy Test"
-extensions = ["sphinxcontrib_django"]
+extensions = [
+ "sphinxcontrib_django",
+ "sphinx.ext.graphviz",
+ "sphinx.ext.inheritance_diagram",
+]
# Configure Django settings module
django_settings = "dummy_django_app.settings"
diff --git a/tests/roots/test-docstrings/dummy_django_app/forms.py b/tests/roots/test-docstrings/dummy_django_app/forms.py
index 0f92c5e..0fbcf50 100644
--- a/tests/roots/test-docstrings/dummy_django_app/forms.py
+++ b/tests/roots/test-docstrings/dummy_django_app/forms.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from django import forms
from .models import SimpleModel
@@ -7,7 +9,7 @@ class SimpleForm(forms.ModelForm):
test1 = forms.CharField(label="Test1")
test2 = forms.CharField(help_text="Test2")
- def __init__(self, *args, **kwargs):
+ def __init__(self, *args, **kwargs) -> None:
"""
This is a custom init method
"""
diff --git a/tests/roots/test-docstrings/dummy_django_app/models.py b/tests/roots/test-docstrings/dummy_django_app/models.py
index bfcf9be..8be4566 100644
--- a/tests/roots/test-docstrings/dummy_django_app/models.py
+++ b/tests/roots/test-docstrings/dummy_django_app/models.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
@@ -95,6 +97,9 @@ class ChoiceModel(models.Model):
choice_limit_above = models.IntegerField(
choices=[(i, i) for i in range(CHOICES_LIMIT + 2)]
)
+ choice_with_empty = models.CharField(
+ choices=[("", "Empty"), ("Something", "Not empty")]
+ )
class TaggedItem(models.Model):
@@ -105,7 +110,7 @@ class TaggedItem(models.Model):
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
- def __str__(self):
+ def __str__(self) -> str:
return self.tag
diff --git a/tests/test_attribute_docstrings.py b/tests/test_attribute_docstrings.py
index f292f14..3b582c3 100644
--- a/tests/test_attribute_docstrings.py
+++ b/tests/test_attribute_docstrings.py
@@ -371,6 +371,64 @@ def test_choice_field_limit_above(app, do_autodoc):
]
+@pytest.mark.sphinx(
+ "html", testroot="docstrings", confoverrides={"django_choices_to_show": 15}
+)
+def test_choice_field_custom_limit(app, do_autodoc):
+ actual = do_autodoc(
+ app, "attribute", "dummy_django_app.models.ChoiceModel.choice_limit_above"
+ )
+ print(actual)
+ assert list(actual) == [
+ "",
+ ".. py:attribute:: ChoiceModel.choice_limit_above",
+ " :module: dummy_django_app.models",
+ "",
+ " Type: :class:`~django.db.models.IntegerField`",
+ "",
+ " Choice limit above",
+ "",
+ " Choices:",
+ "",
+ " * ``0``",
+ " * ``1``",
+ " * ``2``",
+ " * ``3``",
+ " * ``4``",
+ " * ``5``",
+ " * ``6``",
+ " * ``7``",
+ " * ``8``",
+ " * ``9``",
+ " * ``10``",
+ " * ``11``",
+ "",
+ ]
+
+
+@pytest.mark.sphinx("html", testroot="docstrings")
+def test_choice_field_empty(app, do_autodoc):
+ actual = do_autodoc(
+ app, "attribute", "dummy_django_app.models.ChoiceModel.choice_with_empty"
+ )
+ print(actual)
+ assert list(actual) == [
+ "",
+ ".. py:attribute:: ChoiceModel.choice_with_empty",
+ " :module: dummy_django_app.models",
+ "",
+ " Type: :class:`~django.db.models.CharField`",
+ "",
+ " Choice with empty",
+ "",
+ " Choices:",
+ "",
+ " * ``''`` (Empty string)",
+ " * ``Something``",
+ "",
+ ]
+
+
if PHONENUMBER:
@pytest.mark.sphinx("html", testroot="docstrings")
diff --git a/tests/test_class_docstrings.py b/tests/test_class_docstrings.py
index 3456fe5..960f24e 100644
--- a/tests/test_class_docstrings.py
+++ b/tests/test_class_docstrings.py
@@ -81,6 +81,8 @@ def test_simple_model(app, do_autodoc):
" :class:`~dummy_django_app.models.ChildModelB`"
),
"",
+ " .. inheritance-diagram:: dummy_django_app.models.SimpleModel",
+ "",
]
@@ -168,6 +170,8 @@ def test_database_table(app, do_autodoc):
" :class:`~dummy_django_app.models.ChildModelB`"
),
"",
+ " .. inheritance-diagram:: dummy_django_app.models.SimpleModel",
+ "",
]
@@ -199,6 +203,85 @@ def test_abstract_model(app, do_autodoc):
" :class:`~dummy_django_app.models.AbstractModel`"
),
"",
+ " .. inheritance-diagram:: dummy_django_app.models.AbstractModel",
+ "",
+ ]
+
+
+@pytest.mark.sphinx(
+ "html", testroot="docstrings", confoverrides={"django_show_db_tables": True}
+)
+def test_abstract_model_with_tables_names_and_ignore_abstract(app, do_autodoc):
+ actual = do_autodoc(app, "class", "dummy_django_app.models.AbstractModel")
+ print(actual)
+ assert list(actual) == [
+ "",
+ ".. py:class:: AbstractModel(*args, **kwargs)",
+ " :module: dummy_django_app.models",
+ "",
+ "",
+ " Relationship fields:",
+ "",
+ " :param simple_model: Simple model",
+ (
+ " :type simple_model: :class:`~django.db.models.ForeignKey` to"
+ " :class:`~dummy_django_app.models.SimpleModel`"
+ ),
+ " :param user: User",
+ (
+ " :type user: :class:`~django.db.models.ForeignKey` to"
+ " :class:`~django.contrib.auth.models.User`"
+ ),
+ " :param foreignkey_self: Foreignkey self",
+ (
+ " :type foreignkey_self: :class:`~django.db.models.ForeignKey` to"
+ " :class:`~dummy_django_app.models.AbstractModel`"
+ ),
+ "",
+ " .. inheritance-diagram:: dummy_django_app.models.AbstractModel",
+ "",
+ ]
+
+
+@pytest.mark.sphinx(
+ "html",
+ testroot="docstrings",
+ confoverrides={
+ "django_show_db_tables": True,
+ "django_show_db_tables_abstract": True,
+ },
+)
+def test_abstract_model_with_tables_names_and_abstract_show(app, do_autodoc):
+ actual = do_autodoc(app, "class", "dummy_django_app.models.AbstractModel")
+ print(actual)
+ assert list(actual) == [
+ "",
+ ".. py:class:: AbstractModel(*args, **kwargs)",
+ " :module: dummy_django_app.models",
+ "",
+ " **Database table:** ``None``",
+ "",
+ "",
+ " Relationship fields:",
+ "",
+ " :param simple_model: Simple model",
+ (
+ " :type simple_model: :class:`~django.db.models.ForeignKey` to"
+ " :class:`~dummy_django_app.models.SimpleModel`"
+ ),
+ " :param user: User",
+ (
+ " :type user: :class:`~django.db.models.ForeignKey` to"
+ " :class:`~django.contrib.auth.models.User`"
+ ),
+ " :param foreignkey_self: Foreignkey self",
+ (
+ " :type foreignkey_self: :class:`~django.db.models.ForeignKey` to"
+ " :class:`~dummy_django_app.models.AbstractModel`"
+ ),
+ "",
+ " .. inheritance-diagram:: dummy_django_app.models.AbstractModel",
+ "",
]
@@ -227,6 +310,8 @@ def test_file_model(app, do_autodoc):
" :class:`~dummy_django_app.models.SimpleModel`"
),
"",
+ " .. inheritance-diagram:: dummy_django_app.models.FileModel",
+ "",
]
@@ -266,6 +351,8 @@ def test_tagged_item(app, do_autodoc):
" :class:`~django.contrib.contenttypes.models.ContentType`"
),
"",
+ " .. inheritance-diagram:: dummy_django_app.models.TaggedItem",
+ "",
]
diff --git a/tests/test_django_configured.py b/tests/test_django_configured.py
index 01d465d..876448e 100644
--- a/tests/test_django_configured.py
+++ b/tests/test_django_configured.py
@@ -15,4 +15,6 @@ def test_django_configured(app, do_autodoc):
" :param id: Primary key: ID",
" :type id: ~django.db.models.AutoField",
"",
+ " .. inheritance-diagram:: dummy_django_app.models.MonkeyPatched",
+ "",
]