Skip to content

Commit 5c8e1e3

Browse files
authored
Merge branch 'master' into reference-re
2 parents 0683e95 + 2cdd4d9 commit 5c8e1e3

File tree

11 files changed

+295
-131
lines changed

11 files changed

+295
-131
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ cache:
1717
before_install:
1818
- sudo apt-get install texlive texlive-latex-extra latexmk
1919
- pip install --upgrade pip setuptools # Upgrade pip and setuptools to get ones with `wheel` support
20-
- pip install --find-links http://wheels.astropy.org/ --find-links http://wheels2.astropy.org/ --trusted-host wheels.astropy.org --trusted-host wheels2.astropy.org --use-wheel nose numpy matplotlib ${SPHINX_SPEC}
20+
- pip install pytest numpy matplotlib ${SPHINX_SPEC}
2121
script:
2222
- |
2323
python setup.py sdist
2424
cd dist
2525
pip install numpydoc* -v
26-
- nosetests numpydoc
26+
- pytest --pyargs numpydoc
2727
- |
2828
cd ../doc
2929
make SPHINXOPTS=$SPHINXOPTS html

doc/example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def foo(var1, var2, long_var_name='hi'):
9393
9494
.. math:: X(e^{j\omega } ) = x(n)e^{ - j\omega n}
9595
96-
And even use a greek symbol like :math:`omega` inline.
96+
And even use a Greek symbol like :math:`\omega` inline.
9797
9898
References
9999
----------

doc/format.rst

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ The sections of a function's docstring are:
119119

120120
"""
121121

122+
.. highlight:: rst
123+
122124
2. **Deprecation warning**
123125

124126
A section (use if applicable) to warn users that the object is deprecated.
@@ -276,46 +278,46 @@ The sections of a function's docstring are:
276278

277279
10. **Warnings**
278280

279-
An optional section with cautions to the user in free text/reST.
281+
An optional section with cautions to the user in free text/reST.
280282

281283
11. **See Also**
282284

283-
An optional section used to refer to related code. This section
284-
can be very useful, but should be used judiciously. The goal is to
285-
direct users to other functions they may not be aware of, or have
286-
easy means of discovering (by looking at the module docstring, for
287-
example). Routines whose docstrings further explain parameters
288-
used by this function are good candidates.
285+
An optional section used to refer to related code. This section
286+
can be very useful, but should be used judiciously. The goal is to
287+
direct users to other functions they may not be aware of, or have
288+
easy means of discovering (by looking at the module docstring, for
289+
example). Routines whose docstrings further explain parameters
290+
used by this function are good candidates.
289291

290-
As an example, for ``numpy.mean`` we would have::
292+
As an example, for ``numpy.mean`` we would have::
291293

292-
See Also
293-
--------
294-
average : Weighted average
294+
See Also
295+
--------
296+
average : Weighted average
295297

296-
When referring to functions in the same sub-module, no prefix is
297-
needed, and the tree is searched upwards for a match.
298+
When referring to functions in the same sub-module, no prefix is
299+
needed, and the tree is searched upwards for a match.
298300

299-
Prefix functions from other sub-modules appropriately. E.g.,
300-
whilst documenting the ``random`` module, refer to a function in
301-
``fft`` by
301+
Prefix functions from other sub-modules appropriately. E.g.,
302+
whilst documenting the ``random`` module, refer to a function in
303+
``fft`` by
302304

303-
::
305+
::
304306

305-
fft.fft2 : 2-D fast discrete Fourier transform
307+
fft.fft2 : 2-D fast discrete Fourier transform
306308

307-
When referring to an entirely different module::
309+
When referring to an entirely different module::
308310

309-
scipy.random.norm : Random variates, PDFs, etc.
311+
scipy.random.norm : Random variates, PDFs, etc.
310312

311-
Functions may be listed without descriptions, and this is
312-
preferable if the functionality is clear from the function name::
313+
Functions may be listed without descriptions, and this is
314+
preferable if the functionality is clear from the function name::
313315

314-
See Also
315-
--------
316-
func_a : Function a with its description.
317-
func_b, func_c_, func_d
318-
func_e
316+
See Also
317+
--------
318+
func_a : Function a with its description.
319+
func_b, func_c_, func_d
320+
func_e
319321

320322
12. **Notes**
321323

@@ -393,6 +395,8 @@ The sections of a function's docstring are:
393395
docstring, the table markup will be broken by numpydoc processing. See
394396
`numpydoc issue #130 <https://github.com/numpy/numpydoc/issues/130>`_
395397

398+
.. highlight:: pycon
399+
396400
14. **Examples**
397401

398402
An optional section for examples, using the `doctest
@@ -464,6 +468,7 @@ The sections of a function's docstring are:
464468
`matplotlib.sphinxext.plot_directive` is loaded as a Sphinx extension in
465469
``conf.py``.
466470

471+
.. highlight:: rst
467472

468473
Documenting classes
469474
-------------------
@@ -501,7 +506,9 @@ In general, it is not necessary to list class methods. Those that are
501506
not part of the public API have names that start with an underscore.
502507
In some cases, however, a class may have a great many methods, of
503508
which only a few are relevant (e.g., subclasses of ndarray). Then, it
504-
becomes useful to have an additional **Methods** section::
509+
becomes useful to have an additional **Methods** section:
510+
511+
.. code-block:: python
505512
506513
class Photo(ndarray):
507514
"""

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ Documentation
2222
install
2323
format
2424
example
25+
validation

doc/validation.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
==============================
2+
Validating NumpyDoc docstrings
3+
==============================
4+
5+
One tool for validating docstrings is to see how an object's dosctring
6+
translates to Restructured Text. Using numpydoc as a command-line tool
7+
facilitates this. For example to see the Restructured Text generated
8+
for ``numpy.ndarray``, use:
9+
10+
.. code-block:: bash
11+
12+
$ python -m numpydoc numpy.ndarray

numpydoc/__main__.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import argparse
2+
import importlib
3+
import ast
4+
5+
from .docscrape_sphinx import get_doc_object
6+
7+
8+
def main(argv=None):
9+
"""Test numpydoc docstring generation for a given object"""
10+
11+
ap = argparse.ArgumentParser(description=__doc__)
12+
ap.add_argument('import_path', help='e.g. numpy.ndarray')
13+
14+
def _parse_config(s):
15+
key, _, value = s.partition('=')
16+
value = ast.literal_eval(value)
17+
return key, value
18+
19+
ap.add_argument('-c', '--config', type=_parse_config,
20+
action='append',
21+
help='key=val where val will be parsed by literal_eval, '
22+
'e.g. -c use_plots=True. Multiple -c can be used.')
23+
args = ap.parse_args(argv)
24+
25+
parts = args.import_path.split('.')
26+
27+
for split_point in range(len(parts), 0, -1):
28+
try:
29+
path = '.'.join(parts[:split_point])
30+
obj = importlib.import_module(path)
31+
except ImportError:
32+
continue
33+
break
34+
else:
35+
raise ImportError('Could not resolve {!r} to an importable object'
36+
''.format(args.import_path))
37+
38+
for part in parts[split_point:]:
39+
obj = getattr(obj, part)
40+
41+
print(get_doc_object(obj, config=dict(args.config or [])))
42+
43+
if __name__ == '__main__':
44+
main()

numpydoc/docscrape.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
import re
99
import pydoc
1010
from warnings import warn
11-
import collections
11+
from collections import namedtuple
12+
try:
13+
from collections.abc import Callable, Mapping
14+
except ImportError:
15+
from collections import Callable, Mapping
1216
import copy
1317
import sys
1418

@@ -106,7 +110,10 @@ def __str__(self):
106110
return message
107111

108112

109-
class NumpyDocString(collections.Mapping):
113+
Parameter = namedtuple('Parameter', ['name', 'type', 'desc'])
114+
115+
116+
class NumpyDocString(Mapping):
110117
"""Parses a numpydoc string to an abstract representation
111118
112119
Instances define a mapping from section title to structured data.
@@ -225,7 +232,7 @@ def _parse_param_list(self, content):
225232
desc = dedent_lines(desc)
226233
desc = strip_blank_lines(desc)
227234

228-
params.append((arg_name, arg_type, desc))
235+
params.append(Parameter(arg_name, arg_type, desc))
229236

230237
return params
231238

@@ -317,7 +324,8 @@ def _parse_summary(self):
317324
while True:
318325
summary = self._doc.read_to_next_empty_line()
319326
summary_str = " ".join([s.strip() for s in summary]).strip()
320-
if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str):
327+
compiled = re.compile(r'^([\w., ]+=)?\s*[\w\.]+\(.*\)$')
328+
if compiled.match(summary_str):
321329
self['Signature'] = summary_str
322330
if not self._is_at_section():
323331
continue
@@ -389,7 +397,7 @@ def _str_indent(self, doc, indent=4):
389397

390398
def _str_signature(self):
391399
if self['Signature']:
392-
return [self['Signature'].replace('*', '\*')] + ['']
400+
return [self['Signature'].replace('*', r'\*')] + ['']
393401
else:
394402
return ['']
395403

@@ -409,13 +417,13 @@ def _str_param_list(self, name):
409417
out = []
410418
if self[name]:
411419
out += self._str_header(name)
412-
for param, param_type, desc in self[name]:
413-
if param_type:
414-
out += ['%s : %s' % (param, param_type)]
420+
for param in self[name]:
421+
if param.type:
422+
out += ['%s : %s' % (param.name, param.type)]
415423
else:
416-
out += [param]
417-
if desc and ''.join(desc).strip():
418-
out += self._str_indent(desc)
424+
out += [param.name]
425+
if param.desc and ''.join(param.desc).strip():
426+
out += self._str_indent(param.desc)
419427
out += ['']
420428
return out
421429

@@ -521,7 +529,7 @@ def __init__(self, func, role='func', doc=None, config={}):
521529
else:
522530
argspec = inspect.getargspec(func)
523531
signature = inspect.formatargspec(*argspec)
524-
signature = '%s%s' % (func_name, signature.replace('*', '\*'))
532+
signature = '%s%s' % (func_name, signature.replace('*', r'\*'))
525533
except TypeError:
526534
signature = '%s()' % func_name
527535
self['Signature'] = signature
@@ -538,7 +546,7 @@ def __str__(self):
538546
out = ''
539547

540548
func, func_name = self.get_func()
541-
signature = self['Signature'].replace('*', '\*')
549+
signature = self['Signature'].replace('*', r'\*')
542550

543551
roles = {'func': 'function',
544552
'meth': 'method'}
@@ -591,7 +599,8 @@ def splitlines_x(s):
591599
for name in sorted(items):
592600
try:
593601
doc_item = pydoc.getdoc(getattr(self._cls, name))
594-
doc_list.append((name, '', splitlines_x(doc_item)))
602+
doc_list.append(
603+
Parameter(name, '', splitlines_x(doc_item)))
595604
except AttributeError:
596605
pass # method doesn't exist
597606
self[field] = doc_list
@@ -603,7 +612,7 @@ def methods(self):
603612
return [name for name, func in inspect.getmembers(self._cls)
604613
if ((not name.startswith('_')
605614
or name in self.extra_public_methods)
606-
and isinstance(func, collections.Callable)
615+
and isinstance(func, Callable)
607616
and self._is_show_member(name))]
608617

609618
@property

0 commit comments

Comments
 (0)