Skip to content

Enhancement: Support custom provider on types created through 3.14 type statements #853

Description

@bullfest

Summary

Python 3.14 added type aliases through type statements: https://docs.python.org/3/library/typing.html#type-aliases
These aliases are preserved in the annotations:

type ConstrainedString = Annotated[str, pydantic.AfterValidator(validator)]
ConstrainedStringOld = Annotated[str, pydantic.AfterValidator(validator)]
print(repr(ConstrainedString | None))  # ConstrainedString | None
print(repr(ConstrainedStringOld | None))  # typing.Optional[typing.Annotated[str, AfterValidator(func=<function validator at ...)]]

Thus this is something that polyfactory could leverage to allow for easier ways to add custom providers for types that are just constrained versions of built-in types.

Basic Example

Here's an example of some usage of a type alias.
Note that coverage() (accidentally) works when the type alias is part of a Union.

from typing import Annotated

import pydantic
from polyfactory.factories.pydantic_factory import ModelFactory


def validator(value: str) -> str:
    if len(value) % 2 == 0:
        raise ValueError("Must be an odd length string")
    return value


type ConstrainedString = Annotated[str, pydantic.AfterValidator(validator)]

ModelFactory.add_provider(ConstrainedString, lambda: "f" + "oo" * ModelFactory.__random__.randint(0,100))


class MyModel(pydantic.BaseModel):
    s: ConstrainedString

class MyModelFactory(ModelFactory[MyModel]):
    __check_model__ = True

# Neither of these work
print(list(MyModelFactory.coverage()))
print(list(MyModelFactory.batch(10)))

class MyModelWithNone(pydantic.BaseModel):
    s: ConstrainedString | None

class MyModelWithNoneFactory(ModelFactory[MyModelWithNone]):
    __check_model__ = True

print(list(MyModelWithNoneFactory.coverage())) # Surprisingly works
print(list(MyModelWithNoneFactory.batch(10))) # But this doesn't work

Drawbacks and Impact

No response

Unresolved questions

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions