From a2dd8a6bc3f95679e1c2e79ce05d175fb8f89ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Wed, 8 Nov 2023 16:36:45 +0100 Subject: [PATCH] fix: Don't crash when computing MRO for a class that is named after its parent --- docs/loading.md | 24 ++++++++++++++++++++++-- src/griffe/dataclasses.py | 7 ++++++- tests/test_stdlib.py | 2 ++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/loading.md b/docs/loading.md index ae5794b8..6202083c 100644 --- a/docs/loading.md +++ b/docs/loading.md @@ -109,7 +109,7 @@ in extensions, while visiting or inspecting a module. ### Limitations -Currently, there are two limitations to our class inheritance support: +Currently, there are three limitations to our class inheritance support: 1. when visiting (static analysis), some objects are not yet properly recognized as classes, for example named tuples. If you inherit from a named tuple, @@ -123,7 +123,26 @@ Currently, there are two limitations to our class inheritance support: ... ``` -2. when inspecting (dynamic analysis), ephemeral base classes won't be resolved, +2. when visiting (static analysis), subclasses using the same name + as one of their parent class will prevent Griffe from computing the MRO + and therefore the inherited members. To circumvent that, give a + different name to your subclass: + + ```python + from package import SomeClass + + + # instead of + class SomeClass(SomeClass): + ... + + + # do + class SomeOtherClass(SomeClass): + ... + ``` + +3. when inspecting (dynamic analysis), ephemeral base classes won't be resolved, and therefore their members won't appear in child classes. To circumvent that, assign these dynamic classes to variables: @@ -141,4 +160,5 @@ Currently, there are two limitations to our class inheritance support: ... ``` + We will try to lift these limitations in the future. diff --git a/src/griffe/dataclasses.py b/src/griffe/dataclasses.py index 526954fc..c649bc3e 100644 --- a/src/griffe/dataclasses.py +++ b/src/griffe/dataclasses.py @@ -452,8 +452,13 @@ def inherited_members(self) -> dict[str, Alias]: """ if not isinstance(self, Class): return {} + try: + mro = self.mro() + except ValueError as error: + logger.debug(error) + return {} inherited_members = {} - for base in reversed(self.mro()): + for base in reversed(mro): for name, member in base.members.items(): if name not in self.members: inherited_members[name] = Alias(name, member, parent=self, inherited=True) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index e92903e2..dbaef319 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -39,3 +39,5 @@ def test_fuzzing_on_stdlib() -> None: loader.resolve_aliases(implicit=True, external=True) for module in loader.modules_collection.members.values(): _access_inherited_members(module) + + loader.stats()