Skip to content

Instantly share code, notes, and snippets.

@elibixby
Created February 5, 2024 10:07
Show Gist options
  • Save elibixby/7fd8076b15a532f486a8f7e915cd023e to your computer and use it in GitHub Desktop.
Save elibixby/7fd8076b15a532f486a8f7e915cd023e to your computer and use it in GitHub Desktop.
Metaclass Protocol Registry
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'}
@elibixby
Copy link
Author

elibixby commented Feb 5, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment