# Factory Configuration

Factories can be configured by setting special dunder (double underscore) class attributes. You can read the reference for these in the API reference for `BaseFactory`. Below we discuss some configuration options in some depth.

## Seeding Randomness

Seeding the factory’s ‘random.Random’

    from dataclasses import dataclass

    from polyfactory.factories import DataclassFactory

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

    class PersonFactory(DataclassFactory[Person]):
        __random_seed__ = 1

        @classmethod
        def name(cls) -> str:
            return cls.__random__.choice(["John", "Alice", "George"])

    def test_random_seed() -> None:
        # the outcome of 'factory.__random__.choice' is deterministic, because Random has been seeded with a set value.
        assert PersonFactory.build().name == "John"
        assert PersonFactory.build().name == "George"
        assert PersonFactory.build().name == "John"

Seeding randomness allows you to control the random generation of values produced by the factory. This affects all `random.Random` methods as well as faker.

## Setting Random

Setting the factory’s ‘random.Random’

    from dataclasses import dataclass
    from random import Random

    from polyfactory.factories import DataclassFactory

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

    class PersonFactory(DataclassFactory[Person]):
        __random__ = Random(10)

        @classmethod
        def name(cls) -> str:
            return cls.__random__.choice(["John", "Alice", "George"])

    def test_setting_random() -> None:
        # the outcome of 'factory.__random__.choice' is deterministic, because Random is configured with a set value.
        assert PersonFactory.build().name == "George"
        assert PersonFactory.build().name == "John"
        assert PersonFactory.build().name == "Alice"

This configuration option is functionally identical to the previous, with the difference being that here we are setting the actual instance of `random.Random`. This is useful when embedding factories inside more complex logic, such as in other libraries, as well as when factories are being dynamically generated.

## Setting Faker

Setting the factory’s ‘Faker’

    from dataclasses import dataclass

    from faker import Faker

    from polyfactory.factories import DataclassFactory

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

    class PersonFactory(DataclassFactory[Person]):
        __faker__ = Faker(locale="es_ES")

        __random_seed__ = 10

        @classmethod
        def name(cls) -> str:
            return cls.__faker__.name()

    def test_setting_faker() -> None:
        # the outcome of faker deterministic because we seeded random, and it uses a spanish locale.
        assert PersonFactory.build().name == "Alejandra Romeu-Tolosa"

In the above example we are setting the factory’s instance of `Faker` and configure its locale to Spanish. Because we are also setting the random seed value, the results of the test are deterministic.

Note

To understand why we are using a classmethod here, see the documentation about factory fields.

## Persistence Handlers

Factory classes have four optional persistence methods:

- `.create_sync(**kwargs)` - builds and persists a single instance of the factory’s model synchronously

- `.create_batch_sync(size: int, **kwargs)` - builds and persists a list of size n instances synchronously

- `.create_async(**kwargs)` - builds and persists a single instance of the factory’s model asynchronously

- `.create_batch_async(size: int, **kwargs)` - builds and persists a list of size n instances asynchronously

To use these methods, you must first specify a sync and/or async persistence handlers for the factory:

Defining and using persistence handlers.

    from asyncio import sleep
    from dataclasses import dataclass
    from typing import Dict, List
    from uuid import UUID

    from polyfactory import AsyncPersistenceProtocol, SyncPersistenceProtocol
    from polyfactory.factories import DataclassFactory

    @dataclass
    class Person:
        id: UUID
        name: str

    # we will use a dictionary to persist values for the example
    mock_db: Dict[UUID, Person] = {}

    class SyncPersistenceHandler(SyncPersistenceProtocol[Person]):
        def save(self, data: Person) -> Person:
            # do stuff here to persist the value, such as use an ORM or ODM, cache in redis etc.
            # in our case we simply save it in the dictionary.
            mock_db[data.id] = data
            return data

        def save_many(self, data: List[Person]) -> List[Person]:
            # same as for save, here we should store the list in persistence.
            # in this case, we use the same dictionary.
            for person in data:
                mock_db[person.id] = person
            return data

    class AsyncPersistenceHandler(AsyncPersistenceProtocol[Person]):
        async def save(self, data: Person) -> Person:
            # do stuff here to persist the value using an async method, such as an async ORM or ODM.
            # in our case we simply save it in the dictionary and add a minimal sleep to mock async.
            mock_db[data.id] = data
            await sleep(0.0001)
            return data

        async def save_many(self, data: List[Person]) -> List[Person]:
            # same as for the async save, here we should store the list in persistence using async logic.
            # we again store in dict, and mock async using sleep.
            for person in data:
                mock_db[person.id] = person
            await sleep(0.0001)
            return data

    class PersonFactory(DataclassFactory[Person]):
        __sync_persistence__ = SyncPersistenceHandler
        __async_persistence__ = AsyncPersistenceHandler

    def test_sync_persistence_build() -> None:
        person_instance = PersonFactory.create_sync()
        assert mock_db[person_instance.id] is person_instance

    def test_sync_persistence_batch() -> None:
        person_batch = PersonFactory.create_batch_sync(10)
        for person_instance in person_batch:
            assert mock_db[person_instance.id] is person_instance

    async def test_async_persistence_build() -> None:
        person_instance = await PersonFactory.create_async()
        assert mock_db[person_instance.id] is person_instance

    async def test_async_persistence_batch() -> None:
        person_batch = await PersonFactory.create_batch_async(10)
        for person_instance in person_batch:
            assert mock_db[person_instance.id] is person_instance

With the persistence handlers in place, you can now use all persistence methods.

Note

You do not need to define both persistence handlers. If you will only use sync or async persistence, you only need to define the respective handler to use these methods.

## Defining Default Factories

As explained in the section about dynamic factory generation in declaring factories, factories generate new factories for supported types dynamically. This process requires no intervention from the user. Once a factory is generated, it is then cached and reused - when the same type is used.

For example, when build is called for the `PersonFactory` below, a `PetFactory` will be dynamically generated and reused:

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 control the default factory for a type by declaring a factory as the type default:

Setting a factory as a type default.

    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 import Use
    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 PetFactory(DataclassFactory[Pet]):
        __set_as_default_factory_for_type__ = True

        name = Use(DataclassFactory.__random__.choice, ["Roxy", "Spammy", "Moshe"])

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

    def test_default_pet_factory() -> None:
        person_instance = PersonFactory.build()
        assert len(person_instance.pets) > 0
        assert person_instance.pets[0].name in ["Roxy", "Spammy", "Moshe"]

## Randomized Collection Length

Set of fields that allow you to generate a collection with random lengths. By default only one item is generated.

Randomized collection length

    from dataclasses import dataclass
    from typing import Tuple

    from polyfactory.factories import DataclassFactory

    @dataclass
    class Owner:
        cars: Tuple[str, ...]

    class OwnerFactory(DataclassFactory[Owner]):
        __randomize_collection_length__ = True
        __min_collection_length__ = 2
        __max_collection_length__ = 5

    def test_randomized_collection_length() -> None:
        owner = OwnerFactory.build()
        assert 2 <= len(owner.cars) <= 5

## Allow None Optionals

Allow None to be generated as a value for types marked as optional. When set to True, the outputted value will be randomly chosen between None and other allowed types. By default, this is set to True.

By setting to False, then optional types will always be treated as the wrapped type:

Disable Allow None Optionals

    from dataclasses import dataclass
    from typing import Optional
    from uuid import UUID

    from polyfactory.factories.dataclass_factory import DataclassFactory

    @dataclass
    class Person:
        id: UUID
        name: Optional[str]

    class PersonFactory(DataclassFactory[Person]):
        __allow_none_optionals__ = False

    def test_optional_type_ignored() -> None:
        person_instance = PersonFactory.build()
        assert isinstance(person_instance.name, str)

## Check Factory Fields

When __check_model__ is set to True, declaring fields on the factory that don’t exist on the model will trigger an exception.

This is only true when fields are declared with `Use`, `PostGenerated`, `Ignore` and `Require`. Any other field definition will not be checked.

Enable Check Factory Fields

    from dataclasses import dataclass
    from uuid import UUID

    import pytest

    from polyfactory import ConfigurationException, PostGenerated
    from polyfactory.factories.dataclass_factory import DataclassFactory

    @dataclass
    class Person:
        id: UUID

    def test_check_factory_fields() -> None:
        with pytest.raises(
            ConfigurationException,
            match="unknown_field is declared on the factory PersonFactory but it is not part of the model Person",
        ):

            class PersonFactory(DataclassFactory[Person]):
                __check_model__ = True
                unknown_field = PostGenerated(lambda: "foo")

## Use Default Values

If `__use_defaults__` is set to `True`, then the default value will be used instead of creating a random value for a given field, provided there’s a default value for that field.

By default, `__use_defaults__` is set to `False.` If you need more fine grained control, you can override the `should_use_default_value()` classmethod.

Note

Setting `__use_defaults__` has no effect for `TypedDictFactory` since you cannot set default values for `TypedDict`.

Use Default Values

    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
        sound: str = "meow"
        species: Species = Species.CAT

    class PetFactory(DataclassFactory[Pet]):
        __model__ = Pet
        __use_defaults__ = True

    def test_use_default() -> None:
        pet = PetFactory.build()

        assert pet.species == Species.CAT
        assert pet.sound == "meow"