Last active
August 8, 2017 22:49
-
-
Save chadrik/54d7b3d051839f90983676a47368526b to your computer and use it in GitHub Desktop.
This file contains hidden or 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
from __future__ import absolute_import, print_function | |
from typing import Generic | |
# MRO code adapted from https://gist.github.com/pendulm/2271366 | |
def head(l): | |
return l[0] | |
def tail(l): | |
return l[1:] | |
def is_not_in_tail(h, l): | |
if h in tail(l): | |
return False | |
return True | |
def remove_head(h, l): | |
if h is head(l): | |
l.remove(h) | |
return l | |
def merge(list_of_linearization): | |
for l in list_of_linearization: | |
h = head(l) | |
if all(is_not_in_tail(h, l) for l in list_of_linearization): | |
list_of_stripped = [remove_head(h, l) for l in list_of_linearization] | |
list_of_stripped = [i for i in list_of_stripped if len(i) != 0] | |
if len(list_of_stripped) == 0: | |
return [h] | |
return [h] + merge(list_of_stripped) | |
raise TypeError("Cannot create a consostent method resolution") | |
def mro(C): | |
if C is object: | |
return [object] | |
try: | |
bases = list(C.__orig_bases__) | |
except AttributeError: | |
bases = list(C.__bases__) | |
return [C] + merge([mro(b) for b in bases] + [bases]) | |
def get_generic_type(klass, typevar): | |
""" | |
Given a Generic class, find the value for the given TypeVar. | |
Parameters | |
---------- | |
klass : type | |
typevar : TypeVar | |
Returns | |
------- | |
Any | |
""" | |
for sub in mro(klass): | |
# we have an origin every time a generic class is indexed. e.g.: | |
# the origin of Foo[T, V] is Foo | |
origin = getattr(sub, '__origin__', None) | |
if origin is not None: | |
if origin is Generic: | |
# for some reason Generic does not record its args | |
args = sub.__parameters__ | |
params = args | |
else: | |
# the args are the index arguments | |
args = sub.__args__ | |
params = origin.__parameters__ | |
try: | |
index = params.index(typevar) | |
except ValueError: | |
continue | |
else: | |
return args[index] |
This file contains hidden or 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
from __future__ import absolute_import, print_function | |
from typing import Generic, TypeVar | |
from runtime_typing import mro, get_generic_type | |
T = TypeVar('T') | |
U = TypeVar('U', bound=str) | |
V = TypeVar('V') | |
def print_generic_type_info(klass): | |
for sub in mro(klass): | |
print(sub) | |
print(" args: ", getattr(sub, '__args__', None)) | |
print(" params:", getattr(sub, '__parameters__', None)) | |
print(" origin:", getattr(sub, '__origin__', None)) | |
class A(Generic[T]): | |
pass | |
IntA = A[int] | |
class SubIntA(IntA): | |
pass | |
class B(Generic[T, U]): | |
pass | |
class SubB(B[T, U]): # Note: `class SubB(B):` is not allowed | |
pass | |
class Mixin(object): | |
pass | |
class IntB(SubB[int, U], Mixin): | |
pass | |
class SubIntB(IntB): | |
pass | |
class SubIntStrB(IntB[str], Generic[V]): | |
pass | |
def test_types(): | |
print_generic_type_info(IntA) | |
print() | |
print_generic_type_info(SubIntStrB) | |
# FIXME: typing was changed so that this no longer works: | |
# assert issubclass(str, T) | |
# assert issubclass(str, U) | |
# assert not issubclass(int, U) | |
assert get_generic_type(IntA, T) is int | |
assert get_generic_type(SubIntA, T) is int | |
assert get_generic_type(SubIntStrB, T) is int | |
assert get_generic_type(SubIntStrB, U) is str | |
assert get_generic_type(SubIntStrB, V) is V | |
assert get_generic_type(SubIntB, T) is int | |
assert get_generic_type(SubIntB, U) is U | |
assert get_generic_type(SubB, T) is T | |
assert get_generic_type(SubB, U) is U | |
assert get_generic_type(B, T) is T | |
assert get_generic_type(B, U) is U | |
# FIXME: not totally sure what the behavior should be here | |
assert get_generic_type(SubIntStrB, TypeVar('T')) is None | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment