diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 1eb7c59975ace..672ada6c80b55 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -97,6 +97,7 @@ def __init__(self, docstring, config={}): 'Extended Summary': [], 'Parameters': [], 'Returns': [], + 'Yields': [], 'Raises': [], 'Warns': [], 'Other Parameters': [], @@ -288,11 +289,22 @@ def _parse(self): self._doc.reset() self._parse_summary() - for (section,content) in self._read_sections(): + sections = list(self._read_sections()) + section_names = set([section for section, content in sections]) + + has_returns = 'Returns' in section_names + has_yields = 'Yields' in section_names + # We could do more tests, but we are not. Arbitrarily. + if has_returns and has_yields: + msg = 'Docstring contains both a Returns and Yields section.' + raise ValueError(msg) + + for (section, content) in sections: if not section.startswith('..'): section = ' '.join([s.capitalize() for s in section.split(' ')]) - if section in ('Parameters', 'Returns', 'Raises', 'Warns', - 'Other Parameters', 'Attributes', 'Methods'): + if section in ('Parameters', 'Returns', 'Yields', 'Raises', + 'Warns', 'Other Parameters', 'Attributes', + 'Methods'): self[section] = self._parse_param_list(content) elif section.startswith('.. index::'): self['index'] = self._parse_index(section, content) @@ -391,8 +403,8 @@ def __str__(self, func_role=''): out += self._str_signature() out += self._str_summary() out += self._str_extended_summary() - for param_list in ('Parameters', 'Returns', 'Other Parameters', - 'Raises', 'Warns'): + for param_list in ('Parameters', 'Returns', 'Yields', + 'Other Parameters', 'Raises', 'Warns'): out += self._str_param_list(param_list) out += self._str_section('Warnings') out += self._str_see_also(func_role) diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index cdc2a37d17174..0464f11fdcec3 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -46,12 +46,12 @@ def _str_summary(self): def _str_extended_summary(self): return self['Extended Summary'] + [''] - def _str_returns(self): + def _str_returns(self, name='Returns'): out = [] - if self['Returns']: - out += self._str_field_list('Returns') + if self[name]: + out += self._str_field_list(name) out += [''] - for param, param_type, desc in self['Returns']: + for param, param_type, desc in self[name]: if param_type: out += self._str_indent(['**%s** : %s' % (param.strip(), param_type)]) @@ -224,7 +224,8 @@ def __str__(self, indent=0, func_role="obj"): out += self._str_summary() out += self._str_extended_summary() out += self._str_param_list('Parameters') - out += self._str_returns() + out += self._str_returns('Returns') + out += self._str_returns('Yields') for param_list in ('Other Parameters', 'Raises', 'Warns'): out += self._str_param_list(param_list) out += self._str_warnings() diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index f56478787ed87..807a5a349cf68 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -122,6 +122,20 @@ ''' doc = NumpyDocString(doc_txt) +doc_yields_txt = """ +Test generator + +Yields +------ +a : int + The number of apples. +b : int + The number of bananas. +int + The number of unknowns. +""" +doc_yields = NumpyDocString(doc_yields_txt) + def test_signature(): assert doc['Signature'].startswith('numpy.multivariate_normal(') @@ -164,6 +178,37 @@ def test_returns(): assert desc[0].startswith('This is not a real') assert desc[-1].endswith('anonymous return values.') +def test_yields(): + section = doc_yields['Yields'] + assert_equal(len(section), 3) + truth = [('a', 'int', 'apples.'), + ('b', 'int', 'bananas.'), + ('int', '', 'unknowns.')] + for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(section, truth): + assert_equal(arg, arg_) + assert_equal(arg_type, arg_type_) + assert desc[0].startswith('The number of') + assert desc[0].endswith(end) + +def test_returnyield(): + doc_text = """ +Test having returns and yields. + +Returns +------- +int + The number of apples. + +Yields +------ +a : int + The number of apples. +b : int + The number of bananas. + +""" + assert_raises(ValueError, NumpyDocString, doc_text) + def test_notes(): assert doc['Notes'][0].startswith('Instead') assert doc['Notes'][-1].endswith('definite.') @@ -193,6 +238,9 @@ def non_blank_line_by_line_compare(a,b): "\n>>> %s\n<<< %s\n" % (n,line,b[n])) 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), """numpy.multivariate_normal(mean, cov, shape=None, spam=None) @@ -302,6 +350,22 @@ def test_str(): :refguide: random;distributions, random;gauss""") +def test_yield_str(): + non_blank_line_by_line_compare(str(doc_yields), +"""Test generator + +Yields +------ +a : int + The number of apples. +b : int + The number of bananas. +int + The number of unknowns. + +.. index:: """) + + def test_sphinx_str(): sphinx_doc = SphinxDocString(doc_txt) non_blank_line_by_line_compare(str(sphinx_doc), @@ -427,6 +491,27 @@ def test_sphinx_str(): """) +def test_sphinx_yields_str(): + sphinx_doc = SphinxDocString(doc_yields_txt) + non_blank_line_by_line_compare(str(sphinx_doc), +"""Test generator + +:Yields: + + **a** : int + + The number of apples. + + **b** : int + + The number of bananas. + + int + + The number of unknowns. +""") + + doc2 = NumpyDocString(""" Returns array of indices of the maximum values of along the given axis. diff --git a/numpydoc/traitsdoc.py b/numpydoc/traitsdoc.py index 596c54eb389a3..2468565a6ca1e 100644 --- a/numpydoc/traitsdoc.py +++ b/numpydoc/traitsdoc.py @@ -61,6 +61,7 @@ def __init__(self, cls, modulename='', func_doc=SphinxFunctionDoc): 'Extended Summary': [], 'Parameters': [], 'Returns': [], + 'Yields': [], 'Raises': [], 'Warns': [], 'Other Parameters': [], @@ -89,7 +90,7 @@ def __str__(self, indent=0, func_role="func"): out += self._str_summary() out += self._str_extended_summary() for param_list in ('Parameters', 'Traits', 'Methods', - 'Returns','Raises'): + 'Returns', 'Yields', 'Raises'): out += self._str_param_list(param_list) out += self._str_see_also("obj") out += self._str_section('Notes')