Skip to content

Commit ca9fb7b

Browse files
authored
Merge pull request #110 from feature/converter-nested-subclasses
Find all converter subclasses / descendants
2 parents 6eaa0be + 6c8c639 commit ca9fb7b

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

src/undate/converters/base.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,25 @@ def available_converters(cls) -> Dict[str, Type["BaseDateConverter"]]:
114114
return {c.name: c for c in cls.subclasses()} # type: ignore
115115

116116
@classmethod
117-
def subclasses(cls) -> list[Type["BaseDateConverter"]]:
117+
def subclasses(cls) -> set[Type["BaseDateConverter"]]:
118118
"""
119-
List of available converters classes. Includes calendar convert
120-
subclasses.
119+
Set of available converters classes. Includes descendant
120+
subclasses, including calendar converters, but does not include
121+
:class:`BaseCalendarConverter`.
121122
"""
122123
# ensure undate converters are imported
123124
cls.import_converters()
124125

125126
# find all direct subclasses, excluding base calendar converter
126-
subclasses = cls.__subclasses__()
127-
subclasses.remove(BaseCalendarConverter)
128-
# add all subclasses of calendar converter base class
129-
subclasses.extend(BaseCalendarConverter.__subclasses__())
130-
return subclasses
127+
direct_subclasses = cls.__subclasses__()
128+
all_subclasses = set(direct_subclasses)
129+
# recurse to find nested subclasses
130+
for subc in direct_subclasses:
131+
all_subclasses |= subc.subclasses()
132+
133+
# omit the calendar converter base class, which is not itself a converter
134+
all_subclasses -= {BaseCalendarConverter}
135+
return all_subclasses
131136

132137

133138
class BaseCalendarConverter(BaseDateConverter):

tests/test_converters/test_base.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import pytest
44
from undate.converters.base import BaseDateConverter, BaseCalendarConverter
5+
from undate.converters.calendars import (
6+
GregorianDateConverter,
7+
HebrewDateConverter,
8+
HijriDateConverter,
9+
)
510

611

712
class TestBaseDateConverter:
@@ -29,6 +34,18 @@ def test_parse_to_string(self):
2934
with pytest.raises(NotImplementedError):
3035
BaseDateConverter().to_string(1991)
3136

37+
def test_subclasses(self):
38+
# define a nested subclass
39+
class SubSubConverter(HijriDateConverter):
40+
pass
41+
42+
subclasses = BaseDateConverter.subclasses()
43+
assert BaseCalendarConverter not in subclasses
44+
assert HijriDateConverter in subclasses
45+
assert HebrewDateConverter in subclasses
46+
assert GregorianDateConverter in subclasses
47+
assert SubSubConverter in subclasses
48+
3249

3350
def test_import_converters_import_only_once(caplog):
3451
# clear the cache, since any instantiation of an Undate

0 commit comments

Comments
 (0)