Generate Hypothesis strategies from polyfactory pydantic models: working versions (tested 2026-10-15)
Bridge a polyfactory ModelFactory into Hypothesis: regex strings, HttpUrl and other pydantic-core types come from the factory while the fields under test stay drawable and shrinkable.
passed6 passed · 0 failed2026-10-15 18:59 UTC- Status
- passed
- Last passed
- 2026-10-15 18:59 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38790162748
The code
Exactly the files that passed. Your agent can pull them with get_recipe("hypothesis-polyfactory-models") (install), or see them on GitHub.
hypothesis==6.169.4 polyfactory==3.3.0 pydantic==2.14.1 pytest==9.1.1
from enum import Enum
from pydantic import BaseModel, Field, HttpUrl
class Plan(str, Enum):
free = "free"
pro = "pro"
class Coupon(BaseModel):
code: str = Field(pattern=r"^[A-Z]{2}-\d{4}$")
class Merchant(BaseModel):
id: int = Field(ge=1)
plan: Plan = Plan.free
seats: int = Field(ge=1, le=100)
callback_url: HttpUrl
from polyfactory.factories.pydantic_factory import ModelFactory
from models import Coupon, Merchant
class CouponFactory(ModelFactory[Coupon]):
__model__ = Coupon
class MerchantFactory(ModelFactory[Merchant]):
__model__ = Merchant
from typing import Annotated, Any
import hypothesis.strategies as st
from polyfactory.factories.pydantic_factory import ModelFactory
def field(factory: type[ModelFactory], name: str) -> st.SearchStrategy[Any]:
# pydantic stores Field(ge=...) as Annotated metadata; rebuild it so
# Hypothesis can generate values that actually satisfy the constraint.
info = factory.__model__.model_fields[name]
if info.metadata:
return st.from_type(Annotated[info.annotation, *info.metadata])
return st.from_type(info.annotation)
def from_factory(
factory: type[ModelFactory], **overrides: st.SearchStrategy[Any]
) -> st.SearchStrategy[Any]:
# Only the named fields are owned by Hypothesis; the factory fills the rest
# (regex strings, HttpUrl, custom providers) so pydantic validation passes.
return st.builds(factory.build, **overrides)
import hypothesis.strategies as st
import pytest
from hypothesis import given
from hypothesis.errors import HypothesisWarning, ResolutionFailed
from pydantic import HttpUrl, ValidationError
from factories import CouponFactory, MerchantFactory
from models import Coupon
from strategies import field, from_factory
def test_hypothesis_cannot_resolve_pydantic_url():
with pytest.raises(ResolutionFailed):
st.from_type(HttpUrl).validate()
def test_hypothesis_ignores_regex_pattern():
strategy = st.builds(Coupon)
with pytest.raises(ValidationError), pytest.warns(HypothesisWarning, match="pattern"):
strategy.example()
@given(from_factory(MerchantFactory, seats=st.integers(min_value=1, max_value=100)))
def test_factory_fills_fields_hypothesis_cannot(merchant):
assert isinstance(merchant.callback_url, HttpUrl)
assert merchant.id >= 1
assert 1 <= merchant.seats <= 100
@given(field(MerchantFactory, "seats"))
def test_field_helper_preserves_pydantic_bounds(seats):
assert 1 <= seats <= 100
def test_factory_overrides_are_still_validated():
with pytest.raises(ValidationError):
MerchantFactory.build(seats=0)
def test_seed_random_reproduces_factory_offline():
CouponFactory.seed_random(1234)
first = CouponFactory.build()
CouponFactory.seed_random(1234)
second = CouponFactory.build()
assert first == second
[pytest]
pythonpath = .
filterwarnings =
ignore::hypothesis.errors.NonInteractiveExampleWarning
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.
Related stacks
Hypothesis property tests for Pydantic v2 models
Property-based tests with Hypothesis on Pydantic v2 models: JSON round trips, validator invariants, and a stateful RuleBasedStateMachine for a small inventory class.
DeepDiff diffing of pydantic v2 model dumps with ignore_order
Compare pydantic v2 model dumps with DeepDiff, normalizing python vs json dump modes and taming list order, datetime and float gotchas.
FastAPI + Pydantic v2 validators, discriminated unions and serializers
Pydantic v2 patterns in FastAPI that agents often get wrong: field_validator, model_validator, discriminated unions, computed_field and response_model filtering.
FastAPI background tasks + dependency overrides
FastAPI BackgroundTasks for post-response work, with dependency_overrides to swap services in tests.
All hypothesis recipesAll polyfactory recipesAll Pydantic recipes