diff --git a/ChangeLog b/ChangeLog index 00eec586d..f265e4d10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,10 @@ Release date: TBA Refs PyCQA/pylint#2567 +* Prevent returning an empty list for ``ClassDef.slots()`` when the mro list contains one class & it is not ``object``. + + Refs PyCQA/pylint#5099 + * Add ``_value2member_map_`` member to the ``enum`` brain. Refs PyCQA/pylint#3941 diff --git a/astroid/nodes/scoped_nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes/scoped_nodes.py index e3632d6d3..6022c6bac 100644 --- a/astroid/nodes/scoped_nodes/scoped_nodes.py +++ b/astroid/nodes/scoped_nodes/scoped_nodes.py @@ -2967,8 +2967,10 @@ def slots(self): def grouped_slots( mro: list[ClassDef], ) -> Iterator[node_classes.NodeNG | None]: - # Not interested in object, since it can't have slots. - for cls in mro[:-1]: + for cls in mro: + # Not interested in object, since it can't have slots. + if cls.qname() == "builtins.object": + continue try: cls_slots = cls._slots() except NotImplementedError: diff --git a/tests/unittest_brain.py b/tests/unittest_brain.py index 114751c8d..079d98320 100644 --- a/tests/unittest_brain.py +++ b/tests/unittest_brain.py @@ -1820,6 +1820,26 @@ def __init__(self, value): assert isinstance(slots[0], nodes.Const) assert slots[0].value == "value" + def test_collections_generic_alias_slots(self): + """Test slots for a class which is a subclass of a generic alias type.""" + node = builder.extract_node( + """ + import collections + import typing + Type = typing.TypeVar('Type') + class A(collections.abc.AsyncIterator[Type]): + __slots__ = ('_value',) + def __init__(self, value: collections.abc.AsyncIterator[Type]): + self._value = value + """ + ) + inferred = next(node.infer()) + assert isinstance(inferred, nodes.ClassDef) + slots = inferred.slots() + assert len(slots) == 1 + assert isinstance(slots[0], nodes.Const) + assert slots[0].value == "_value" + def test_has_dunder_args(self) -> None: ast_node = builder.extract_node( """