From 9af63b575c3b82205ecc63bc6118a69a4c1e9f24 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Thu, 18 May 2017 16:03:04 -0400 Subject: [PATCH 1/4] add context to signature mangling errors --- numpydoc/numpydoc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index eab47569..74052eda 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -113,8 +113,11 @@ def mangle_signature(app, what, name, obj, options, sig, retann): if not hasattr(obj, '__doc__'): return - - doc = SphinxDocString(pydoc.getdoc(obj)) + try: + doc = SphinxDocString(pydoc.getdoc(obj)) + except ValueError as e: + filename = obj.__code__.co_filename + raise ValueError(str(e) + " in {}:{}".format(filename, name)) sig = doc['Signature'] or getattr(obj, '__text_signature__', None) if sig: sig = re.sub(sixu("^[^(]*"), sixu(""), sig) From 4b19002113e4ad8b6dd1b9df6fe169903a97f36a Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Sun, 18 Jun 2017 14:54:58 -0400 Subject: [PATCH 2/4] make getting filename python2 compatible --- numpydoc/numpydoc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 74052eda..38396388 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -116,7 +116,10 @@ def mangle_signature(app, what, name, obj, options, sig, retann): try: doc = SphinxDocString(pydoc.getdoc(obj)) except ValueError as e: - filename = obj.__code__.co_filename + try: + filename = inspect.getsourcefile(obj) + except TypeError: + filename = None raise ValueError(str(e) + " in {}:{}".format(filename, name)) sig = doc['Signature'] or getattr(obj, '__text_signature__', None) if sig: From 46036b0a4e458f79ee6b8980b9d0e15fe204b143 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Sun, 18 Jun 2017 15:27:14 -0400 Subject: [PATCH 3/4] less hacky solution to duplicate section error message, added tests --- numpydoc/docscrape.py | 16 +++++++-- numpydoc/numpydoc.py | 9 +---- numpydoc/tests/test_docscrape.py | 57 +++++++++++++++++++++++++++++--- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 8acc54cf..074a7f73 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -331,9 +331,19 @@ def _parse(self): section = (s.capitalize() for s in section.split(' ')) section = ' '.join(section) if self.get(section): - msg = ("The section %s appears twice in the docstring." % - section) - raise ValueError(msg) + 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) if section in ('Parameters', 'Returns', 'Yields', 'Raises', 'Warns', 'Other Parameters', 'Attributes', diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 38396388..7deecc55 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -113,14 +113,7 @@ def mangle_signature(app, what, name, obj, options, sig, retann): if not hasattr(obj, '__doc__'): return - try: - doc = SphinxDocString(pydoc.getdoc(obj)) - except ValueError as e: - try: - filename = inspect.getsourcefile(obj) - except TypeError: - filename = None - raise ValueError(str(e) + " in {}:{}".format(filename, name)) + doc = SphinxDocString(pydoc.getdoc(obj)) sig = doc['Signature'] or getattr(obj, '__text_signature__', None) if sig: sig = re.sub(sixu("^[^(]*"), sixu(""), sig) diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 8fae0dfb..4d662a50 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1,8 +1,8 @@ # -*- encoding:utf-8 -*- from __future__ import division, absolute_import, print_function -import sys, textwrap -import io +import sys +import textwrap import jinja2 @@ -12,8 +12,10 @@ ClassDoc, ParseError ) -from numpydoc.docscrape_sphinx import SphinxDocString, SphinxClassDoc -from nose.tools import * +from numpydoc.docscrape_sphinx import (SphinxDocString, SphinxClassDoc, + SphinxFunctionDoc) +from nose.tools import (assert_equal, assert_raises, assert_list_equal, + assert_true) if sys.version_info[0] >= 3: sixu = lambda s: s @@ -232,6 +234,51 @@ def test_section_twice(): """ assert_raises(ValueError, NumpyDocString, doc_text) + # if we have a numpydoc object, we know where the error came from + class Dummy(object): + """ + Dummy class. + + Notes + ----- + First note. + + Notes + ----- + Second note. + + """ + def spam(self, a, b): + """Spam\n\nSpam spam.""" + pass + + def ham(self, c, d): + """Cheese\n\nNo cheese.""" + pass + + def dummy_func(arg): + """ + Dummy function. + + Notes + ----- + First note. + + Notes + ----- + Second note. + """ + + try: + SphinxClassDoc(Dummy) + except ValueError as e: + assert_true("test_section_twice..Dummy" in str(e)) + + try: + SphinxFunctionDoc(dummy_func) + except ValueError as e: + assert_true("test_section_twice..dummy_func" in str(e)) + def test_notes(): assert doc['Notes'][0].startswith('Instead') @@ -969,6 +1016,8 @@ def test_templated_sections(): """) + + if __name__ == "__main__": import nose nose.run() From 52f247c498b83f4146d3534b15af44e8f8c9be50 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Sun, 18 Jun 2017 16:28:39 -0400 Subject: [PATCH 4/4] make tests run under python2.7 --- numpydoc/tests/test_docscrape.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 4d662a50..297a0acb 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -272,12 +272,16 @@ def dummy_func(arg): try: SphinxClassDoc(Dummy) except ValueError as e: - assert_true("test_section_twice..Dummy" in str(e)) + # python 3 version or python 2 version + assert_true("test_section_twice..Dummy" in str(e) + or 'test_docscrape.Dummy' in str(e)) try: SphinxFunctionDoc(dummy_func) except ValueError as e: - assert_true("test_section_twice..dummy_func" in str(e)) + # python 3 version or python 2 version + assert_true("test_section_twice..dummy_func" in str(e) + or 'function dummy_func' in str(e)) def test_notes():