commit:     ab5772e6e32a35de6a9cda03282fb0757239bf3b
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Fri Nov 28 21:31:31 2025 +0000
Commit:     Brian Harring <ferringb <AT> gmail <DOT> com>
CommitDate: Fri Nov 28 21:46:48 2025 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/snakeoil.git/commit/?id=ab5772e6

chore: address diamond inheritance for get_subclasses_of

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>

 src/snakeoil/klass/util.py |  6 ++++++
 tests/klass/test_util.py   | 11 +++++++++++
 2 files changed, 17 insertions(+)

diff --git a/src/snakeoil/klass/util.py b/src/snakeoil/klass/util.py
index 689aca9..3f94117 100644
--- a/src/snakeoil/klass/util.py
+++ b/src/snakeoil/klass/util.py
@@ -107,9 +107,15 @@ def get_subclasses_of(
     """
     if is_metaclass(cls):
         return
+    seen = set()
     stack = cls.__subclasses__()
     while stack:
         current = stack.pop()
+        if (
+            current in seen
+        ):  # diamond inheritance can lead to seeing the same leaft multiple 
times.
+            continue
+        seen.add(current)
 
         subclasses = () if is_metaclass(current) else current.__subclasses__()
         stack.extend(subclasses)

diff --git a/tests/klass/test_util.py b/tests/klass/test_util.py
index 3b0799c..2a66cf8 100644
--- a/tests/klass/test_util.py
+++ b/tests/klass/test_util.py
@@ -172,6 +172,17 @@ def test_get_subclasses_of():
 
     assert_it(layer3, [ABClayer6], ABC=True, only_leaf_nodes=True)
 
+    # stupid diamond inheritance
+    class base: ...
+
+    class left(base): ...
+
+    class right(base): ...
+
+    class combined(left, right): ...
+
+    assert_it(base, [left, right, combined])
+
 
 def test_is_metaclass():
     assert not is_metaclass(object)

Reply via email to