Skip to content

Add class and line number to warning about unknown section #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions numpydoc/docscrape.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def __getitem__(self, key):

def __setitem__(self, key, val):
if key not in self._parsed_data:
warn("Unknown section %s" % key)
self._error_location("Unknown section %s" % key, error=False)
else:
self._parsed_data[key] = val

Expand Down Expand Up @@ -331,19 +331,8 @@ def _parse(self):
section = (s.capitalize() for s in section.split(' '))
section = ' '.join(section)
if self.get(section):
if hasattr(self, '_obj'):
# we know where the docs came from:
try:
filename = inspect.getsourcefile(self._obj)
except TypeError:
filename = None
msg = ("The section %s appears twice in "
"the docstring of %s in %s." %
(section, self._obj, filename))
raise ValueError(msg)
else:
msg = ("The section %s appears twice" % section)
raise ValueError(msg)
self._error_location("The section %s appears twice"
% section)

if section in ('Parameters', 'Returns', 'Yields', 'Raises',
'Warns', 'Other Parameters', 'Attributes',
Expand All @@ -356,6 +345,20 @@ def _parse(self):
else:
self[section] = content

def _error_location(self, msg, error=True):
if hasattr(self, '_obj'):
# we know where the docs came from:
try:
filename = inspect.getsourcefile(self._obj)
except TypeError:
filename = None
msg = msg + (" in the docstring of %s in %s."
% (self._obj, filename))
if error:
raise ValueError(msg)
else:
warn(msg)

# string conversion routines

def _str_header(self, name, symbol='-'):
Expand Down
65 changes: 62 additions & 3 deletions numpydoc/tests/test_docscrape.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import sys
import textwrap
import warnings

import jinja2

Expand Down Expand Up @@ -151,13 +152,16 @@ def test_signature():
assert doc['Signature'].startswith('numpy.multivariate_normal(')
assert doc['Signature'].endswith('spam=None)')


def test_summary():
assert doc['Summary'][0].startswith('Draw values')
assert doc['Summary'][-1].endswith('covariance.')


def test_extended_summary():
assert doc['Extended Summary'][0].startswith('The multivariate normal')


def test_parameters():
assert_equal(len(doc['Parameters']), 3)
assert_equal([n for n,_,_ in doc['Parameters']], ['mean','cov','shape'])
Expand All @@ -167,13 +171,15 @@ def test_parameters():
assert desc[0].startswith('Covariance matrix')
assert doc['Parameters'][0][-1][-2] == ' (1+2+3)/3'


def test_other_parameters():
assert_equal(len(doc['Other Parameters']), 1)
assert_equal([n for n,_,_ in doc['Other Parameters']], ['spam'])
arg, arg_type, desc = doc['Other Parameters'][0]
assert_equal(arg_type, 'parrot')
assert desc[0].startswith('A parrot off its mortal coil')


def test_returns():
assert_equal(len(doc['Returns']), 2)
arg, arg_type, desc = doc['Returns'][0]
Expand All @@ -188,6 +194,7 @@ 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)
Expand All @@ -200,6 +207,7 @@ def test_yields():
assert desc[0].startswith('The number of')
assert desc[0].endswith(end)


def test_returnyield():
doc_text = """
Test having returns and yields.
Expand Down Expand Up @@ -289,26 +297,31 @@ def test_notes():
assert doc['Notes'][-1].endswith('definite.')
assert_equal(len(doc['Notes']), 17)


def test_references():
assert doc['References'][0].startswith('..')
assert doc['References'][-1].endswith('2001.')


def test_examples():
assert doc['Examples'][0].startswith('>>>')
assert doc['Examples'][-1].endswith('True]')


def test_index():
assert_equal(doc['index']['default'], 'random')
assert_equal(len(doc['index']), 2)
assert_equal(len(doc['index']['refguide']), 2)

def non_blank_line_by_line_compare(a,b):

def non_blank_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()]
assert_list_equal(a, b)


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
Expand Down Expand Up @@ -595,15 +608,18 @@ def test_sphinx_yields_str():
If None, the index is into the flattened array, otherwise along
the specified axis""")


def test_parameters_without_extended_description():
assert_equal(len(doc2['Parameters']), 2)


doc3 = NumpyDocString("""
my_signature(*params, **kwds)

Return this and that.
""")


def test_escape_stars():
signature = str(doc3).split('\n')[0]
assert_equal(signature, 'my_signature(\*params, \*\*kwds)')
Expand All @@ -614,14 +630,17 @@ def my_func(a, b, **kwargs):
fdoc = FunctionDoc(func=my_func)
assert_equal(fdoc['Signature'], 'my_func(a, b, \*\*kwargs)')


doc4 = NumpyDocString(
"""a.conj()

Return an array with all complex-valued elements conjugated.""")


def test_empty_extended_summary():
assert_equal(doc4['Extended Summary'], [])


doc5 = NumpyDocString(
"""
a.something()
Expand All @@ -637,18 +656,21 @@ def test_empty_extended_summary():
If needed
""")


def test_raises():
assert_equal(len(doc5['Raises']), 1)
name,_,desc = doc5['Raises'][0]
assert_equal(name,'LinAlgException')
assert_equal(desc,['If array is singular.'])


def test_warns():
assert_equal(len(doc5['Warns']), 1)
name,_,desc = doc5['Warns'][0]
assert_equal(name,'SomeWarning')
assert_equal(desc,['If needed'])


def test_see_also():
doc6 = NumpyDocString(
"""
Expand Down Expand Up @@ -726,12 +748,45 @@ class Dummy(object):
assert(' some relationship' in s)
assert(':func:`func_d`' in s)


def test_unknown_section():
doc_text = """
Test having an unknown section

Mope
----
This should be ignored and warned about
"""

class BadSection(object):
"""Class with bad section.

Nope
----
This class has a nope section.
"""
pass

with warnings.catch_warnings(record=True) as w:
NumpyDocString(doc_text)
assert len(w) == 1
assert "Unknown section Mope" == str(w[0].message)

with warnings.catch_warnings(record=True) as w:
SphinxClassDoc(BadSection)
assert len(w) == 1
assert_true('test_docscrape.test_unknown_section.<locals>.BadSection'
in str(w[0].message)
or 'test_docscrape.BadSection' in str(w[0].message))


doc7 = NumpyDocString("""

Doc starts on second line.

""")


def test_empty_first_line():
assert doc7['Summary'][0].startswith('Doc starts')

Expand Down Expand Up @@ -762,6 +817,7 @@ def test_unicode():
assert isinstance(doc['Summary'][0], str)
assert doc['Summary'][0] == 'öäöäöäöäöåååå'


def test_plot_examples():
cfg = dict(use_plots=True)

Expand All @@ -785,6 +841,7 @@ def test_plot_examples():
""", config=cfg)
assert str(doc).count('plot::') == 1, str(doc)


def test_class_members():

class Dummy(object):
Expand Down Expand Up @@ -866,6 +923,7 @@ def bar(self, a, b):
else:
assert 'Spammity index' in str(doc), str(doc)


def test_duplicate_signature():
# Duplicate function signatures occur e.g. in ufuncs, when the
# automatic mechanism adds one, and a more detailed comes from the
Expand Down Expand Up @@ -911,6 +969,7 @@ def test_duplicate_signature():
For usage examples, see `ode`.
"""


def test_class_members_doc():
doc = ClassDoc(None, class_doc_txt)
non_blank_line_by_line_compare(str(doc),
Expand Down Expand Up @@ -949,6 +1008,7 @@ def test_class_members_doc():

""")


def test_class_members_doc_sphinx():
class Foo:
@property
Expand Down Expand Up @@ -997,6 +1057,7 @@ def x(self):

""")


def test_templated_sections():
doc = SphinxClassDoc(None, class_doc_txt,
config={'template': jinja2.Template('{{examples}}{{parameters}}')})
Expand All @@ -1020,8 +1081,6 @@ def test_templated_sections():
""")




if __name__ == "__main__":
import nose
nose.run()