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! |
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 |
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_GenericAliasback, 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_originandget_argsonly return something on a_GenericAliasand not the unbound generic type.__orig_bases__looks correct to me. So I don't thinkSomeModelgets erased.Why not just pass in the type as an additional parameter? It seems more readable to me anyways i.e.: