Python 如何将对象添加到Sphinx';s全局索引,还是按别名交叉引用?

Python 如何将对象添加到Sphinx';s全局索引,还是按别名交叉引用?,python,python-sphinx,cross-reference,Python,Python Sphinx,Cross Reference,每次我必须引用一个方法,而不是:func:`package.subpackage.module.method`,特别是对于常用方法。是否有一种方法可以通过某种方式“注册”package.subpackage,这样只有module.method就足够了?(更好的是,package.subpackage.module,这样方法就足够了,假设没有冲突) 解决方案不应该包括向包或子包添加目录,但我可以向文档/添加任何内容。请注意,这里的问题涉及在docstring模块之外定义的方法(否则.method有

每次我必须引用一个方法,而不是
:func:`package.subpackage.module.method`
,特别是对于常用方法。是否有一种方法可以通过某种方式“注册”
package.subpackage
,这样只有
module.method
就足够了?(更好的是,
package.subpackage.module
,这样
方法就足够了,假设没有冲突)


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

从您看到类、函数或方法的那一刻起,您就可以在索引中省去名称的书写。 例如 不使用完全限定名称编写交叉引用:

:func:`~package.subpackage.module.method`
:meth:`~package.subpackage.module.method`
你可以简单地写:

:func:`.method`
:meth:`。方法`
请注意,如果要交叉引用本地范围之外的内容,则必须使用点
。例如,如果您正在编写交叉引用的类中引用属性或方法,则以下操作不起作用:

:meth:`method`
:attr:`方法`
还请注意,在范围
:meth:
:func:
中,这两种方法都可以互换工作。但是,在范围之外,您必须使用确切的角色,这取决于您是引用方法还是函数

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

检查索引以验证对象是否已插入其中非常重要(这由
.rst
文件中的autodoc或domain指令自动完成)。普通索引将显示“对象名(完全限定名)”,如果它在索引中,则可以交叉引用


编辑:下面是一个变通方法,可以将
方法
显示为
类.方法
;以上信息适用

`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)

现在,所有引用
:role:`foo.spam`
将替换为
:role:`spam`
,而不考虑确切的角色(
class
func
mod
,等等)。当然,这只是一个草稿,未经测试,但你应该了解这个想法。甚至可能是一个新的Sphinx扩展项目的良好起点:-)

“因此,对于Sphinx中的交叉引用,没有“索引X为Y”的方法。使用这个,
:meth:'X.Y'
看起来很有希望,“重命名”部分可以工作,但不能“重定目标”;没有超链接/交叉引用。我做到了:
{'Class.method':('package.subpackage.module.Class.method','Class.method')}
-我认为这是预期用途。恐怕我对“草稿”做不了什么"由于我对
docutils
&其余部分一无所知,但是如果你编辑一个工作代码,它将是我正在寻找的确切答案。链接用于实际项目、和的参考。@OverLordGoldDragon你是对的,这只是intersphinx引用解决方案的一部分——我误读了你的问题,出于某种原因考虑了intersphinx引用n、 我添加了一个用于解析内部引用的类似代码,方法基本相同;可以在单独的函数中提取重复的代码等。此外,如果不使用intersphinx,您可以安全地删除
缺少引用事件的侦听器,只保留
doctree read
一个。我将与您共享此-事实上,它应该是一个扩展,一旦是,我们会问“这怎么就不是一件事了”。@OverLordGoldDragon我不打算对我的
conf.py
进行猴子补丁,原因有几个。首先,docutils没有完整的API规范(这一部分说:“todo”),我认为这是“放手”。然后,你破坏了信任,给试图阅读你的代码的人带来了一个不合理的问题。没有文档,理解reST和Sphinx就足够困难了。不能保证这不会破坏你的Sphinx,任何后续的错误或错误都会让你猜测是否是猴子补丁造成的。从工程角度来看,这是一个糟糕的做法。