From 6354d5ab66c119ed05ec3faa71c27a520b862e3d Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Wed, 30 Sep 2015 15:48:22 +0300 Subject: Don't consider a class abstract if its members can't be properly inferred. This fixes a false positive related to abstract-class-instantiated. Closes issue #648. --- ChangeLog | 6 ++++++ pylint/checkers/utils.py | 6 ++++++ .../functional/abstract_class_instantiated_py2.py | 21 ++++++++++++++++++--- .../functional/abstract_class_instantiated_py2.txt | 8 ++++---- .../functional/abstract_class_instantiated_py3.py | 20 +++++++++++++++++--- .../functional/abstract_class_instantiated_py3.txt | 8 ++++---- 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index abd0ad3..30365f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -303,6 +303,12 @@ ChangeLog for Pylint * 'deprecated-module' can be shown for modules which aren't available. Closes issue #362. + * Don't consider a class abstract if its members can't + be properly inferred. + + This fixes a false positive related to abstract-class-instantiated. + Closes issue #648. + 2015-03-14 -- 1.4.3 diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 767bba8..dda5f44 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -524,6 +524,12 @@ def unimplemented_abstract_methods(node, is_abstract_cb=None): if isinstance(obj, astroid.AssignName): infered = safe_infer(obj) if not infered: + # Might be an abstract function, + # but since we don't have enough information + # in order to take this decision, we're taking + # the *safe* decision instead. + if obj.name in visited: + del visited[obj.name] continue if not isinstance(infered, astroid.FunctionDef): if obj.name in visited: diff --git a/pylint/test/functional/abstract_class_instantiated_py2.py b/pylint/test/functional/abstract_class_instantiated_py2.py index 9b3f315..d30c1a5 100644 --- a/pylint/test/functional/abstract_class_instantiated_py2.py +++ b/pylint/test/functional/abstract_class_instantiated_py2.py @@ -5,12 +5,12 @@ abstract methods. # pylint: disable=too-few-public-methods, missing-docstring # pylint: disable=no-absolute-import, metaclass-assignment -# pylint: disable=abstract-method - -__revision__ = 0 +# pylint: disable=abstract-method, import-error, wildcard-import import abc from abc import ABCMeta +from lala import Bala + class GoodClass(object): __metaclass__ = abc.ABCMeta @@ -56,6 +56,20 @@ class FourthBadClass(ThirdBadClass): pass +class SomeMetaclass(object): + __metaclass__ = ABCMeta + + @abc.abstractmethod + def prop(self): + pass + +class FifthGoodClass(SomeMetaclass): + """Don't consider this abstract if some attributes are + there, but can't be inferred. + """ + prop = Bala # missing + + def main(): """ do nothing """ GoodClass() @@ -66,3 +80,4 @@ def main(): SecondBadClass() # [abstract-class-instantiated] ThirdBadClass() # [abstract-class-instantiated] FourthBadClass() # [abstract-class-instantiated] + diff --git a/pylint/test/functional/abstract_class_instantiated_py2.txt b/pylint/test/functional/abstract_class_instantiated_py2.txt index 68e7eb5..1e4a72d 100644 --- a/pylint/test/functional/abstract_class_instantiated_py2.txt +++ b/pylint/test/functional/abstract_class_instantiated_py2.txt @@ -1,4 +1,4 @@ -abstract-class-instantiated:65:main:Abstract class 'BadClass' with abstract methods instantiated -abstract-class-instantiated:66:main:Abstract class 'SecondBadClass' with abstract methods instantiated -abstract-class-instantiated:67:main:Abstract class 'ThirdBadClass' with abstract methods instantiated -abstract-class-instantiated:68:main:Abstract class 'FourthBadClass' with abstract methods instantiated +abstract-class-instantiated:79:main:Abstract class 'BadClass' with abstract methods instantiated +abstract-class-instantiated:80:main:Abstract class 'SecondBadClass' with abstract methods instantiated +abstract-class-instantiated:81:main:Abstract class 'ThirdBadClass' with abstract methods instantiated +abstract-class-instantiated:82:main:Abstract class 'FourthBadClass' with abstract methods instantiated diff --git a/pylint/test/functional/abstract_class_instantiated_py3.py b/pylint/test/functional/abstract_class_instantiated_py3.py index 0b2dd4a..f373189 100644 --- a/pylint/test/functional/abstract_class_instantiated_py3.py +++ b/pylint/test/functional/abstract_class_instantiated_py3.py @@ -4,12 +4,12 @@ abstract methods. """ # pylint: disable=too-few-public-methods, missing-docstring -# pylint: disable=abstract-method - -__revision__ = 0 +# pylint: disable=abstract-method, import-error import abc import weakref +from lala import Bala + class GoodClass(object, metaclass=abc.ABCMeta): pass @@ -82,11 +82,25 @@ class NoMroAbstractMethods(Container, Iterator, Sizable, Hashable): class BadMroAbstractMethods(Container, Iterator, AbstractSizable): pass +class SomeMetaclass(metaclass=abc.ABCMeta): + + @abc.abstractmethod + def prop(self): + pass + +class FourthGoodClass(SomeMetaclass): + """Don't consider this abstract if some attributes are + there, but can't be inferred. + """ + prop = Bala # missing + + def main(): """ do nothing """ GoodClass() SecondGoodClass() ThirdGoodClass() + FourthGoodClass() weakref.WeakKeyDictionary() weakref.WeakValueDictionary() NoMroAbstractMethods() diff --git a/pylint/test/functional/abstract_class_instantiated_py3.txt b/pylint/test/functional/abstract_class_instantiated_py3.txt index 6469929..629eec7 100644 --- a/pylint/test/functional/abstract_class_instantiated_py3.txt +++ b/pylint/test/functional/abstract_class_instantiated_py3.txt @@ -1,4 +1,4 @@ -abstract-class-instantiated:94:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated -abstract-class-instantiated:95:main:Abstract class 'BadClass' with abstract methods instantiated -abstract-class-instantiated:96:main:Abstract class 'SecondBadClass' with abstract methods instantiated -abstract-class-instantiated:97:main:Abstract class 'ThirdBadClass' with abstract methods instantiated +abstract-class-instantiated:108:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated +abstract-class-instantiated:109:main:Abstract class 'BadClass' with abstract methods instantiated +abstract-class-instantiated:110:main:Abstract class 'SecondBadClass' with abstract methods instantiated +abstract-class-instantiated:111:main:Abstract class 'ThirdBadClass' with abstract methods instantiated -- cgit v1.2.1