diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | pylint/checkers/typecheck.py | 13 | ||||
-rw-r--r-- | pylint/test/functional/member_checks.py | 12 | ||||
-rw-r--r-- | pylint/test/functional/member_checks.txt | 3 |
4 files changed, 34 insertions, 4 deletions
@@ -39,6 +39,16 @@ Release date: TBA Close #2494 +* ``no-member`` is emitted for enums when they lack a member + + Previously we weren't doing this because we detected a + ``__getattr__`` implementation on the ``Enum`` class + (and this check is skipped for classes with ``__getattr__``), + but that is fine for Enums, given that they are inferred in a customised + way in astroid. + + Close #2565 + What's New in Pylint 2.2.2? =========================== diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index c3ef6b490..976e7fa89 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -404,7 +404,17 @@ def _emit_no_member(node, owner, owner_name, ignored_mixins=True, ignored_none=T if isinstance(owner, astroid.FunctionDef) and owner.decorators: return False if isinstance(owner, (astroid.Instance, astroid.ClassDef)): - if owner.has_dynamic_getattr() or not has_known_bases(owner): + if owner.has_dynamic_getattr(): + # Issue #2565: Don't ignore enums, as they have a `__getattr__` but it's not + # invoked at this point. + try: + metaclass = owner.metaclass() + except exceptions.MroError: + return False + if metaclass: + return metaclass.qname() == "enum.EnumMeta" + return False + if not has_known_bases(owner): return False if isinstance(owner, objects.Super): # Verify if we are dealing with an invalid Super object. @@ -886,7 +896,6 @@ accessed. Python regular expressions are accepted.", ignored_mixins=self.config.ignore_mixin_members, ignored_none=self.config.ignore_none, ): - continue missingattr.add((owner, name)) continue diff --git a/pylint/test/functional/member_checks.py b/pylint/test/functional/member_checks.py index d4aef7c5f..cb6062676 100644 --- a/pylint/test/functional/member_checks.py +++ b/pylint/test/functional/member_checks.py @@ -1,5 +1,5 @@ # 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 +# pylint: disable=using-constant-test,expression-not-assigned, assigning-non-slot, unused-variable,pointless-statement, wrong-import-order, wrong-import-position from __future__ import print_function import six class Provider(object): @@ -197,3 +197,13 @@ class ClassWithMangledAttribute(object): 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] diff --git a/pylint/test/functional/member_checks.txt b/pylint/test/functional/member_checks.txt index bf5f2c2c8..dd2c927b9 100644 --- a/pylint/test/functional/member_checks.txt +++ b/pylint/test/functional/member_checks.txt @@ -15,4 +15,5 @@ no-member:134::Class 'Client' has no 'ala' member:INFERENCE no-member:135::Class 'dict' has no 'bala' member:INFERENCE no-member:136::Class 'str' has no 'portocala' member:INFERENCE no-member:171:NoDunderNameInInstance.__init__:Instance of 'NoDunderNameInInstance' has no '__name__' member:INFERENCE -no-member:177:InvalidAccessBySlots.__init__:Instance of 'InvalidAccessBySlots' has no 'teta' member:INFERENCE
\ No newline at end of file +no-member:177:InvalidAccessBySlots.__init__:Instance of 'InvalidAccessBySlots' has no 'teta' member:INFERENCE +no-member:209::Class 'Cls' has no 'Baz' member; maybe 'Bar'?:INFERENCE |