如何将对象添加到 Sphinx 的全局索引,或通过别名进行交叉引用?

How to add objects to Sphinx's global index, or cross-reference by alias?

每次我不得不引用一个方法时,我宁愿不:func:`package.subpackage.module.method`,尤其是对于经常使用的方法。有没有办法以某种方式 "register" package.subpackage 使得只有 module.method 就足够了? (更好的是,package.subpackage.module,所以 method 就足够了,假设没有冲突)。

解决方案不应涉及向 packagesubpackage 添加目录,但我可以向 docs/ 添加任何内容。请注意,这里的问题涉及在文档字符串模块之外定义的 method(否则 .method 有效)。

从你能看到class、函数或方法的那一刻起,在索引中你就可以省略名字的写法了。 例如, 而不是使用完全限定名称编写交叉引用:

:func:`~package.subpackage.module.method`
:meth:`~package.subpackage.module.method`

你可以简单地写:

:func:`.method`
:meth:`.method`

请注意,如果您要交叉引用本地范围之外的内容,则 使用点 . 是必要的。例如,如果您在编写交叉引用的 class 中引用属性或方法,则以下内容有效:

:meth:`method`
:attr:`method`

另请注意,在范围内 :meth::func: 两者可以互换使用。但是,在范围之外,您必须使用精确的角色,具体取决于您引用的是方法还是函数。

请注意,您可能会遇到名称冲突,因为相同的名称可能会在不同的模块中用于不同的对象。在那种情况下,您应该使用完全限定名称来准确区分您引用的是哪个对象。

重要的是检查索引以验证对象是否已插入(这是由 .rst 文件中的 autodoc 或域指令自动完成的)。正常索引会显示"object name (fully qualified name)",如果在索引中就可以交叉引用


编辑:下面是将 .method 显示为 class.method 的解决方法;以上信息适用。

`ClassName.`:meth:`.method`

您可以添加一个简单的扩展来解析您定义的别名。下面的例子是一个简短的概念证明:

# add this to conf.py

from sphinx.addnodes import pending_xref
from sphinx.ext.intersphinx import missing_reference
from docutils.nodes import Text

# alias ref is mapped to a pair (real ref, text to render)
reftarget_aliases = {
    'foo.spam': ('foo.bar.baz.spam', 'spam'),
}


def resolve_intersphinx_aliases(app, env, node, contnode):
    alias = node.get('reftarget', None)
    if alias is not None and alias in reftarget_aliases:
        real_ref, text_to_render = reftarget_aliases[alias]
        # this will resolve the ref
        node['reftarget'] = real_ref

        # this will rewrite the rendered text:
        # find the text node child
        text_node = next(iter(contnode.traverse(lambda n: n.tagname == '#text')))
        # remove the old text node, add new text node with custom text
        text_node.parent.replace(text_node, Text(text_to_render, ''))

        # delegate all the rest of dull work to intersphinx
        return missing_reference(app, env, node, contnode)


def resolve_internal_aliases(app, doctree):
    pending_xrefs = doctree.traverse(condition=pending_xref)
    for node in pending_xrefs:
        alias = node.get('reftarget', None)
        if alias is not None and alias in reftarget_aliases:
            real_ref, text_to_render = reftarget_aliases[alias]
            # this will resolve the ref
            node['reftarget'] = real_ref

            # this will rewrite the rendered text:
            # find the text node child
            text_node = next(iter(node.traverse(lambda n: n.tagname == '#text')))
            # remove the old text node, add new text node with custom text
            text_node.parent.replace(text_node, Text(text_to_render, ''))


def setup(app):
    app.connect('doctree-read', resolve_internal_aliases)
    app.connect('missing-reference', resolve_intersphinx_aliases)

现在所有 refs :role:`foo.spam` 都将替换为 :role:`spam <foo.bar.baz.spam>`,而不管确切的角色是什么(classfuncmod,等等)。当然,这只是草稿且未经测试,但您应该明白了。甚至可能是新 Sphinx 扩展项目的良好起点:-)