Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sphinx.ext.apidoc extension #13333

Merged
merged 17 commits into from
Feb 18, 2025
Merged
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ Features added
* #13354: Insert abbreviation nodes (hover text) for positional- and keyword-only
separators in Python signatures.
Patch by Adam Turner.
* #13333: Add the :mod:`sphinx.ext.autodoc` extension,
to automate API documentation generation from Python modules.
Patch by Chris Sewell and Adam Turner.

Bugs fixed
----------
Expand Down
172 changes: 172 additions & 0 deletions doc/usage/extensions/apidoc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
.. _ext-apidoc:

:mod:`sphinx.ext.apidoc` -- Generate API documentation from Python packages
===========================================================================

.. py:module:: sphinx.ext.apidoc
:synopsis: Generate API documentation from Python modules

.. index:: pair: automatic; documentation
.. index:: pair: generation; documentation
.. index:: pair: generate; documentation

.. versionadded:: 8.2

.. role:: code-py(code)
:language: Python

:mod:`sphinx.ext.apidoc` is a tool for automatic generation
of Sphinx sources from Python packages.
It provides the :program:`sphinx-apidoc` command-line tool as an extension,
allowing it to be run during the Sphinx build process.

The extension writes generated source files to a provided directory,
which are then read by Sphinx using the :mod:`sphinx.ext.autodoc` extension.

.. warning::

:mod:`sphinx.ext.apidoc` generates source files that
use :mod:`sphinx.ext.autodoc` to document all found modules.
If any modules have side effects on import,
these will be executed by ``autodoc`` when :program:`sphinx-build` is run.

If you document scripts (as opposed to library modules),
make sure their main routine is protected by
an ``if __name__ == '__main__'`` condition.


Configuration
-------------

The apidoc extension uses the following configuration values:

.. confval:: apidoc_modules
:type: :code-py:`Sequence[dict[str, str | int | bool | Sequence[str] | Set[str]]`
:default: :code-py:`()`

A list or sequence of dictionaries describing modules to document.
If a value is left unspecified in any dictionary,
the general configuration value is used as the default.

For example:

.. code-block:: python

apidoc_modules = [
{'path': 'path/to/module', 'destination': 'source/'},
{
'path': 'path/to/another_module',
'destination': 'source/',
'exclude_patterns': ['**/test*'],
'max_depth': 4,
'follow_links': False,
'separate_modules': False,
'include_private': False,
'no_headings': False,
'module_first': False,
'implicit_namespaces': False,
'automodule_options': {
'members', 'show-inheritance', 'undoc-members'
},
},
]


Valid keys are:

:code-py:`'path'`
The path to the module to document (**required**).
This must be absolute or relative to the configuration directory.

:code-py:`'destination'`
The output directory for generated files (**required**).
This must be relative to the source directory,
and will be created if it does not exist.

:code-py:`'exclude_patterns'`
See :confval:`apidoc_exclude_patterns`.

:code-py:`'max_depth'`
See :confval:`apidoc_max_depth`.

:code-py:`'follow_links'`
See :confval:`apidoc_follow_links`.

:code-py:`'separate_modules'`
See :confval:`apidoc_separate_modules`.

:code-py:`'include_private'`
See :confval:`apidoc_include_private`.

:code-py:`'no_headings'`
See :confval:`apidoc_no_headings`.

:code-py:`'module_first'`
See :confval:`apidoc_module_first`.

:code-py:`'implicit_namespaces'`
See :confval:`apidoc_implicit_namespaces`.

:code-py:`'automodule_options'`
See :confval:`apidoc_automodule_options`.

.. confval:: apidoc_exclude_patterns
:type: :code-py:`Sequence[str]`
:default: :code-py:`()`

A sequence of patterns to exclude from generation.
These may be literal paths or :py:mod:`fnmatch`-style patterns.

.. confval:: apidoc_max_depth
:type: :code-py:`int`
:default: :code-py:`4`

The maximum depth of submodules to show in the generated table of contents.

.. confval:: apidoc_follow_links
:type: :code-py:`bool`
:default: :code-py:`False`

Follow symbolic links.

.. confval:: apidoc_separate_modules
:type: :code-py:`bool`
:default: :code-py:`False`

Put documentation for each module on an individual page.

.. confval:: apidoc_include_private
:type: :code-py:`bool`
:default: :code-py:`False`

Generate documentation for '_private' modules with leading underscores.

.. confval:: apidoc_no_headings
:type: :code-py:`bool`
:default: :code-py:`False`

Do not create headings for the modules/packages.
Useful when source docstrings already contain headings.

.. confval:: apidoc_module_first
:type: :code-py:`bool`
:default: :code-py:`False`

Place module documentation before submodule documentation.

.. confval:: apidoc_implicit_namespaces
:type: :code-py:`bool`
:default: :code-py:`False`

By default sphinx-apidoc processes sys.path searching for modules only.
Python 3.3 introduced :pep:`420` implicit namespaces that allow module path
structures such as ``foo/bar/module.py`` or ``foo/bar/baz/__init__.py``
(notice that ``bar`` and ``foo`` are namespaces, not modules).

Interpret module paths using :pep:`420` implicit namespaces.

.. confval:: apidoc_automodule_options
:type: :code-py:`Set[str]`
:default: :code-py:`{'members', 'show-inheritance', 'undoc-members'}`

Options to pass to generated :rst:dir:`automodule` directives.
1 change: 1 addition & 0 deletions doc/usage/extensions/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ These extensions are built in and can be activated by respective entries in the
.. toctree::
:maxdepth: 1

apidoc
autodoc
autosectionlabel
autosummary
Expand Down
47 changes: 46 additions & 1 deletion sphinx/ext/apidoc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,54 @@

from typing import TYPE_CHECKING

import sphinx
from sphinx.ext.apidoc._cli import main

if TYPE_CHECKING:
from collections.abc import Sequence

__all__: Sequence[str] = ('main',)
from sphinx.application import Sphinx
from sphinx.util.typing import ExtensionMetadata

__all__: Sequence[str] = 'main', 'setup'


def setup(app: Sphinx) -> ExtensionMetadata:
from sphinx.ext.apidoc._extension import run_apidoc

# Require autodoc
app.setup_extension('sphinx.ext.autodoc')

# Configuration values
app.add_config_value(
'apidoc_exclude_patterns', (), 'env', types=frozenset({list, tuple})
)
app.add_config_value('apidoc_max_depth', 4, 'env', types=frozenset({int}))
app.add_config_value('apidoc_follow_links', False, 'env', types=frozenset({bool}))
app.add_config_value(
'apidoc_separate_modules', False, 'env', types=frozenset({bool})
)
app.add_config_value(
'apidoc_include_private', False, 'env', types=frozenset({bool})
)
app.add_config_value('apidoc_no_headings', False, 'env', types=frozenset({bool}))
app.add_config_value('apidoc_module_first', False, 'env', types=frozenset({bool}))
app.add_config_value(
'apidoc_implicit_namespaces', False, 'env', types=frozenset({bool})
)
app.add_config_value(
'apidoc_automodule_options',
frozenset(('members', 'undoc-members', 'show-inheritance')),
'env',
types=frozenset({frozenset, list, set, tuple}),
)
app.add_config_value('apidoc_modules', (), 'env', types=frozenset({list, tuple}))

# Entry point to run apidoc
app.connect('builder-inited', run_apidoc)

return {
'version': sphinx.__display_version__,
'parallel_read_safe': True,
'parallel_write_safe': True,
}
Loading