summaryrefslogtreecommitdiff
path: root/pylint/checkers/classes.py
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2019-03-11 16:26:43 +0100
committerClaudiu Popa <pcmanticore@gmail.com>2019-03-11 16:26:43 +0100
commit40e8ef97b13c62e36308185b30c82c808b177c30 (patch)
tree957b3f66b60f51ea804278680143963abc0ca906 /pylint/checkers/classes.py
parent00726c8a021df2845b20ae9ea7cb13aabb81438c (diff)
downloadpylint-git-40e8ef97b13c62e36308185b30c82c808b177c30.tar.gz
``assigning-non-slot`` not emitted for classes with unknown base classes.
It's possible to lint classes that don't have known bases (e.g. one of them might come from a C extension), in which case we cannot make a lot of assumptions about the class layout with respect to `__slots__`. As such, it's best to ignore these classes from this check. Close #2807
Diffstat (limited to 'pylint/checkers/classes.py')
-rw-r--r--pylint/checkers/classes.py72
1 files changed, 37 insertions, 35 deletions
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 273cc47d1..543b27ecf 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -1147,43 +1147,45 @@ a metaclass class method.",
""" Check that the given AssignAttr node
is defined in the class slots.
"""
- infered = safe_infer(node.expr)
- if infered and isinstance(infered, astroid.Instance):
- klass = infered._proxied
- if "__slots__" not in klass.locals or not klass.newstyle:
- return
+ inferred = safe_infer(node.expr)
+ if not isinstance(inferred, astroid.Instance):
+ return
- slots = klass.slots()
- if slots is None:
- return
- # If any ancestor doesn't use slots, the slots
- # defined for this class are superfluous.
- if any(
- "__slots__" not in ancestor.locals and ancestor.name != "object"
- for ancestor in klass.ancestors()
- ):
- return
+ klass = inferred._proxied
+ if not has_known_bases(klass):
+ return
+ if "__slots__" not in klass.locals or not klass.newstyle:
+ return
- if not any(slot.value == node.attrname for slot in slots):
- # If we have a '__dict__' in slots, then
- # assigning any name is valid.
- if not any(slot.value == "__dict__" for slot in slots):
- if _is_attribute_property(node.attrname, klass):
- # 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
- if node.attrname == "__class__" and _has_same_layout_slots(
- slots, node.parent.value
- ):
- return
- self.add_message(
- "assigning-non-slot", args=(node.attrname,), node=node
- )
+ slots = klass.slots()
+ if slots is None:
+ return
+ # If any ancestor doesn't use slots, the slots
+ # defined for this class are superfluous.
+ if any(
+ "__slots__" not in ancestor.locals and ancestor.name != "object"
+ for ancestor in klass.ancestors()
+ ):
+ return
+
+ if not any(slot.value == node.attrname for slot in slots):
+ # If we have a '__dict__' in slots, then
+ # assigning any name is valid.
+ if not any(slot.value == "__dict__" for slot in slots):
+ if _is_attribute_property(node.attrname, klass):
+ # 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
+ if node.attrname == "__class__" and _has_same_layout_slots(
+ slots, node.parent.value
+ ):
+ return
+ self.add_message("assigning-non-slot", args=(node.attrname,), node=node)
@check_messages(
"protected-access", "no-classmethod-decorator", "no-staticmethod-decorator"