CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-polyfactory

Mock data generation factories for Python types with support for dataclasses, Pydantic, SQLAlchemy, and more

Pending
Overview
Eval results
Files

customization.mddocs/

Customization

Extensible system for registering custom value generators, configuring factory behavior, and adapting polyfactory to specific types and use cases. The provider system allows fine-grained control over how values are generated for any type.

Capabilities

Provider Registration

Register custom value generators for specific types, overriding default generation behavior with domain-specific logic.

@classmethod
def add_provider(cls, provider_type: Any, provider_function: Callable[[], Any]) -> None:
    """
    Register a custom provider function for a specific type.
    
    Parameters:
    - provider_type: The type to register the provider for
    - provider_function: Callable with no arguments that generates values for the type
    """

@classmethod
def get_provider_map(cls) -> dict[type, Callable[[], Any]]:
    """
    Get the current mapping of types to provider functions.
    
    Returns:
    Dictionary mapping types to their provider functions
    """

Usage Example:

from dataclasses import dataclass
from polyfactory.factories import DataclassFactory
from enum import Enum
import random

class Priority(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"

@dataclass
class Task:
    title: str
    priority: Priority
    estimated_hours: int

class TaskFactory(DataclassFactory[Task]):
    __model__ = Task
    
    # Register custom provider for Priority enum
    @classmethod
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.add_provider(Priority, lambda: random.choice(list(Priority)))
        
        # Custom provider for estimated hours based on priority
        def hours_provider():
            # This would have access to other generated values in real implementation
            return random.randint(1, 40)
        
        cls.add_provider(int, hours_provider)  # Override int generation for this factory

task = TaskFactory.build()  # Uses custom Priority and hours logic

Random Seed Control

Control randomization for reproducible test data generation across faker and random instances.

@classmethod
def seed_random(cls, seed: int) -> None:
    """
    Seed the random number generators for deterministic generation.
    
    Parameters:
    - seed: Integer seed value for reproducible random generation
    """

Usage Example:

from polyfactory.factories import DataclassFactory

# Set seed for reproducible generation
UserFactory.seed_random(42)

# These will generate the same data every time
user1 = UserFactory.build()
user2 = UserFactory.build()

# Reset with same seed to get identical results
UserFactory.seed_random(42)
user3 = UserFactory.build()  # Identical to user1

Factory Configuration Attributes

Comprehensive set of configuration attributes that control factory behavior and generation patterns.

class ConfigurableFactory(BaseFactory[T]):
    # Core configuration
    __model__: type  # Required: Model type for the factory
    __faker__: Faker  # Faker instance for realistic data generation
    __random__: Random  # Random instance for deterministic generation
    
    # Collection behavior
    __randomize_collection_length__: bool = False  # Randomize collection sizes
    __min_collection_length__: int = 0  # Minimum collection size
    __max_collection_length__: int = 5  # Maximum collection size
    
    # Generation behavior
    __allow_none_optionals__: bool = True  # Allow None for optional fields
    __use_defaults__: bool = True  # Use model default values when available
    __check_model__: bool = True  # Validate generated instances
    
    # Persistence handlers
    __sync_persistence__: SyncPersistenceProtocol | None = None
    __async_persistence__: AsyncPersistenceProtocol | None = None
    
    # Factory registration
    __set_as_default_factory_for_type__: bool = False  # Register as default factory

Configuration Examples:

from dataclasses import dataclass
from polyfactory.factories import DataclassFactory
from faker import Faker

@dataclass
class Product:
    name: str
    tags: list[str]
    description: str | None = None

class ProductFactory(DataclassFactory[Product]):
    __model__ = Product
    
    # Custom faker instance with specific locale
    __faker__ = Faker('es_ES')  # Spanish locale
    
    # Collection configuration
    __randomize_collection_length__ = True
    __min_collection_length__ = 2
    __max_collection_length__ = 8
    
    # Always include description (no None values)
    __allow_none_optionals__ = False
    
    # Enable model validation
    __check_model__ = True

product = ProductFactory.build()  # Spanish names, 2-8 tags, always has description

Global Type Providers

Register providers that apply across all factories for common custom types.

from polyfactory import BaseFactory
from decimal import Decimal
import random

# Global provider for Decimal type
BaseFactory.add_provider(
    Decimal, 
    lambda: Decimal(str(round(random.uniform(0.01, 999.99), 2)))
)

# Now all factories will use this for Decimal fields
from dataclasses import dataclass

@dataclass
class Price:
    amount: Decimal
    currency: str

class PriceFactory(DataclassFactory[Price]):
    __model__ = Price

price = PriceFactory.build()  # Uses global Decimal provider

Custom Factory Creation

Create factories dynamically for types without explicit factory class definition.

@classmethod
def create_factory(
    cls, 
    model: type, 
    **kwargs
) -> type[BaseFactory]:
    """
    Dynamically create a factory class for a model type.
    
    Parameters:
    - model: The model type to create a factory for
    - **kwargs: Configuration attributes for the factory class
    
    Returns:
    Factory class configured for the specified model
    """

Usage Example:

from typing import TypedDict

class OrderDict(TypedDict):
    id: int
    total: float
    items: list[str]

# Create factory dynamically with custom configuration
OrderFactory = BaseFactory.create_factory(
    OrderDict,
    __min_collection_length__=1,
    __max_collection_length__=10,
    __allow_none_optionals__=False
)

# Add custom provider to dynamic factory
OrderFactory.add_provider(
    float, 
    lambda: round(random.uniform(10.0, 1000.0), 2)
)

order = OrderFactory.build()

Type Support and Extensions

Check type support and extend polyfactory's capabilities for custom types.

@classmethod
def is_supported_type(cls, value: Any) -> bool:
    """
    Check if a type is supported for automatic generation.
    
    Parameters:
    - value: Type or value to check for support
    
    Returns:
    True if the type can be automatically generated, False otherwise
    """

Usage Example:

from typing import NewType
from polyfactory import BaseFactory

# Custom type
UserId = NewType('UserId', int)

# Check if supported
if not BaseFactory.is_supported_type(UserId):
    # Add provider for custom type
    BaseFactory.add_provider(
        UserId, 
        lambda: UserId(random.randint(1, 999999))
    )

# Now UserId is supported
assert BaseFactory.is_supported_type(UserId)

Advanced Customization Patterns

Factory Inheritance with Custom Behavior

class BaseModelFactory(DataclassFactory[T]):
    """Base factory with common customizations."""
    
    # Common configuration
    __randomize_collection_length__ = True
    __min_collection_length__ = 1
    __max_collection_length__ = 3
    __allow_none_optionals__ = False
    
    @classmethod
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        
        # Add common providers to all subclasses
        cls.add_provider(
            str, 
            lambda: cls.__faker__.sentence(nb_words=3).rstrip('.')
        )

@dataclass
class User:
    name: str
    tags: list[str]

class UserFactory(BaseModelFactory[User]):
    __model__ = User
    # Inherits all base customizations

user = UserFactory.build()  # Uses inherited behavior

Context-Aware Providers

class ContextAwareFactory(DataclassFactory[Model]):
    _context = {}
    
    @classmethod
    def with_context(cls, **context):
        """Create factory instance with context."""
        factory = type(cls.__name__, (cls,), {})
        factory._context = context
        return factory
    
    @classmethod
    def context_provider(cls, key: str, default_provider: Callable):
        """Provider that uses context if available."""
        def provider():
            if key in cls._context:
                return cls._context[key]
            return default_provider()
        return provider

# Usage
@dataclass
class TestData:
    environment: str
    version: str

class TestDataFactory(ContextAwareFactory[TestData]):
    __model__ = TestData
    
    @classmethod
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.add_provider(
            str, 
            cls.context_provider('environment', lambda: 'development')
        )

# Use with context
ProductionFactory = TestDataFactory.with_context(environment='production')
data = ProductionFactory.build()  # environment will be 'production'

Conditional Generation

class ConditionalFactory(DataclassFactory[Model]):
    @classmethod
    def build_with_condition(cls, condition: str, **kwargs):
        """Build instance with conditional logic."""
        
        if condition == 'premium':
            cls.add_provider(int, lambda: random.randint(100, 1000))
        elif condition == 'basic':
            cls.add_provider(int, lambda: random.randint(1, 100))
        
        return cls.build(**kwargs)

# Usage
premium_user = UserFactory.build_with_condition('premium', name='VIP User')
basic_user = UserFactory.build_with_condition('basic', name='Regular User')

Install with Tessl CLI

npx tessl i tessl/pypi-polyfactory

docs

customization.md

factory-operations.md

field-configuration.md

index.md

persistence.md

specialized-factories.md

tile.json