polyfactory generates typed test instances from any Python type. pip install polyfactory. Pydantic: from polyfactory.factories.pydantic_factory import ModelFactory. class UserFactory(ModelFactory): __model__ = User. user = UserFactory.build() → User instance with random valid data. UserFactory.build(email="[email protected]") — override fields. UserFactory.batch(10) — list of 10. Dataclass: from polyfactory.factories.dataclass_factory import DataclassFactory. class OrderFactory(DataclassFactory): __model__ = Order. Attrs: from polyfactory.factories.attrs_factory import AttrsFactory. TypedDict: from polyfactory.factories.typed_dict_factory import TypedDictFactory. Base: from polyfactory.factories.base import BaseFactory — works with any class via __init__. Custom field: from polyfactory.field_meta import FieldMeta. class UserFactory(ModelFactory): email = FactoryField(alias="email", value=lambda: "[email protected]"). __faker__: from faker import Faker; class UserFactory(ModelFactory): __faker__ = Faker("de_DE"). Constraints: polyfactory respects Pydantic Field(min_length=1, ge=0) automatically. Coverage: UserFactory.coverage() — generates instances that hit every Literal and Enum variant. for user in UserFactory.coverage(): assert process(user). create vs build: build() — in-memory, no persistence. create() — calls __async_persistence__ / __sync_persistence__ hook. Nested: polyfactory recursively creates nested models. UserFactory.build() with address: Address → Address is also built. Union: polyfactory picks a branch. Generics: supported. Optional[X] — randomly None or X. __random_seed__ — reproducible. pytest: @pytest.fixture def user_factory(): return UserFactory. def test_fn(user_factory): user = user_factory.build(). Claude Code generates polyfactory Factory classes, coverage tests, and pytest fixture sets.
CLAUDE.md for polyfactory
## polyfactory Stack
- Version: polyfactory >= 2.16 | pip install polyfactory
- Pydantic: class F(ModelFactory): __model__ = MyModel — auto-respects Field constraints
- Dataclass: class F(DataclassFactory): __model__ = MyDataclass
- Build: F.build() | F.build(field=override) | F.batch(N) for lists
- Coverage: F.coverage() — yields instances covering every Literal/Enum variant
- Custom: FactoryField(value=lambda: ...) | __faker__ = Faker("de_DE")
- Persistence: __sync_persistence__ / __async_persistence__ hooks for DB insert
polyfactory Test Data Pipeline
# tests/factories.py — polyfactory factory definitions
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Annotated, Dict, List, Literal, Optional, TypedDict
from uuid import UUID
import attrs
import pytest
from pydantic import BaseModel, EmailStr, Field
from pydantic import field_validator
from polyfactory.factories.attrs_factory import AttrsFactory
from polyfactory.factories.base import BaseFactory
from polyfactory.factories.dataclass_factory import DataclassFactory
from polyfactory.factories.pydantic_factory import ModelFactory
from polyfactory.factories.typed_dict_factory import TypedDictFactory
from polyfactory.field_meta import Alias, FactoryField
# ─────────────────────────────────────────────────────────────────────────────
# Domain models
# ─────────────────────────────────────────────────────────────────────────────
class UserRole(str, Enum):
USER = "user"
MODERATOR = "moderator"
ADMIN = "admin"
class OrderStatus(str, Enum):
PENDING = "pending"
PAID = "paid"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
# Pydantic models
class AddressModel(BaseModel):
street: Annotated[str, Field(min_length=1, max_length=200)]
city: Annotated[str, Field(min_length=1, max_length=100)]
state: Annotated[str, Field(min_length=2, max_length=2)]
postal_code: Annotated[str, Field(pattern=r"^\d{5}(-\d{4})?$")]
country: str = "US"
class UserModel(BaseModel):
id: UUID
email: EmailStr
first_name: Annotated[str, Field(min_length=1, max_length=100)]
last_name: Annotated[str, Field(min_length=1, max_length=100)]
role: UserRole = UserRole.USER
is_active: bool = True
address: Optional[AddressModel] = None
age: Annotated[Optional[int], Field(None, ge=0, le=130)] = None
class OrderLineModel(BaseModel):
product_id: UUID
sku: Annotated[str, Field(min_length=1)]
quantity: Annotated[int, Field(ge=1, le=10_000)]
unit_price: Annotated[float, Field(gt=0, le=100_000)]
class OrderModel(BaseModel):
id: UUID
user_id: UUID
lines: Annotated[List[OrderLineModel], Field(min_length=1)]
status: OrderStatus = OrderStatus.PENDING
notes: Optional[str] = None
# Stdlib dataclass
@dataclass
class ProductDC:
sku: str
name: str
price: float
stock: int
category: str
is_active: bool = True
id: str = field(default_factory=lambda: "prod-000")
# attrs class
@attrs.define
class AddressAttrs:
street: str
city: str
state: str
postal_code: str
country: str = "US"
# TypedDict
class UserPayloadDict(TypedDict):
email: str
first_name: str
last_name: str
role: str
# ─────────────────────────────────────────────────────────────────────────────
# 1. Pydantic ModelFactory — respects Field constraints automatically
# ─────────────────────────────────────────────────────────────────────────────
class AddressFactory(ModelFactory):
__model__ = AddressModel
# polyfactory generates valid postal_code matching the pattern automatically
state = "CA" # pin state to a known-valid 2-char string
class UserFactory(ModelFactory):
__model__ = UserModel
# Override specific fields
email = FactoryField(value=lambda: f"test_{UserFactory.__faker__.uuid4()[:8]}@example.com")
is_active = True # always active in tests unless explicitly overridden
class OrderLineFactory(ModelFactory):
__model__ = OrderLineModel
class OrderFactory(ModelFactory):
__model__ = OrderModel
# polyfactory recursively builds OrderLineModel for the `lines` field
# ─────────────────────────────────────────────────────────────────────────────
# 2. DataclassFactory
# ─────────────────────────────────────────────────────────────────────────────
class ProductFactory(DataclassFactory):
__model__ = ProductDC
category = FactoryField(
value=lambda: ProductFactory.__faker__.random_element(
["Electronics", "Clothing", "Books", "Home", "Sports"]
)
)
# ─────────────────────────────────────────────────────────────────────────────
# 3. AttrsFactory
# ─────────────────────────────────────────────────────────────────────────────
class AddressAttrsFactory(AttrsFactory):
__model__ = AddressAttrs
state = "NY"
# ─────────────────────────────────────────────────────────────────────────────
# 4. TypedDictFactory
# ─────────────────────────────────────────────────────────────────────────────
class UserPayloadFactory(TypedDictFactory):
__model__ = UserPayloadDict
role = FactoryField(value=lambda: "user")
# ─────────────────────────────────────────────────────────────────────────────
# 5. coverage() — exhaustive Enum/Literal coverage
# ─────────────────────────────────────────────────────────────────────────────
class StatusCoverageModel(BaseModel):
status: OrderStatus
role: UserRole
flag: Literal["red", "green", "blue"]
class StatusCoverageFactory(ModelFactory):
__model__ = StatusCoverageModel
def test_coverage_hits_all_variants() -> None:
"""
coverage() generates one instance per combination of Literal/Enum variants.
Use this to ensure your code handles every variant.
"""
instances = list(StatusCoverageFactory.coverage())
statuses = {i.status for i in instances}
roles = {i.role for i in instances}
flags = {i.flag for i in instances}
assert statuses == set(OrderStatus)
assert roles == set(UserRole)
assert flags == {"red", "green", "blue"}
print(f"coverage() generated {len(instances)} instances")
# ─────────────────────────────────────────────────────────────────────────────
# 6. build, batch, and overrides
# ─────────────────────────────────────────────────────────────────────────────
def demo_build() -> None:
# Single instance — all fields auto-generated, respecting constraints
user = UserFactory.build()
assert isinstance(user, UserModel)
assert user.is_active is True # our override
assert len(user.first_name) >= 1 # Field(min_length=1) respected
# Override specific fields
admin = UserFactory.build(role=UserRole.ADMIN, age=35)
assert admin.role == UserRole.ADMIN
assert admin.age == 35
# Batch — list of N instances
users = UserFactory.batch(5)
assert len(users) == 5
assert all(isinstance(u, UserModel) for u in users)
# Nested — address auto-built
user_with_address = UserFactory.build(
address=AddressFactory.build(city="San Francisco"),
)
assert user_with_address.address.city == "San Francisco"
# Order with lines
order = OrderFactory.build()
assert len(order.lines) >= 1
assert all(line.quantity >= 1 for line in order.lines)
# Dataclass factory
product = ProductFactory.build()
assert isinstance(product, ProductDC)
assert product.category in ["Electronics", "Clothing", "Books", "Home", "Sports"]
# attrs factory
address = AddressAttrsFactory.build()
assert isinstance(address, AddressAttrs)
assert address.state == "NY"
# TypedDict factory
payload = UserPayloadFactory.build()
assert isinstance(payload, dict)
assert payload["role"] == "user"
print("All build() demos passed.")
# ─────────────────────────────────────────────────────────────────────────────
# 7. pytest fixtures
# ─────────────────────────────────────────────────────────────────────────────
@pytest.fixture
def fake_user() -> UserModel:
return UserFactory.build()
@pytest.fixture
def fake_admin() -> UserModel:
return UserFactory.build(role=UserRole.ADMIN)
@pytest.fixture
def fake_users() -> list[UserModel]:
return UserFactory.batch(10)
@pytest.fixture
def fake_order() -> OrderModel:
return OrderFactory.build()
@pytest.fixture
def fake_product() -> ProductDC:
return ProductFactory.build()
# ─────────────────────────────────────────────────────────────────────────────
# 8. Tests using fixtures
# ─────────────────────────────────────────────────────────────────────────────
def test_user_model_is_valid(fake_user: UserModel) -> None:
assert fake_user.email
assert "@" in fake_user.email
assert len(fake_user.first_name) > 0
assert fake_user.role in UserRole
def test_order_has_lines(fake_order: OrderModel) -> None:
assert len(fake_order.lines) > 0
for line in fake_order.lines:
assert line.quantity >= 1
assert line.unit_price > 0
def test_all_order_statuses_handled() -> None:
"""Use coverage() to ensure your handler processes every OrderStatus."""
class OrderWithStatus(BaseModel):
status: OrderStatus
class TestFactory(ModelFactory):
__model__ = OrderWithStatus
for instance in TestFactory.coverage():
# Replace with your real handler
result = f"handled {instance.status.value}"
assert result.startswith("handled")
if __name__ == "__main__":
demo_build()
test_coverage_hits_all_variants()
print("All polyfactory demos complete.")
For the factory_boy alternative — factory_boy’s Factory.create() integrates with SQLAlchemy, Django ORM, and Mongoengine to persist objects during test setup, while polyfactory’s build() focuses on in-memory instance creation from type annotations — polyfactory automatically infers how to generate valid data for Annotated[str, Field(min_length=1, pattern=r"^\d{5}$")] without any explicit override, where factory_boy would require a LazyAttribute or Fake declaration. For the pytest fixtures with hardcoded dicts alternative — hardcoded dicts go stale when the model gains required fields (the test silently passes with the old dict while the real code breaks), while UserFactory.build() always reflects the current UserModel definition — add a required field to UserModel and UserFactory.build() immediately generates it with valid data, no fixture update needed. The Claude Skills 360 bundle includes polyfactory skill sets covering ModelFactory for Pydantic, DataclassFactory for stdlib dataclasses, AttrsFactory for attrs classes, TypedDictFactory for TypedDict, build/batch/create patterns, FactoryField for field-level overrides, coverage() for exhaustive Enum and Literal testing, faker locale configuration, random_seed for reproducibility, nested model auto-generation, and pytest fixture integration. Start with the free tier to try universal test factory code generation.