Type gets erased in generic loader classmethod #1433
-
Hello all, trying to figure out I can make a generic loader function for some Pydantic models. For some reason this code: from pydantic import BaseModel
from pydantic.generics import GenericModel
from typing import TypeVar, Generic, get_args, get_origin
TIM = TypeVar("TIM", bound=BaseModel)
class TemplateTestCase(GenericModel, Generic[TIM]):
input: TIM
class SomeModel(BaseModel):
age: int
class GenericTestCaseLoader(Generic[TIM]):
@classmethod
def load_test_case(cls: type["GenericTestCaseLoader[TIM]"], data: dict) -> TemplateTestCase[TIM]:
print(get_args(cls))
print(get_origin(cls))
print(get_origin(cls))
print(cls.__orig_bases__)
return TemplateTestCase[TIM].parse_obj(data)
def test_generic_model() -> None:
test_case = TemplateTestCase(
input=SomeModel(age=33),
)
root_data = test_case.dict()
template_test_case_2 = GenericTestCaseLoader[SomeModel].load_test_case(root_data)
print(template_test_case_2)
if __name__ == "__main__":
test_generic_model() Prints:
As if that SomeModel gets completely erased and it falls back to the BaseModel that the TypeVar is bound to. What am I doing wrong? I'm just trying to build something that can serialize a model, and then deserialize into the specified model. Thanks for the help! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
IIRC the type you get within an instance is not quite the same as the one you get from specifying the type parameters on a generic, since calling Why not just pass in the type as an additional parameter? It seems more readable to me anyways i.e.: class GenericTestCaseLoader:
@classmethod
def load_test_case(cls, model: type[TIM], data: dict) -> TemplateTestCase[TIM]:
return TemplateTestCase[TIM].parse_obj(data)
GenericTestCaseLoader.load_test_case(SomeModel, root_data) If you absolutely must have it work the way you wrote it, you could accomplish it by overwriting |
Beta Was this translation helpful? Give feedback.
IIRC the type you get within an instance is not quite the same as the one you get from specifying the type parameters on a generic, since calling
__getitem__
on a generic gives you a_GenericAlias
back, which behaves like the original type for many use cases, since the original class gets inserted into its mro, but is not the actual type.get_origin
andget_args
only return something on a_GenericAlias
and not the unbound generic type.__orig_bases__
looks correct to me. So I don't thinkSomeModel
gets erased.Why not just pass in the type as an additional parameter? It seems more readable to me anyways i.e.: