Declaring Factories#

Defining factories is done using a declarative syntax. That is - users declare factory classes, which are subclasses of base factories.

Declaring a factory for a dataclass#
from dataclasses import dataclass

from polyfactory.factories import DataclassFactory


@dataclass
class Person:
    name: str
    age: float
    height: float
    weight: float


class PersonFactory(DataclassFactory[Person]):
    __model__ = Person


def test_is_person() -> None:
    person_instance = PersonFactory.build()
    assert isinstance(person_instance, Person)
    assert isinstance(person_instance.name, str)
    assert isinstance(person_instance.age, float)
    assert isinstance(person_instance.height, float)
    assert isinstance(person_instance.weight, float)

You can also specify the model type by only specifying the factory generic type parameter.

@dataclass
class Person:
    name: str
    age: float
    height: float
    weight: float

class PersonFactory(DataclassFactory[Person]):
    ...

Note

The syntax with the __model__ class attribute omitting is only available since version 2.13.0.

The same applies to the other factories exported by this library, for example:

Declaring a factory for a typed-dict#
from typing import TypedDict

from polyfactory.factories import TypedDictFactory


class Person(TypedDict):
    name: str
    age: float
    height: float
    weight: float


class PersonFactory(TypedDictFactory[Person]):
    ...


def test_is_person() -> None:
    person_instance = PersonFactory.build()
    assert isinstance(person_instance, dict)
    assert isinstance(person_instance.get("name"), str)
    assert isinstance(person_instance.get("age"), float)
    assert isinstance(person_instance.get("height"), float)
    assert isinstance(person_instance.get("weight"), float)

Or for pydantic models:

Declaring a factory for a pydantic model#
from pydantic import BaseModel

from polyfactory.factories.pydantic_factory import ModelFactory


class Person(BaseModel):
    name: str
    age: float
    height: float
    weight: float


class PersonFactory(ModelFactory[Person]):
    ...


def test_is_person() -> None:
    person_instance = PersonFactory.build()
    assert isinstance(person_instance, Person)
    assert isinstance(person_instance.name, str)
    assert isinstance(person_instance.age, float)
    assert isinstance(person_instance.height, float)
    assert isinstance(person_instance.weight, float)

Note

You can also define factories for any 3rd party implementation of dataclasses, as long as it fulfills the stdlib dataclasses interface. For example, this is using the pydantic @dataclass decorator:

Declaring a factory for a pydantic dataclass#
from pydantic.dataclasses import dataclass

from polyfactory.factories import DataclassFactory


@dataclass
class Person:
    name: str
    age: float
    height: float
    weight: float


class PersonFactory(DataclassFactory[Person]):
    ...


def test_is_person() -> None:
    person_instance = PersonFactory.build()
    assert isinstance(person_instance, Person)
    assert isinstance(person_instance.name, str)
    assert isinstance(person_instance.age, float)
    assert isinstance(person_instance.height, float)
    assert isinstance(person_instance.weight, float)

Or for attrs models:

Declaring a factory for a attrs model#
from datetime import date, datetime
from typing import Any, Dict, List, Union
from uuid import UUID

import attrs

from polyfactory.factories.attrs_factory import AttrsFactory


@attrs.define
class Person:
    id: UUID
    name: str
    hobbies: List[str]
    age: Union[float, int]
    # an aliased variable
    birthday: Union[datetime, date] = attrs.field(alias="date_of_birth")
    # a "private" variable
    _assets: List[Dict[str, Dict[str, Any]]]


class PersonFactory(AttrsFactory[Person]):
    ...


def test_person_factory() -> None:
    person = PersonFactory.build()

    assert isinstance(person, Person)

Note

Validators are not currently supported - neither the built in validators that come with attrs nor custom validators.

Imperative Factory Creation#

Although the definition of factories is primarily meant to be done imperatively, factories expose the create_factory method. This method is used internally inside factories to dynamically create factories for models. For example, below the PersonFactory will dynamically create a PetFactory:

Dynamic factory generation#
from dataclasses import dataclass
from datetime import date, datetime
from enum import Enum
from typing import Any, Dict, List, Union
from uuid import UUID

from polyfactory.factories import DataclassFactory


class Species(str, Enum):
    CAT = "Cat"
    DOG = "Dog"


@dataclass
class Pet:
    name: str
    species: Species
    sound: str


@dataclass
class Person:
    id: UUID
    name: str
    hobbies: List[str]
    age: Union[float, int]
    birthday: Union[datetime, date]
    pets: List[Pet]
    assets: List[Dict[str, Dict[str, Any]]]


class PersonFactory(DataclassFactory[Person]):
    ...


def test_dynamic_factory_generation() -> None:
    person_instance = PersonFactory.build()
    assert len(person_instance.pets) > 0
    assert isinstance(person_instance.pets[0], Pet)

You can also use this method to create factories imperatively:

Imperative factory creation#
from dataclasses import dataclass
from enum import Enum

from polyfactory.factories import DataclassFactory


class Species(str, Enum):
    CAT = "Cat"
    DOG = "Dog"


@dataclass
class Pet:
    name: str
    species: Species
    sound: str


def test_imperative_factory_creation() -> None:
    pet_factory = DataclassFactory.create_factory(model=Pet)
    pet_instance = pet_factory.build()
    assert isinstance(pet_instance, Pet)

Eventually you can use this method on an existing concrete factory to create a sub factory overriding some parent configuration:

Imperative sub factory creation#
from dataclasses import dataclass
from enum import Enum

from polyfactory.factories import DataclassFactory


class Species(str, Enum):
    CAT = "Cat"
    DOG = "Dog"
    RABBIT = "Rabbit"
    MOUSE = "Mouse"


@dataclass
class Pet:
    name: str
    species: Species
    sound: str


def test_imperative_sub_factory_creation() -> None:
    pet_factory = DataclassFactory.create_factory(model=Pet)
    cat_factory = pet_factory.create_factory(species=Species.CAT)
    cat_instance = cat_factory.build()

    assert isinstance(cat_instance, Pet)
    assert cat_instance.species == Species.CAT

In this case you don’t need to specify the model argument to the create_factory method. The one from the parent factory will be used.