polyfactory

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

polyfactory

polyfactory

Polyfactory is a typed mock-data factory library: declare
ModelFactory[T]
(or
DataclassFactory
,
MsgspecFactory
,
AttrsFactory
,
TypedDictFactory
) and
.build()
returns a fully-populated, validation-passing instance of
T
. Because the factory inspects the model's annotations and constraints, generated data already respects
msgspec.Meta
ranges, Pydantic
Field
constraints, and attrs validators — no additional fixtures needed for happy-path tests.
In Litestar projects, polyfactory's pytest plugin is the canonical way to feed
TestClient.post(...)
/
AsyncTestClient.put(...)
payloads. The companion skill
litestar:litestar-testing
covers the request side.
Polyfactory是一个类型化模拟数据工厂库:声明
ModelFactory[T]
(或
DataclassFactory
MsgspecFactory
AttrsFactory
TypedDictFactory
)后,调用
.build()
会返回一个完全填充且通过验证的
T
实例。由于工厂会检查模型的注解和约束,生成的数据天然符合
msgspec.Meta
范围、Pydantic
Field
约束以及attrs验证器——快乐路径测试无需额外夹具。
在Litestar项目中,polyfactory的pytest插件是为
TestClient.post(...)
/
AsyncTestClient.put(...)
提供负载数据的标准方式。配套技能
litestar:litestar-testing
涵盖请求侧相关内容。

Code Style Rules

代码风格规则

  • PEP 604 unions:
    T | None
    , never
    Optional[T]
    .
  • from __future__ import annotations
    rule
    — Modules that define factory subclasses with introspected
    Meta
    config (
    __model__
    ,
    __random_seed__
    ,
    __set_as_default_factory_for_type__
    ) are library-like and SHOULD avoid future annotations on the factory module itself if the model class is also defined there. Test modules that use factories (call
    .build()
    , register fixtures) MAY and typically SHOULD use future annotations — they are pure consumer code. The same rule applies as msgspec/dishka/SAQ.
  • One factory per model. Don't reuse a factory across unrelated models — clarity beats DRY when the test fails at 3am.
  • Pick the right factory base by backend:
    ModelFactory
    (Pydantic),
    DataclassFactory
    ,
    MsgspecFactory
    ,
    AttrsFactory
    ,
    TypedDictFactory
    . The wrong base silently degrades to attribute-by-attribute introspection and produces lower-quality data.
  • Prefer
    register_fixture
    over hand-rolled
    @pytest.fixture
    wrappers — it gives you both the fixture and the factory class with one decorator.
  • PEP 604联合类型:使用
    T | None
    ,绝不使用
    Optional[T]
  • from __future__ import annotations
    规则
    ——如果模块定义了带有可自省
    Meta
    配置(
    __model__
    __random_seed__
    __set_as_default_factory_for_type__
    )的工厂子类,且模型类也定义在该模块中,那么这类模块属于类库性质,应避免在工厂模块本身使用future annotations。而使用工厂的测试模块(调用
    .build()
    、注册夹具)可以且通常应该使用future annotations——它们是纯消费代码。该规则与msgspec/dishka/SAQ的规则一致。
  • 一个模型对应一个工厂。不要在不相关的模型之间复用工厂——当测试在凌晨3点失败时,清晰性比DRY原则更重要。
  • 根据后端选择正确的工厂基类:
    ModelFactory
    (Pydantic)、
    DataclassFactory
    MsgspecFactory
    AttrsFactory
    TypedDictFactory
    。错误的基类会静默退化为逐属性自省,生成的数据质量更低。
  • 优先使用
    register_fixture
    而非手动编写的
    @pytest.fixture
    包装器——它只需一个装饰器就能同时提供夹具和工厂类。

Quick Reference

快速参考

Picking the right factory base

选择合适的工厂基类

Model kindFactory baseImport
pydantic.BaseModel
ModelFactory
from polyfactory.factories.pydantic_factory import ModelFactory
@dataclass
DataclassFactory
from polyfactory.factories import DataclassFactory
msgspec.Struct
MsgspecFactory
from polyfactory.factories.msgspec_factory import MsgspecFactory
@attrs.define
/
attr.s
AttrsFactory
from polyfactory.factories.attrs_factory import AttrsFactory
TypedDict
TypedDictFactory
from polyfactory.factories.typed_dict_factory import TypedDictFactory
Beanie / Odmantic / SQLAdedicated basessee factories.md
模型类型工厂基类导入语句
pydantic.BaseModel
ModelFactory
from polyfactory.factories.pydantic_factory import ModelFactory
@dataclass
DataclassFactory
from polyfactory.factories import DataclassFactory
msgspec.Struct
MsgspecFactory
from polyfactory.factories.msgspec_factory import MsgspecFactory
@attrs.define
/
attr.s
AttrsFactory
from polyfactory.factories.attrs_factory import AttrsFactory
TypedDict
TypedDictFactory
from polyfactory.factories.typed_dict_factory import TypedDictFactory
Beanie / Odmantic / SQLA专用基类参见factories.md

Defining a factory

定义工厂

python
from dataclasses import dataclass
from polyfactory.factories import DataclassFactory


@dataclass
class Order:
    id: int
    customer_email: str
    total_cents: int
    status: str


class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
python
from dataclasses import dataclass
from polyfactory.factories import DataclassFactory


@dataclass
class Order:
    id: int
    customer_email: str
    total_cents: int
    status: str


class OrderFactory(DataclassFactory[Order]):
    __model__ = Order

Use it

使用示例

one = OrderFactory.build() many = OrderFactory.batch(10)

`build()` returns a single populated instance. `batch(n)` returns `list[T]` of size `n`. `coverage()` yields one instance per Union/Optional branch — useful for parametrized tests across discriminated unions.
one = OrderFactory.build() many = OrderFactory.batch(10)

`build()`返回单个填充后的实例。`batch(n)`返回大小为`n`的`list[T]`。`coverage()`会为每个Union/Optional分支生成一个实例——在判别联合的参数化测试中非常有用。

Customizing fields

自定义字段

python
from polyfactory import Use
from polyfactory.factories import DataclassFactory


class OrderFactory(DataclassFactory[Order]):
    __model__ = Order

    # Plain literal — every build returns this exact value
    status = "pending"

    # Callable — re-evaluated per build
    customer_email = Use(lambda: "test@example.com")

    # Random choice — re-evaluated per build
    total_cents = Use(DataclassFactory.__random__.randint, 100, 10_000)
Use(callable, *args, **kwargs)
is re-invoked on every
build()
, so each generated instance gets a fresh value.
python
from polyfactory import Use
from polyfactory.factories import DataclassFactory


class OrderFactory(DataclassFactory[Order]):
    __model__ = Order

    # 纯字面量——每次构建都返回该精确值
    status = "pending"

    # 可调用对象——每次构建都会重新计算
    customer_email = Use(lambda: "test@example.com")

    # 随机选择——每次构建都会重新计算
    total_cents = Use(DataclassFactory.__random__.randint, 100, 10_000)
Use(callable, *args, **kwargs)
在每次调用
build()
时都会重新执行,因此每个生成的实例都会获得新值。

Determinism

确定性

python
class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
    __random_seed__ = 42  # same seed → same output across runs
Set
__random_seed__
(or
__faker__ = Faker(seed=...)
for finer Faker control) when test assertions depend on the exact generated values.
python
class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
    __random_seed__ = 42  # 相同种子→多次运行输出一致
当测试断言依赖于精确生成的值时,设置
__random_seed__
(或
__faker__ = Faker(seed=...)
以获得更精细的Faker控制)。

Default factory registration

默认工厂注册

python
class CustomerFactory(DataclassFactory[Customer]):
    __model__ = Customer
    __set_as_default_factory_for_type__ = True


@dataclass
class Order:
    id: int
    customer: Customer  # automatically populated by CustomerFactory.build()


class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
When
__set_as_default_factory_for_type__ = True
, polyfactory uses that factory whenever the type appears as a field on another model — no manual nesting required.
python
class CustomerFactory(DataclassFactory[Customer]):
    __model__ = Customer
    __set_as_default_factory_for_type__ = True


@dataclass
class Order:
    id: int
    customer: Customer  # 自动由CustomerFactory.build()填充


class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
__set_as_default_factory_for_type__ = True
时,只要该类型作为其他模型的字段出现,polyfactory就会使用该工厂——无需手动嵌套。

Pytest fixture from a factory

从工厂创建pytest夹具

python
import pytest
from polyfactory.pytest_plugin import register_fixture
from polyfactory.factories import DataclassFactory


@register_fixture
class OrderFactory(DataclassFactory[Order]):
    __model__ = Order


def test_order_total(order_factory: OrderFactory) -> None:
    order = order_factory.build()
    assert order.total_cents >= 0
@register_fixture
turns the class into a pytest fixture (snake-cased class name). The factory itself is still importable as
OrderFactory
for use outside fixtures.
python
import pytest
from polyfactory.pytest_plugin import register_fixture
from polyfactory.factories import DataclassFactory


@register_fixture
class OrderFactory(DataclassFactory[Order]):
    __model__ = Order


def test_order_total(order_factory: OrderFactory) -> None:
    order = order_factory.build()
    assert order.total_cents >= 0
@register_fixture
会将类转换为pytest夹具(类名转为蛇形命名)。工厂本身仍可作为
OrderFactory
导入,用于夹具之外的场景。

Cross-model relationships

跨模型关系

python
import pytest
from polyfactory import Use
from polyfactory.pytest_plugin import register_fixture


@register_fixture
class CustomerFactory(DataclassFactory[Customer]):
    __model__ = Customer
    __set_as_default_factory_for_type__ = True


@register_fixture
class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
    customer = Use(CustomerFactory.build)  # explicit local override
__set_as_default_factory_for_type__ = True
lets Polyfactory populate nested
Customer
fields with
CustomerFactory
. Use
Use(CustomerFactory.build)
when one parent factory needs an explicit local override.
<workflow>
python
import pytest
from polyfactory import Use
from polyfactory.pytest_plugin import register_fixture


@register_fixture
class CustomerFactory(DataclassFactory[Customer]):
    __model__ = Customer
    __set_as_default_factory_for_type__ = True


@register_fixture
class OrderFactory(DataclassFactory[Order]):
    __model__ = Order
    customer = Use(CustomerFactory.build)  # 显式本地覆盖
__set_as_default_factory_for_type__ = True
允许Polyfactory使用
CustomerFactory
填充嵌套的
Customer
字段。当父工厂需要显式本地覆盖时,使用
Use(CustomerFactory.build)
<workflow>

Workflow

工作流程

Step 1: Pick the factory base

步骤1:选择工厂基类

Match the base to your model backend (table above). Wrong base = silent degradation to generic attribute introspection. If your project uses multiple backends (e.g., Pydantic for HTTP DTOs + msgspec for internal events), import each base separately and don't try to share a factory across backends.
根据模型后端选择对应的基类(见上表)。错误的基类会静默退化为通用属性自省。如果项目使用多个后端(例如,HTTP DTO使用Pydantic + 内部事件使用msgspec),请分别导入每个基类,不要尝试跨后端共享工厂。

Step 2: Define one factory per model

步骤2:为每个模型定义一个工厂

Subclass the appropriate base, set
__model__
. Keep the factory adjacent to the test files that consume it — typically
tests/factories.py
or
tests/<feature>/factories.py
. Don't put factories in production code paths.
继承合适的基类,设置
__model__
。将工厂放在使用它的测试文件附近——通常是
tests/factories.py
tests/<feature>/factories.py
。不要将工厂放在生产代码路径中。

Step 3: Customize only what the test cares about

步骤3:仅自定义测试关心的字段

If a field can take any valid value, leave it for the factory to randomize. Override (literal value or
Use(...)
) only fields the assertion depends on. Tests that pin every field defeat the purpose of using a factory.
如果字段可以接受任何有效值,留给工厂随机生成。仅覆盖(字面量值或
Use(...)
)断言依赖的字段。固定每个字段的测试违背了使用工厂的初衷。

Step 4: Register as a pytest fixture (if used widely)

步骤4:注册为pytest夹具(如果广泛使用)

For factories used in many tests, decorate with
@register_fixture
and consume via the snake-cased fixture name. For one-off use, call
Factory.build()
directly inline.
对于在多个测试中使用的工厂,用
@register_fixture
装饰,并通过蛇形命名的夹具名称使用。对于一次性使用,直接在代码中调用
Factory.build()

Step 5: Wire cross-model relationships

步骤5:连接跨模型关系

Set
__set_as_default_factory_for_type__ = True
on a base factory and let nested fields be populated automatically, or use
Use(OtherFactory.build)
for a local relationship override.
在基础工厂上设置
__set_as_default_factory_for_type__ = True
,让嵌套字段自动填充,或使用
Use(OtherFactory.build)
进行本地关系覆盖。

Step 6: Pin determinism only when needed

步骤6:仅在需要时固定确定性

Tests that assert on specific generated values need
__random_seed__
. Tests that assert on shape or invariants (e.g.,
total >= 0
) should not — leaving randomization on widens coverage across runs.
</workflow> <guardrails>
对特定生成值进行断言的测试需要
__random_seed__
。对形状或不变量(例如
total >= 0
)进行断言的测试则不需要——保持随机化可以在多次运行中扩大覆盖范围。
</workflow> <guardrails>

Guardrails

注意事项

  • Always set
    __model__
    .
    The factory base reads
    __model__
    to introspect annotations; without it
    .build()
    errors at runtime, not at class definition.
  • Don't override fields you're about to assert on with random values. Either pin the value (
    status = "pending"
    ) or assert on shape, not both.
  • Don't reuse
    __random_seed__
    across factories that share a Faker instance.
    They will collide and produce unexpected duplicates. Use a different seed per factory or a single shared seeded
    __faker__
    .
  • Use the right base for the backend.
    ModelFactory
    on a
    msgspec.Struct
    falls back to generic introspection and can produce values that violate
    Meta
    constraints. Always use
    MsgspecFactory
    for msgspec.
  • Factories belong under
    tests/
    .
    Importing them from production modules ties test data to runtime code and is a refactor hazard.
  • coverage()
    is a parametrize tool, not a build tool.
    It returns one instance per Union/Optional branch, not per field — use it via
    pytest.mark.parametrize
    to fan out test cases over polymorphic shapes.
  • from __future__ import annotations
    — same rule as msgspec / dishka. The module that defines the factory + model SHOULD avoid future annotations if the model is runtime-introspected. Test modules that use factories MAY freely use future annotations.
</guardrails> <validation>
  • 始终设置
    __model__
    。工厂基类通过读取
    __model__
    来自省注解;如果没有设置,
    .build()
    会在运行时而非类定义时报错。
  • 不要用随机值覆盖即将断言的字段。要么固定值(
    status = "pending"
    ),要么断言形状,不要两者都做。
  • 不要在共享Faker实例的工厂之间复用
    __random_seed__
    。它们会冲突并产生意外的重复值。每个工厂使用不同的种子,或使用单个共享的带种子
    __faker__
  • 为后端使用正确的基类。在
    msgspec.Struct
    上使用
    ModelFactory
    会退化为通用自省,可能生成违反
    Meta
    约束的值。请始终为msgspec使用
    MsgspecFactory
  • 工厂应放在
    tests/
    目录下
    。从生产模块导入工厂会将测试数据与运行时代码绑定,存在重构风险。
  • coverage()
    是参数化工具,不是构建工具
    。它会为每个Union/Optional分支返回一个实例,而非每个字段——通过
    pytest.mark.parametrize
    使用它,在多态形状上展开测试用例。
  • from __future__ import annotations
    ——与msgspec / dishka的规则相同。如果模块同时定义了可运行时自省的模型类和工厂,那么该模块应避免使用future annotations。使用工厂的测试模块可以自由使用future annotations。
</guardrails> <validation>

Validation Checkpoint

验证检查点

Before delivering polyfactory code, verify:
  • Factory base matches the model backend (Pydantic →
    ModelFactory
    , dataclass →
    DataclassFactory
    , msgspec →
    MsgspecFactory
    , attrs →
    AttrsFactory
    ).
  • __model__
    is set on every factory subclass.
  • Factories live under
    tests/
    (or a sibling test-only module), never in production code.
  • Fields overridden in the factory match what the test asserts on; fields the test does not care about are left for randomization.
  • If the test asserts on exact values,
    __random_seed__
    is set; otherwise it is not.
  • @register_fixture
    is used for factories shared across more than ~2 test files; one-offs call
    .build()
    inline.
  • Cross-model relationships use
    __set_as_default_factory_for_type__
    or
    Use(OtherFactory.build)
    .
  • Factory module avoids
    from __future__ import annotations
    if and only if it co-defines runtime-introspected model classes.
</validation> <example>
在交付polyfactory代码之前,请验证:
  • 工厂基类与模型后端匹配(Pydantic →
    ModelFactory
    ,dataclass →
    DataclassFactory
    ,msgspec →
    MsgspecFactory
    ,attrs →
    AttrsFactory
    )。
  • 每个工厂子类都设置了
    __model__
  • 工厂位于
    tests/
    (或同级测试专用模块)下,绝不在生产代码中。
  • 工厂中覆盖的字段与测试断言的内容匹配;测试不关心的字段留给随机生成。
  • 如果测试断言精确值,则设置了
    __random_seed__
    ;否则不设置。
  • 对于在超过约2个测试文件中共享的工厂,使用
    @register_fixture
    ;一次性使用的工厂直接调用
    .build()
  • 跨模型关系使用
    __set_as_default_factory_for_type__
    Use(OtherFactory.build)
  • 当且仅当工厂模块同时定义了可运行时自省的模型类时,该模块避免使用
    from __future__ import annotations
</validation> <example>

Example: Litestar handler test with msgspec DTOs and polyfactory

示例:使用msgspec DTO和polyfactory的Litestar处理器测试

python
undefined
python
undefined

tests/factories.py

tests/factories.py

from polyfactory.factories.msgspec_factory import MsgspecFactory from polyfactory.pytest_plugin import register_fixture
from myapp.events import OrderCreatedEvent # msgspec.Struct
@register_fixture class OrderCreatedEventFactory(MsgspecFactory[OrderCreatedEvent]): model = OrderCreatedEvent

```python
from polyfactory.factories.msgspec_factory import MsgspecFactory from polyfactory.pytest_plugin import register_fixture
from myapp.events import OrderCreatedEvent # msgspec.Struct
@register_fixture class OrderCreatedEventFactory(MsgspecFactory[OrderCreatedEvent]): model = OrderCreatedEvent

```python

tests/test_orders.py

tests/test_orders.py

from future import annotations # consumer module — fine to use future annotations
from litestar.testing import AsyncTestClient
import pytest
@pytest.mark.anyio async def test_create_order_emits_event( client: AsyncTestClient, order_created_event_factory: OrderCreatedEventFactory, ) -> None: payload = order_created_event_factory.build() response = await client.post("/orders", json=payload)
assert response.status_code == 201
assert response.json()["id"] == payload.id

The factory provides a fully-populated, validation-passing `OrderCreatedEvent`; the test focuses on the request/response contract instead of constructing fake data inline.

</example>

---
from future import annotations # 消费模块——可以使用future annotations
from litestar.testing import AsyncTestClient
import pytest
@pytest.mark.anyio async def test_create_order_emits_event( client: AsyncTestClient, order_created_event_factory: OrderCreatedEventFactory, ) -> None: payload = order_created_event_factory.build() response = await client.post("/orders", json=payload)
assert response.status_code == 201
assert response.json()["id"] == payload.id

工厂提供了一个完全填充且通过验证的`OrderCreatedEvent`;测试专注于请求/响应契约,而非在代码中手动构造假数据。

</example>

---

References Index

参考索引

For detailed guides, refer to the following documents in
references/
:
  • Factories — Per-backend factory bases (Pydantic / dataclass / msgspec / attrs / TypedDict / ODM), randomization control (
    __random_seed__
    ,
    __faker__
    ,
    __allow_none_optionals__
    ),
    __set_as_default_factory_for_type__
    defaults, dynamic factories via
    Factory.create_factory
    ,
    coverage()
    for discriminated unions.
  • Pytest integration
    @register_fixture
    , fixture scoping, the
    polyfactory.pytest_plugin
    module, async fixtures, and the difference between class-decorator and function-decorator forms.
  • Litestar patterns — Using factories with
    TestClient
    /
    AsyncTestClient
    , parametrizing handler tests via
    coverage()
    , integrating with
    litestar-testing
    fixtures, msgspec DTOs, advanced-alchemy model factories, and SAQ task payload generation.

如需详细指南,请参考
references/
中的以下文档:
  • Factories——各后端工厂基类(Pydantic / dataclass / msgspec / attrs / TypedDict / ODM)、随机化控制(
    __random_seed__
    __faker__
    __allow_none_optionals__
    )、
    __set_as_default_factory_for_type__
    默认值、通过
    Factory.create_factory
    创建动态工厂、用于判别联合的
    coverage()
  • Pytest integration——
    @register_fixture
    、夹具作用域、
    polyfactory.pytest_plugin
    模块、异步夹具,以及类装饰器和函数装饰器形式的区别。
  • Litestar patterns——将工厂与
    TestClient
    /
    AsyncTestClient
    配合使用、通过
    coverage()
    参数化处理器测试、与
    litestar-testing
    夹具集成、msgspec DTO、advanced-alchemy模型工厂,以及SAQ任务负载生成。

Official References

官方参考

Shared Styleguide Baseline

共享风格指南基准

  • General Principles
  • Python
  • 通用原则
  • Python