ProvenPin Install

Faker and polyfactory seeded Pydantic model factories offline: working versions (tested 2026-10-16)

Define Pydantic models and generate fixtures offline with polyfactory, binding one Faker instance so Use() providers and seed_random stay reproducible.

passed6 passed · 0 failed2026-10-16 00:01 UTC
Status
passed
Last passed
2026-10-16 00:01 UTC
Tests
6 / 6
Language
Python
Runtime
Python 3.13.16
pinned versions4
faker@40.43.0polyfactory@3.3.0pydantic@2.14.1pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38826982604

The code

Exactly the files that passed. Your agent can pull them with get_recipe("faker-polyfactory-seeded") (install), or see them on GitHub.

requirements.txt
faker==40.43.0
polyfactory==3.3.0
pydantic==2.14.1
pytest==9.1.1
factories.py
from typing import Annotated, Literal

from faker import Faker
from polyfactory import Use
from polyfactory.factories.pydantic_factory import ModelFactory
from pydantic import BaseModel, Field


class Address(BaseModel):
    city: str
    country_code: Annotated[str, Field(pattern=r"^[A-Z]{2}$")]


class Customer(BaseModel):
    id: int
    email: str
    age: int = Field(ge=18, le=99)
    plan: Literal["free", "pro"]
    address: Address


class CustomerFactory(ModelFactory[Customer]):
    # no __faker__ of its own, so it inherits the Faker shared by every factory
    __model__ = Customer


_fake = Faker()


class SeededCustomerFactory(ModelFactory[Customer]):
    # bind one Faker instance so seed_random() and Use() drive the same generator
    __model__ = Customer
    __faker__ = _fake
    email = Use(_fake.email)


def reseed(factory: type[ModelFactory[Customer]], seed: int) -> type[ModelFactory[Customer]]:
    factory.seed_random(seed)
    return factory
tests/test_factories.py
import pytest
from pydantic import ValidationError

from factories import (
    Customer,
    CustomerFactory,
    ModelFactory,
    SeededCustomerFactory,
    reseed,
)


def test_type_generation_ignores_field_names():
    reseed(CustomerFactory, 1)
    assert "@" not in CustomerFactory.build().email  # str becomes pystr(), not an email

    reseed(SeededCustomerFactory, 1)
    assert "@" in SeededCustomerFactory.build().email  # Use(fake.email) instead


def test_seed_random_makes_batches_repeatable():
    first = [c.model_dump() for c in reseed(SeededCustomerFactory, 1234).batch(3)]
    second = [c.model_dump() for c in reseed(SeededCustomerFactory, 1234).batch(3)]
    assert first == second


def test_batch_resumes_the_faker_stream_without_a_reseed():
    reseed(SeededCustomerFactory, 7)
    a = SeededCustomerFactory.build().email
    b = SeededCustomerFactory.build().email
    assert a != b  # __random_seed__ only fires once, when the class is created


def test_field_constraints_are_enforced_while_generating():
    for customer in reseed(SeededCustomerFactory, 99).batch(25):
        assert 18 <= customer.age <= 99
        assert customer.plan in {"free", "pro"}
        assert len(customer.address.country_code) == 2
        assert customer.address.country_code.isupper()


def test_construct_build_bypasses_validation():
    with pytest.raises(ValidationError):
        SeededCustomerFactory.build(age=10)

    invalid = SeededCustomerFactory.build(factory_use_construct=True, age=10)
    assert invalid.age == 10  # model_construct() skips the ge=18 constraint


def test_default_faker_is_shared_so_seeding_leaks():
    other = ModelFactory.create_factory(Customer)
    assert other.__faker__ is CustomerFactory.__faker__

    a = [c.model_dump() for c in reseed(CustomerFactory, 11).batch(2)]
    b = [c.model_dump() for c in reseed(other, 11).batch(2)]
    assert a == b  # both draw from BaseFactory's single Faker instance

    assert SeededCustomerFactory.__faker__ is not CustomerFactory.__faker__
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.