Skip to content

Commit b215bed

Browse files
authored
Merge pull request #106 from jnothman/member-definition-list
Format attributes like parameters
2 parents 057ef57 + c917226 commit b215bed

File tree

2 files changed

+206
-23
lines changed

2 files changed

+206
-23
lines changed

numpydoc/docscrape_sphinx.py

+123-7
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,136 @@ def _str_returns(self, name='Returns'):
7979
out += ['']
8080
return out
8181

82-
def _str_param_list(self, name):
82+
def _process_param(self, param, desc, autosum):
83+
"""Determine how to display a parameter
84+
85+
Emulates autosummary behavior if autosum is not None.
86+
87+
Parameters
88+
----------
89+
param : str
90+
The name of the parameter
91+
desc : list of str
92+
The parameter description as given in the docstring. This is
93+
ignored when autosummary logic applies.
94+
autosum : list or None
95+
If a list, autosummary-style behaviour will apply for params
96+
that are attributes of the class and have a docstring.
97+
Names for autosummary generation will be appended to this list.
98+
99+
If None, autosummary is disabled.
100+
101+
Returns
102+
-------
103+
display_param : str
104+
The marked up parameter name for display. This may include a link
105+
to the corresponding attribute's own documentation.
106+
desc : list of str
107+
A list of description lines. This may be identical to the input
108+
``desc``, if ``autosum is None`` or ``param`` is not a class
109+
attribute, or it will be a summary of the class attribute's
110+
docstring.
111+
112+
Notes
113+
-----
114+
This does not have the autosummary functionality to display a method's
115+
signature, and hence is not used to format methods. It may be
116+
complicated to incorporate autosummary's signature mangling, as it
117+
relies on Sphinx's plugin mechanism.
118+
"""
119+
param = param.strip()
120+
display_param = '**%s**' % param
121+
122+
if autosum is None:
123+
return display_param, desc
124+
125+
param_obj = getattr(self._obj, param, None)
126+
if not (callable(param_obj)
127+
or isinstance(param_obj, property)
128+
or inspect.isgetsetdescriptor(param_obj)):
129+
param_obj = None
130+
obj_doc = pydoc.getdoc(param_obj)
131+
132+
if not (param_obj and obj_doc):
133+
return display_param, desc
134+
135+
prefix = getattr(self, '_name', '')
136+
if prefix:
137+
autosum_prefix = '~%s.' % prefix
138+
link_prefix = '%s.' % prefix
139+
else:
140+
autosum_prefix = ''
141+
link_prefix = ''
142+
143+
# Referenced object has a docstring
144+
autosum.append(" %s%s" % (autosum_prefix, param))
145+
display_param = ':obj:`%s <%s%s>`' % (param,
146+
link_prefix,
147+
param)
148+
if obj_doc:
149+
# Overwrite desc. Take summary logic of autosummary
150+
desc = re.split('\n\s*\n', obj_doc.strip(), 1)[0]
151+
# XXX: Should this have DOTALL?
152+
# It does not in autosummary
153+
m = re.search(r"^([A-Z].*?\.)(?:\s|$)",
154+
' '.join(desc.split()))
155+
if m:
156+
desc = m.group(1).strip()
157+
else:
158+
desc = desc.partition('\n')[0]
159+
desc = desc.split('\n')
160+
return display_param, desc
161+
162+
def _str_param_list(self, name, fake_autosummary=False):
163+
"""Generate RST for a listing of parameters or similar
164+
165+
Parameter names are displayed as bold text, and descriptions
166+
are in blockquotes. Descriptions may therefore contain block
167+
markup as well.
168+
169+
Parameters
170+
----------
171+
name : str
172+
Section name (e.g. Parameters)
173+
fake_autosummary : bool
174+
When True, the parameter names may correspond to attributes of the
175+
object beign documented, usually ``property`` instances on a class.
176+
In this case, names will be linked to fuller descriptions.
177+
178+
Returns
179+
-------
180+
rst : list of str
181+
"""
83182
out = []
84183
if self[name]:
184+
if fake_autosummary:
185+
autosum = []
186+
else:
187+
autosum = None
188+
85189
out += self._str_field_list(name)
86190
out += ['']
87191
for param, param_type, desc in self[name]:
192+
display_param, desc = self._process_param(param, desc, autosum)
193+
88194
if param_type:
89-
out += self._str_indent(['**%s** : %s' % (param.strip(),
90-
param_type)])
195+
out += self._str_indent(['%s : %s' % (display_param,
196+
param_type)])
91197
else:
92-
out += self._str_indent(['**%s**' % param.strip()])
198+
out += self._str_indent([display_param])
93199
if desc:
94-
out += ['']
200+
out += [''] # produces a blockquote, rather than a dt/dd
95201
out += self._str_indent(desc, 8)
96202
out += ['']
203+
204+
if fake_autosummary and autosum:
205+
if self.class_members_toctree:
206+
autosum.insert(0, ' :toctree:')
207+
autosum.insert(0, '.. autosummary::')
208+
out += ['..', ' HACK to make autogen generate docs:']
209+
out += self._str_indent(autosum, 4)
210+
out += ['']
211+
97212
return out
98213

99214
@property
@@ -130,7 +245,7 @@ def _str_member_list(self, name):
130245
or inspect.isgetsetdescriptor(param_obj)):
131246
param_obj = None
132247

133-
if param_obj and (pydoc.getdoc(param_obj) or not desc):
248+
if param_obj and pydoc.getdoc(param_obj):
134249
# Referenced object has a docstring
135250
autosum += [" %s%s" % (prefix, param)]
136251
else:
@@ -250,7 +365,8 @@ def __str__(self, indent=0, func_role="obj"):
250365
'notes': self._str_section('Notes'),
251366
'references': self._str_references(),
252367
'examples': self._str_examples(),
253-
'attributes': self._str_member_list('Attributes'),
368+
'attributes': self._str_param_list('Attributes',
369+
fake_autosummary=True),
254370
'methods': self._str_member_list('Methods'),
255371
}
256372
ns = dict((k, '\n'.join(v)) for k, v in ns.items())

numpydoc/tests/test_docscrape.py

+83-16
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from nose.tools import (assert_equal, assert_raises, assert_list_equal,
1818
assert_true)
1919

20+
assert_list_equal.__self__.maxDiff = None
21+
2022
if sys.version_info[0] >= 3:
2123
sixu = lambda s: s
2224
else:
@@ -897,8 +899,17 @@ def test_duplicate_signature():
897899
Current time.
898900
y : ndarray
899901
Current variable values.
900-
x : float
901-
Some parameter
902+
903+
* hello
904+
* world
905+
an_attribute : float
906+
The docstring is printed instead
907+
no_docstring : str
908+
But a description
909+
no_docstring2 : str
910+
multiline_sentence
911+
midword_period
912+
no_period
902913
903914
Methods
904915
-------
@@ -934,8 +945,17 @@ def test_class_members_doc():
934945
Current time.
935946
y : ndarray
936947
Current variable values.
937-
x : float
938-
Some parameter
948+
949+
* hello
950+
* world
951+
an_attribute : float
952+
The docstring is printed instead
953+
no_docstring : str
954+
But a description
955+
no_docstring2 : str
956+
multiline_sentence
957+
midword_period
958+
no_period
939959
940960
Methods
941961
-------
@@ -952,10 +972,38 @@ def test_class_members_doc():
952972
def test_class_members_doc_sphinx():
953973
class Foo:
954974
@property
955-
def x(self):
975+
def an_attribute(self):
956976
"""Test attribute"""
957977
return None
958978

979+
@property
980+
def no_docstring(self):
981+
return None
982+
983+
@property
984+
def no_docstring2(self):
985+
return None
986+
987+
@property
988+
def multiline_sentence(self):
989+
"""This is a
990+
sentence. It spans multiple lines."""
991+
return None
992+
993+
@property
994+
def midword_period(self):
995+
"""The sentence for numpy.org."""
996+
return None
997+
998+
@property
999+
def no_period(self):
1000+
"""This does not have a period
1001+
so we truncate its summary to the first linebreak
1002+
1003+
Apparently.
1004+
"""
1005+
return None
1006+
9591007
doc = SphinxClassDoc(Foo, class_doc_txt)
9601008
non_blank_line_by_line_compare(str(doc),
9611009
"""
@@ -975,17 +1023,36 @@ def x(self):
9751023
9761024
For usage examples, see `ode`.
9771025
978-
.. rubric:: Attributes
979-
980-
.. autosummary::
981-
:toctree:
982-
983-
x
984-
985-
===== ==========
986-
**t** (float) Current time.
987-
**y** (ndarray) Current variable values.
988-
===== ==========
1026+
:Attributes:
1027+
1028+
**t** : float
1029+
Current time.
1030+
**y** : ndarray
1031+
Current variable values.
1032+
1033+
* hello
1034+
* world
1035+
:obj:`an_attribute <an_attribute>` : float
1036+
Test attribute
1037+
**no_docstring** : str
1038+
But a description
1039+
**no_docstring2** : str
1040+
:obj:`multiline_sentence <multiline_sentence>`
1041+
This is a sentence.
1042+
:obj:`midword_period <midword_period>`
1043+
The sentence for numpy.org.
1044+
:obj:`no_period <no_period>`
1045+
This does not have a period
1046+
1047+
..
1048+
HACK to make autogen generate docs:
1049+
.. autosummary::
1050+
:toctree:
1051+
1052+
an_attribute
1053+
multiline_sentence
1054+
midword_period
1055+
no_period
9891056
9901057
.. rubric:: Methods
9911058

0 commit comments

Comments
 (0)