Reputation: 5724
Assume the following class definition,
import typing
from dataclasses import dataclass
T1 = typing.TypeVar('T1')
T2 = typing.TypeVar('T2')
@dataclass
class Test(Generic[T1, T2]):
some_property: T2
some_other_property: T1
I would like to get the type hints of a specific bound version of this class, something like
# I would like to get back: {'some_property': str, 'some_other_property': int}
hints = typing.get_type_hints(Test[int,str])
Unfortunately, this don't work in python 3.9, raising a type error "Test[int,str] is not a module, class, method or function". Now, I could do something like
hints = typing.get_type_hints(typing.get_origin(Test[int,str]))
However, in that case, some_property and some_other_properties are returned as TypeVars, rather than specific bound types (int and str).
Binding these manually seems a little annoying; Test[int,str] is of type typing._GenericAlias, which seems to have a property _ _ args _ _ which is [int, str]. I could in theory try to bind them back to the type vars in the order in which they appear first from get_type_hints(get_origin()), but I'm not sure if that is reliable.
Is there any equivalent of get_type_hints that would return fully bound type hints? Or any reasonable other way of doing this?
Upvotes: 3
Views: 1943
Reputation: 1422
I upgraded to 3.9.2 and it did not solve the problem for me.
There appears to be a limitation on the scope of what typing.get_type_hints() can do. I thought it very odd this sort of type construct doesn't seem to be a problem in other scenarios. Some quick testing found that it can handle your Test type just fine as a child of another class type.
I modified your example to create a new function, my_type_hints() and it dynamically creates a temporary class object with the provided type as it's only child element.
I believe the following solves your problem. I don't know if it's a comprehensive solution, but I believe it's probably more robust than digging into __args__
, __origin__
, etc.
from typing import Any, Generic, get_type_hints, TypeVar
from dataclasses import dataclass
T1 = TypeVar('T1')
T2 = TypeVar('T2')
@dataclass
class Test ( Generic[T1,T2] ):
some_property: T2
some_other_property: T1
def my_type_hints ( obj: Any ) -> Any:
class X:
x: obj
return get_type_hints ( X )['x']
hints = my_type_hints ( Test[int,str] )
print ( f'{hints=}' )
Upvotes: 2