def test_multi_name_detection_majority(self): classes = astroid.extract_node(""" class classb(object): #@ pass class CLASSA(object): #@ pass class CLASSC(object): #@ pass """) message = Message('invalid-name', node=classes[0], args=('Class', 'classb', "'(?:(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern")) with self.assertAddsMessages(message): for cls in classes: self.checker.visit_classdef(cls) self.checker.leave_module(cls.root)
def test_find_missing_google_raises(self): node = astroid.extract_node(''' def my_func(self): """This is a docstring. Raises: NameError: Never """ raise RuntimeError('hi') raise NameError('hi') ''') raise_node = node.body[0] with self.assertAddsMessages( Message(msg_id="missing-raises-doc", node=node, args=("RuntimeError", ))): self.checker.visit_raise(raise_node)
def test_multi_name_detection_exempt(self): function_defs = test_utils.extract_node(""" def FOO(): #@ pass def lower(): #@ pass def FOO(): #@ pass def UPPER(): #@ pass """) message = Message('invalid-name', node=function_defs[3], args=('function', 'UPPER', '')) with self.assertAddsMessages(message): for func in function_defs: self.checker.visit_functiondef(func) self.checker.leave_module(func.root)
def test_method_deprecated_kwarg_only(self): # Tests raising error when calling method with deprecated keyword only argument node = astroid.extract_node(""" class MyClass: def mymethod3(self, arg1, *, deprecated_arg1): pass MyClass().mymethod3(None, deprecated_arg1='deprecated') """) with self.assertAddsMessages( Message( msg_id="deprecated-argument", args=("deprecated_arg1", "mymethod3"), node=node, confidence=UNDEFINED, )): self.checker.visit_call(node)
def test_find_missing_sphinx_raises_infer_from_instance(self): raise_node = astroid.extract_node(''' def my_func(self): """This is a docstring. :raises NameError: Never """ my_exception = RuntimeError('hi') raise my_exception #@ raise NameError('hi') ''') node = raise_node.frame() with self.assertAddsMessages( Message(msg_id="missing-raises-doc", node=node, args=("RuntimeError", ))): self.checker.visit_raise(raise_node)
def test_multi_name_detection_group(self): function_defs = astroid.extract_node(""" class First(object): def func(self): #@ pass def FUNC(): #@ pass """, module_name='test') message = Message('invalid-name', node=function_defs[1], args=('function', 'FUNC', '')) with self.assertAddsMessages(message): for func in function_defs: self.checker.visit_functiondef(func) self.checker.leave_module(func.root)
def test_find_valid_missing_google_attr_raises(self): node = astroid.extract_node(''' def my_func(self): """This is a google docstring. Raises: re.anothererror: Sometimes """ from re import error raise error('hi') ''') raise_node = node.body[1] with self.assertAddsMessages( Message(msg_id="missing-raises-doc", node=node, args=("error", ))): self.checker.visit_raise(raise_node)
def test_ellipsis_is_ignored(self): code = """ from typing import overload @overload def concat2(arg1: str) -> str: ... """ tree = astroid.extract_node(code) with self.assertNoMessages(): self.visitFirst(tree) code = """ def concat2(arg1: str) -> str: ... """ stmt = astroid.extract_node(code) with self.assertAddsMessages( Message("multiple-statements", node=stmt.body[0])): self.visitFirst(stmt)
def test_no_member_in_getattr(self): """Make sure that a module attribute access is checked by pylint.""" node = astroid.extract_node( """ import optparse optparse.THIS_does_not_EXIST """ ) with self.assertAddsMessages( Message( "no-member", node=node, args=("Module", "optparse", "THIS_does_not_EXIST", ""), ) ): self.checker.visit_attribute(node)
def test_import_outside_toplevel(self): node = astroid.extract_node(""" def f(): import astroid """).body[0] with self.assertNoMessages(): self.checker.visit_import(node) node = astroid.extract_node(""" def g(): import pylint """).body[0] with self.assertAddsMessages( Message("import-outside-toplevel", node=node, args="pylint")): self.checker.visit_import(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_numpy_redundant_rtype_doc(self): node = astroid.extract_node( ''' def my_func(self): """This is a docstring. Returns ------- int """ return None ''' ) with self.assertAddsMessages( Message(msg_id="redundant-returns-doc", node=node) ): self.checker.visit_functiondef(node)
def test_warn_partial_google_returns(self): node = astroid.extract_node( ''' def my_func(self): """This is a docstring. Returns: Always False """ return False ''' ) return_node = node.body[0] with self.assertAddsMessages( Message(msg_id="missing-return-type-doc", node=node) ): self.checker.visit_return(return_node)
def test_uninferable_attribute(self): """Make sure protect-access doesn't raise an exception Uninferable attributes""" node = astroid.extract_node(""" class MC(): @property def nargs(self): return 1 if self._nargs else 2 class Application(metaclass=MC): def __new__(cls): nargs = obj._nargs #@ """) with self.assertAddsMessages( Message("protected-access", node=node.value, args="_nargs")): self.checker.visit_attribute(node.value)
def test_too_many_classes(self): node = astroid.parse(""" class A(object): pass class B(object): pass class C(object): pass class D(object): pass class E(object): pass class F(object): pass class G(object): pass class H(object): pass class I(object): pass class J(object): pass class K(object): # too many pass """) module_def = node with self.assertAddsMessages( Message( 'too-many-classes', node=module_def, args=('', 11, 10), )): self.walk(node.root())
def test_warn_missing_numpy_returns(self): node = test_utils.extract_node(''' def my_func(self, doc_type): """This is a docstring. Arguments --------- doc_type : str Numpy """ return False ''') return_node = node.body[0] with self.assertAddsMessages( Message( msg_id='missing-returns-doc', node=node)): self.checker.visit_return(return_node)
def getitem_on_modules(self): """Mainly validate the code won't crash if we're not having a function.""" module = astroid.parse( """ import collections test = collections[int] """ ) subscript = module.body[-1].value with self.assertAddsMessages( Message( "unsubscriptable-object", node=subscript.value, args="collections", confidence=UNDEFINED, ) ): self.checker.visit_subscript(subscript)
def test_deprecated_method(self): # Tests detecting deprecated method node = astroid.extract_node(""" class Deprecated: def deprecated_method(): pass d = Deprecated() d.deprecated_method() """) with self.assertAddsMessages( Message( msg_id="deprecated-method", args=("deprecated_method", ), node=node, confidence=UNDEFINED, )): self.checker.visit_call(node)
def test_multi_name_detection_exempt(self): function_defs = astroid.extract_node(""" def FOO(): #@ pass def lower(): #@ pass def FOO(): #@ pass def UPPER(): #@ pass """) message = Message('invalid-name', node=function_defs[3], args=('Function', 'UPPER', "'(?:(?P<ignore>FOO)|(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern")) with self.assertAddsMessages(message): for func in function_defs: self.checker.visit_functiondef(func) self.checker.leave_module(func.root)
def test_single_line_double_quote_docstring_with_cfg_single_multiple_cls( self): test_str = ''' class TestClass1(object): """Class docstring""" class TestClass2(object): #@ """Class level docstring on a single line.""" class TestClass3(object): """Another class level docstring on single line.""" ''' msg = Message(msg_id='invalid-docstring-quote', line=6, args=(TRI_Q_DOUB, TRI_Q_SING)) self.check_class(test_str, msg)
def test_handle_words_joined_by_forward_slash(self): stmt = astroid.extract_node(''' class ComentAbc(object): """This is Comment/Abcz with a bad comment""" pass ''') with self.assertAddsMessages( Message( "wrong-spelling-in-docstring", line=3, args=( "Abcz", "This is Comment/Abcz with a bad comment", " ^^^^", self._get_msg_suggestions("Abcz"), ), )): self.checker.visit_classdef(stmt)
def test_find_missing_sphinx_raises_infer_from_function(self): raise_node = astroid.extract_node(''' def my_func(self): """This is a docstring. :raises NameError: Never """ def ex_func(val): return RuntimeError(val) raise ex_func('hi') #@ raise NameError('hi') ''') node = raise_node.frame() with self.assertAddsMessages( Message(msg_id='missing-raises-doc', node=node, args=('RuntimeError', ))): self.checker.visit_raise(raise_node)
def test_warns_missing_args_google(self): node = astroid.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_warn_missing_numpy_yields(self): node = astroid.extract_node(''' def my_func(self, doc_type): """This is a docstring. Arguments --------- doc_type : str Numpy """ yield False ''') yield_node = node.body[0] with self.assertAddsMessages( Message( msg_id='missing-yields-doc', node=node)): self.checker.visit_yield(yield_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 = astroid.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, zarg', )), Message(msg_id='missing-type-doc', node=node, args=('xarg, zarg', )), Message(msg_id='differing-param-doc', node=node, args=('xarg1, zarg1', )), Message(msg_id='differing-type-doc', node=node, args=('xarg1, zarg1', )), ): self.checker.visit_functiondef(node) node = astroid.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='differing-param-doc', node=node, args=('yarg1', )), Message(msg_id='differing-type-doc', node=node, args=('yarg1', ))): self.checker.visit_functiondef(node)
def decorated_by_subscriptable_then_unsubscriptable_class( self, decorators): module = astroid.parse(decorators + """ @Unsubscriptable @Subscriptable def decorated(): ... test = decorated[None] """) subscript = module.body[-1].value with self.assertAddsMessages( Message( "unsubscriptable-object", node=subscript.value, args="decorated", confidence=UNDEFINED, )): self.checker.visit_subscript(subscript)
def test_invalid_metaclass_function_metaclasses(self): module = astroid.parse(""" def invalid_metaclass_1(name, bases, attrs): return int def invalid_metaclass_2(name, bases, attrs): return 1 class Invalid(metaclass=invalid_metaclass_1): pass class InvalidSecond(metaclass=invalid_metaclass_2): pass """) for class_obj, metaclass_name in (("Invalid", "int"), ("InvalidSecond", "1")): classdef = module[class_obj] message = Message("invalid-metaclass", node=classdef, args=(metaclass_name, )) with self.assertAddsMessages(message): self.checker.visit_classdef(classdef)
def test_invalid_metaclass_function_metaclasses(self): module = astroid.parse(''' def invalid_metaclass_1(name, bases, attrs): return int def invalid_metaclass_2(name, bases, attrs): return 1 class Invalid(metaclass=invalid_metaclass_1): pass class InvalidSecond(metaclass=invalid_metaclass_2): pass ''') for class_obj, metaclass_name in (('Invalid', 'int'), ('InvalidSecond', '1')): classdef = module[class_obj] message = Message('invalid-metaclass', node=classdef, args=(metaclass_name, )) with self.assertAddsMessages(message): self.checker.visit_classdef(classdef)
def test_docstring_lines_that_look_like_comments_2(self): stmt = astroid.extract_node( # fmt: off 'def f():\n' ' """# msitake"""' # fmt: on ) with self.assertAddsMessages( Message( "wrong-spelling-in-docstring", line=2, args=( "msitake", "# msitake", " ^^^^^^^", self._get_msg_suggestions("msitake"), ), )): self.checker.visit_functiondef(stmt)
def test_triggered_if_block_ends_with_if(self): """ Given an if-elif construct When the body of the if ends with an if Then the message confusing-consecutive-elif must be triggered. """ example_code = """ def foo(a, b, c): if a > b: #@ if a > 0: return a elif a > c: #@ return c """ if_node_to_test, elif_node = astroid.extract_node(example_code) with self.assertAddsMessages( Message(msg_id=MSG_ID_CONFUSING_CONSECUTIVE_ELIF, node=elif_node)): self.checker.visit_if(if_node_to_test)