Skip to content

Commit 6f911f6

Browse files
authored
Command-line tool to help debug NumpyDocString (#146)
2 parents 136d4dd + faafc79 commit 6f911f6

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed

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/tests/test_main.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from __future__ import print_function
2+
3+
from contextlib import contextmanager
4+
import os
5+
import sys
6+
import tempfile
7+
try:
8+
from StringIO import StringIO
9+
except ImportError:
10+
from io import StringIO
11+
12+
from numpydoc.__main__ import main
13+
14+
15+
PACKAGE_CODE = """
16+
'''This package has test stuff'''
17+
"""
18+
19+
MODULE_CODE = """
20+
'''This module has test stuff'''
21+
22+
def foo(a, b=5):
23+
'''Hello world
24+
25+
Parameters
26+
----------
27+
something : foo
28+
bar
29+
something_else
30+
bar
31+
'''
32+
"""
33+
34+
35+
@contextmanager
36+
def _mock_module(pkg_name):
37+
try:
38+
tempdir = tempfile.mkdtemp()
39+
os.mkdir(os.path.join(tempdir, pkg_name))
40+
with open(os.path.join(tempdir, pkg_name, '__init__.py'), 'w') as f:
41+
print(PACKAGE_CODE, file=f)
42+
with open(os.path.join(tempdir, pkg_name, 'module.py'), 'w') as f:
43+
print(MODULE_CODE, file=f)
44+
45+
sys.path.insert(0, tempdir)
46+
yield tempdir
47+
finally:
48+
try:
49+
os.path.rmdir(tempdir)
50+
sys.path.remove(tempdir)
51+
except:
52+
pass
53+
54+
55+
def _capture_main(*args):
56+
f = StringIO()
57+
sys.stdout, old_stdout = f, sys.stdout
58+
try:
59+
main(args)
60+
return f.getvalue().strip('\n\r')
61+
finally:
62+
sys.stdout = old_stdout
63+
64+
65+
def test_main():
66+
# TODO: does not currently check that numpydoc transformations are applied
67+
68+
assert (_capture_main('numpydoc.__main__.main') ==
69+
main.__doc__.strip())
70+
71+
# check it works with modules not imported from __init__
72+
with _mock_module('somepackage1'):
73+
out = _capture_main('somepackage1.module.foo')
74+
assert out.startswith('Hello world\n')
75+
with _mock_module('somepackage2'):
76+
out = _capture_main('somepackage2.module')
77+
assert out.startswith('This module has test')
78+
with _mock_module('somepackage3'):
79+
out = _capture_main('somepackage3')
80+
assert out.startswith('This package has test')

0 commit comments

Comments
 (0)