I want to document Python object attributes with Sphinx. I understand I should use
:ivar varname: description
:ivar type varname: description
Here is a workaround provided by @acrisci
on github: prefix your variable name with ~.
. For example replace
:ivar float bandwidth: blah
with this:
:ivar float ~.bandwidth: blah
Source: https://github.com/sphinx-doc/sphinx/issues/2549#issuecomment-488896939
As mzjn referred there is an open issue for this SO post. In that thread there is also already a work-around for the issue posted. In sum, you use inline comments #:
instead of the docstring.
Take a look at the python.py
file in the commit referred by the user here. The docstring entries were removed (red lines), and he added inline comments in the constructor (green lines).
I have been looking for documentation on this but could not find it. For instance:
(...)
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
(...)
As noted by Nick Bastin this work-around renders completely differently from :ivar:
. There is no type support, and it always renders the default value.
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.
There's an alternative with other advantages. Just define you member variables at class scope and document them with plain docstring. Later you can reference them with py:attr: role. It's more readable, self-documented (yeah, I know this is under python-sphinx, but anyway) and introspection-friendly approach.
module.py
class A:
x = None
'''This way there's no issue. It is more readable and friendly
for class member introspection.'''
def __init__(self, x):
self.x = x
class B:
'''Something about :py:attr:`.A.x`'''
def x(self):
'''Method x of B'''
return 1
README.txt
****
Test
****
.. autoclass:: module.A
:members:
.. autoclass:: module.B
:members:
conf.py
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']}
Build like PYTHONPATH=. sphinx-build . html
.