summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Nowikowski <godfryd@gmail.com>2014-08-14 17:00:04 +0200
committerMichal Nowikowski <godfryd@gmail.com>2014-08-14 17:00:04 +0200
commitaa87ee9e70d9f6a4ab037b67e8646f7237acfb46 (patch)
treea5f4e33367c5ea953411de44e55bebba47739f69
parentbf0467a41888a17bfa7f49463140cd800c07b308 (diff)
parent2cc172844e311f820c4582232d0cd0c3c9366c9b (diff)
downloadpylint-aa87ee9e70d9f6a4ab037b67e8646f7237acfb46.tar.gz
Merged default into make
-rw-r--r--ChangeLog3
-rw-r--r--checkers/typecheck.py14
-rw-r--r--doc/installation.rst7
-rw-r--r--test/functional/class_members_py27.py51
-rw-r--r--test/functional/class_members_py27.rc3
-rw-r--r--test/functional/class_members_py27.txt6
-rw-r--r--test/functional/class_members_py30.py49
-rw-r--r--test/functional/class_members_py30.rc2
-rw-r--r--test/functional/class_members_py30.txt6
-rw-r--r--test/input/func_class_members.py32
-rw-r--r--test/messages/func_class_members.txt4
11 files changed, 137 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index d533162..7b70fa7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -59,6 +59,9 @@ ChangeLog for Pylint
* Don't emit 'unused-import' when a special object is imported
(__all__, __doc__ etc.). Closes issue #309.
+
+ * Look in the metaclass, if defined, for members not found in the current
+ class. Closes issue #306.
2014-07-26 -- 1.3.0
diff --git a/checkers/typecheck.py b/checkers/typecheck.py
index 537a220..a8851a2 100644
--- a/checkers/typecheck.py
+++ b/checkers/typecheck.py
@@ -249,6 +249,20 @@ accessed. Python regular expressions are accepted.'}
# explicit skipping of module member access
if owner.root().name in self.config.ignored_modules:
continue
+ if isinstance(owner, astroid.Class):
+ # Look up in the metaclass only if the owner is itself
+ # a class.
+ # TODO: getattr doesn't return by default members
+ # from the metaclass, because handling various cases
+ # of methods accessible from the metaclass itself
+ # and/or subclasses only is too complicated for little to
+ # no benefit.
+ metaclass = owner.metaclass()
+ try:
+ if metaclass and metaclass.getattr(node.attrname):
+ continue
+ except NotFoundError:
+ pass
missingattr.add((owner, name))
continue
# stop on the first found
diff --git a/doc/installation.rst b/doc/installation.rst
index 5992bfc..56115c7 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -1,4 +1,3 @@
-
Installation
------------
@@ -67,12 +66,12 @@ directory, or on your system path. (*setup.py* install install *python.bat*
to the *Scripts* subdirectory of your Python installation -- e.g.
C:\Python24\Scripts.) You can do any of the following to solve this:
-1. change to the appropriate directory before running pylint.bat
+1. Change to the appropriate directory before running pylint.bat
-2. add the Scripts directory to your path statement in your autoexec.bat
+2. Add the Scripts directory to your path statement in your autoexec.bat
file (this file is found in the root directory of your boot-drive)
-3. create a 'redirect' batch file in a directory actually on your
+3. Create a 'redirect' batch file in a directory actually on your
systems path
To effect (2), simply append the appropriate directory name to the PATH=
diff --git a/test/functional/class_members_py27.py b/test/functional/class_members_py27.py
new file mode 100644
index 0000000..d60458b
--- /dev/null
+++ b/test/functional/class_members_py27.py
@@ -0,0 +1,51 @@
+""" Various tests for class members access. """
+# pylint: disable=R0903
+
+class MyClass(object):
+ """class docstring"""
+
+ def __init__(self):
+ """init"""
+ self.correct = 1
+
+ def test(self):
+ """test"""
+ self.correct += 2
+ self.incorrect += 2 # [no-member]
+ del self.havenot # [no-member]
+ self.nonexistent1.truc() # [no-member]
+ self.nonexistent2[1] = 'hehe' # [no-member]
+
+class XYZMixin(object):
+ """access to undefined members should be ignored in mixin classes by
+ default
+ """
+ def __init__(self):
+ print self.nonexistent
+
+
+class NewClass(object):
+ """use object.__setattr__"""
+ def __init__(self):
+ self.__setattr__('toto', 'tutu')
+
+from abc import ABCMeta
+
+class TestMetaclass(object):
+ """ Test attribute access for metaclasses. """
+ __metaclass__ = ABCMeta
+
+class Metaclass(type):
+ """ metaclass """
+ @classmethod
+ def test(mcs):
+ """ classmethod """
+
+class UsingMetaclass(object):
+ """ empty """
+ __metaclass__ = Metaclass
+
+TestMetaclass.register(int)
+UsingMetaclass.test()
+TestMetaclass().register(int) # [no-member]
+UsingMetaclass().test() # [no-member]
diff --git a/test/functional/class_members_py27.rc b/test/functional/class_members_py27.rc
new file mode 100644
index 0000000..80170b7
--- /dev/null
+++ b/test/functional/class_members_py27.rc
@@ -0,0 +1,3 @@
+[testoptions]
+min_pyver=2.7
+max_pyver=3.0 \ No newline at end of file
diff --git a/test/functional/class_members_py27.txt b/test/functional/class_members_py27.txt
new file mode 100644
index 0000000..3e88b55
--- /dev/null
+++ b/test/functional/class_members_py27.txt
@@ -0,0 +1,6 @@
+no-member:14:MyClass.test:Instance of 'MyClass' has no 'incorrect' member
+no-member:15:MyClass.test:Instance of 'MyClass' has no 'havenot' member
+no-member:16:MyClass.test:Instance of 'MyClass' has no 'nonexistent1' member
+no-member:17:MyClass.test:Instance of 'MyClass' has no 'nonexistent2' member
+no-member:50::Instance of 'TestMetaclass' has no 'register' member
+no-member:51::Instance of 'UsingMetaclass' has no 'test' member
diff --git a/test/functional/class_members_py30.py b/test/functional/class_members_py30.py
new file mode 100644
index 0000000..c9b2612
--- /dev/null
+++ b/test/functional/class_members_py30.py
@@ -0,0 +1,49 @@
+""" Various tests for class members access. """
+# pylint: disable=R0903
+
+class MyClass(object):
+ """class docstring"""
+
+ def __init__(self):
+ """init"""
+ self.correct = 1
+
+ def test(self):
+ """test"""
+ self.correct += 2
+ self.incorrect += 2 # [no-member]
+ del self.havenot # [no-member]
+ self.nonexistent1.truc() # [no-member]
+ self.nonexistent2[1] = 'hehe' # [no-member]
+
+class XYZMixin(object):
+ """access to undefined members should be ignored in mixin classes by
+ default
+ """
+ def __init__(self):
+ print self.nonexistent
+
+
+class NewClass(object):
+ """use object.__setattr__"""
+ def __init__(self):
+ self.__setattr__('toto', 'tutu')
+
+from abc import ABCMeta
+
+class TestMetaclass(object, metaclass=ABCMeta):
+ """ Test attribute access for metaclasses. """
+
+class Metaclass(type):
+ """ metaclass """
+ @classmethod
+ def test(mcs):
+ """ classmethod """
+
+class UsingMetaclass(object, metaclass=Metaclass):
+ """ empty """
+
+TestMetaclass.register(int)
+UsingMetaclass.test()
+TestMetaclass().register(int) # [no-member]
+UsingMetaclass().test() # [no-member]
diff --git a/test/functional/class_members_py30.rc b/test/functional/class_members_py30.rc
new file mode 100644
index 0000000..8c6eb56
--- /dev/null
+++ b/test/functional/class_members_py30.rc
@@ -0,0 +1,2 @@
+[testoptions]
+min_pyver=3.0 \ No newline at end of file
diff --git a/test/functional/class_members_py30.txt b/test/functional/class_members_py30.txt
new file mode 100644
index 0000000..0cb808f
--- /dev/null
+++ b/test/functional/class_members_py30.txt
@@ -0,0 +1,6 @@
+no-member:14:MyClass.test:Instance of 'MyClass' has no 'incorrect' member
+no-member:15:MyClass.test:Instance of 'MyClass' has no 'havenot' member
+no-member:16:MyClass.test:Instance of 'MyClass' has no 'nonexistent1' member
+no-member:17:MyClass.test:Instance of 'MyClass' has no 'nonexistent2' member
+no-member:48::Instance of 'TestMetaclass' has no 'register' member
+no-member:49::Instance of 'UsingMetaclass' has no 'test' member
diff --git a/test/input/func_class_members.py b/test/input/func_class_members.py
deleted file mode 100644
index ad147e5..0000000
--- a/test/input/func_class_members.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# pylint: disable=R0903
-"""test class members"""
-
-__revision__ = ''
-
-class MyClass(object):
- """class docstring"""
-
- def __init__(self):
- """init"""
- self.correct = 1
-
- def test(self):
- """test"""
- self.correct += 2
- self.incorrect += 2
- del self.havenot
- self.nonexistent1.truc()
- self.nonexistent2[1] = 'hehe'
-
-class XYZMixin(object):
- """access to undefined members should be ignored in mixin classes by
- default
- """
- def __init__(self):
- print self.nonexistent
-
-
-class NewClass(object):
- """use object.__setattr__"""
- def __init__(self):
- self.__setattr__('toto', 'tutu')
diff --git a/test/messages/func_class_members.txt b/test/messages/func_class_members.txt
deleted file mode 100644
index 054e21a..0000000
--- a/test/messages/func_class_members.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-E: 16:MyClass.test: Instance of 'MyClass' has no 'incorrect' member
-E: 17:MyClass.test: Instance of 'MyClass' has no 'havenot' member
-E: 18:MyClass.test: Instance of 'MyClass' has no 'nonexistent1' member
-E: 19:MyClass.test: Instance of 'MyClass' has no 'nonexistent2' member