From 966ca80bdcc9d8d2494d041ab67175f933b65c50 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Tue, 1 Nov 2022 22:01:32 +0100 Subject: [PATCH 1/3] Prevent returning an empty list for ``ClassDef.slots()`` when the mro list contains one class & it is not ``object``. Refs PyCQA/pylint#5099 --- ChangeLog | 4 ++++ astroid/nodes/scoped_nodes/scoped_nodes.py | 2 +- tests/unittest_brain.py | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) 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..b1f944c5a 100644 --- a/astroid/nodes/scoped_nodes/scoped_nodes.py +++ b/astroid/nodes/scoped_nodes/scoped_nodes.py @@ -2968,7 +2968,7 @@ 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 [cls for cls in mro if cls.qname() != "builtins.object"]: try: cls_slots = cls._slots() except NotImplementedError: diff --git a/tests/unittest_brain.py b/tests/unittest_brain.py index 114751c8d..520f181b6 100644 --- a/tests/unittest_brain.py +++ b/tests/unittest_brain.py @@ -1820,6 +1820,27 @@ 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( """ From cc661ccc3427e5c091433c9a0f28465badc37141 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:21:54 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/unittest_brain.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unittest_brain.py b/tests/unittest_brain.py index 520f181b6..079d98320 100644 --- a/tests/unittest_brain.py +++ b/tests/unittest_brain.py @@ -1820,7 +1820,6 @@ 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( From f48e7acea328b2be7ea6693f9b7f7c458a55b6c3 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Thu, 3 Nov 2022 12:41:47 +0100 Subject: [PATCH 3/3] Use Marc's suggestion from code review. Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- astroid/nodes/scoped_nodes/scoped_nodes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/astroid/nodes/scoped_nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes/scoped_nodes.py index b1f944c5a..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 [cls for cls in mro if cls.qname() != "builtins.object"]: + 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: