Python 斯芬克斯:ivar标签寻找交叉引用

Python 斯芬克斯:ivar标签寻找交叉引用,python,python-sphinx,Python,Python Sphinx,我想用Sphinx记录Python对象属性。我知道我应该使用 :ivar varname: description :ivar type varname: description 然而,我看到了一种奇怪的行为,那就是Sphinx在我的项目中搜索变量名并试图创建符号链接。 例如,该代码: class A(object): """ :ivar x: some description """ def __init__(self, x): self.x

我想用Sphinx记录Python对象属性。我知道我应该使用

:ivar varname: description
:ivar type varname: description
然而,我看到了一种奇怪的行为,那就是Sphinx在我的项目中搜索变量名并试图创建符号链接。 例如,该代码:

class A(object):
    """
    :ivar x: some description
    """
    def __init__(self, x):
        self.x = x

class B(object):
    def x(self):
        return 1

class C(object):
    def x(self):
        return 2
将导致此错误:

module1.py:mylibrary.module1.A的docstring:None:警告:找到多个交叉引用u'x的目标:mylibrary.module1.C.x,mylibrary.module1.B.x


我是否错误地理解了:ivar的用途或用法?

因为mzjn提到了一个。在该线程中,也已经有一个针对发布问题的解决方案。总之,您使用内联注释
而不是docstring

查看用户引用的提交中的
python.py
文件。删除了docstring条目(红线),并在构造函数中添加了内联注释(绿线)

我一直在寻找这方面的文档,但找不到它。 例如:

(...)
def __init__(self, function, fixtureinfo, config, cls=None, module=None):
    #: access to the :class:`_pytest.config.Config` object for the test session
    self.config = config
    (...)
正如尼克·巴斯汀(Nick Bastin)所指出的,这项工作与
:ivar:
完全不同。没有类型支持,它总是呈现默认值。

这里有一个猴子补丁(基于Sphinx 1.5.1),它禁用了
ivar
交叉引用。我不知道最好的解决方案是什么,所以考虑补丁是一个实验性的建议。要进行尝试,请将下面的代码添加到
conf.py

from docutils import nodes
from sphinx.util.docfields import TypedField
from sphinx import addnodes

def patched_make_field(self, types, domain, items):
    # type: (List, unicode, Tuple) -> nodes.field
    def handle_item(fieldarg, content):
        par = nodes.paragraph()
        par += addnodes.literal_strong('', fieldarg)  # Patch: this line added
        #par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
        #                           addnodes.literal_strong))
        if fieldarg in types:
            par += nodes.Text(' (')
            # NOTE: using .pop() here to prevent a single type node to be
            # inserted twice into the doctree, which leads to
            # inconsistencies later when references are resolved
            fieldtype = types.pop(fieldarg)
            if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text):
                typename = u''.join(n.astext() for n in fieldtype)
                par.extend(self.make_xrefs(self.typerolename, domain, typename,
                                           addnodes.literal_emphasis))
            else:
                par += fieldtype
            par += nodes.Text(')')
        par += nodes.Text(' -- ')
        par += content
        return par

    fieldname = nodes.field_name('', self.label)
    if len(items) == 1 and self.can_collapse:
        fieldarg, content = items[0]
        bodynode = handle_item(fieldarg, content)
    else:
        bodynode = self.list_type()
        for fieldarg, content in items:
            bodynode += nodes.list_item('', handle_item(fieldarg, content))
    fieldbody = nodes.field_body('', bodynode)
    return nodes.field('', fieldname, fieldbody)

TypedField.make_field = patched_make_field

原始的
TypedField.make\u field方法如下:。

还有一种具有其他优点的替代方法。只需在类范围内定义成员变量,并用普通docstring记录它们。稍后,您可以使用角色引用它们。它更具可读性,自我记录(是的,我知道这是在,但无论如何)和内省友好的方法

模块.py

自述文件

conf.py


像PYTHONPATH=一样构建。斯芬克斯建造。html

以下是github上的
@acrisci
提供的一种解决方法:在变量名前面加上
~。
。例如,替换

:ivar float bandwidth: blah
为此:

:ivar float ~.bandwidth: blah

资料来源:

这最终在2021年4月12日发布的《狮身人面像4.0.0》中得到了修正

Sphinx的下一个稳定版本将是4.0或4.1


< P>(问题:PR:修正了:4的beta 1:)如果你删除<代码>:IVAR X:一些描述< /代码>,错误消失了。是的,错误是由IVAR引起的,如果我删除C类,那么我就不会出错,但是在HTML中,我得到一个从A.x到B.Xi的不想要的链接也有同样的问题。这并非适用于所有:ivar,仅在实例变量的名称被其他类/模块使用的情况下才会发生。令人担忧的是:ivar(据我所知)根本不应该创建一个被报告为bug的交叉引用:问题是
的呈现方式与
:ivar:
(及其类似内容)完全不同。没有类型支持,它总是呈现默认值,并且没有那么紧凑。我感觉到了,它不是一个解决方案,只是一个变通方法。我只是在这里添加了信息来完成这个线程,因为这个问题源于这里。我还将添加您的注释。这从根本上改变了代码类属性与实例属性完全不同的功能。另外,您可以只使用
:py:attr:
,而不这样做,但它也不是以相同的方式呈现的(作为类或实例属性)。@NickBastin我看不到以这种方式“定义”其成员的类有任何“根本性更改”。我只看到好处。你能详细解释一下你的意思吗?最简单的例子是,你的更改允许
A.x
有一个值,而在正确的代码中,只有
A().x
有一个值(尝试访问
A.x
会给你一个异常)。这很容易导致细微的错误,甚至更糟。无论如何,文档不应该要求更改实际代码的行为。@NickBastin在我的示例中,尽管我想讨论类成员的更高级别抽象,但类属性得到了
None
值。初始化器中的对象属性重新绑定它们。我无法想象编写良好的代码会因此而崩溃。或者它是一个已经损坏的代码,错误地将类而不是实例传递到某个地方。或者它是一个写得很差的代码,它根据属性的存在(在
\uuuu dict\uuuu
中)而不是属性的值来做出决定。所以我再次认为你的观点是没有根据的…@NickBastin…好吧,除了一个人显然不需要重写他们的类,因为
var
在Sphinx中不能正常工作。从这个问题的意义上说,这是一个解决办法。但就我个人而言,我总是以这种方式编写类,从来没有遇到过这样的问题。您还可以在一些已知的包(如cherrypy、sqlalchemy和其他可能的包)中看到这种模式。这是一种编写类本身的方法。一种声明类范围(类的第一缩进级别)中所有成员的方法,以便更容易对其状态和功能进行推理。这确实有效!当然,这感觉有点不对劲,我不知道它在RTD上是否有效,但授予赏金是因为它满足了请求的参数(希望有人能在某个时候修复斯芬克斯票据,但这同时会起作用);一行代码代替另一行代码。顺便说一句,该补丁也可以应用于Sphinx的早期版本。不过,它抱怨的理由不匹配。只需将另一个可选参数作为
patched\u make\u字段(self、type、domain、items、env=None)
@SauravSahu:是的,猴子补丁可能很脆弱。在我发布答案后,docfields.py已经做了一些更改。相关错误报告仍处于打开状态:。显然已被Sphinx 3.4.0破坏:不工作:
警告:未找到py:obj参考目标:。带宽
extensions = ['sphinx.ext.autodoc']

source_suffix = '.txt'

master_doc = 'README'

project = 'Test'

pygments_style = 'sphinx'

html_theme = 'alabaster'

html_use_index       = False
html_show_sourcelink = False
html_show_copyright  = False

html_sidebars = {'**': ['localtoc.html']}
:ivar float bandwidth: blah
:ivar float ~.bandwidth: blah