diff options
Diffstat (limited to 'tests/functional/m/member')
25 files changed, 576 insertions, 0 deletions
diff --git a/tests/functional/m/member/member_checks.py b/tests/functional/m/member/member_checks.py new file mode 100644 index 000000000..291daee12 --- /dev/null +++ b/tests/functional/m/member/member_checks.py @@ -0,0 +1,233 @@ +# pylint: disable=print-statement,missing-docstring,no-self-use,too-few-public-methods,bare-except,broad-except, useless-object-inheritance +# pylint: disable=using-constant-test,expression-not-assigned, assigning-non-slot, unused-variable,pointless-statement, wrong-import-order, wrong-import-position,import-outside-toplevel +from __future__ import print_function +class Provider(object): + """provide some attributes and method""" + cattr = 4 + def __init__(self): + self.attr = 4 + def method(self, val): + """impressive method""" + return self.attr * val + def hophop(self): + """hop method""" + print('hop hop hop', self) + + +class Client(object): + """use provider class""" + + def __init__(self): + self._prov = Provider() + self._prov_attr = Provider.cattr + self._prov_attr2 = Provider.cattribute # [no-member] + self.set_later = 0 + + def set_set_later(self, value): + """set set_later attribute (introduce an inference ambiguity)""" + self.set_later = value + + def use_method(self): + """use provider's method""" + self._prov.hophop() + self._prov.hophophop() # [no-member] + + def use_attr(self): + """use provider's attr""" + print(self._prov.attr) + print(self._prov.attribute) # [no-member] + + def debug(self): + """print debug information""" + print(self.__class__.__name__) + print(self.__doc__) + print(self.__dict__) + print(self.__module__) + + def test_bt_types(self): + """test access to unexistant member of builtin types""" + lis = [] + lis.apppend(self) # [no-member] + dic = {} + dic.set(self) # [no-member] + tup = () + tup.append(self) # [no-member] + string = 'toto' + print(string.loower()) # [no-member] + integer = 1 + print(integer.whatever) # [no-member] + + def test_no_false_positives(self): + none = None + print(none.whatever) + # No misssing in the parents. + super().misssing() # [no-member] + + +class Mixin(object): + """No no-member should be emitted for mixins.""" + +class Getattr(object): + """no-member shouldn't be emitted for classes with dunder getattr.""" + + def __getattr__(self, attr): + return self.__dict__[attr] + + +class Getattribute(object): + """no-member shouldn't be emitted for classes with dunder getattribute.""" + + def __getattribute__(self, attr): + return 42 + +print(object.__init__) +print(property.__init__) +print(Client().set_later.lower()) +print(Mixin().nanana()) +print(Getattr().nananan()) +print(Getattribute().batman()) + +try: + Client().missing_method() +except AttributeError: + pass + +try: + Client().indeed() # [no-member] +except ImportError: + pass + +try: + Client.missing() +except AttributeError: + Client.missing() # [no-member] + +try: + Client.missing() +except AttributeError: + try: + Client.missing() # [no-member] + except ValueError: + pass + +try: + if Client: + Client().missing() +except AttributeError: + pass + +try: + Client().indeed() +except AttributeError: + try: + Client.missing() # [no-member] + except Exception: + pass + + +class SuperChecks(str, str): # pylint: disable=duplicate-bases + """Don't fail when the MRO is invalid.""" + def test(self): + super().lalala() + +type(Client()).ala # [no-member] +type({}).bala # [no-member] +type('').portocala # [no-member] + + +def socket_false_positive(): + """Test a regression + Version used: + + - Pylint 0.10.0 + - Logilab common 0.15.0 + - Logilab astroid 0.15.1 + + False E1101 positive, line 23: + Instance of '_socketobject' has no 'connect' member + """ + + import socket + sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sckt.connect(('127.0.0.1', 80)) + sckt.close() + + +def no_conjugate_member(magic_flag): + """should not raise E1101 on something.conjugate""" + if magic_flag: + something = 1.0 + else: + something = 1.0j + if isinstance(something, float): + return something + return something.conjugate() + + +class NoDunderNameInInstance(object): + """Emit a warning when accessing __name__ from an instance.""" + def __init__(self): + self.var = self.__name__ # [no-member] + + +class InvalidAccessBySlots(object): + __slots__ = ('a', ) + def __init__(self): + var = self.teta # [no-member] + self.teta = 24 + + +class MetaWithDynamicGetattr(type): + + def __getattr__(cls, attr): + return attr + + +class SomeClass(object, metaclass=MetaWithDynamicGetattr): + pass + + +SomeClass.does_not_exist + +class ClassWithMangledAttribute(object): + def __init__(self): + self.name = 'Bug1643' + def __bar(self): + print(self.name + "xD") + +ClassWithMangledAttribute()._ClassWithMangledAttribute__bar() # pylint: disable=protected-access + + +import enum + + +class Cls(enum.IntEnum): + BAR = 0 + + +SOME_VALUE = Cls.BAZ # [no-member] + + + +# Does not crash when inferring the `append` attribute on the slice object +class SomeClassUsingSlice: + def __init__(self, flag): + if flag: + self.attribute = slice(None) + else: + self.attribute = [] + self.attribute.append(1) + +from enum import Enum +class Animal(Enum): + ANT = 1 + BEE = 2 + CAT = 3 + DOG = 4 +# To test false positive no-member on Enum.__members__.items() +for itm in Animal.__members__.items(): + print(itm) +for keyy in Animal.__members__.keys: + print(keyy) +for vall in Animal.__members__.values: + print(vall) diff --git a/tests/functional/m/member/member_checks.txt b/tests/functional/m/member/member_checks.txt new file mode 100644 index 000000000..0b7ee9478 --- /dev/null +++ b/tests/functional/m/member/member_checks.txt @@ -0,0 +1,19 @@ +no-member:23:27:Client.__init__:Class 'Provider' has no 'cattribute' member:INFERENCE +no-member:33:8:Client.use_method:Instance of 'Provider' has no 'hophophop' member:INFERENCE +no-member:38:14:Client.use_attr:Instance of 'Provider' has no 'attribute' member:INFERENCE +no-member:50:8:Client.test_bt_types:Instance of 'list' has no 'apppend' member; maybe 'append'?:INFERENCE +no-member:52:8:Client.test_bt_types:Instance of 'dict' has no 'set' member; maybe 'get'?:INFERENCE +no-member:54:8:Client.test_bt_types:Instance of 'tuple' has no 'append' member:INFERENCE +no-member:56:14:Client.test_bt_types:Instance of 'str' has no 'loower' member; maybe 'lower'?:INFERENCE +no-member:58:14:Client.test_bt_types:Instance of 'int' has no 'whatever' member:INFERENCE +no-member:64:8:Client.test_no_false_positives:Super of 'Client' has no 'misssing' member:INFERENCE +no-member:96:4::Instance of 'Client' has no 'indeed' member:INFERENCE +no-member:103:4::Class 'Client' has no 'missing' member:INFERENCE +no-member:109:8::Class 'Client' has no 'missing' member:INFERENCE +no-member:123:8::Class 'Client' has no 'missing' member:INFERENCE +no-member:133:0::Class 'Client' has no 'ala' member:INFERENCE +no-member:134:0::Class 'dict' has no 'bala' member:INFERENCE +no-member:135:0::Class 'str' has no 'portocala' member:INFERENCE +no-member:170:19:NoDunderNameInInstance.__init__:Instance of 'NoDunderNameInInstance' has no '__name__' member:INFERENCE +no-member:176:14:InvalidAccessBySlots.__init__:Instance of 'InvalidAccessBySlots' has no 'teta' member:INFERENCE +no-member:208:13::Class 'Cls' has no 'BAZ' member; maybe 'BAR'?:INFERENCE diff --git a/tests/functional/m/member/member_checks_hints.py b/tests/functional/m/member/member_checks_hints.py new file mode 100644 index 000000000..3925f4741 --- /dev/null +++ b/tests/functional/m/member/member_checks_hints.py @@ -0,0 +1,27 @@ +# pylint: disable=missing-docstring, too-few-public-methods, pointless-statement, useless-object-inheritance + + +class Parent(object): + + def __init__(self): + self._parent = 42 + self._registry = {} + self._similar1 = 24 + self._similar2 = 23 + self._similar3 = 24 + self._really_similar1 = 23 + self._really_similar2 = 42 + + +class Child(Parent): + + def __init__(self): + super().__init__() + + self._similar # [no-member] + self._really_similar # [no-member] + self._paren # [no-member] + # Distance is too big + self._registryyyy # [no-member] + # Nothing close. + self._pretty_sure_this_wont_match # [no-member] diff --git a/tests/functional/m/member/member_checks_hints.rc b/tests/functional/m/member/member_checks_hints.rc new file mode 100644 index 000000000..8d4b587f4 --- /dev/null +++ b/tests/functional/m/member/member_checks_hints.rc @@ -0,0 +1,3 @@ +[TYPECHECK] +missing-member-max-choices = 3 +missing-member-hint-distance = 1 diff --git a/tests/functional/m/member/member_checks_hints.txt b/tests/functional/m/member/member_checks_hints.txt new file mode 100644 index 000000000..9dd977b13 --- /dev/null +++ b/tests/functional/m/member/member_checks_hints.txt @@ -0,0 +1,5 @@ +no-member:21:8:Child.__init__:Instance of 'Child' has no '_similar' member; maybe one of '_similar1', '_similar2' or '_similar3'?:INFERENCE +no-member:22:8:Child.__init__:Instance of 'Child' has no '_really_similar' member; maybe one of '_really_similar1' or '_really_similar2'?:INFERENCE +no-member:23:8:Child.__init__:Instance of 'Child' has no '_paren' member; maybe '_parent'?:INFERENCE +no-member:25:8:Child.__init__:Instance of 'Child' has no '_registryyyy' member:INFERENCE +no-member:27:8:Child.__init__:Instance of 'Child' has no '_pretty_sure_this_wont_match' member:INFERENCE diff --git a/tests/functional/m/member/member_checks_ignore_none.py b/tests/functional/m/member/member_checks_ignore_none.py new file mode 100644 index 000000000..06f01cb6a --- /dev/null +++ b/tests/functional/m/member/member_checks_ignore_none.py @@ -0,0 +1,7 @@ +# pylint: disable=missing-docstring, useless-return + +def func(): + return None + + +SOME_VAR = func().DOES_NOT_EXIST # [no-member] diff --git a/tests/functional/m/member/member_checks_ignore_none.rc b/tests/functional/m/member/member_checks_ignore_none.rc new file mode 100644 index 000000000..9ec706ec6 --- /dev/null +++ b/tests/functional/m/member/member_checks_ignore_none.rc @@ -0,0 +1,2 @@ +[TYPECHECK] +ignore-none=no diff --git a/tests/functional/m/member/member_checks_ignore_none.txt b/tests/functional/m/member/member_checks_ignore_none.txt new file mode 100644 index 000000000..ead0e7efe --- /dev/null +++ b/tests/functional/m/member/member_checks_ignore_none.txt @@ -0,0 +1 @@ +no-member:7:11::Instance of 'NoneType' has no 'DOES_NOT_EXIST' member:INFERENCE diff --git a/tests/functional/m/member/member_checks_inference_improvements.py b/tests/functional/m/member/member_checks_inference_improvements.py new file mode 100644 index 000000000..6eefa7958 --- /dev/null +++ b/tests/functional/m/member/member_checks_inference_improvements.py @@ -0,0 +1,11 @@ +# pylint: disable=missing-docstring + + +def test_oserror_has_strerror(): + # https://github.com/PyCQA/pylint/issues/2553 + try: + raise OSError() + except OSError as exc: + if exc.strerror is not None: + return exc.strerror.lower() + return None diff --git a/tests/functional/m/member/member_checks_no_hints.py b/tests/functional/m/member/member_checks_no_hints.py new file mode 100644 index 000000000..3925f4741 --- /dev/null +++ b/tests/functional/m/member/member_checks_no_hints.py @@ -0,0 +1,27 @@ +# pylint: disable=missing-docstring, too-few-public-methods, pointless-statement, useless-object-inheritance + + +class Parent(object): + + def __init__(self): + self._parent = 42 + self._registry = {} + self._similar1 = 24 + self._similar2 = 23 + self._similar3 = 24 + self._really_similar1 = 23 + self._really_similar2 = 42 + + +class Child(Parent): + + def __init__(self): + super().__init__() + + self._similar # [no-member] + self._really_similar # [no-member] + self._paren # [no-member] + # Distance is too big + self._registryyyy # [no-member] + # Nothing close. + self._pretty_sure_this_wont_match # [no-member] diff --git a/tests/functional/m/member/member_checks_no_hints.rc b/tests/functional/m/member/member_checks_no_hints.rc new file mode 100644 index 000000000..0f9c9ca3b --- /dev/null +++ b/tests/functional/m/member/member_checks_no_hints.rc @@ -0,0 +1,2 @@ +[TYPECHECK] +missing-member-hint=no diff --git a/tests/functional/m/member/member_checks_no_hints.txt b/tests/functional/m/member/member_checks_no_hints.txt new file mode 100644 index 000000000..6d818641e --- /dev/null +++ b/tests/functional/m/member/member_checks_no_hints.txt @@ -0,0 +1,5 @@ +no-member:21:8:Child.__init__:Instance of 'Child' has no '_similar' member:INFERENCE +no-member:22:8:Child.__init__:Instance of 'Child' has no '_really_similar' member:INFERENCE +no-member:23:8:Child.__init__:Instance of 'Child' has no '_paren' member:INFERENCE +no-member:25:8:Child.__init__:Instance of 'Child' has no '_registryyyy' member:INFERENCE +no-member:27:8:Child.__init__:Instance of 'Child' has no '_pretty_sure_this_wont_match' member:INFERENCE diff --git a/tests/functional/m/member/member_checks_opaque.py b/tests/functional/m/member/member_checks_opaque.py new file mode 100644 index 000000000..9b592af64 --- /dev/null +++ b/tests/functional/m/member/member_checks_opaque.py @@ -0,0 +1,12 @@ +# pylint: disable=missing-docstring,import-error + +from unknown import Unknown, some_value + + +def test(argument): + if argument: + return 42 + return Unknown + + +test(some_value).test() # [no-member] diff --git a/tests/functional/m/member/member_checks_opaque.rc b/tests/functional/m/member/member_checks_opaque.rc new file mode 100644 index 000000000..025cd2a0f --- /dev/null +++ b/tests/functional/m/member/member_checks_opaque.rc @@ -0,0 +1,2 @@ +[TYPECHECK] +ignore-on-opaque-inference=n diff --git a/tests/functional/m/member/member_checks_opaque.txt b/tests/functional/m/member/member_checks_opaque.txt new file mode 100644 index 000000000..2fabce4e2 --- /dev/null +++ b/tests/functional/m/member/member_checks_opaque.txt @@ -0,0 +1 @@ +no-member:12:0::Instance of 'int' has no 'test' member:INFERENCE diff --git a/tests/functional/m/member/member_checks_py37.py b/tests/functional/m/member/member_checks_py37.py new file mode 100644 index 000000000..8d59b7d80 --- /dev/null +++ b/tests/functional/m/member/member_checks_py37.py @@ -0,0 +1,19 @@ +# pylint: disable=missing-docstring +import collections +import asyncio + +isinstance([], collections.Iterable) + + +async def gen(): + await asyncio.sleep(0.1) + value = yield 42 + print(value) + await asyncio.sleep(0.2) + + +async def test(): + generator = gen() + + await generator.asend(None) + await generator.send(None) # [no-member] diff --git a/tests/functional/m/member/member_checks_py37.rc b/tests/functional/m/member/member_checks_py37.rc new file mode 100644 index 000000000..a17bb22da --- /dev/null +++ b/tests/functional/m/member/member_checks_py37.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.7 diff --git a/tests/functional/m/member/member_checks_py37.txt b/tests/functional/m/member/member_checks_py37.txt new file mode 100644 index 000000000..c52eab13c --- /dev/null +++ b/tests/functional/m/member/member_checks_py37.txt @@ -0,0 +1 @@ +no-member:19:10:test:AsyncGenerator 'async_generator' has no 'send' member; maybe 'asend'?:INFERENCE diff --git a/tests/functional/m/member/member_checks_typed_annotations.py b/tests/functional/m/member/member_checks_typed_annotations.py new file mode 100644 index 000000000..90f775a43 --- /dev/null +++ b/tests/functional/m/member/member_checks_typed_annotations.py @@ -0,0 +1,25 @@ +# pylint: disable=missing-docstring,invalid-name,too-few-public-methods +class A: + myfield: int + +class B(A): + pass + +class C: + pass + +class D(C, B): + pass + + +a = A() +print(a.myfield) + +b = B() +print(b.myfield) + +d = D() +print(d.myfield) + +c = C() +print(c.myfield) # [no-member] diff --git a/tests/functional/m/member/member_checks_typed_annotations.txt b/tests/functional/m/member/member_checks_typed_annotations.txt new file mode 100644 index 000000000..6261a31aa --- /dev/null +++ b/tests/functional/m/member/member_checks_typed_annotations.txt @@ -0,0 +1 @@ +no-member:25:6::Instance of 'C' has no 'myfield' member:INFERENCE diff --git a/tests/functional/m/member/membership_protocol.py b/tests/functional/m/member/membership_protocol.py new file mode 100644 index 000000000..3401f4bb4 --- /dev/null +++ b/tests/functional/m/member/membership_protocol.py @@ -0,0 +1,123 @@ +# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,too-few-public-methods,import-error,no-init,wrong-import-position,no-else-return, comparison-with-itself, useless-object-inheritance + +# standard types +1 in [1, 2, 3] +1 in {'a': 1, 'b': 2} +1 in {1, 2, 3} +1 in (1, 2, 3) +'1' in "123" +'1' in u"123" +'1' in bytearray(b"123") +1 in frozenset([1, 2, 3]) + +# comprehensions +1 in [x ** 2 % 10 for x in range(10)] +1 in {x ** 2 % 10 for x in range(10)} +1 in {x: x ** 2 % 10 for x in range(10)} + +# iterators +1 in iter([1, 2, 3]) + +# generator +def count(upto=float("inf")): + i = 0 + while True: + if i > upto: + break + yield i + i += 1 + +10 in count(upto=10) + +# custom instance +class UniversalContainer(object): + def __contains__(self, key): + return True + +42 in UniversalContainer() + +# custom iterable +class CustomIterable(object): + def __iter__(self): + return iter((1, 2, 3)) +3 in CustomIterable() + +# old-style iterable +class OldStyleIterable(object): + def __getitem__(self, key): + if key < 10: + return 2 ** key + else: + raise IndexError("bad index") +64 in OldStyleIterable() + +# do not emit warning if class has unknown bases +from some_missing_module import ImportedClass + +class MaybeIterable(ImportedClass): + pass + +10 in MaybeIterable() + +# do not emit warning inside mixins/abstract/base classes +class UsefulMixin(object): + stuff = None + + def get_stuff(self): + return self.stuff + + def act(self, thing): + stuff = self.get_stuff() + if thing in stuff: + pass + +class BaseThing(object): + valid_values = None + + def validate(self, value): + if self.valid_values is None: + return True + else: + # error should not be emitted here + return value in self.valid_values + +class AbstractThing(object): + valid_values = None + + def validate(self, value): + if self.valid_values is None: + return True + else: + # error should not be emitted here + return value in self.valid_values + +# class is not named as abstract +# but still is deduceably abstract +class Thing(object): + valid_values = None + + def __init__(self): + self._init_values() + + def validate(self, value): + if self.valid_values is None: + return True + else: + # error should not be emitted here + return value in self.valid_values + + def _init_values(self): + raise NotImplementedError + +# error cases +42 in 42 # [unsupported-membership-test] +42 not in None # [unsupported-membership-test] +42 in 8.5 # [unsupported-membership-test] + +class EmptyClass(object): + pass + +42 not in EmptyClass() # [unsupported-membership-test] +42 in EmptyClass # [unsupported-membership-test] +42 not in count # [unsupported-membership-test] +42 in range # [unsupported-membership-test] diff --git a/tests/functional/m/member/membership_protocol.txt b/tests/functional/m/member/membership_protocol.txt new file mode 100644 index 000000000..e021062da --- /dev/null +++ b/tests/functional/m/member/membership_protocol.txt @@ -0,0 +1,7 @@ +unsupported-membership-test:113:6::Value '42' doesn't support membership test +unsupported-membership-test:114:10::Value 'None' doesn't support membership test +unsupported-membership-test:115:6::Value '8.5' doesn't support membership test +unsupported-membership-test:120:10::Value 'EmptyClass()' doesn't support membership test +unsupported-membership-test:121:6::Value 'EmptyClass' doesn't support membership test +unsupported-membership-test:122:10::Value 'count' doesn't support membership test +unsupported-membership-test:123:6::Value 'range' doesn't support membership test diff --git a/tests/functional/m/member/membership_protocol_py3.py b/tests/functional/m/member/membership_protocol_py3.py new file mode 100644 index 000000000..678072354 --- /dev/null +++ b/tests/functional/m/member/membership_protocol_py3.py @@ -0,0 +1,36 @@ +# pylint: disable=missing-docstring,too-few-public-methods,no-init,no-self-use,unused-argument,pointless-statement,expression-not-assigned + +# metaclasses that support membership test protocol +class MetaIterable(type): + def __iter__(cls): + return iter((1, 2, 3)) + +class MetaOldIterable(type): + def __getitem__(cls, key): + if key < 10: + return key ** 2 + + raise IndexError("bad index") + +class MetaContainer(type): + def __contains__(cls, key): + return False + + +class IterableClass(metaclass=MetaOldIterable): + pass + +class OldIterableClass(metaclass=MetaOldIterable): + pass + +class ContainerClass(metaclass=MetaContainer): + pass + + +def test(): + 1 in IterableClass + 1 in OldIterableClass + 1 in ContainerClass + 1 in IterableClass() # [unsupported-membership-test] + 1 in OldIterableClass() # [unsupported-membership-test] + 1 in ContainerClass() # [unsupported-membership-test] diff --git a/tests/functional/m/member/membership_protocol_py3.rc b/tests/functional/m/member/membership_protocol_py3.rc new file mode 100644 index 000000000..c093be204 --- /dev/null +++ b/tests/functional/m/member/membership_protocol_py3.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.0 diff --git a/tests/functional/m/member/membership_protocol_py3.txt b/tests/functional/m/member/membership_protocol_py3.txt new file mode 100644 index 000000000..495cf94db --- /dev/null +++ b/tests/functional/m/member/membership_protocol_py3.txt @@ -0,0 +1,3 @@ +unsupported-membership-test:34:9:test:Value 'IterableClass()' doesn't support membership test +unsupported-membership-test:35:9:test:Value 'OldIterableClass()' doesn't support membership test +unsupported-membership-test:36:9:test:Value 'ContainerClass()' doesn't support membership test |