Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get_type_hints for generic type

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?

like image 532
Bogey Avatar asked Oct 15 '25 01:10

Bogey


1 Answers

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=}' )
like image 150
royce3 Avatar answered Oct 17 '25 15:10

royce3



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!