Created
February 5, 2024 10:07
-
-
Save elibixby/7fd8076b15a532f486a8f7e915cd023e to your computer and use it in GitHub Desktop.
Metaclass Protocol Registry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ProtocolEnum(type): | |
registry: Dict[Type[Protocol], Set[Type[Protocol]] = defaultdict(set) | |
def __new__(cls, name, bases, dct): | |
for base in bases: | |
if issubclass(base, Protocol) and not base is Protocol: | |
registry[base].add(cls) | |
return cls | |
@classmethod | |
def get_enum(cls, protocol: Type[Protocol]) -> Type[enum.Enum]: | |
return enum.Enum(protocol.__name__, ((subprot.__name__: subprot.__name__) for subprot in registry[protocol])) | |
class MyFunProtocol(Protocol, meta=ProtocolEnum): | |
def foo(...): | |
pass | |
class MyThingy1(MyFunProtocol): | |
def foo(...): | |
print('yay') | |
class MyThingy2(MyFunProtocol): | |
def foo(...): | |
print('hooray') | |
>>>print(ProtocolEnum.get_enum(MyFunProtocol).__members__) | |
{'MyThingy1': 'MyThingy1', 'MyThingy2': 'MyThingy2'} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Obviously we'd want to use fully qualified names as values rather than just class names. (i.e.
f'{subprot.__module__.__name__}.{subprot.__name__}'
)Then retrieving the type object given an enum value is simple.