From a48a9152dbb732562e42bd6c9cb79ef086c1088a Mon Sep 17 00:00:00 2001 From: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> Date: Thu, 3 Nov 2022 21:33:51 +0100 Subject: [PATCH] Prevent returning an empty list for `ClassDef.slots()` (#1861) Prevent returning an empty list for `ClassDef.slots()` when the mro list contains one class & it is not `object`. Refs PyCQA/pylint#5099 Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- ChangeLog | 4 ++++ astroid/nodes/scoped_nodes/scoped_nodes.py | 6 ++++-- tests/unittest_brain.py | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index faccd1456..faed12c04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,10 @@ What's New in astroid 2.13.0? Release date: TBA +* 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 475ae46b0..6c161fbe2 100644 --- a/astroid/nodes/scoped_nodes/scoped_nodes.py +++ b/astroid/nodes/scoped_nodes/scoped_nodes.py @@ -2959,8 +2959,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 d6d4ef5aa..2b0b7230c 100644 --- a/tests/unittest_brain.py +++ b/tests/unittest_brain.py @@ -1819,6 +1819,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( """