summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaura M?dioni <laura.medioni@logilab.fr>2015-10-29 11:17:35 +0100
committerLaura M?dioni <laura.medioni@logilab.fr>2015-10-29 11:17:35 +0100
commit171326299f836782edd6167ac15de4a738dd53f8 (patch)
tree6a9b372413d13f9c996702b758509b7a30af37de
parente2da1f9f3dbd9a6462e0549da75b37249467afb8 (diff)
downloadpylint-171326299f836782edd6167ac15de4a738dd53f8.tar.gz
check for static methods declared without a decorator
closes issue #675
-rw-r--r--CONTRIBUTORS.txt3
-rw-r--r--pylint/checkers/classes.py17
-rw-r--r--pylint/test/functional/bad_staticmethod_argument.py2
-rw-r--r--pylint/test/functional/no_staticmethod_decorator.py28
-rw-r--r--pylint/test/functional/no_staticmethod_decorator.txt1
-rw-r--r--pylint/test/input/func_noerror_classes_protected_member_access.py2
-rw-r--r--pylint/test/input/func_noerror_static_method.py2
7 files changed, 46 insertions, 9 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 5409b8f..7dc35ab 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -73,4 +73,5 @@ Order doesn't matter (not that much, at least ;)
* Dmitry Pribysh: multiple-imports, not-iterable, not-a-mapping, various patches.
-* Laura Medioni (Logilab): misplaced-comparison-constant
+* Laura Medioni (Logilab, on behalf of the CNES): misplaced-comparison-constant,
+ no-classmethod-decorator, no-staticmethod-decorator
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 98a13bf..ee3c985 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -266,6 +266,10 @@ MSGS = {
'no-classmethod-decorator',
'Used when a class method is defined without using the decorator '
'syntax.'),
+ 'R0203': ('Consider using a decorator instead of calling staticmethod',
+ 'no-staticmethod-decorator',
+ 'Used when a static method is defined without using the decorator '
+ 'syntax.'),
}
@@ -616,7 +620,8 @@ a metaclass class method.'}
self.add_message('assigning-non-slot',
args=(node.attrname, ), node=node)
- @check_messages('protected-access', 'no-classmethod-decorator')
+ @check_messages('protected-access', 'no-classmethod-decorator',
+ 'no-staticmethod-decorator')
def visit_assign(self, assign_node):
self._check_classmethod_declaration(assign_node)
node = assign_node.targets[0]
@@ -637,10 +642,13 @@ a metaclass class method.'}
"""
if not isinstance(node.value, astroid.Call):
return
- # check the function called is "classmethod"
+ # check the function called is "classmethod" or "staticmethod"
func = node.value.func
- if not isinstance(func, astroid.Name) or not func.name == 'classmethod':
+ if (not isinstance(func, astroid.Name) or
+ func.name not in('classmethod', 'staticmethod')):
return
+ msg = ('no-classmethod-decorator' if func.name == 'classmethod' else
+ 'no-staticmethod-decorator')
# assignment must be at a class scope
parent_class = node.parent
if not isinstance(parent_class, astroid.ClassDef):
@@ -653,8 +661,7 @@ a metaclass class method.'}
for member in parent_class.get_children():
if (isinstance(member, astroid.FunctionDef) and
method_name == member.name):
- self.add_message('no-classmethod-decorator',
- node=node.targets[0])
+ self.add_message(msg, node=node.targets[0])
break
def _check_protected_attribute_access(self, node):
diff --git a/pylint/test/functional/bad_staticmethod_argument.py b/pylint/test/functional/bad_staticmethod_argument.py
index 0ff5d9b..a71a40e 100644
--- a/pylint/test/functional/bad_staticmethod_argument.py
+++ b/pylint/test/functional/bad_staticmethod_argument.py
@@ -1,4 +1,4 @@
-# pylint: disable=missing-docstring
+# pylint: disable=missing-docstring, no-staticmethod-decorator
class Abcd(object):
diff --git a/pylint/test/functional/no_staticmethod_decorator.py b/pylint/test/functional/no_staticmethod_decorator.py
new file mode 100644
index 0000000..636b2a5
--- /dev/null
+++ b/pylint/test/functional/no_staticmethod_decorator.py
@@ -0,0 +1,28 @@
+"""Checks static methods are declared with a decorator if whithin the class
+scope and if static method's argument is a member of the class
+"""
+
+# pylint: disable=too-few-public-methods
+
+class MyClass(object):
+ """Some class"""
+ def __init__(self):
+ pass
+
+ def smethod():
+ """static method-to-be"""
+ smethod = staticmethod(smethod) # [no-staticmethod-decorator]
+
+ @staticmethod
+ def my_second_method():
+ """correct static method definition"""
+
+def helloworld():
+ """says hello"""
+ print 'hello world'
+
+MyClass.new_static_method = staticmethod(helloworld)
+
+class MyOtherClass(object):
+ """Some other class"""
+ _make = staticmethod(tuple.__new__)
diff --git a/pylint/test/functional/no_staticmethod_decorator.txt b/pylint/test/functional/no_staticmethod_decorator.txt
new file mode 100644
index 0000000..b8d23ae
--- /dev/null
+++ b/pylint/test/functional/no_staticmethod_decorator.txt
@@ -0,0 +1 @@
+no-staticmethod-decorator:14:MyClass:Consider using a decorator instead of calling staticmethod
diff --git a/pylint/test/input/func_noerror_classes_protected_member_access.py b/pylint/test/input/func_noerror_classes_protected_member_access.py
index 670e3e8..2ffd9d1 100644
--- a/pylint/test/input/func_noerror_classes_protected_member_access.py
+++ b/pylint/test/input/func_noerror_classes_protected_member_access.py
@@ -3,7 +3,7 @@
"""
__revision__ = 1
-# pylint: disable=no-classmethod-decorator
+# pylint: disable=no-classmethod-decorator, no-staticmethod-decorator
class A3123(object):
"""oypuee"""
_protected = 1
diff --git a/pylint/test/input/func_noerror_static_method.py b/pylint/test/input/func_noerror_static_method.py
index 8a7a0a2..7457f45 100644
--- a/pylint/test/input/func_noerror_static_method.py
+++ b/pylint/test/input/func_noerror_static_method.py
@@ -3,7 +3,7 @@
from __future__ import print_function
__revision__ = ''
-#pylint: disable=no-classmethod-decorator
+#pylint: disable=no-classmethod-decorator, no-staticmethod-decorator
class MyClass(object):
"""doc
"""