diff options
-rw-r--r-- | doc/whatsnew/1.8.rst | 24 | ||||
-rw-r--r-- | pylint/extensions/_check_docs_utils.py | 17 | ||||
-rw-r--r-- | pylint/test/extensions/test_check_docs.py | 332 |
3 files changed, 366 insertions, 7 deletions
diff --git a/doc/whatsnew/1.8.rst b/doc/whatsnew/1.8.rst index 5322dd8d4..a652e8cfe 100644 --- a/doc/whatsnew/1.8.rst +++ b/doc/whatsnew/1.8.rst @@ -60,3 +60,27 @@ Summary -- Release highlights def __next__(self): return 42 next = __next__ + +* The docparams extension now allows a property docstring to document both + the property and the setter. Therefore setters can also have no docstring. + +* The docparams extension now understands property type syntax. + + .. code-block:: python + + class Foo(object): + @property + def foo(self): + """My Sphinx style docstring description. + + :type: int + """ + return 10 + + .. code-block:: python + + class Foo(object): + @property + def foo(self): + """int: My Numpy and Google docstring style description.""" + return 10 diff --git a/pylint/extensions/_check_docs_utils.py b/pylint/extensions/_check_docs_utils.py index dccf2b748..14831eb07 100644 --- a/pylint/extensions/_check_docs_utils.py +++ b/pylint/extensions/_check_docs_utils.py @@ -295,7 +295,8 @@ class SphinxDocstring(Docstring): return bool(self.re_param_in_docstring.search(self.doc) or self.re_raise_in_docstring.search(self.doc) or self.re_rtype_in_docstring.search(self.doc) or - self.re_returns_in_docstring.search(self.doc)) + self.re_returns_in_docstring.search(self.doc) or + self.re_property_type_in_docstring.search(self.doc)) def exceptions(self): types = set() @@ -318,7 +319,7 @@ class SphinxDocstring(Docstring): # If this is a property docstring, the summary is the return doc. if self.re_property_type_in_docstring.search(self.doc): - first_line = self.doc.lsplit().split('\n', 1)[0] + first_line = self.doc.lstrip().split('\n', 1)[0] # The summary line is the first line without a directive. return not first_line.startswith(':') @@ -456,7 +457,8 @@ class GoogleDocstring(Docstring): return bool(self.re_param_section.search(self.doc) or self.re_raise_section.search(self.doc) or self.re_returns_section.search(self.doc) or - self.re_yields_section.search(self.doc)) + self.re_yields_section.search(self.doc) or + self.re_property_returns_line.search(self._first_line())) def has_params(self): if not self.doc: @@ -478,8 +480,7 @@ class GoogleDocstring(Docstring): if return_desc: return True - first_line = self.doc.lstrip().split('\n', 1)[0] - return bool(self.re_property_returns_line.match(first_line)) + return bool(self.re_property_returns_line.match(self._first_line())) def has_rtype(self): if not self.doc: @@ -495,8 +496,7 @@ class GoogleDocstring(Docstring): if return_type: return True - first_line = self.doc.lstrip().split('\n', 1)[0] - return bool(self.re_property_returns_line.match(first_line)) + return bool(self.re_property_returns_line.match(self._first_line())) def has_yields(self): if not self.doc: @@ -567,6 +567,9 @@ class GoogleDocstring(Docstring): return params_with_doc, params_with_type + def _first_line(self): + return self.doc.lstrip().split('\n', 1)[0] + @staticmethod def min_section_indent(section_match): return len(section_match.group(1)) + 1 diff --git a/pylint/test/extensions/test_check_docs.py b/pylint/test/extensions/test_check_docs.py index 78c3f71f9..7c505e11d 100644 --- a/pylint/test/extensions/test_check_docs.py +++ b/pylint/test/extensions/test_check_docs.py @@ -1352,3 +1352,335 @@ class TestParamDocChecker(CheckerTestCase): ''') with self.assertNoMessages(): self.checker.visit_functiondef(node) + + def test_finds_missing_raises_from_setter_sphinx(self): + """Example of a setter having missing raises documentation in + the Sphinx style docstring of the property + """ + property_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''docstring ... + + :type: int + ''' + return 10 + + @foo.setter + def foo(self, value): + raise AttributeError() #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-raises-doc', + node=property_node, + args=('AttributeError',)), + ): + self.checker.visit_raise(node) + + def test_finds_missing_raises_from_setter_google(self): + """Example of a setter having missing raises documentation in + the Google style docstring of the property + """ + property_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''int: docstring + + Include a "Raises" section so that this is identified + as a Google docstring and not a Numpy docstring. + + Raises: + RuntimeError: Always + ''' + raise RuntimeError() + return 10 + + @foo.setter + def foo(self, value): + raises AttributeError() #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-raises-doc', + node=property_node, + args=('AttributeError',)), + ): + self.checker.visit_raise(node) + + def test_finds_missing_raises_from_setter_numpy(self): + """Example of a setter having missing raises documentation in + the Numpy style docstring of the property + """ + property_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''int: docstring + + Include a "Raises" section so that this is identified + as a Numpy docstring and not a Google docstring. + + Raises + ------ + RuntimeError + Always + ''' + raise RuntimeError() + return 10 + + @foo.setter + def foo(self, value): + raises AttributeError() #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-raises-doc', + node=property_node, + args=('AttributeError',)), + ): + self.checker.visit_raise(node) + + def test_finds_missing_raises_in_setter_sphinx(self): + """Example of a setter having missing raises documentation in + its own Sphinx style docstring + """ + setter_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): + '''docstring ... + + :type: int + :raises RuntimeError: Always + ''' + raise RuntimeError() + return 10 + + @foo.setter + def foo(self, value): #@ + '''setter docstring ... + + :type: None + ''' + raise AttributeError() #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-raises-doc', + node=setter_node, + args=('AttributeError',)), + ): + self.checker.visit_raise(node) + + def test_finds_missing_raises_from_setter_google(self): + """Example of a setter having missing raises documentation in + its own Google style docstring of the property + """ + setter_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): + '''int: docstring ... + + Raises: + RuntimeError: Always + ''' + raise RuntimeError() + return 10 + + @foo.setter + def foo(self, value): #@ + '''setter docstring ... + + Raises: + RuntimeError: Never + ''' + if True: + raise AttributeError() #@ + raise RuntimeError() + """) + with self.assertAddsMessages( + Message( + msg_id='missing-raises-doc', + node=setter_node, + args=('AttributeError',)), + ): + self.checker.visit_raise(node) + + def test_finds_missing_raises_from_setter_numpy(self): + """Example of a setter having missing raises documentation in + its own Numpy style docstring of the property + """ + setter_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): + '''int: docstring ... + + Raises + ------ + RuntimeError + Always + ''' + raise RuntimeError() + return 10 + + @foo.setter + def foo(self, value): #@ + '''setter docstring ... + + Raises + ------ + RuntimeError + Never + ''' + if True: + raise AttributeError() #@ + raise RuntimeError() + """) + with self.assertAddsMessages( + Message( + msg_id='missing-raises-doc', + node=setter_node, + args=('AttributeError',)), + ): + self.checker.visit_raise(node) + + def test_finds_property_return_type_sphinx(self): + """Example of a property having return documentation in + a Sphinx style docstring + """ + node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''docstring ... + + :type: int + ''' + return 10 + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_finds_property_return_type_google(self): + """Example of a property having return documentation in + a Google style docstring + """ + node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''int: docstring ... + + Raises: + RuntimeError: Always + ''' + raise RuntimeError() + return 10 + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_finds_property_return_type_numpy(self): + """Example of a property having return documentation in + a numpy style docstring + """ + node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''int: docstring ... + + Raises + ------ + RuntimeError + Always + ''' + raise RuntimeError() + return 10 + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_finds_missing_property_return_type_sphinx(self): + """Example of a property having missing return documentation in + a Sphinx style docstring + """ + property_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''docstring ... + + :raises RuntimeError: Always + ''' + raise RuntimeError() + return 10 #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-return-doc', + node=property_node), + Message( + msg_id='missing-return-type-doc', + node=property_node), + ): + self.checker.visit_return(node) + + def test_finds_property_return_type_google(self): + """Example of a property having return documentation in + a Google style docstring + """ + property_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''docstring ... + + Raises: + RuntimeError: Always + ''' + raise RuntimeError() + return 10 #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-return-doc', + node=property_node), + Message( + msg_id='missing-return-type-doc', + node=property_node), + ): + self.checker.visit_return(node) + + def test_finds_property_return_type_numpy(self): + """Example of a property having return documentation in + a numpy style docstring + """ + property_node, node = astroid.extract_node(""" + class Foo(object): + @property + def foo(self): #@ + '''docstring ... + + Raises + ------ + RuntimeError + Always + ''' + raise RuntimeError() + return 10 #@ + """) + with self.assertAddsMessages( + Message( + msg_id='missing-return-doc', + node=property_node), + Message( + msg_id='missing-return-type-doc', + node=property_node), + ): + self.checker.visit_return(node) |