简体   繁体   中英

Pydantic create_model_from_typeddict does not play nice with mypy?

I am using pydantic models generated from typeddicts in a project with mypy but I get a invalid type error when using one of those models as a return type.

This does not happend when directly using a BaseModel.

from pydantic import create_model_from_typeddict
from typing import TypedDict


class TD_Foo(TypedDict):
    bar: int


M_Foo = create_model_from_typeddict(TD_Foo)

# error: Variable "pls.M_Foo" is not valid as a type  [valid-type]
def make_foo() -> M_Foo:
    return M_Foo(bar=42)


print(make_foo())

Is there an issue with my code or should I raise an issue? Also if anyone knows if I should raise it on mypy or pydantic's repo?

Looking at the source , it appears create_model_from_typeddict calls regular old create_model under the hood and passes along all **kwargs to it.

The function create_model by default always returns the type Type[BaseModel] . This is also how the return type of create_model_from_typeddict is annotated. Thus, it will definitely be correct in your case to annotate make_foo accordingly:

from pydantic import BaseModel, create_model_from_typeddict
from typing import TypedDict


class TD_Foo(TypedDict):
    bar: int


M_Foo = create_model_from_typeddict(TD_Foo)


def make_foo() -> BaseModel:
    return M_Foo(bar=42)

No issues with mypy .


What I have an issue with, now that I am looking at this, is that create_model_from_typeddict doesn't mirror the overloaded annotations of create_model and thus the following causes a type error:

from pydantic import BaseModel, create_model_from_typeddict                                                     from typing import TypedDict


class TD_Foo(TypedDict):
    bar: int


class FooModel(BaseModel):
    pass


M_Foo = create_model_from_typeddict(
    TD_Foo,
    __base__=FooModel,
)


def make_foo() -> FooModel:
    return M_Foo(bar=42)

Mypy correctly picks up the following:

20: error: Incompatible return value type (got "BaseModel", expected "FooModel")  [return-value]

Actually the type returned indeed is FooModel because M_Foo is in fact Type[FooModel] . This is, in my opinion, due to create_model_from_typeddict being wrongly (or incompletely) annotated. If passed a base class, the return type should be inferred accordingly, as it does with create_model .

I think I'll create a Pull Request for this, once I verify this is warranted.


Anyway, I hope this helps.

PS

In case you are still wondering, why you can't just use M_Foo as an annotation, that is due to that class being dynamically created at runtime. It is just the old dilemma between static type checking and dynamic typing. Generally speaking, the type checker will not be able to handle such types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM