summaryrefslogtreecommitdiff
path: root/scoped_nodes.py
diff options
context:
space:
mode:
Diffstat (limited to 'scoped_nodes.py')
-rw-r--r--scoped_nodes.py54
1 files changed, 54 insertions, 0 deletions
diff --git a/scoped_nodes.py b/scoped_nodes.py
index e354c5b8..95d45a5d 100644
--- a/scoped_nodes.py
+++ b/scoped_nodes.py
@@ -45,6 +45,8 @@ from astroid.mixins import FilterStmtsMixin
from astroid.bases import Statement
from astroid.manager import AstroidManager
+ITER_METHODS = ('__iter__', '__getitem__')
+
def remove_nodes(func, cls):
def wrapper(*args, **kwargs):
@@ -1133,3 +1135,55 @@ class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin):
if klass is not None:
break
return klass
+
+ def _islots(self):
+ """ Return an iterator with the inferred slots. """
+ if '__slots__' not in self.locals:
+ return
+ for slots in self.igetattr('__slots__'):
+ # check if __slots__ is a valid type
+ for meth in ITER_METHODS:
+ try:
+ slots.getattr(meth)
+ break
+ except NotFoundError:
+ continue
+ else:
+ continue
+
+ if isinstance(slots, Const):
+ # a string. Ignore the following checks,
+ # but yield the node, only if it has a value
+ if slots.value:
+ yield slots
+ continue
+ if not hasattr(slots, 'itered'):
+ # we can't obtain the values, maybe a .deque?
+ continue
+
+ if isinstance(slots, Dict):
+ values = [item[0] for item in slots.items]
+ else:
+ values = slots.itered()
+ if values is YES:
+ continue
+
+ for elt in values:
+ try:
+ for infered in elt.infer():
+ if infered is YES:
+ continue
+ if (not isinstance(infered, Const) or
+ not isinstance(infered.value, str)):
+ continue
+ if not infered.value:
+ continue
+ yield infered
+ except InferenceError:
+ continue
+
+ # Cached, because inferring them all the time is expensive
+ @cached
+ def slots(self):
+ """ Return all the slots for this node. """
+ return list(self._islots())