diff options
author | Ashley Whetter <asw@dneg.com> | 2018-05-04 11:18:20 -0700 |
---|---|---|
committer | Ashley Whetter <ashley@awhetter.co.uk> | 2018-05-09 22:05:56 -0700 |
commit | 5915041a113508a0f72232a8234b4a55808f6dd4 (patch) | |
tree | 6b002b7cb672549834e65cbbc353cf223fe98265 | |
parent | 2df42c20e804004cd3106c895ce77e5f9b3fbec6 (diff) | |
download | pylint-git-5915041a113508a0f72232a8234b4a55808f6dd4.tar.gz |
Relaxed docstring checks for abstract methods
Abstract methods are allowed to document returns documentation even
if the default implementation does not return something.
This is so that an abstract method can document what an implementation
should return.
Abstract methods also do not need to document that they raise a
NotImplementedError. This is because a docstring author may choose to
indicate that the method is abstract in the docstring description,
which is something that we cannot detect.
Closes #2044
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | doc/whatsnew/1.9.rst | 4 | ||||
-rw-r--r-- | pylint/extensions/docparams.py | 11 | ||||
-rw-r--r-- | pylint/test/extensions/test_check_docs.py | 111 |
4 files changed, 130 insertions, 2 deletions
@@ -7,6 +7,12 @@ What's New in Pylint 1.9.0? Release date: + * docparams extension allows abstract methods to document what overriding + implementations should return, and to raise NotImplementedError without + documenting it. + + Closes #2044 + * Special methods do not count towards `too-few-methods`, and are considered part of the public API. diff --git a/doc/whatsnew/1.9.rst b/doc/whatsnew/1.9.rst index 67482404f..f9e60111f 100644 --- a/doc/whatsnew/1.9.rst +++ b/doc/whatsnew/1.9.rst @@ -65,3 +65,7 @@ Other Changes and are considered part of the public API. They are still not counted towards the number of methods for `too-many-methods`. + +* docparams allows abstract methods to document returns documentation even + if the default implementation does not return something. + They also no longer need to document raising a NotImplementedError. diff --git a/pylint/extensions/docparams.py b/pylint/extensions/docparams.py index a304683e2..b0f0f0bc7 100644 --- a/pylint/extensions/docparams.py +++ b/pylint/extensions/docparams.py @@ -169,7 +169,8 @@ class DocstringParameterChecker(BaseChecker): node_doc, node.args, node, node_allow_no_param) def check_functiondef_returns(self, node, node_doc): - if not node_doc.supports_yields and node.is_generator(): + if ((not node_doc.supports_yields and node.is_generator()) + or node.is_abstract()): return return_nodes = node.nodes_of_class(astroid.Return) @@ -180,7 +181,7 @@ class DocstringParameterChecker(BaseChecker): node=node) def check_functiondef_yields(self, node, node_doc): - if not node_doc.supports_yields: + if not node_doc.supports_yields or node.is_abstract(): return if ((node_doc.has_yields() or node_doc.has_yields_type()) and @@ -418,6 +419,12 @@ class DocstringParameterChecker(BaseChecker): :param node: The node show the message on. :type node: astroid.node_classes.NodeNG """ + if node.is_abstract(): + try: + missing_excs.remove('NotImplementedError') + except ValueError: + pass + if not missing_excs: return diff --git a/pylint/test/extensions/test_check_docs.py b/pylint/test/extensions/test_check_docs.py index 3950cedb9..4e5e09234 100644 --- a/pylint/test/extensions/test_check_docs.py +++ b/pylint/test/extensions/test_check_docs.py @@ -1875,3 +1875,114 @@ class TestParamDocChecker(CheckerTestCase): node=func_node), ): self.checker.visit_return(node) + + def test_ignores_return_in_abstract_method_sphinx(self): + """Example of an abstract method documenting the return type that an + implementation should return. + """ + node = astroid.extract_node(""" + import abc + class Foo(object): + @abc.abstractmethod + def foo(self): #@ + '''docstring ... + + :returns: Ten + :rtype: int + ''' + return 10 + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_ignores_return_in_abstract_method_google(self): + """Example of an abstract method documenting the return type that an + implementation should return. + """ + node = astroid.extract_node(""" + import abc + class Foo(object): + @abc.abstractmethod + def foo(self): #@ + '''docstring ... + + Returns: + int: Ten + ''' + return 10 + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_ignores_return_in_abstract_method_numpy(self): + """Example of an abstract method documenting the return type that an + implementation should return. + """ + node = astroid.extract_node(""" + import abc + class Foo(object): + @abc.abstractmethod + def foo(self): #@ + '''docstring ... + + Returns + ------- + int + Ten + ''' + return 10 + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_ignores_raise_notimplementederror_sphinx(self): + """Example of an abstract + """ + node = astroid.extract_node(""" + class Foo(object): + def foo(self, arg): #@ + '''docstring ... + + :param arg: An argument. + :type arg: int + ''' + raise NotImplementedError() + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_ignores_return_in_abstract_method_google(self): + """Example of a method documenting the return type that an + implementation should return. + """ + node = astroid.extract_node(""" + class Foo(object): + def foo(self, arg): #@ + '''docstring ... + + Args: + arg (int): An argument. + ''' + raise NotImplementedError() + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) + + def test_ignores_return_in_abstract_method_numpy(self): + """Example of a method documenting the return type that an + implementation should return. + """ + node = astroid.extract_node(""" + class Foo(object): + def foo(self, arg): #@ + '''docstring ... + + Parameters + ---------- + arg : int + An argument. + ''' + raise NotImplementedError() + """) + with self.assertNoMessages(): + self.checker.visit_functiondef(node) |