summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-09-30 15:48:22 +0300
committerClaudiu Popa <pcmanticore@gmail.com>2015-09-30 15:48:22 +0300
commit6354d5ab66c119ed05ec3faa71c27a520b862e3d (patch)
treece06d717ea6a6d8029c43c652624d0ff61dda2b8
parentfd17d09f94aa286139723de9f86b5d04e7acf858 (diff)
downloadpylint-6354d5ab66c119ed05ec3faa71c27a520b862e3d.tar.gz
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.
-rw-r--r--ChangeLog6
-rw-r--r--pylint/checkers/utils.py6
-rw-r--r--pylint/test/functional/abstract_class_instantiated_py2.py21
-rw-r--r--pylint/test/functional/abstract_class_instantiated_py2.txt8
-rw-r--r--pylint/test/functional/abstract_class_instantiated_py3.py20
-rw-r--r--pylint/test/functional/abstract_class_instantiated_py3.txt8
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