diff --git a/doc/install.rst b/doc/install.rst index ea193893..d408189c 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -38,6 +38,10 @@ numpydoc_citation_re : str should be mangled to avoid conflicts due to duplication across the documentation. Defaults to ``[\w-]+``. +numpydoc_use_blockqutoes : bool + Until version 0.8, parameter definitions were shown as blockquotes, rather + than in a definition list. If your styling requires blockquotes, switch + this config option to True. This option will be removed in version 0.10. numpydoc_edit_link : bool .. deprecated:: edit your HTML template instead diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index b1bab1d7..6ca62922 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -13,6 +13,15 @@ import sys +def strip_blank_lines(l): + "Remove leading and trailing blank lines from a list of lines" + while l and not l[0].strip(): + del l[0] + while l and not l[-1].strip(): + del l[-1] + return l + + class Reader(object): """A line-based string reader. @@ -214,6 +223,7 @@ def _parse_param_list(self, content): desc = r.read_to_next_unindented_line() desc = dedent_lines(desc) + desc = strip_blank_lines(desc) params.append((arg_name, arg_type, desc)) @@ -404,7 +414,8 @@ def _str_param_list(self, name): out += ['%s : %s' % (param, param_type)] else: out += [param] - out += self._str_indent(desc) + if desc and ''.join(desc).strip(): + out += self._str_indent(desc) out += [''] return out diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index d2bc923e..ff5be26c 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -31,6 +31,7 @@ def __init__(self, docstring, config={}): def load_config(self, config): self.use_plots = config.get('use_plots', False) + self.use_blockquotes = config.get('use_blockquotes', False) self.class_members_toctree = config.get('class_members_toctree', True) self.template = config.get('template', None) if self.template is None: @@ -66,18 +67,26 @@ def _str_extended_summary(self): return self['Extended Summary'] + [''] def _str_returns(self, name='Returns'): + if self.use_blockquotes: + typed_fmt = '**%s** : %s' + untyped_fmt = '**%s**' + else: + typed_fmt = '%s : %s' + untyped_fmt = '%s' + out = [] if self[name]: out += self._str_field_list(name) out += [''] for param, param_type, desc in self[name]: if param_type: - out += self._str_indent(['**%s** : %s' % (param.strip(), - param_type)]) + out += self._str_indent([typed_fmt % (param.strip(), + param_type)]) else: - out += self._str_indent([param.strip()]) + out += self._str_indent([untyped_fmt % param.strip()]) if desc: - out += [''] + if self.use_blockquotes: + out += [''] out += self._str_indent(desc, 8) out += [''] return out @@ -117,7 +126,7 @@ def _process_param(self, param, desc, fake_autosummary): relies on Sphinx's plugin mechanism. """ param = param.strip() - display_param = '**%s**' % param + display_param = ('**%s**' if self.use_blockquotes else '%s') % param if not fake_autosummary: return display_param, desc @@ -192,7 +201,8 @@ def _str_param_list(self, name, fake_autosummary=False): else: out += self._str_indent([display_param]) if desc: - out += [''] # produces a blockquote, rather than a dt/dd + if self.use_blockquotes: + out += [''] out += self._str_indent(desc, 8) out += [''] @@ -262,7 +272,6 @@ def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) - out += [''] content = textwrap.dedent("\n".join(self[name])).split("\n") out += content out += [''] @@ -281,6 +290,7 @@ def _str_warnings(self): if self['Warnings']: out = ['.. warning::', ''] out += self._str_indent(self['Warnings']) + out += [''] return out def _str_index(self): @@ -297,6 +307,7 @@ def _str_index(self): out += [' single: %s' % (', '.join(references))] else: out += [' %s: %s' % (section, ','.join(references))] + out += [''] return out def _str_references(self): diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index c14fb0e4..7b513f6a 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -71,6 +71,7 @@ def mangle_docstrings(app, what, name, obj, options, lines): return cfg = {'use_plots': app.config.numpydoc_use_plots, + 'use_blockquotes': app.config.numpydoc_use_blockquotes, 'show_class_members': app.config.numpydoc_show_class_members, 'show_inherited_class_members': app.config.numpydoc_show_inherited_class_members, @@ -139,6 +140,7 @@ def setup(app, get_doc_object_=get_doc_object): app.connect('autodoc-process-signature', mangle_signature) app.add_config_value('numpydoc_edit_link', None, False) app.add_config_value('numpydoc_use_plots', None, False) + app.add_config_value('numpydoc_use_blockquotes', None, False) app.add_config_value('numpydoc_show_class_members', True, True) app.add_config_value('numpydoc_show_inherited_class_members', True, True) app.add_config_value('numpydoc_class_members_toctree', True, True) diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 81f914e4..8fa3d23f 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1,6 +1,7 @@ # -*- encoding:utf-8 -*- from __future__ import division, absolute_import, print_function +import re import sys import textwrap import warnings @@ -171,7 +172,7 @@ def test_parameters(): arg, arg_type, desc = doc['Parameters'][1] assert_equal(arg_type, '(N, N) ndarray') assert desc[0].startswith('Covariance matrix') - assert doc['Parameters'][0][-1][-2] == ' (1+2+3)/3' + assert doc['Parameters'][0][-1][-1] == ' (1+2+3)/3' def test_other_parameters(): @@ -316,11 +317,19 @@ def test_index(): assert_equal(len(doc['index']['refguide']), 2) -def non_blank_line_by_line_compare(a, b): +def _strip_blank_lines(s): + "Remove leading, trailing and multiple blank lines" + s = re.sub(r'^\s*\n', '', s) + s = re.sub(r'\n\s*$', '', s) + s = re.sub(r'\n\s*\n', r'\n\n', s) + return s + + +def line_by_line_compare(a, b): a = textwrap.dedent(a) b = textwrap.dedent(b) - a = [l.rstrip() for l in a.split('\n') if l.strip()] - b = [l.rstrip() for l in b.split('\n') if l.strip()] + a = [l.rstrip() for l in _strip_blank_lines(a).split('\n')] + b = [l.rstrip() for l in _strip_blank_lines(b).split('\n')] assert_list_equal(a, b) @@ -328,7 +337,7 @@ def test_str(): # doc_txt has the order of Notes and See Also sections flipped. # This should be handled automatically, and so, one thing this test does # is to make sure that See Also precedes Notes in the output. - non_blank_line_by_line_compare(str(doc), + line_by_line_compare(str(doc), """numpy.multivariate_normal(mean, cov, shape=None, spam=None) Draw values from a multivariate normal distribution with specified @@ -345,7 +354,6 @@ def test_str(): .. math:: (1+2+3)/3 - cov : (N, N) ndarray Covariance matrix of the distribution. shape : tuple of ints @@ -387,6 +395,7 @@ def test_str(): See Also -------- + `some`_, `other`_, `funcs`_ `otherfunc`_ @@ -438,7 +447,7 @@ def test_str(): def test_yield_str(): - non_blank_line_by_line_compare(str(doc_yields), + line_by_line_compare(str(doc_yields), """Test generator Yields @@ -455,7 +464,7 @@ def test_yield_str(): def test_sphinx_str(): sphinx_doc = SphinxDocString(doc_txt) - non_blank_line_by_line_compare(str(sphinx_doc), + line_by_line_compare(str(sphinx_doc), """ .. index:: random single: random;distributions, random;gauss @@ -468,28 +477,24 @@ def test_sphinx_str(): :Parameters: - **mean** : (N,) ndarray - + mean : (N,) ndarray Mean of the N-dimensional distribution. .. math:: (1+2+3)/3 - **cov** : (N, N) ndarray - + cov : (N, N) ndarray Covariance matrix of the distribution. - **shape** : tuple of ints - + shape : tuple of ints Given a shape of, for example, (m,n,k), m*n*k samples are generated, and packed in an m-by-n-by-k arrangement. Because each sample is N-dimensional, the output shape is (m,n,k,N). :Returns: - **out** : ndarray - + out : ndarray The drawn samples, arranged according to `shape`. If the shape given is (m,n,...), then the shape of `out` is is (m,n,...,N). @@ -498,26 +503,22 @@ def test_sphinx_str(): value drawn from the distribution. list of str - This is not a real return value. It exists to test anonymous return values. :Other Parameters: - **spam** : parrot - + spam : parrot A parrot off its mortal coil. :Raises: - **RuntimeError** - + RuntimeError Some error :Warns: - **RuntimeWarning** - + RuntimeWarning Some warning .. warning:: @@ -580,21 +581,18 @@ def test_sphinx_str(): def test_sphinx_yields_str(): sphinx_doc = SphinxDocString(doc_yields_txt) - non_blank_line_by_line_compare(str(sphinx_doc), + line_by_line_compare(str(sphinx_doc), """Test generator :Yields: - **a** : int - + a : int The number of apples. - **b** : int - + b : int The number of bananas. int - The number of unknowns. """) @@ -855,6 +853,46 @@ def test_plot_examples(): assert str(doc).count('plot::') == 1, str(doc) +def test_use_blockquotes(): + cfg = dict(use_blockquotes=True) + doc = SphinxDocString(""" + Parameters + ---------- + abc : def + ghi + jkl + mno + + Returns + ------- + ABC : DEF + GHI + JKL + MNO + """, config=cfg) + line_by_line_compare(str(doc), ''' + :Parameters: + + **abc** : def + + ghi + + **jkl** + + mno + + :Returns: + + **ABC** : DEF + + GHI + + **JKL** + + MNO + ''') + + def test_class_members(): class Dummy(object): @@ -960,6 +998,7 @@ def test_duplicate_signature(): f : callable ``f(t, y, *f_args)`` Aaa. jac : callable ``jac(t, y, *jac_args)`` + Bbb. Attributes @@ -994,7 +1033,7 @@ def test_duplicate_signature(): def test_class_members_doc(): doc = ClassDoc(None, class_doc_txt) - non_blank_line_by_line_compare(str(doc), + line_by_line_compare(str(doc), """ Foo @@ -1030,9 +1069,7 @@ def test_class_members_doc(): Methods ------- a - b - c .. index:: @@ -1076,18 +1113,16 @@ def no_period(self): return None doc = SphinxClassDoc(Foo, class_doc_txt) - non_blank_line_by_line_compare(str(doc), + line_by_line_compare(str(doc), """ Foo :Parameters: - **f** : callable ``f(t, y, *f_args)`` - + f : callable ``f(t, y, *f_args)`` Aaa. - **jac** : callable ``jac(t, y, *jac_args)`` - + jac : callable ``jac(t, y, *jac_args)`` Bbb. .. rubric:: Examples @@ -1096,22 +1131,29 @@ def no_period(self): :Attributes: - **t** : float + t : float Current time. - **y** : ndarray + + y : ndarray Current variable values. * hello * world + :obj:`an_attribute ` : float Test attribute - **no_docstring** : str + + no_docstring : str But a description - **no_docstring2** : str + + no_docstring2 : str + :obj:`multiline_sentence ` This is a sentence. + :obj:`midword_period ` The sentence for numpy.org. + :obj:`no_period ` This does not have a period @@ -1128,22 +1170,19 @@ def no_period(self): def test_templated_sections(): doc = SphinxClassDoc(None, class_doc_txt, - config={'template': jinja2.Template('{{examples}}{{parameters}}')}) - non_blank_line_by_line_compare(str(doc), + config={'template': jinja2.Template('{{examples}}\n{{parameters}}')}) + line_by_line_compare(str(doc), """ .. rubric:: Examples For usage examples, see `ode`. - :Parameters: - **f** : callable ``f(t, y, *f_args)`` - + f : callable ``f(t, y, *f_args)`` Aaa. - **jac** : callable ``jac(t, y, *jac_args)`` - + jac : callable ``jac(t, y, *jac_args)`` Bbb. """)