Guillaume
Guillaume

Reputation: 2899

Pydantic, polyfactory and ParamSpec

Using polyfactory to generate test pydantic objects, I end up with this to describe the typing, but it is not correct according to pyright (runtime, all is fine) and I wonder how to fix this.

from typing import Self

from polyfactory.factories.pydantic_factory import ModelFactory
from pydantic import BaseModel


class Parent(BaseModel):
    @classmethod
    def generate_test_instance[**P](cls, *_: P.args, **kwargs: P.kwargs) -> Self:
        class Factorio(ModelFactory[cls]):
            __model__ = cls

        return Factorio.build(**kwargs)


class Child(Parent):
    param: str


Child.generate_test_instance()

The whole file is correct typing-wise, except the last line, complaining that Param spec "P@generate_test_instance" has no bound value.

To bind P, I could use cls:Callable[P, T] as first parameter of generate_test_instance but it breaks other things (typing wise): classmethod, use of cls in the __model__.

I understand that P needs to be bound, but I am not sure how.

Experimenting, I ended up with this option for the parent

class Parent2(BaseModel):
    @classmethod
    def generate_test_instance[T: BaseModel, **P](cls: Type[Callable[P, T]], *_: P.args, **kwargs: P.kwargs) -> T:
        class Factorio(ModelFactory[T]):
            __model__ = cls

        return Factorio.build(**kwargs)

The child is happy (parameters are auto completed) but __model__ = cls in Parent2 gives a typing error (Expected type expression but received "(**P@generate_test_instance) -> T@generate_test_instance" respectively) which is not unexpected.

How could I get both of both worlds, ie. complete valid typing?

Upvotes: 0

Views: 680

Answers (0)

Related Questions