diff options
author | Laura M?dioni <laura.medioni@logilab.fr> | 2015-10-29 11:17:35 +0100 |
---|---|---|
committer | Laura M?dioni <laura.medioni@logilab.fr> | 2015-10-29 11:17:35 +0100 |
commit | 171326299f836782edd6167ac15de4a738dd53f8 (patch) | |
tree | 6a9b372413d13f9c996702b758509b7a30af37de | |
parent | e2da1f9f3dbd9a6462e0549da75b37249467afb8 (diff) | |
download | pylint-171326299f836782edd6167ac15de4a738dd53f8.tar.gz |
check for static methods declared without a decorator
closes issue #675
-rw-r--r-- | CONTRIBUTORS.txt | 3 | ||||
-rw-r--r-- | pylint/checkers/classes.py | 17 | ||||
-rw-r--r-- | pylint/test/functional/bad_staticmethod_argument.py | 2 | ||||
-rw-r--r-- | pylint/test/functional/no_staticmethod_decorator.py | 28 | ||||
-rw-r--r-- | pylint/test/functional/no_staticmethod_decorator.txt | 1 | ||||
-rw-r--r-- | pylint/test/input/func_noerror_classes_protected_member_access.py | 2 | ||||
-rw-r--r-- | pylint/test/input/func_noerror_static_method.py | 2 |
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 """ |