使用Sphinx autodoc自动递归文档所有模块

231 投票
7 回答
84078 浏览
提问于 2025-04-15 21:57

我正在尝试用Sphinx来为一个超过5000行的Python项目写文档。这个项目大约有7个基础模块。根据我的了解,为了使用自动文档功能,我需要为项目中的每个文件写类似下面的代码:

.. automodule:: mods.set.tests
    :members:
    :show-inheritance:

这样做实在是太麻烦了,因为我有很多文件。如果我能简单地指定想要文档化的' mods '包就好了。这样Sphinx就可以自动遍历这个包,为每个子模块生成一个页面。

有没有这样的功能?如果没有,我可以写个脚本来生成所有的.rst文件,但那样会花费很多时间。

7 个回答

63

我不确定在最初提问的时候,Sphinx是否已经有了autosummary这个扩展,但现在其实可以不使用sphinx-apidoc或类似的脚本,轻松设置自动生成文档。下面是我在一个项目中使用的设置。

  1. 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']
    
  2. 在你的index.rst文件的目录结构(TOC tree)中使用autosummary::。在这个例子中,project.module1project.module2的文档将会自动生成,并放在_autosummary目录下。

    PROJECT
    =======
    
    .. toctree::
    
    .. autosummary::
       :toctree: _autosummary
    
       project.module1
       project.module2
    
  3. 默认情况下,autosummary只会为模块及其函数生成非常简短的总结。如果你想改变这个,可以把自定义的模板文件放到_templates/autosummary/module.rst中(这个文件会用Jinja2来解析):

    {{ fullname }}
    {{ underline }}
    
    .. automodule:: {{ fullname }}
        :members:
    

最后,_autosummary目录不需要进行版本控制。你可以随意命名它,并把它放在源代码树的任何地方(不过放在_build下面是行不通的)。

171

从 Sphinx 3.1 版本开始(2020年6月),sphinx.ext.autosummary 终于支持自动递归了。

这意味着你不再需要手动输入模块名称,也不需要依赖像 Sphinx AutoAPISphinx 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 %}
163

你可以看看我做的这个 脚本,我觉得它能帮到你。

这个脚本会扫描一个文件夹,寻找里面的Python模块和包,然后生成合适的ReST文件,以便用Sphinx来创建代码文档。它还会生成一个模块索引。

更新

这个脚本现在已经成为Sphinx 1.1的一部分,叫做 apidoc

撰写回答