diff options
Diffstat (limited to 'scoped_nodes.py')
-rw-r--r-- | scoped_nodes.py | 54 |
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()) |