summaryrefslogtreecommitdiff
path: root/pylint/checkers/classes.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylint/checkers/classes.py')
-rw-r--r--pylint/checkers/classes.py23
1 files changed, 23 insertions, 0 deletions
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 71041ea..0fc0fae 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -57,6 +57,25 @@ def _is_invalid_base_class(cls):
return cls.name in INVALID_BASE_CLASSES and is_builtin_object(cls)
+def _has_data_descriptor(cls, attr):
+ attributes = cls.getattr(attr)
+ for attribute in attributes:
+ try:
+ for inferred in attribute.infer():
+ if isinstance(inferred, astroid.Instance):
+ try:
+ inferred.getattr('__get__')
+ inferred.getattr('__set__')
+ except astroid.NotFoundError:
+ continue
+ else:
+ return True
+ except astroid.InferenceError:
+ # Can't infer, avoid emitting a false positive in this case.
+ return True
+ return False
+
+
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.
@@ -578,6 +597,10 @@ a metaclass class method.'}
# Properties circumvent the slots mechanism,
# so we should not emit a warning for them.
return
+ if (node.attrname in klass.locals
+ and _has_data_descriptor(klass, node.attrname)):
+ # Descriptors circumvent the slots mechanism as well.
+ return
self.add_message('assigning-non-slot',
args=(node.attrname, ), node=node)