Skip to content

Commit

Permalink
Move various tests from TestTypeChecker to functional tests (#5455)
Browse files Browse the repository at this point in the history
* Remove duplicate test already in 'not_context_manager.py'
  • Loading branch information
DanielNoord authored Dec 2, 2021
1 parent 8f12337 commit 35813de
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 183 deletions.
173 changes: 0 additions & 173 deletions tests/checkers/unittest_typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
32 changes: 32 additions & 0 deletions tests/functional/i/invalid/m/invalid_metaclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions tests/functional/i/invalid/m/invalid_metaclass.txt
Original file line number Diff line number Diff line change
@@ -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
57 changes: 56 additions & 1 deletion tests/functional/n/not_callable.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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]
19 changes: 10 additions & 9 deletions tests/functional/n/not_callable.txt
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions tests/functional/u/unsubscriptable_object.py
Original file line number Diff line number Diff line change
@@ -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]

0 comments on commit 35813de

Please sign in to comment.