diff --git a/tests/checkers/unittest_typecheck.py b/tests/checkers/unittest_typecheck.py index f378fc402b..3a384ba4b3 100644 --- a/tests/checkers/unittest_typecheck.py +++ b/tests/checkers/unittest_typecheck.py @@ -200,179 +200,6 @@ def test_nomember_on_c_extension_info_msg(self) -> None: with self.assertAddsMessages(message): self.checker.visit_attribute(node) - @set_config( - contextmanager_decorators=( - "contextlib.contextmanager", - ".custom_contextmanager", - ) - ) - def test_custom_context_manager(self): - """Test that @custom_contextmanager is recognized as configured.""" - node = astroid.extract_node( - """ - from contextlib import contextmanager - def custom_contextmanager(f): - return contextmanager(f) - @custom_contextmanager - def dec(): - yield - with dec(): - pass - """ - ) - with self.assertNoMessages(): - self.checker.visit_with(node) - - def test_invalid_metaclass(self) -> None: - module = astroid.parse( - """ - class InvalidAsMetaclass(object): - pass - - class FirstInvalid(object, metaclass=int): - pass - - class SecondInvalid(object, metaclass=InvalidAsMetaclass): - pass - - class ThirdInvalid(object, metaclass=2): - pass - - class FourthInvalid(object, metaclass=InvalidAsMetaclass()): - pass - """ - ) - for class_obj, metaclass_name in ( - ("FourthInvalid", "Instance of .InvalidAsMetaclass"), - ("ThirdInvalid", "2"), - ("SecondInvalid", "InvalidAsMetaclass"), - ("FirstInvalid", "int"), - ): - classdef = module[class_obj] - message = MessageTest( - "invalid-metaclass", node=classdef, args=(metaclass_name,) - ) - with self.assertAddsMessages(message): - self.checker.visit_classdef(classdef) - - def test_invalid_metaclass_function_metaclasses(self) -> None: - 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 = MessageTest( - "invalid-metaclass", node=classdef, args=(metaclass_name,) - ) - with self.assertAddsMessages(message): - self.checker.visit_classdef(classdef) - - def test_typing_namedtuple_not_callable_issue1295(self) -> None: - module = astroid.parse( - """ - import typing - Named = typing.NamedTuple('Named', [('foo', int), ('bar', int)]) - named = Named(1, 2) - """ - ) - call = module.body[-1].value - callables = call.func.inferred() - assert len(callables) == 1 - assert callables[0].callable() - with self.assertNoMessages(): - self.checker.visit_call(call) - - def test_typing_namedtuple_unsubscriptable_object_issue1295(self) -> None: - module = astroid.parse( - """ - import typing - MyType = typing.Tuple[str, str] - """ - ) - subscript = module.body[-1].value - with self.assertNoMessages(): - self.checker.visit_subscript(subscript) - - def test_staticmethod_multiprocessing_call(self) -> None: - """Make sure not-callable isn't raised for descriptors - - astroid can't process descriptors correctly so - pylint needs to ignore not-callable for them - right now - - Test for https://github.com/PyCQA/pylint/issues/1699 - """ - call = astroid.extract_node( - """ - import multiprocessing - multiprocessing.current_process() #@ - """ - ) - with self.assertNoMessages(): - self.checker.visit_call(call) - - def test_not_callable_uninferable_property(self) -> None: - """Make sure not-callable isn't raised for uninferable - properties - """ - call = astroid.extract_node( - """ - class A: - @property - def call(self): - return undefined - - a = A() - a.call() #@ - """ - ) - with self.assertNoMessages(): - self.checker.visit_call(call) - - def test_descriptor_call(self) -> None: - call = astroid.extract_node( - """ - def func(): - pass - - class ADescriptor: - def __get__(self, instance, owner): - return func - - class AggregateCls: - a = ADescriptor() - - AggregateCls().a() #@ - """ - ) - with self.assertNoMessages(): - self.checker.visit_call(call) - - def test_unknown_parent(self) -> None: - """Make sure the callable check does not crash when a node's parent - cannot be determined. - """ - call = astroid.extract_node( - """ - def get_num(n): - return 2 * n - get_num(10)() - """ - ) - with self.assertAddsMessages( - MessageTest("not-callable", node=call, args="get_num(10)") - ): - self.checker.visit_call(call) - class TestTypeCheckerOnDecorators(CheckerTestCase): "Tests for pylint.checkers.typecheck on decorated functions." diff --git a/tests/functional/i/invalid/m/invalid_metaclass.py b/tests/functional/i/invalid/m/invalid_metaclass.py index c0e9d74be9..ec251e47dd 100644 --- a/tests/functional/i/invalid/m/invalid_metaclass.py +++ b/tests/functional/i/invalid/m/invalid_metaclass.py @@ -32,3 +32,35 @@ class ThirdGood(object): @six.add_metaclass(ValidAsMetaclass) class FourthGood(object): pass + + +class FirstInvalid(object, metaclass=int): # [invalid-metaclass] + pass + + +class SecondInvalid(object, metaclass=InvalidAsMetaclass): # [invalid-metaclass] + pass + + +class ThirdInvalid(object, metaclass=2): # [invalid-metaclass] + pass + + +class FourthInvalid(object, metaclass=InvalidAsMetaclass()): # [invalid-metaclass] + pass + + +def invalid_metaclass_1(name, bases, attrs): + return int + + +def invalid_metaclass_2(name, bases, attrs): + return 1 + + +class Invalid(metaclass=invalid_metaclass_1): # [invalid-metaclass] + pass + + +class InvalidSecond(metaclass=invalid_metaclass_2): # [invalid-metaclass] + pass diff --git a/tests/functional/i/invalid/m/invalid_metaclass.txt b/tests/functional/i/invalid/m/invalid_metaclass.txt new file mode 100644 index 0000000000..c5ca48d760 --- /dev/null +++ b/tests/functional/i/invalid/m/invalid_metaclass.txt @@ -0,0 +1,6 @@ +invalid-metaclass:37:0:38:8:FirstInvalid:Invalid metaclass 'int' used:UNDEFINED +invalid-metaclass:41:0:42:8:SecondInvalid:Invalid metaclass 'InvalidAsMetaclass' used:UNDEFINED +invalid-metaclass:45:0:46:8:ThirdInvalid:Invalid metaclass '2' used:UNDEFINED +invalid-metaclass:49:0:50:8:FourthInvalid:Invalid metaclass 'Instance of invalid_metaclass.InvalidAsMetaclass' used:UNDEFINED +invalid-metaclass:61:0:62:8:Invalid:Invalid metaclass 'int' used:UNDEFINED +invalid-metaclass:65:0:66:8:InvalidSecond:Invalid metaclass '1' used:UNDEFINED diff --git a/tests/functional/n/not_callable.py b/tests/functional/n/not_callable.py index 7c361aa6a3..38232dc465 100644 --- a/tests/functional/n/not_callable.py +++ b/tests/functional/n/not_callable.py @@ -1,4 +1,5 @@ # pylint: disable=missing-docstring,no-self-use,too-few-public-methods,wrong-import-position,useless-object-inheritance,use-dict-literal +# pylint: disable=wrong-import-order, undefined-variable REVISION = None @@ -117,7 +118,8 @@ def does_not_make_sense(self): PROP1.does_not_make_sense() -import missing # pylint: disable=import-error +import missing # pylint: disable=import-error + class UnknownBaseCallable(missing.Blah): pass @@ -133,3 +135,56 @@ def value(self): return 42 CLASS_WITH_PROP = ClassWithProperty().value() # [not-callable] + +# Test typing.Namedtuple not callable +# See: https://github.com/PyCQA/pylint/issues/1295 +import typing + +Named = typing.NamedTuple("Named", [("foo", int), ("bar", int)]) +named = Named(1, 2) + +# Test descriptor call +def func(): + pass + + +class ADescriptor: + def __get__(self, instance, owner): + return func + + +class AggregateCls: + a = ADescriptor() + + +AggregateCls().a() + + +# Make sure not-callable isn't raised for descriptors + +# astroid can't process descriptors correctly so +# pylint needs to ignore not-callable for them +# right now + +# Test for https://github.com/PyCQA/pylint/issues/1699 + +import multiprocessing + +multiprocessing.current_process() + +# Make sure not-callable isn't raised for uninferable properties +class MyClass: + @property + def call(self): + return undefined + + +a = A() +a.call() + +# Make sure the callable check does not crash when a node's parent cannot be determined. +def get_number(arg): + return 2 * arg + + +get_number(10)() # [not-callable] diff --git a/tests/functional/n/not_callable.txt b/tests/functional/n/not_callable.txt index a7066e5b21..f079bbfe83 100644 --- a/tests/functional/n/not_callable.txt +++ b/tests/functional/n/not_callable.txt @@ -1,9 +1,10 @@ -not-callable:5:0:5:10::REVISION is not callable:UNDEFINED -not-callable:23:12:23:22::INSTANCE is not callable:UNDEFINED -not-callable:25:12:25:18::LIST is not callable:UNDEFINED -not-callable:27:12:27:18::DICT is not callable:UNDEFINED -not-callable:29:12:29:19::TUPLE is not callable:UNDEFINED -not-callable:31:12:31:17::INT is not callable:UNDEFINED -not-callable:66:0:66:13::PROP.test is not callable:UNDEFINED -not-callable:67:0:67:13::PROP.custom is not callable:UNDEFINED -not-callable:135:18:135:45::ClassWithProperty().value is not callable:UNDEFINED +not-callable:6:0:6:10::REVISION is not callable:UNDEFINED +not-callable:24:12:24:22::INSTANCE is not callable:UNDEFINED +not-callable:26:12:26:18::LIST is not callable:UNDEFINED +not-callable:28:12:28:18::DICT is not callable:UNDEFINED +not-callable:30:12:30:19::TUPLE is not callable:UNDEFINED +not-callable:32:12:32:17::INT is not callable:UNDEFINED +not-callable:67:0:67:13::PROP.test is not callable:UNDEFINED +not-callable:68:0:68:13::PROP.custom is not callable:UNDEFINED +not-callable:137:18:137:45::ClassWithProperty().value is not callable:UNDEFINED +not-callable:190:0:190:16::get_number(10) is not callable:UNDEFINED diff --git a/tests/functional/u/unsubscriptable_object.py b/tests/functional/u/unsubscriptable_object.py new file mode 100644 index 0000000000..0b7da78b38 --- /dev/null +++ b/tests/functional/u/unsubscriptable_object.py @@ -0,0 +1,7 @@ +"""Tests for unscubscriptable-object""" + +# Test for typing.NamedTuple +# See: https://github.com/PyCQA/pylint/issues/1295 +import typing + +MyType = typing.Tuple[str, str]