Skip to content

Commit

Permalink
Command-line tool to help debug NumpyDocString (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
jnothman committed Jun 6, 2018
2 parents 136d4dd + faafc79 commit 6f911f6
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ Documentation
install
format
example
validation
12 changes: 12 additions & 0 deletions doc/validation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
==============================
Validating NumpyDoc docstrings
==============================

One tool for validating docstrings is to see how an object's dosctring
translates to Restructured Text. Using numpydoc as a command-line tool
facilitates this. For example to see the Restructured Text generated
for ``numpy.ndarray``, use:

.. code-block:: bash
$ python -m numpydoc numpy.ndarray
44 changes: 44 additions & 0 deletions numpydoc/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import argparse
import importlib
import ast

from .docscrape_sphinx import get_doc_object


def main(argv=None):
"""Test numpydoc docstring generation for a given object"""

ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument('import_path', help='e.g. numpy.ndarray')

def _parse_config(s):
key, _, value = s.partition('=')
value = ast.literal_eval(value)
return key, value

ap.add_argument('-c', '--config', type=_parse_config,
action='append',
help='key=val where val will be parsed by literal_eval, '
'e.g. -c use_plots=True. Multiple -c can be used.')
args = ap.parse_args(argv)

parts = args.import_path.split('.')

for split_point in range(len(parts), 0, -1):
try:
path = '.'.join(parts[:split_point])
obj = importlib.import_module(path)
except ImportError:
continue
break
else:
raise ImportError('Could not resolve {!r} to an importable object'
''.format(args.import_path))

for part in parts[split_point:]:
obj = getattr(obj, part)

print(get_doc_object(obj, config=dict(args.config or [])))

if __name__ == '__main__':
main()
80 changes: 80 additions & 0 deletions numpydoc/tests/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from __future__ import print_function

from contextlib import contextmanager
import os
import sys
import tempfile
try:
from StringIO import StringIO
except ImportError:
from io import StringIO

from numpydoc.__main__ import main


PACKAGE_CODE = """
'''This package has test stuff'''
"""

MODULE_CODE = """
'''This module has test stuff'''
def foo(a, b=5):
'''Hello world
Parameters
----------
something : foo
bar
something_else
bar
'''
"""


@contextmanager
def _mock_module(pkg_name):
try:
tempdir = tempfile.mkdtemp()
os.mkdir(os.path.join(tempdir, pkg_name))
with open(os.path.join(tempdir, pkg_name, '__init__.py'), 'w') as f:
print(PACKAGE_CODE, file=f)
with open(os.path.join(tempdir, pkg_name, 'module.py'), 'w') as f:
print(MODULE_CODE, file=f)

sys.path.insert(0, tempdir)
yield tempdir
finally:
try:
os.path.rmdir(tempdir)
sys.path.remove(tempdir)
except:
pass


def _capture_main(*args):
f = StringIO()
sys.stdout, old_stdout = f, sys.stdout
try:
main(args)
return f.getvalue().strip('\n\r')
finally:
sys.stdout = old_stdout


def test_main():
# TODO: does not currently check that numpydoc transformations are applied

assert (_capture_main('numpydoc.__main__.main') ==
main.__doc__.strip())

# check it works with modules not imported from __init__
with _mock_module('somepackage1'):
out = _capture_main('somepackage1.module.foo')
assert out.startswith('Hello world\n')
with _mock_module('somepackage2'):
out = _capture_main('somepackage2.module')
assert out.startswith('This module has test')
with _mock_module('somepackage3'):
out = _capture_main('somepackage3')
assert out.startswith('This package has test')

0 comments on commit 6f911f6

Please sign in to comment.