1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
class _SubscribedType(type):
"""
This class is a placeholder to let the IDE know the attributes of the
returned type after a __getitem__.
"""
__origin__ = None
__args__ = None
class SubscriptableType(type):
"""
This metaclass will allow a type to become subscriptable.
>>> class SomeType(metaclass=SubscriptableType):
... pass
>>> SomeTypeSub = SomeType['some args']
>>> SomeTypeSub.__args__
'some args'
>>> SomeTypeSub.__origin__.__name__
'SomeType'
"""
def __init_subclass__(mcs, **kwargs):
mcs._hash = None
mcs.__args__ = None
mcs.__origin__ = None
def __getitem__(self, item) -> _SubscribedType:
body = {
**self.__dict__,
'__args__': item,
'__origin__': self,
}
bases = self, *self.__bases__
result = type(self.__name__, bases, body)
if hasattr(result, '_after_subscription'):
# TODO check if _after_subscription is static
result._after_subscription(item)
return result
def __eq__(self, other):
self_args = getattr(self, '__args__', None)
self_origin = getattr(self, '__origin__', None)
other_args = getattr(other, '__args__', None)
other_origin = getattr(other, '__origin__', None)
return self_args == other_args and self_origin == other_origin
def __hash__(self):
if not getattr(self, '_hash', None):
self._hash = hash('{}{}'.format(self.__origin__, self.__args__))
return self._hash
|