Home > Software design >  Get generic substituted type
Get generic substituted type

Time:11-24

I have such class:

from typing import Generic, TypeVar
from pydantic import BaseModel

T = TypeVar("T", bound=BaseModel)

class A(Generic[T]):
    def some_method(self) -> T:
        ... # some data processing
        return T.from_orm(some_data_model)

# in tests package:
class Model(BaseModel): ...
A[Model].some_method()
assert Model.from_orm.called_once

But it doesn't work because T is not a real type(BaseModel) but only TypeVar that bounds to BaseModel.

So the question is: how can I get the real(substituted) type T?

Important notes:

it doesn't matter for me what the type the method is(classmethod, method of object instance or staticmethod)

my python version is 3.8

This answer doesn't helped me:

I tried this:

from typing import ..., get_args
#   ...
    def some_method(self) -> T:
        ...
        return get_args(type(self))[0].from_orm(some_data_model)

This:

from typing import ..., get_args
#   ...
    @classmethod
    def some_method(cls) -> T:
        ...
        return get_args(cls)[0].from_orm(some_data_model)

And this:

from typing import ..., get_args
#   ...
    @classmethod
    def some_method(cls) -> T:
        ...
        return get_args(A)[0].from_orm(some_data_model)

And I call it in a such way(if it is class/static method):

A[Model].some_method()

And if it is instance method:

A[Model]().some_method()

And all of it(without calling from_orm and getting index 0) just returns empty tuple and the whole method ends with IndexError(which is totally right).

CodePudding user response:

In the comments @alex_noname posted a link to another such question.

In my case the answer was to use the __orig_class__ attribute of the self object:

from typing import Generic, TypeVar, get_args
from pydantic import BaseModel

T = TypeVar("T", bound=BaseModel)

class A(Generic[T]):
    def some_method(self) -> T:
        ... # some data processing
        return get_args(self.__orig_class__)[0].from_orm(some_data_model)

For more information please refer to this answer

  • Related