1010
1111from logilab .astng import node_classes
1212from logilab .astng import scoped_nodes
13+ from logilab .astng .exceptions import InferenceError
1314
1415from pylint .interfaces import IASTNGChecker
1516from pylint .checkers .base import DocStringChecker as PylintDocStringChecker
@@ -35,6 +36,40 @@ class or inner function.
3536
3637
3738
39+ def _getDecoratorsName (node ):
40+ """
41+ Return a list with names of decorators attached to this node.
42+
43+ @param node: current node of pylint
44+ """
45+ try :
46+ return node .decoratornames ()
47+ except InferenceError :
48+ # For setter properties pylint fails so we use a custom code.
49+ decorators = []
50+ for decorator in node .decorators .nodes :
51+ decorators .append (decorator .as_string ())
52+ return decorators
53+
54+
55+ def _isSetter (node_type , node ):
56+ """
57+ Determine whether the given node is a setter property.
58+
59+ @param node_type: The type of the node to inspect.
60+ @param node: The L{logilab.astng.bases.NodeNG} to inspect.
61+
62+ @return: a boolean indicating if the given node is a setter.
63+ """
64+ if node_type not in ['function' , 'method' ]:
65+ return False
66+
67+ for name in _getDecoratorsName (node ):
68+ if '.setter' in name :
69+ return True
70+ return False
71+
72+
3873class DocstringChecker (PylintDocStringChecker ):
3974 """
4075 A checker for checking docstrings.
@@ -114,9 +149,16 @@ def _check_docstring(self, node_type, node):
114149 docstring = node .doc
115150 if docstring is None :
116151 # The node does not have a docstring.
117- # But do not check things inside a function or method.
118- if not _isInner (node ):
119- self .add_message ('W9208' , node = node )
152+ if _isInner (node ):
153+ # Do not check things inside a function or method.
154+ return
155+
156+ if _isSetter (node_type , node ):
157+ # Setters don't need a docstring as they are documented in
158+ # the getter.
159+ return
160+
161+ self .add_message ('W9208' , node = node )
120162 return
121163 elif not docstring .strip ():
122164 # Empty docstring.
@@ -206,15 +248,46 @@ def _checkEpytext(self, node_type, node, linenoDocstring):
206248 # The first argument usually named 'self'.
207249 argnames = (node .argnames ()[1 :] if node_type == 'method'
208250 else node .argnames ())
251+
252+ if _isSetter (node_type , node ):
253+ # For setter methods we remove the `value` argument as it
254+ # does not need to be documented.
255+ try :
256+ argnames .remove ('value' )
257+ except ValueError :
258+ # No `value` in arguments.
259+ pass
260+
209261 for argname in argnames :
210262 if not re .search (r"@param\s+%s\s*:" % argname , node .doc ):
211263 self .add_message ('W9202' , line = linenoDocstring ,
212264 node = node , args = argname )
213265 if not re .search (r"@type\s+%s\s*:" % argname , node .doc ):
214266 self .add_message ('W9203' , line = linenoDocstring ,
215267 node = node , args = argname )
268+
269+ self ._checkReturnValueEpytext (node , linenoDocstring )
270+
271+
272+ def _checkReturnValueEpytext (self , node , linenoDocstring ):
273+ """
274+ Check if return value is documented.
275+
276+ @param node: current node of pylint
277+ @param linenoDocstring: linenumber of docstring
278+ """
279+ # Getter properties don't need to document their return value,
280+ # but then need to have a return value.
281+ if '__builtin__.property' in _getDecoratorsName (node ):
282+ if self ._hasReturnValue (node ):
283+ # Getter properties don't need a docstring.
284+ return
285+
216286 # Check for return value.
217287 if self ._hasReturnValue (node ):
288+ if node .name .startswith ('test_' ):
289+ # Ignore return documentation for test methods.
290+ return
218291 if not re .search (r"@return[s]{0,1}\s*:" , node .doc ):
219292 self .add_message ('W9204' , line = linenoDocstring , node = node )
220293 if not re .search (r"@rtype\s*:" , node .doc ):
0 commit comments