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 #13220

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions doc/usage/extensions/apidoc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
.. _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
:no-index:
:type: :code-py:`Sequence[dict[str, Any]]`
:default: :code-py:`()`

A list or sequence of dictionaries describing modules to document.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a side note, I could see the case for making config parameters applying to all modules. This would remove the need for repeating a lot of keys for multiple modules.

apidoc_module_config = {
        'followlinks': False,
        'separatemodules': False,
        'includeprivate': False,
        'noheadings': False,
}
apidoc_modules = {
        {'path': 'path/to/module'},
        {'path': 'path/to/other_module'},
        {'path': 'path/to/third_module', 'includeprivate': True}, # overriding global settings
}

Implementation-wise one would just merge the dicts apidoc_module_config and the individual config dicts.

But that could also be added later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cc @chrisjsewell -- I just rebased the original PR so would prefer to have your input on larger design changes such as Tim suggests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @AA-Turner I'll have a look in the next few days


For example:

.. code-block:: python

apidoc_modules = [
{'destination': 'source/', 'path': 'path/to/module'},
{
'destination': 'source/',
'path': 'path/to/another_module',
Comment on lines +55 to +58
Copy link
Contributor

@timhoffm timhoffm Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I would put 'path' first. The module to be documented is the main aspect.

Suggested change
{'destination': 'source/', 'path': 'path/to/module'},
{
'destination': 'source/',
'path': 'path/to/another_module',
{'path': 'path/to/module', 'destination': 'source/'},
{
'path': 'path/to/another_module',
'destination': 'source/',

Alternatively, the modules are so prominent that one could make them keys of a dict:

apidoc_modules = {
    'path/to/module': {'destination': 'source/'},
    'path/to/other_module': {
        'destination': 'source/',
        'exclude_patterns': ['**/test*'],
        'maxdepth': 4,
        'followlinks': False,
        'separatemodules': False,
        'includeprivate': False,
        'noheadings': False,
        'modulefirst': False,
        'implicit_namespaces': False,
    },
}

'exclude_patterns': ['**/test*'],
'maxdepth': 4,
'followlinks': False,
'separatemodules': False,
'includeprivate': False,
'noheadings': False,
'modulefirst': False,
'implicit_namespaces': False,
'automodule_options': {
'members', 'show-inheritance', 'undoc-members'
},
},
]


Valid keys are:

: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:`'path'`
The path to the module to document (**required**).
This must be absolute or relative to the configuration directory.

:code-py:`'exclude_patterns'`
A sequence of patterns to exclude from generation.
These may be literal paths or :py:mod:`fnmatch`-style patterns.
Defaults to :code-py:`()`.

:code-py:`'maxdepth'`
The maximum depth of submodules to show in the generated table of contents.
Defaults to :code-py:`4`.

:code-py:`'followlinks'`
Follow symbolic links.
Defaults to :code-py:`False`.

:code-py:`'separatemodules'`
Put documentation for each module on an individual page.
Defaults to :code-py:`False`.

:code-py:`'includeprivate'`
Generate documentation for '_private' modules with leading underscores.
Defaults to :code-py:`False`.

:code-py:`'noheadings'`
Do not create headings for the modules/packages.
Useful when source docstrings already contain headings.
Defaults to :code-py:`False`.

:code-py:`'modulefirst'`
Place module documentation before submodule documentation.
Defaults to :code-py:`False`.

:code-py:`'implicit_namespaces'`
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.
Defaults to :code-py:`False`.

:code-py:`'automodule_options'`
Options to pass to generated :rst:dir:`automodule` directives.
Defaults to :code-py:`{'members', 'show-inheritance', 'undoc-members'}`.
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
19 changes: 18 additions & 1 deletion sphinx/ext/apidoc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,26 @@

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')
app.add_config_value('apidoc_modules', (), 'env', types=frozenset((list, tuple)))
app.connect('builder-inited', run_apidoc)
return {
'version': sphinx.__display_version__,
'parallel_read_safe': True,
}
8 changes: 2 additions & 6 deletions sphinx/ext/apidoc/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@
import sphinx.locale
from sphinx import __display_version__
from sphinx.cmd.quickstart import EXTENSIONS
from sphinx.ext.apidoc._generate import (
ApidocOptions,
create_modules_toc_file,
recurse_tree,
)
from sphinx.ext.apidoc._shared import LOGGER, _remove_old_files
from sphinx.ext.apidoc._generate import create_modules_toc_file, recurse_tree
from sphinx.ext.apidoc._shared import LOGGER, ApidocOptions, _remove_old_files
from sphinx.locale import __
from sphinx.util.osutil import ensuredir

Expand Down
Loading
Loading