diff options
author | Michal Nowikowski <godfryd@gmail.com> | 2014-08-14 17:00:04 +0200 |
---|---|---|
committer | Michal Nowikowski <godfryd@gmail.com> | 2014-08-14 17:00:04 +0200 |
commit | aa87ee9e70d9f6a4ab037b67e8646f7237acfb46 (patch) | |
tree | a5f4e33367c5ea953411de44e55bebba47739f69 | |
parent | bf0467a41888a17bfa7f49463140cd800c07b308 (diff) | |
parent | 2cc172844e311f820c4582232d0cd0c3c9366c9b (diff) | |
download | pylint-aa87ee9e70d9f6a4ab037b67e8646f7237acfb46.tar.gz |
Merged default into make
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | checkers/typecheck.py | 14 | ||||
-rw-r--r-- | doc/installation.rst | 7 | ||||
-rw-r--r-- | test/functional/class_members_py27.py | 51 | ||||
-rw-r--r-- | test/functional/class_members_py27.rc | 3 | ||||
-rw-r--r-- | test/functional/class_members_py27.txt | 6 | ||||
-rw-r--r-- | test/functional/class_members_py30.py | 49 | ||||
-rw-r--r-- | test/functional/class_members_py30.rc | 2 | ||||
-rw-r--r-- | test/functional/class_members_py30.txt | 6 | ||||
-rw-r--r-- | test/input/func_class_members.py | 32 | ||||
-rw-r--r-- | test/messages/func_class_members.txt | 4 |
11 files changed, 137 insertions, 40 deletions
@@ -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 |