Skip to content

Commit de494ff

Browse files
authored
Merge pull request #77 from jnothman/templated-order
ENH: render numpydoc strings from a template
2 parents 4c7909c + 6c2e67f commit de494ff

File tree

5 files changed

+93
-28
lines changed

5 files changed

+93
-28
lines changed

numpydoc/docscrape_sphinx.py

+46-21
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
import inspect
66
import textwrap
77
import pydoc
8-
import sphinx
98
import collections
9+
import os
10+
11+
from jinja2 import FileSystemLoader
12+
from jinja2.sandbox import SandboxedEnvironment
13+
import sphinx
14+
from sphinx.jinja2glue import BuiltinTemplateLoader
1015

1116
from .docscrape import NumpyDocString, FunctionDoc, ClassDoc
1217

@@ -24,6 +29,12 @@ def __init__(self, docstring, config={}):
2429
def load_config(self, config):
2530
self.use_plots = config.get('use_plots', False)
2631
self.class_members_toctree = config.get('class_members_toctree', True)
32+
self.template = config.get('template', None)
33+
if self.template is None:
34+
template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')]
35+
template_loader = FileSystemLoader(template_dirs)
36+
template_env = SandboxedEnvironment(loader=template_loader)
37+
self.template = template_env.get_template('numpydoc_docstring.rst')
2738

2839
# string conversion routines
2940
def _str_header(self, name, symbol='`'):
@@ -223,25 +234,29 @@ def _str_examples(self):
223234
return self._str_section('Examples')
224235

225236
def __str__(self, indent=0, func_role="obj"):
226-
out = []
227-
out += self._str_signature()
228-
out += self._str_index() + ['']
229-
out += self._str_summary()
230-
out += self._str_extended_summary()
231-
out += self._str_param_list('Parameters')
232-
out += self._str_returns('Returns')
233-
out += self._str_returns('Yields')
234-
for param_list in ('Other Parameters', 'Raises', 'Warns'):
235-
out += self._str_param_list(param_list)
236-
out += self._str_warnings()
237-
out += self._str_see_also(func_role)
238-
out += self._str_section('Notes')
239-
out += self._str_references()
240-
out += self._str_examples()
241-
for param_list in ('Attributes', 'Methods'):
242-
out += self._str_member_list(param_list)
243-
out = self._str_indent(out, indent)
244-
return '\n'.join(out)
237+
ns = {
238+
'signature': self._str_signature(),
239+
'index': self._str_index(),
240+
'summary': self._str_summary(),
241+
'extended_summary': self._str_extended_summary(),
242+
'parameters': self._str_param_list('Parameters'),
243+
'returns': self._str_returns('Returns'),
244+
'yields': self._str_returns('Yields'),
245+
'other_parameters': self._str_param_list('Other Parameters'),
246+
'raises': self._str_param_list('Raises'),
247+
'warns': self._str_param_list('Warns'),
248+
'warnings': self._str_warnings(),
249+
'see_also': self._str_see_also(func_role),
250+
'notes': self._str_section('Notes'),
251+
'references': self._str_references(),
252+
'examples': self._str_examples(),
253+
'attributes': self._str_member_list('Attributes'),
254+
'methods': self._str_member_list('Methods'),
255+
}
256+
ns = dict((k, '\n'.join(v)) for k, v in ns.items())
257+
258+
rendered = self.template.render(**ns)
259+
return '\n'.join(self._str_indent(rendered.split('\n'), indent))
245260

246261

247262
class SphinxFunctionDoc(SphinxDocString, FunctionDoc):
@@ -263,7 +278,7 @@ def __init__(self, obj, doc=None, config={}):
263278
SphinxDocString.__init__(self, doc, config=config)
264279

265280

266-
def get_doc_object(obj, what=None, doc=None, config={}):
281+
def get_doc_object(obj, what=None, doc=None, config={}, builder=None):
267282
if what is None:
268283
if inspect.isclass(obj):
269284
what = 'class'
@@ -273,6 +288,16 @@ def get_doc_object(obj, what=None, doc=None, config={}):
273288
what = 'function'
274289
else:
275290
what = 'object'
291+
292+
template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')]
293+
if builder is not None:
294+
template_loader = BuiltinTemplateLoader()
295+
template_loader.init(builder, dirs=template_dirs)
296+
else:
297+
template_loader = FileSystemLoader(template_dirs)
298+
template_env = SandboxedEnvironment(loader=template_loader)
299+
config['template'] = template_env.get_template('numpydoc_docstring.rst')
300+
276301
if what == 'class':
277302
return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc,
278303
config=config)

numpydoc/numpydoc.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ def mangle_docstrings(app, what, name, obj, options, lines):
7777
title_re = re.compile(sixu(pattern), re.I | re.S)
7878
lines[:] = title_re.sub(sixu(''), u_NL.join(lines)).split(u_NL)
7979
else:
80-
doc = get_doc_object(obj, what, u_NL.join(lines), config=cfg)
80+
doc = get_doc_object(obj, what, u_NL.join(lines), config=cfg,
81+
builder=app.builder)
8182
if sys.version_info[0] >= 3:
8283
doc = str(doc)
8384
else:
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{index}}
2+
{{summary}}
3+
{{extended_summary}}
4+
{{parameters}}
5+
{{returns}}
6+
{{yields}}
7+
{{other_parameters}}
8+
{{raises}}
9+
{{warns}}
10+
{{warnings}}
11+
{{see_also}}
12+
{{notes}}
13+
{{references}}
14+
{{examples}}
15+
{{attributes}}
16+
{{methods}}

numpydoc/tests/test_docscrape.py

+28-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from __future__ import division, absolute_import, print_function
33

44
import sys, textwrap
5+
import io
6+
7+
import jinja2
58

69
from numpydoc.docscrape import NumpyDocString, FunctionDoc, ClassDoc
710
from numpydoc.docscrape_sphinx import SphinxDocString, SphinxClassDoc
@@ -248,11 +251,8 @@ def non_blank_line_by_line_compare(a,b):
248251
b = textwrap.dedent(b)
249252
a = [l.rstrip() for l in a.split('\n') if l.strip()]
250253
b = [l.rstrip() for l in b.split('\n') if l.strip()]
251-
for n,line in enumerate(a):
252-
if not line == b[n]:
253-
raise AssertionError("Lines %s of a and b differ: "
254-
"\n>>> %s\n<<< %s\n" %
255-
(n,line,b[n]))
254+
assert_list_equal(a, b)
255+
256256
def test_str():
257257
# doc_txt has the order of Notes and See Also sections flipped.
258258
# This should be handled automatically, and so, one thing this test does
@@ -924,6 +924,29 @@ def x(self):
924924
925925
""")
926926

927+
def test_templated_sections():
928+
doc = SphinxClassDoc(None, class_doc_txt,
929+
config={'template': jinja2.Template('{{examples}}{{parameters}}')})
930+
non_blank_line_by_line_compare(str(doc),
931+
"""
932+
.. rubric:: Examples
933+
934+
For usage examples, see `ode`.
935+
936+
937+
:Parameters:
938+
939+
**f** : callable ``f(t, y, *f_args)``
940+
941+
Aaa.
942+
943+
**jac** : callable ``jac(t, y, *jac_args)``
944+
945+
Bbb.
946+
947+
""")
948+
949+
927950
if __name__ == "__main__":
928951
import nose
929952
nose.run()

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
author_email="[email protected]",
3838
url="https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt",
3939
license="BSD",
40-
install_requires=["sphinx >= 1.0.1"],
40+
install_requires=["sphinx >= 1.0.1", 'Jinja2>=2.3'],
4141
package_data={'numpydoc': ['tests/test_*.py']},
4242
test_suite = 'nose.collector',
4343
cmdclass={"sdist": sdist},

0 commit comments

Comments
 (0)