# Handling Custom Types

Sometimes you need to handle custom types, either from 3rd party libraries or from your own codebase. To achieve this, you can extend what’s referred as the providers_map:

Extending the provider map

    from dataclasses import dataclass
    from typing import Any, Dict, Type
    from uuid import UUID

    from polyfactory.factories import DataclassFactory

    # we created a special class we will use in our code
    class CustomSecret:
        def __init__(self, value: str) -> None:
            self.value = value

        def __repr__(self) -> str:
            return "*" * len(self.value)

        def __str__(self) -> str:
            return "*" * len(self.value)

    @dataclass
    class Person:
        id: UUID
        secret: CustomSecret

    # by default the factory class cannot handle unknown types,
    # so we need to override the provider map to add it:
    class PersonFactory(DataclassFactory[Person]):
        @classmethod
        def get_provider_map(cls) -> Dict[Type, Any]:
            providers_map = super().get_provider_map()

            return {
                CustomSecret: lambda: CustomSecret("jeronimo"),
                **providers_map,
            }

    def test_custom_secret_creation() -> None:
        person_instance = PersonFactory.build()
        assert isinstance(person_instance.secret, CustomSecret)
        assert repr(person_instance.secret) == "*" * len("jeronimo")
        assert str(person_instance.secret) == "*" * len("jeronimo")
        assert person_instance.secret.value == "jeronimo"

In the above example we override the get_provider_map class method, which maps types to callables. Each callable in the map returns an appropriate mock value for the type. In the above example, an instance of CustomSecret with the hardcoded string ‘jeronimo’.

## Creating Custom Base Factories

The above works great when you need to do this in a localised fashion, but if you need to use some custom types in many places it will lead to unnecessary duplication. The solution for this is to create a custom base factory, in this case for handling dataclasses:

Creating a custom dataclass factory with extended provider map

    from dataclasses import dataclass
    from typing import Any, Dict, Generic, Type, TypeVar
    from uuid import UUID

    from polyfactory.factories import DataclassFactory

    # we created a special class we will use in our code
    class CustomSecret:
        def __init__(self, value: str) -> None:
            self.value = value

        def __repr__(self) -> str:
            return "*" * len(self.value)

        def __str__(self) -> str:
            return "*" * len(self.value)

    T = TypeVar("T")

    # we create a custom base factory to handle dataclasses, with an extended provider map
    class CustomDataclassFactory(Generic[T], DataclassFactory[T]):
        __is_base_factory__ = True

        @classmethod
        def get_provider_map(cls) -> Dict[Type, Any]:
            providers_map = super().get_provider_map()

            return {
                CustomSecret: lambda: CustomSecret("jeronimo"),
                **providers_map,
            }

    @dataclass
    class Person:
        id: UUID
        secret: CustomSecret

    # we use our CustomDataclassFactory as a base for the PersonFactory
    class PersonFactory(CustomDataclassFactory[Person]): ...

    def test_custom_dataclass_base_factory() -> None:
        person_instance = PersonFactory.build()
        assert isinstance(person_instance.secret, CustomSecret)
        assert repr(person_instance.secret) == "*" * len("jeronimo")
        assert str(person_instance.secret) == "*" * len("jeronimo")
        assert person_instance.secret.value == "jeronimo"

Note

If extra configs values are defined for custom base classes, then `__config_keys__` should be extended so that these values are correctly passed onto to concrete factories.