diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2014-12-21 17:07:52 +0200 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2014-12-21 17:07:52 +0200 |
commit | fc12599809c8a7397bee2b49c8162b3c60e36db6 (patch) | |
tree | 271674821cebd7d0df96c4056f4e373cc38fae84 /checkers/classes.py | |
parent | 49da69cade967362dff9933929f82e5fe6890df4 (diff) | |
download | pylint-fc12599809c8a7397bee2b49c8162b3c60e36db6.tar.gz |
Use a mro traversal for finding abstract methods. Closes issue #415.
This patch adds a new unimplemented_abstract_methods in pylint.checkers.utils,
which is used to obtain all the abstract methods which weren't implemented
anywhere in the mro of a class. The code works now by traversing the mro, gathering
all abstract methods encountered at each step and resolving the implemented ones
through either definition or assignment. This disables a couple of false
positives on classes with complex hierarchies.
Diffstat (limited to 'checkers/classes.py')
-rw-r--r-- | checkers/classes.py | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/checkers/classes.py b/checkers/classes.py index 030bee6..f7a344e 100644 --- a/checkers/classes.py +++ b/checkers/classes.py @@ -30,7 +30,7 @@ from pylint.checkers import BaseChecker from pylint.checkers.utils import ( PYMETHODS, overrides_a_method, check_messages, is_attr_private, is_attr_protected, node_frame_class, safe_infer, is_builtin_object, - decorated_with_property) + decorated_with_property, unimplemented_abstract_methods) import six if sys.version_info >= (3, 0): @@ -800,21 +800,28 @@ a metaclass class method.'} """check that the given class node implements abstract methods from base classes """ + def is_abstract(method): + return method.is_abstract(pass_is_abstract=False) + # check if this class abstract if class_is_abstract(node): return - for method in node.methods(): + + methods = sorted( + unimplemented_abstract_methods(node, is_abstract).items(), + key=lambda item: item[0], + ) + for name, method in methods: owner = method.parent.frame() if owner is node: continue # owner is not this class, it must be a parent class # check that the ancestor's method is not abstract - if method.name in node.locals: + if name in node.locals: # it is redefined as an attribute or with a descriptor continue - if method.is_abstract(pass_is_abstract=False): - self.add_message('abstract-method', node=node, - args=(method.name, owner.name)) + self.add_message('abstract-method', node=node, + args=(name, owner.name)) def _check_interfaces(self, node): """check that the given class node really implements declared |