diff options
Diffstat (limited to 'pylint/checkers/classes.py')
-rw-r--r-- | pylint/checkers/classes.py | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py index 4dc00fe..6597602 100644 --- a/pylint/checkers/classes.py +++ b/pylint/checkers/classes.py @@ -25,6 +25,7 @@ from astroid import YES, Instance, are_exclusive, AssAttr, Class from astroid.bases import Generator, BUILTINS from astroid.exceptions import InconsistentMroError, DuplicateBasesError from astroid import objects +from astroid.scoped_nodes import function_to_method from pylint.interfaces import IAstroidChecker from pylint.checkers import BaseChecker @@ -43,6 +44,14 @@ else: NEXT_METHOD = 'next' ITER_METHODS = ('__iter__', '__getitem__') + +def _get_method_args(method): + args = method.args.args + if method.type == 'classmethod': + return len(args) - 1 + return len(args) + + def _called_in_methods(func, klass, methods): """ Check if the func was called in any of the given methods, belonging to the *klass*. Returns True if so, False otherwise. @@ -418,7 +427,7 @@ a metaclass class method.'} continue if not isinstance(meth_node, astroid.Function): continue - self._check_signature(node, meth_node, 'overridden') + self._check_signature(node, meth_node, 'overridden', klass) break if node.decorators: for decorator in node.decorators.nodes: @@ -832,23 +841,40 @@ a metaclass class method.'} continue self.add_message('super-init-not-called', args=klass.name, node=node) - def _check_signature(self, method1, refmethod, class_type): + def _check_signature(self, method1, refmethod, class_type, cls): """check that the signature of the two given methods match - """ + """ if not (isinstance(method1, astroid.Function) and isinstance(refmethod, astroid.Function)): self.add_message('method-check-failed', args=(method1, refmethod), node=method1) return - # don't care about functions with unknown argument (builtins) + + instance = cls.instanciate_class() + method1 = function_to_method(method1, instance) + refmethod = function_to_method(refmethod, instance) + + # Don't care about functions with unknown argument (builtins). if method1.args.args is None or refmethod.args.args is None: return - # if we use *args, **kwargs, skip the below checks + # If we use *args, **kwargs, skip the below checks. if method1.args.vararg or method1.args.kwarg: return + # Ignore private to class methods. if is_attr_private(method1.name): return - if len(method1.args.args) != len(refmethod.args.args): + # Ignore setters, they have an implicit extra argument, + # which shouldn't be taken in consideration. + if method1.decorators: + for decorator in method1.decorators.nodes: + if (isinstance(decorator, astroid.Getattr) and + decorator.attrname == 'setter'): + return + + method1_args = _get_method_args(method1) + refmethod_args = _get_method_args(refmethod) + + if method1_args != refmethod_args: self.add_message('arguments-differ', args=(class_type, method1.name), node=method1) |