third_party.pylibs.pylint.src/pylint/test/extensions/test_check_docs.py

1170 lines
33 KiB
Python

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
"""Unit tests for the pylint checkers in :mod:`pylint.extensions.check_docs`,
in particular the parameter documentation checker `DocstringChecker`
"""
from __future__ import division, print_function, absolute_import
import unittest
import sys
import astroid
from astroid import test_utils
from pylint.testutils import CheckerTestCase, Message, set_config
from pylint.extensions.check_docs import DocstringChecker
class ParamDocCheckerTest(CheckerTestCase):
"""Tests for pylint_plugin.ParamDocChecker"""
CHECKER_CLASS = DocstringChecker
def test_missing_func_params_in_sphinx_docstring(self):
"""Example of a function with missing Sphinx parameter documentation in
the docstring
"""
node = test_utils.extract_node("""
def function_foo(x, y, z):
'''docstring ...
:param x: bla
:param int z: bar
'''
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('y',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self.checker.visit_functiondef(node)
def test_missing_func_params_in_google_docstring(self):
"""Example of a function with missing Google style parameter
documentation in the docstring
"""
node = test_utils.extract_node("""
def function_foo(x, y, z):
'''docstring ...
Args:
x: bla
z (int): bar
some other stuff
'''
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('y',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self.checker.visit_functiondef(node)
def test_missing_func_params_in_numpy_docstring(self):
"""Example of a function with missing NumPy style parameter
documentation in the docstring
"""
node = test_utils.extract_node("""
def function_foo(x, y, z):
'''docstring ...
Parameters
----------
x:
bla
z: int
bar
some other stuff
'''
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('y',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self.checker.visit_functiondef(node)
def test_tolerate_no_param_documentation_at_all(self):
"""Example of a function with no parameter documentation at all
No error message is emitted.
"""
node = test_utils.extract_node("""
def function_foo(x, y):
'''docstring ...
missing parameter documentation'''
pass
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
@set_config(accept_no_param_doc=False)
def test_don_t_tolerate_no_param_documentation_at_all(self):
"""Example of a function with no parameter documentation at all
No error message is emitted.
"""
node = test_utils.extract_node("""
def function_foo(x, y):
'''docstring ...
missing parameter documentation'''
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('x, y',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self.checker.visit_functiondef(node)
def _visit_methods_of_class(self, node):
"""Visit all methods of a class node
:param node: class node
:type node: :class:`astroid.scoped_nodes.Class`
"""
for body_item in node.body:
if (isinstance(body_item, astroid.FunctionDef)
and hasattr(body_item, 'name')):
self.checker.visit_functiondef(body_item)
def test_missing_method_params_in_sphinx_docstring(self):
"""Example of a class method with missing parameter documentation in
the Sphinx style docstring
"""
node = test_utils.extract_node("""
class Foo(object):
def method_foo(self, x, y):
'''docstring ...
missing parameter documentation
:param x: bla
'''
pass
""")
method_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=method_node,
args=('y',)),
Message(
msg_id='missing-type-doc',
node=method_node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_missing_method_params_in_google_docstring(self):
"""Example of a class method with missing parameter documentation in
the Google style docstring
"""
node = test_utils.extract_node("""
class Foo(object):
def method_foo(self, x, y):
'''docstring ...
missing parameter documentation
Args:
x: bla
'''
pass
""")
method_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=method_node,
args=('y',)),
Message(
msg_id='missing-type-doc',
node=method_node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_missing_method_params_in_numpy_docstring(self):
"""Example of a class method with missing parameter documentation in
the Numpy style docstring
"""
node = test_utils.extract_node("""
class Foo(object):
def method_foo(self, x, y):
'''docstring ...
missing parameter documentation
Parameters
----------
x:
bla
'''
pass
""")
method_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=method_node,
args=('y',)),
Message(
msg_id='missing-type-doc',
node=method_node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_existing_func_params_in_sphinx_docstring(self):
"""Example of a function with correctly documented parameters and
return values (Sphinx style)
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg, zarg):
'''function foo ...
:param xarg: bla xarg
:type xarg: int
:param yarg: bla yarg
:type yarg: float
:param int zarg: bla zarg
:return: sum
:rtype: float
'''
return xarg + yarg
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_existing_func_params_in_google_docstring(self):
"""Example of a function with correctly documented parameters and
return values (Google style)
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg, zarg):
'''function foo ...
Args:
xarg (int): bla xarg
yarg (float): bla
bla yarg
zarg (int): bla zarg
Returns:
float: sum
'''
return xarg + yarg
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_existing_func_params_in_numpy_docstring(self):
"""Example of a function with correctly documented parameters and
return values (Numpy style)
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg, zarg):
'''function foo ...
Parameters
----------
xarg: int
bla xarg
yarg: float
bla yarg
zarg: int
bla zarg
Returns
-------
float
sum
'''
return xarg + yarg
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_wrong_name_of_func_params_in_sphinx_docstring(self):
"""Example of functions with inconsistent parameter names in the
signature and in the Sphinx style documentation
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg, zarg):
'''function foo ...
:param xarg1: bla xarg
:type xarg: int
:param yarg: bla yarg
:type yarg1: float
:param str zarg1: bla zarg
'''
return xarg + yarg
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('xarg, xarg1, zarg, zarg1',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('yarg, yarg1, zarg, zarg1',)),
):
self.checker.visit_functiondef(node)
node = test_utils.extract_node("""
def function_foo(xarg, yarg):
'''function foo ...
:param yarg1: bla yarg
:type yarg1: float
For the other parameters, see bla.
'''
return xarg + yarg
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('yarg1',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('yarg1',))
):
self.checker.visit_functiondef(node)
def test_wrong_name_of_func_params_in_google_docstring(self):
"""Example of functions with inconsistent parameter names in the
signature and in the Google style documentation
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg, zarg):
'''function foo ...
Args:
xarg1 (int): bla xarg
yarg (float): bla yarg
zarg1 (str): bla zarg
'''
return xarg + yarg
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('xarg, xarg1, zarg, zarg1',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('xarg, xarg1, zarg, zarg1',)),
):
self.checker.visit_functiondef(node)
node = test_utils.extract_node("""
def function_foo(xarg, yarg):
'''function foo ...
Args:
yarg1 (float): bla yarg
For the other parameters, see bla.
'''
return xarg + yarg
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('yarg1',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('yarg1',))
):
self.checker.visit_functiondef(node)
def test_wrong_name_of_func_params_in_numpy_docstring(self):
"""Example of functions with inconsistent parameter names in the
signature and in the Numpy style documentation
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg, zarg):
'''function foo ...
Parameters
----------
xarg1: int
bla xarg
yarg: float
bla yarg
zarg1: str
bla zarg
'''
return xarg + yarg
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('xarg, xarg1, zarg, zarg1',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('xarg, xarg1, zarg, zarg1',)),
):
self.checker.visit_functiondef(node)
node = test_utils.extract_node("""
def function_foo(xarg, yarg):
'''function foo ...
Parameters
----------
yarg1: float
bla yarg
For the other parameters, see bla.
'''
return xarg + yarg
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('yarg1',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('yarg1',))
):
self.checker.visit_functiondef(node)
def test_see_sentence_for_func_params_in_sphinx_docstring(self):
"""Example for the usage of "For the other parameters, see" to avoid
too many repetitions, e.g. in functions or methods adhering to a
given interface (Sphinx style)
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg):
'''function foo ...
:param yarg: bla yarg
:type yarg: float
For the other parameters, see :func:`bla`
'''
return xarg + yarg
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_see_sentence_for_func_params_in_google_docstring(self):
"""Example for the usage of "For the other parameters, see" to avoid
too many repetitions, e.g. in functions or methods adhering to a
given interface (Google style)
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg):
'''function foo ...
Args:
yarg (float): bla yarg
For the other parameters, see :func:`bla`
'''
return xarg + yarg
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_see_sentence_for_func_params_in_numpy_docstring(self):
"""Example for the usage of "For the other parameters, see" to avoid
too many repetitions, e.g. in functions or methods adhering to a
given interface (Numpy style)
"""
node = test_utils.extract_node("""
def function_foo(xarg, yarg):
'''function foo ...
Parameters
----------
yarg: float
bla yarg
For the other parameters, see :func:`bla`
'''
return xarg + yarg
""")
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_constr_params_in_class_sphinx(self):
"""Example of a class with missing constructor parameter documentation
(Sphinx style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
'''docstring foo
:param y: bla
missing constructor parameter documentation
'''
def __init__(self, x, y):
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_constr_params_in_class_google(self):
"""Example of a class with missing constructor parameter documentation
(Google style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
'''docstring foo
Args:
y: bla
missing constructor parameter documentation
'''
def __init__(self, x, y):
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_constr_params_in_class_numpy(self):
"""Example of a class with missing constructor parameter documentation
(Numpy style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
'''docstring foo
Parameters
----------
y:
bla
missing constructor parameter documentation
'''
def __init__(self, x, y):
pass
""")
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_constr_params_in_init_sphinx(self):
"""Example of a class with missing constructor parameter documentation
(Sphinx style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
def __init__(self, x, y):
'''docstring foo constructor
:param y: bla
missing constructor parameter documentation
'''
pass
""")
constructor_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=constructor_node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=constructor_node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_constr_params_in_init_google(self):
"""Example of a class with missing constructor parameter documentation
(Google style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
def __init__(self, x, y):
'''docstring foo constructor
Args:
y: bla
missing constructor parameter documentation
'''
pass
""")
constructor_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=constructor_node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=constructor_node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_constr_params_in_init_numpy(self):
"""Example of a class with missing constructor parameter documentation
(Numpy style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
def __init__(self, x, y):
'''docstring foo constructor
Parameters
----------
y:
bla
missing constructor parameter documentation
'''
pass
""")
constructor_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=constructor_node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=constructor_node,
args=('x, y',))
):
self._visit_methods_of_class(node)
def test_constr_params_in_class_and_init_sphinx(self):
"""Example of a class with missing constructor parameter documentation
in both the init docstring and the class docstring
(Sphinx style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
'''docstring foo
:param y: None
missing constructor parameter documentation
'''
def __init__(self, x, y):
'''docstring foo
:param y: bla
missing constructor parameter documentation
'''
pass
""")
constructor_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='multiple-constructor-doc',
node=node,
args=(node.name,)),
Message(
msg_id='missing-param-doc',
node=node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',)),
Message(
msg_id='missing-param-doc',
node=constructor_node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=constructor_node,
args=('x, y',)),
):
self._visit_methods_of_class(node)
def test_constr_params_in_class_and_init_google(self):
"""Example of a class with missing constructor parameter documentation
in both the init docstring and the class docstring
(Google style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
'''docstring foo
Args:
y: bla
missing constructor parameter documentation
'''
def __init__(self, x, y):
'''docstring foo
Args:
y: bla
missing constructor parameter documentation
'''
pass
""")
constructor_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='multiple-constructor-doc',
node=node,
args=(node.name,)),
Message(
msg_id='missing-param-doc',
node=node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',)),
Message(
msg_id='missing-param-doc',
node=constructor_node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=constructor_node,
args=('x, y',)),
):
self._visit_methods_of_class(node)
def test_constr_params_in_class_and_init_numpy(self):
"""Example of a class with missing constructor parameter documentation
in both the init docstring and the class docstring
(Numpy style)
Everything is completely analogous to functions.
"""
node = test_utils.extract_node("""
class ClassFoo(object):
'''docstring foo
Parameters
----------
y:
bla
missing constructor parameter documentation
'''
def __init__(self, x, y):
'''docstring foo
Parameters
----------
y:
bla
missing constructor parameter documentation
'''
pass
""")
constructor_node = node.body[0]
with self.assertAddsMessages(
Message(
msg_id='multiple-constructor-doc',
node=node,
args=(node.name,)),
Message(
msg_id='missing-param-doc',
node=node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=node,
args=('x, y',)),
Message(
msg_id='missing-param-doc',
node=constructor_node,
args=('x',)),
Message(
msg_id='missing-type-doc',
node=constructor_node,
args=('x, y',)),
):
self._visit_methods_of_class(node)
@unittest.skipIf(sys.version_info[0] != 3, "Enabled on Python 3")
def test_kwonlyargs_are_taken_in_account(self):
node = test_utils.extract_node('''
def my_func(arg, *, kwonly, missing_kwonly):
"""The docstring
:param int arg: The argument.
:param bool kwonly: A keyword-arg.
"""
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('missing_kwonly', )),
Message(
msg_id='missing-type-doc',
node=node,
args=('missing_kwonly', ))):
self.checker.visit_functiondef(node)
def test_warns_missing_args_sphinx(self):
node = test_utils.extract_node('''
def my_func(named_arg, *args):
"""The docstring
:param named_arg: Returned
:type named_arg: object
:returns: Maybe named_arg
:rtype: object or None
"""
if args:
return named_arg
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('args',))):
self.checker.visit_functiondef(node)
def test_warns_missing_kwargs_sphinx(self):
node = test_utils.extract_node('''
def my_func(named_arg, **kwargs):
"""The docstring
:param named_arg: Returned
:type named_arg: object
:returns: Maybe named_arg
:rtype: object or None
"""
if kwargs:
return named_arg
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('kwargs',))):
self.checker.visit_functiondef(node)
def test_warns_missing_args_google(self):
node = test_utils.extract_node('''
def my_func(named_arg, *args):
"""The docstring
Args:
named_arg (object): Returned
Returns:
object or None: Maybe named_arg
"""
if args:
return named_arg
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('args',))):
self.checker.visit_functiondef(node)
def test_warns_missing_kwargs_google(self):
node = test_utils.extract_node('''
def my_func(named_arg, **kwargs):
"""The docstring
Args:
named_arg (object): Returned
Returns:
object or None: Maybe named_arg
"""
if kwargs:
return named_arg
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('kwargs',))):
self.checker.visit_functiondef(node)
def test_warns_missing_args_numpy(self):
node = test_utils.extract_node('''
def my_func(named_arg, *args):
"""The docstring
Args
----
named_arg : object
Returned
Returns
-------
object or None
Maybe named_arg
"""
if args:
return named_arg
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('args',))):
self.checker.visit_functiondef(node)
def test_warns_missing_kwargs_numpy(self):
node = test_utils.extract_node('''
def my_func(named_arg, **kwargs):
"""The docstring
Args
----
named_arg : object
Returned
Returns
-------
object or None
Maybe named_arg
"""
if kwargs:
return named_arg
''')
with self.assertAddsMessages(
Message(
msg_id='missing-param-doc',
node=node,
args=('kwargs',))):
self.checker.visit_functiondef(node)
def test_finds_args_without_type_sphinx(self):
node = test_utils.extract_node('''
def my_func(named_arg, *args):
"""The docstring
:param named_arg: Returned
:type named_arg: object
:param args: Optional arguments
:returns: Maybe named_arg
:rtype: object or None
"""
if args:
return named_arg
''')
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_finds_kwargs_without_type_sphinx(self):
node = test_utils.extract_node('''
def my_func(named_arg, **kwargs):
"""The docstring
:param named_arg: Returned
:type named_arg: object
:param kwargs: Keyword arguments
:returns: Maybe named_arg
:rtype: object or None
"""
if kwargs:
return named_arg
''')
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_finds_args_without_type_google(self):
node = test_utils.extract_node('''
def my_func(named_arg, *args):
"""The docstring
Args:
named_arg (object): Returned
*args: Optional arguments
Returns:
object or None: Maybe named_arg
"""
if args:
return named_arg
''')
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_finds_kwargs_without_type_google(self):
node = test_utils.extract_node('''
def my_func(named_arg, **kwargs):
"""The docstring
Args:
named_arg (object): Returned
**kwargs: Keyword arguments
Returns:
object or None: Maybe named_arg
"""
if kwargs:
return named_arg
''')
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_finds_args_without_type_numpy(self):
node = test_utils.extract_node('''
def my_func(named_arg, *args):
"""The docstring
Args
----
named_arg : object
Returned
args :
Optional Arguments
Returns
-------
object or None
Maybe named_arg
"""
if args:
return named_arg
''')
with self.assertNoMessages():
self.checker.visit_functiondef(node)
def test_finds_kwargs_without_type_numpy(self):
node = test_utils.extract_node('''
def my_func(named_arg, **kwargs):
"""The docstring
Args
----
named_arg : object
Returned
kwargs :
Keyword arguments
Returns
-------
object or None
Maybe named_arg
"""
if kwargs:
return named_arg
''')
with self.assertNoMessages():
self.checker.visit_functiondef(node)
if __name__ == '__main__':
unittest.main()