使用Sphinx autodoc自动递归文档所有模块
我正在尝试用Sphinx来为一个超过5000行的Python项目写文档。这个项目大约有7个基础模块。根据我的了解,为了使用自动文档功能,我需要为项目中的每个文件写类似下面的代码:
.. automodule:: mods.set.tests
:members:
:show-inheritance:
这样做实在是太麻烦了,因为我有很多文件。如果我能简单地指定想要文档化的' mods '包就好了。这样Sphinx就可以自动遍历这个包,为每个子模块生成一个页面。
有没有这样的功能?如果没有,我可以写个脚本来生成所有的.rst文件,但那样会花费很多时间。
7 个回答
我不确定在最初提问的时候,Sphinx是否已经有了autosummary
这个扩展,但现在其实可以不使用sphinx-apidoc
或类似的脚本,轻松设置自动生成文档。下面是我在一个项目中使用的设置。
在
conf.py
文件中启用autosummary
扩展(同时也要启用autodoc
),并将autosummary_generate
选项设置为True
。如果你没有使用自定义的*.rst
模板,这样设置可能就够了。否则,你需要把你的模板目录添加到排除列表中,否则autosummary
会把它们当作输入文件来处理(这似乎是个bug)。extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary'] autosummary_generate = True templates_path = [ '_templates' ] exclude_patterns = ['_build', '_templates']
在你的
index.rst
文件的目录结构(TOC tree)中使用autosummary::
。在这个例子中,project.module1
和project.module2
的文档将会自动生成,并放在_autosummary
目录下。PROJECT ======= .. toctree:: .. autosummary:: :toctree: _autosummary project.module1 project.module2
默认情况下,
autosummary
只会为模块及其函数生成非常简短的总结。如果你想改变这个,可以把自定义的模板文件放到_templates/autosummary/module.rst
中(这个文件会用Jinja2来解析):{{ fullname }} {{ underline }} .. automodule:: {{ fullname }} :members:
最后,_autosummary
目录不需要进行版本控制。你可以随意命名它,并把它放在源代码树的任何地方(不过放在_build
下面是行不通的)。
从 Sphinx 3.1 版本开始(2020年6月),sphinx.ext.autosummary
终于支持自动递归了。
这意味着你不再需要手动输入模块名称,也不需要依赖像 Sphinx AutoAPI 或 Sphinx AutoPackageSummary 这样的第三方库来自动检测包了。
下面是一个示例 Python 3.7 包的文档(可以在 GitHub 上查看代码,以及在 ReadTheDocs 上查看结果):
mytoolbox
|-- mypackage
| |-- __init__.py
| |-- foo.py
| |-- mysubpackage
| |-- __init__.py
| |-- bar.py
|-- doc
| |-- source
| |--index.rst
| |--conf.py
| |-- _templates
| |-- custom-module-template.rst
| |-- custom-class-template.rst
conf.py
:
import os
import sys
sys.path.insert(0, os.path.abspath('../..')) # Source code dir relative to this file
extensions = [
'sphinx.ext.autodoc', # Core library for html generation from docstrings
'sphinx.ext.autosummary', # Create neat summary tables
]
autosummary_generate = True # Turn on sphinx.ext.autosummary
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
index.rst
(注意新的 :recursive:
选项):
Welcome to My Toolbox
=====================
Some words.
.. autosummary::
:toctree: _autosummary
:template: custom-module-template.rst
:recursive:
mypackage
这样就足够自动总结包中的每个模块,无论它们嵌套得多深。对于每个模块,它还会总结该模块中的每个属性、函数、类和异常。
奇怪的是,默认的 sphinx.ext.autosummary
模板并不会为每个属性、函数、类和异常生成单独的文档页面,也不会从总结表中链接到这些页面。虽然可以扩展模板来实现这一点,如下所示,但我不明白为什么这不是默认行为——这肯定是大多数人想要的吧?我已经将这个问题提出来作为功能请求了 。
我不得不在本地复制默认模板,然后进行修改:
- 将
site-packages/sphinx/ext/autosummary/templates/autosummary/module.rst
复制到mytoolbox/doc/source/_templates/custom-module-template.rst
- 将
site-packages/sphinx/ext/autosummary/templates/autosummary/class.rst
复制到mytoolbox/doc/source/_templates/custom-class-template.rst
对 custom-module-template.rst
的引用在上面的 index.rst
中,使用了 :template:
选项。(删除那一行可以看看使用默认模板会发生什么。)
custom-module-template.rst
(右侧标注了额外的行):
{{ fullname | escape | underline}}
.. automodule:: {{ fullname }}
{% block attributes %}
{% if attributes %}
.. rubric:: Module Attributes
.. autosummary::
:toctree: <-- add this line
{% for item in attributes %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block functions %}
{% if functions %}
.. rubric:: {{ _('Functions') }}
.. autosummary::
:toctree: <-- add this line
{% for item in functions %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block classes %}
{% if classes %}
.. rubric:: {{ _('Classes') }}
.. autosummary::
:toctree: <-- add this line
:template: custom-class-template.rst <-- add this line
{% for item in classes %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block exceptions %}
{% if exceptions %}
.. rubric:: {{ _('Exceptions') }}
.. autosummary::
:toctree: <-- add this line
{% for item in exceptions %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block modules %}
{% if modules %}
.. rubric:: Modules
.. autosummary::
:toctree:
:template: custom-module-template.rst <-- add this line
:recursive:
{% for item in modules %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
custom-class-template.rst
(右侧标注了额外的行):
{{ fullname | escape | underline}}
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
:members: <-- add at least this line
:show-inheritance: <-- plus I want to show inheritance...
:inherited-members: <-- ...and inherited members too
{% block methods %}
.. automethod:: __init__
{% if methods %}
.. rubric:: {{ _('Methods') }}
.. autosummary::
{% for item in methods %}
~{{ name }}.{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block attributes %}
{% if attributes %}
.. rubric:: {{ _('Attributes') }}
.. autosummary::
{% for item in attributes %}
~{{ name }}.{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}