Created
October 17, 2021 12:20
-
-
Save jorenham/1c241a1cf33d2cc8235631b63fa8f279 to your computer and use it in GitHub Desktop.
Generic type argument matching on builtin collections using slicing syntax
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 FancyGeneric: | |
def __class_getitem__(cls, params): | |
if not isinstance(params, tuple): | |
params = (params,) | |
newparams = [] | |
for param in params: | |
if isinstance(param, slice): | |
assert param.start is None and param.step is None | |
type_pattern = param.stop | |
if isinstance(type_pattern, tuple): | |
assert len(type_pattern) > 0 | |
newparam = tuple[type_pattern] | |
elif isinstance(type_pattern, (list, set)): | |
newparam = list[tuple(type_pattern)] | |
elif isinstance(type_pattern, dict): | |
# I see potential for TypedDict's here | |
kv_type = next(iter(type_pattern.items())) | |
newparam = dict[kv_type] | |
else: | |
raise TypeError( | |
f'Type pattern parameters must be either a tuple, list, ' | |
f'set or dict, Got {type_pattern!r}.' | |
) | |
else: | |
newparam = param | |
newparams.append(newparam) | |
params_repr = ', '.join(map(repr, newparams)) | |
print(f'{cls.__name__}[{params_repr}]') | |
# return the generic alias here | |
# FancyGeneric[tuple[str, ...]] | |
TupleSpam = FancyGeneric[:(str, ...)] | |
# FancyGeneric[list[float]] | |
ListSpam = FancyGeneric[:[float]] | |
# FancyGeneric[list[int]] | |
SetSpam = FancyGeneric[:{int}] | |
# FancyGeneric[dict[str, int]] | |
DictSpam = FancyGeneric[:{str: int}] | |
# FancyGeneric[tuple[str, ...], <class 'int'>, dict[str, int], Ellipsis] | |
MixedSpam = FancyGeneric[:(str, ...), int, :{str: int}, ...] | |
# TypeError | |
BadSpam = FancyGeneric[:"not a builtin collection"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment