Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format attributes like parameters #106

Merged
merged 5 commits into from
Sep 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 123 additions & 7 deletions numpydoc/docscrape_sphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,136 @@ def _str_returns(self, name='Returns'):
out += ['']
return out

def _str_param_list(self, name):
def _process_param(self, param, desc, autosum):
"""Determine how to display a parameter

Emulates autosummary behavior if autosum is not None.

Parameters
----------
param : str
The name of the parameter
desc : list of str
The parameter description as given in the docstring. This is
ignored when autosummary logic applies.
autosum : list or None
If a list, autosummary-style behaviour will apply for params
that are attributes of the class and have a docstring.
Names for autosummary generation will be appended to this list.

If None, autosummary is disabled.

Returns
-------
display_param : str
The marked up parameter name for display. This may include a link
to the corresponding attribute's own documentation.
desc : list of str
A list of description lines. This may be identical to the input
``desc``, if ``autosum is None`` or ``param`` is not a class
attribute, or it will be a summary of the class attribute's
docstring.

Notes
-----
This does not have the autosummary functionality to display a method's
signature, and hence is not used to format methods. It may be
complicated to incorporate autosummary's signature mangling, as it
relies on Sphinx's plugin mechanism.
"""
param = param.strip()
display_param = '**%s**' % param

if autosum is None:
return display_param, desc

param_obj = getattr(self._obj, param, None)
if not (callable(param_obj)
or isinstance(param_obj, property)
or inspect.isgetsetdescriptor(param_obj)):
param_obj = None
obj_doc = pydoc.getdoc(param_obj)

if not (param_obj and obj_doc):
return display_param, desc

prefix = getattr(self, '_name', '')
if prefix:
autosum_prefix = '~%s.' % prefix
link_prefix = '%s.' % prefix
else:
autosum_prefix = ''
link_prefix = ''

# Referenced object has a docstring
autosum.append(" %s%s" % (autosum_prefix, param))
display_param = ':obj:`%s <%s%s>`' % (param,
link_prefix,
param)
if obj_doc:
# Overwrite desc. Take summary logic of autosummary
desc = re.split('\n\s*\n', obj_doc.strip(), 1)[0]
# XXX: Should this have DOTALL?
# It does not in autosummary
m = re.search(r"^([A-Z].*?\.)(?:\s|$)",
' '.join(desc.split()))
if m:
desc = m.group(1).strip()
else:
desc = desc.partition('\n')[0]
desc = desc.split('\n')
return display_param, desc

def _str_param_list(self, name, fake_autosummary=False):
"""Generate RST for a listing of parameters or similar

Parameter names are displayed as bold text, and descriptions
are in blockquotes. Descriptions may therefore contain block
markup as well.

Parameters
----------
name : str
Section name (e.g. Parameters)
fake_autosummary : bool
When True, the parameter names may correspond to attributes of the
object beign documented, usually ``property`` instances on a class.
In this case, names will be linked to fuller descriptions.

Returns
-------
rst : list of str
"""
out = []
if self[name]:
if fake_autosummary:
autosum = []
else:
autosum = None

out += self._str_field_list(name)
out += ['']
for param, param_type, desc in self[name]:
display_param, desc = self._process_param(param, desc, autosum)

if param_type:
out += self._str_indent(['**%s** : %s' % (param.strip(),
param_type)])
out += self._str_indent(['%s : %s' % (display_param,
param_type)])
else:
out += self._str_indent(['**%s**' % param.strip()])
out += self._str_indent([display_param])
if desc:
out += ['']
out += [''] # produces a blockquote, rather than a dt/dd
out += self._str_indent(desc, 8)
out += ['']

if fake_autosummary and autosum:
if self.class_members_toctree:
autosum.insert(0, ' :toctree:')
autosum.insert(0, '.. autosummary::')
out += ['..', ' HACK to make autogen generate docs:']
out += self._str_indent(autosum, 4)
out += ['']

return out

@property
Expand Down Expand Up @@ -130,7 +245,7 @@ def _str_member_list(self, name):
or inspect.isgetsetdescriptor(param_obj)):
param_obj = None

if param_obj and (pydoc.getdoc(param_obj) or not desc):
if param_obj and pydoc.getdoc(param_obj):
# Referenced object has a docstring
autosum += [" %s%s" % (prefix, param)]
else:
Expand Down Expand Up @@ -250,7 +365,8 @@ def __str__(self, indent=0, func_role="obj"):
'notes': self._str_section('Notes'),
'references': self._str_references(),
'examples': self._str_examples(),
'attributes': self._str_member_list('Attributes'),
'attributes': self._str_param_list('Attributes',
fake_autosummary=True),
'methods': self._str_member_list('Methods'),
}
ns = dict((k, '\n'.join(v)) for k, v in ns.items())
Expand Down
99 changes: 83 additions & 16 deletions numpydoc/tests/test_docscrape.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from nose.tools import (assert_equal, assert_raises, assert_list_equal,
assert_true)

assert_list_equal.__self__.maxDiff = None

if sys.version_info[0] >= 3:
sixu = lambda s: s
else:
Expand Down Expand Up @@ -897,8 +899,17 @@ def test_duplicate_signature():
Current time.
y : ndarray
Current variable values.
x : float
Some parameter

* hello
* world
an_attribute : float
The docstring is printed instead
no_docstring : str
But a description
no_docstring2 : str
multiline_sentence
midword_period
no_period

Methods
-------
Expand Down Expand Up @@ -934,8 +945,17 @@ def test_class_members_doc():
Current time.
y : ndarray
Current variable values.
x : float
Some parameter

* hello
* world
an_attribute : float
The docstring is printed instead
no_docstring : str
But a description
no_docstring2 : str
multiline_sentence
midword_period
no_period

Methods
-------
Expand All @@ -952,10 +972,38 @@ def test_class_members_doc():
def test_class_members_doc_sphinx():
class Foo:
@property
def x(self):
def an_attribute(self):
"""Test attribute"""
return None

@property
def no_docstring(self):
return None

@property
def no_docstring2(self):
return None

@property
def multiline_sentence(self):
"""This is a
sentence. It spans multiple lines."""
return None

@property
def midword_period(self):
"""The sentence for numpy.org."""
return None

@property
def no_period(self):
"""This does not have a period
so we truncate its summary to the first linebreak

Apparently.
"""
return None

doc = SphinxClassDoc(Foo, class_doc_txt)
non_blank_line_by_line_compare(str(doc),
"""
Expand All @@ -975,17 +1023,36 @@ def x(self):

For usage examples, see `ode`.

.. rubric:: Attributes

.. autosummary::
:toctree:

x

===== ==========
**t** (float) Current time.
**y** (ndarray) Current variable values.
===== ==========
:Attributes:

**t** : float
Current time.
**y** : ndarray
Current variable values.

* hello
* world
:obj:`an_attribute <an_attribute>` : float
Test attribute
**no_docstring** : str
But a description
**no_docstring2** : str
:obj:`multiline_sentence <multiline_sentence>`
This is a sentence.
:obj:`midword_period <midword_period>`
The sentence for numpy.org.
:obj:`no_period <no_period>`
This does not have a period

..
HACK to make autogen generate docs:
.. autosummary::
:toctree:

an_attribute
multiline_sentence
midword_period
no_period

.. rubric:: Methods

Expand Down