Skip to content

Bug: Unsupported type: ForwardRef on field for pydantic ModelFactory #686

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 of 4 tasks
mshonichev opened this issue Apr 4, 2025 · 1 comment
Open
2 of 4 tasks
Labels
bug Something isn't working

Comments

@mshonichev
Copy link

mshonichev commented Apr 4, 2025

Description

Seems like Polyfactory don't respect forward type annotations when generating factories for Pydantic models.

When Pydantic model references another model and the latter is not yet defined, it is advised to either explicitly put type annotation in quotes to annotate type in forward or use implicit automatic forward annotations by doing from __future__ import annotations.

For such models, Polyfactory fails to create proper working ModelFactory which raises exceptions upon model build.

URL to code causing the issue

No response

MCVE

from __future__ import annotations

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


class Resp(BaseModel):
    name: str | None = Field(default=None, examples=["response"])
    coll: Coll | None


class Item(BaseModel):
    name: str = Field(..., examples=["item"])
    field: str | None = None


class Coll(BaseModel):
    items: list[Item] | None = None


# Resp.model_rebuild()


class RespFactory(ModelFactory[Resp]):
    ...


def test_inc() -> None:
    resp = RespFactory.build(name="9287")
    print(resp)

Steps to reproduce

1. Run example

Expected: No errors, model built

Actual: 

E       polyfactory.exceptions.ParameterException: Unsupported type: ForwardRef('Coll | None') on field 'coll' from class RespFactory.
E       
E       Either use 'add_provider', extend the providers map, or add a factory function for the field on the model.

(partial) workaround:
Sometimes <Model>.model_rebuild() helps fix forward annotations.

Sometimes if one to remove from __future__ import annotations and reorder model classes definitions so that no forward annotations occur, then ModelFactory works as expected.

However, this is not always the case, due to e.g. legacy imported code or circular referencing data structures.

Screenshots

"In the format of: ![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

Release Version

2.20.0

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)
@mshonichev mshonichev added the bug Something isn't working label Apr 4, 2025
@adhtruong
Copy link
Collaborator

adhtruong commented Apr 5, 2025

PRs welcome to fix. I think for main use case here can call BaseModel.model_rebuild - either in your base class or in ModelFactory.__init_subclass__.

Probably out of scope to support all models for unbuilt schema and try resolve references in general and try delegate this to exposed pydantic api if possible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants