Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sphinx :ivar tag goes looking for cross-references

I want to document Python object attributes with Sphinx. I understand I should use

:ivar varname: description
:ivar type varname: description

However I'm seeing a weird behaviour, that is Sphinx searches my project for the variable name and tries to create symlinks. E.g. this code:

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

will cause this error:

module1.py:docstring of mylibrary.module1.A:None: WARNING: more than one target found for cross-reference u'x': mylibrary.module1.C.x, mylibrary.module1.B.x

Did I understand incorrectly the purpose or usage of :ivar?

like image 333
crusaderky Avatar asked Aug 03 '15 10:08

crusaderky


1 Answers

Here is a monkey patch (based on Sphinx 1.5.1) that disables ivar cross-references. I'm not sure what the best solution is, so consider the patch an experimental suggestion. To try it out, add the code below to 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

The original TypedField.make_field method is here: https://github.com/sphinx-doc/sphinx/blob/master/sphinx/util/docfields.py.

like image 194
mzjn Avatar answered Oct 16 '22 02:10

mzjn