summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAshley Whetter <asw@dneg.com>2018-05-04 11:18:20 -0700
committerAshley Whetter <ashley@awhetter.co.uk>2018-05-09 22:05:56 -0700
commit5915041a113508a0f72232a8234b4a55808f6dd4 (patch)
tree6b002b7cb672549834e65cbbc353cf223fe98265
parent2df42c20e804004cd3106c895ce77e5f9b3fbec6 (diff)
downloadpylint-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--ChangeLog6
-rw-r--r--doc/whatsnew/1.9.rst4
-rw-r--r--pylint/extensions/docparams.py11
-rw-r--r--pylint/test/extensions/test_check_docs.py111
4 files changed, 130 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 396271c69..9138b683b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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)