From e17862654fc0585e63f5ab6785eab23787e91e9b Mon Sep 17 00:00:00 2001 From: doranid Date: Sun, 1 Aug 2021 22:04:46 +0300 Subject: [PATCH] Don't calculate slots when MRO parsing fails. (#1089) * Don't calculate slots when MRO parsing fails. * Added changelog entry. Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Pierre Sassoulas --- ChangeLog | 4 ++++ astroid/scoped_nodes.py | 16 +++++++++++++--- tests/unittest_scoped_nodes.py | 11 +++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index e65a4c4104..ca355f1b39 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,6 +44,10 @@ Release date: 2021-07-19 * Added ``If.is_sys_guard`` and ``If.is_typing_guard`` helper methods +* Fix handling of classes with duplicated bases with the same name + + Closes PyCQA/astroid#1088 + * Fix a bad inferenece type for yield values inside of a derived class. Closes PyCQA/astroid#1090 diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.py index c7c287798c..910d303564 100644 --- a/astroid/scoped_nodes.py +++ b/astroid/scoped_nodes.py @@ -42,6 +42,7 @@ import builtins import io import itertools +import typing from typing import List, Optional from astroid import bases @@ -2906,9 +2907,11 @@ def slots(self): :rtype: list(str) or None """ - def grouped_slots(): + def grouped_slots( + mro: List["ClassDef"], + ) -> typing.Iterator[Optional[node_classes.NodeNG]]: # Not interested in object, since it can't have slots. - for cls in self.mro()[:-1]: + for cls in mro[:-1]: try: cls_slots = cls._slots() except NotImplementedError: @@ -2923,7 +2926,14 @@ def grouped_slots(): "The concept of slots is undefined for old-style classes." ) - slots = list(grouped_slots()) + try: + mro = self.mro() + except MroError as e: + raise NotImplementedError( + "Cannot get slots while parsing mro fails." + ) from e + + slots = list(grouped_slots(mro)) if not all(slot is not None for slot in slots): return None diff --git a/tests/unittest_scoped_nodes.py b/tests/unittest_scoped_nodes.py index 8fd890d163..56e1ed2996 100644 --- a/tests/unittest_scoped_nodes.py +++ b/tests/unittest_scoped_nodes.py @@ -2230,5 +2230,16 @@ class C(B[str]): pass ] +def test_slots_duplicate_bases_issue_1089(): + astroid = builder.parse( + """ + class First(object, object): #@ + pass + """ + ) + with pytest.raises(NotImplementedError): + astroid["First"].slots() + + if __name__ == "__main__": unittest.main()