summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/whatsnew/1.8.rst24
-rw-r--r--pylint/extensions/_check_docs_utils.py17
-rw-r--r--pylint/test/extensions/test_check_docs.py332
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)