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)