将 Jinja2 与 Sphinx 自动摘要结合使用

Using Jinja2 with Sphinx autosummary

我正在尝试使用 sphinx.ext.autosummary 来记录 Python 包。由于 'autosummary' 要求我们列出所有要包含的项目,我想使用 Jinja2 指定这些项目。

我的conf.py如下(相关部分显示):

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.autosummary',
    'sphinx.ext.doctest',
    'sphinx.ext.todo',
    'sphinx.ext.coverage',
    'sphinx.ext.viewcode',
    'sphinx.ext.napoleon',
    'sphinx_automodapi.automodapi'
]

autodoc_default_options = {
    'imported-members':True
}
add_module_names = False
autosummary_generate = True
numpydoc_show_class_members = False

def rstjinja(app, docname, source):
    """
    Render our pages as a jinja template for fancy templating goodness.
    """
    # Make sure we're outputting HTML
    if app.builder.format != 'html':
        return
    src = source[0]
    rendered = app.builder.templates.render_string(
        src, app.config.html_context
    )
    source[0] = rendered

def setup(app):
    app.connect("source-read", rstjinja)

# in actual usage, `entities` is determined at docs generation time via some code
html_context = {
    'entities' : ["classA", "classB", "classD"]
}

方法rstjinja()setup()借鉴自here。它明确指出:

The Jinja templates will be rendered before the RST is processed.

我的.rst文件如下:

#####
Title
#####

.. currentmodule:: Package.SubModule

.. autosummary::
    :nosignatures:
    :toctree:

    {% for item in entities %}
        {{ item }}
    {% endfor %}

输出正确地向我显示了包含 3 个条目的摘要 table(我指定的三个 classes 中的每一个:"classA"、"classB"、 "classD")。第一列显示 class 的名称,第二列显示单行描述(来自其文档字符串)。第二列中的数据清楚地表明 Sphinx 能够识别相关的 classes 并提取其文档字符串。

我的问题是 'autosummary' 不会为这些 class 生成 存根 ,因此 table 中的这些条目不会可点击。在终端上,我看到每个 class 缺少存根的警告:

WARNING: autosummary: stub file not found 'Package.SubModule.classA'. Check your autosummary_generate setting.

如我的 conf.py 文件所示,此设置已经 True

如果我(为了探索)将 .rst 文件更改为以下内容:

#####
Title
#####

.. currentmodule:: Package.SubModule

.. autosummary::
    :nosignatures:
    :toctree:

    {% for item in entities %}
        {{ item }}
    {% endfor %}
    classA

然后我得到一个类似于前一个案例的 table,但在末尾有一个额外的行对应于 "classA"。有趣的是,"classA" 的两个条目(第一个通过 Jinja 生成,第二个通过明确指定)现在超链接到为 "classA".

创建的存根

为什么会这样?为什么仅通过 Jinja 指定相同的信息时不创建存根(即使 sphinx 确实在 table 中显示了这些的文档字符串)?

我该如何解决这个问题?能够通过 Jinja 提供要记录的实体列表对我来说很重要(因为我通过 conf.py 中的一些 Python 代码确定了这些)。

附加信息: 在上面的示例中,可以通过

导入 classes

from Package.SubModule import classA, classB, classD

我找到了使用 sphinx_automodapi.automodapi 扩展的解决方法。

我的相关位 conf.py:

import sphinx_automodapi

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.doctest',
    'sphinx.ext.todo',
    'sphinx.ext.coverage',
    'sphinx.ext.viewcode',
    'sphinx.ext.napoleon',
    'sphinx_automodapi.automodapi'
]

add_module_names = False
autosummary_generate = True
numpydoc_show_class_members = False

def rstjinja(app, docname, source):
    """
    Render our pages as a jinja template for fancy templating goodness.
    """
    # Make sure we're outputting HTML
    if app.builder.format != 'html':
        return
    src = source[0]
    rendered = app.builder.templates.render_string(
        src, app.config.html_context
    )
    source[0] = rendered

def setup(app):
    app.connect("source-read", rstjinja)


html_context = {
    'entities'       : ["classC", "classE"] # NOTE: specify classes NOT to be included/documented; items specified here will be skipped in doc generation
}

注意:通过 html_context 传递的 类 列表是要从文档中 排除 的 类。如果扩展允许直接指定所需的 类 就好了。我已经为相同的(目前未解决)开了一张票(这里:https://github.com/astropy/sphinx-automodapi/issues/92)。

在实际使用中,类的列表是可以动态确定的。例如:

import inspect, importlib, sciunit
package_import_name = "package_name"

submodule = "{}.submodule_name".format(package_import_name)
module = importlib.import_module(submodule)
exlcude_classes = [x[0] for x in inspect.getmembers(module,
                    lambda member: inspect.isclass(member)
                                    and not(<<specify condition>>))]

html_context = {
    'entities'       : exlcude_classes
}

我的 .rst 文件示例:

##########
Submodules
##########

.. automodapi:: package_name.submodule_name
    :nosignatures:
    :no-main-docstr:
    :skip: {{ entities|join(', ') }}