CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-factory-boy

A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby

Pending
Overview
Eval results
Files

helpers-and-utilities.mddocs/

Helper Functions and Utilities

Convenience functions for direct object creation, debugging tools, factory generation utilities, and functional-style declaration wrappers. These utilities provide alternative ways to use Factory Boy and simplify common patterns.

Capabilities

Direct Object Creation Functions

Standalone functions for creating objects without defining factory classes, useful for simple cases and one-off object generation.

def build(klass, **kwargs):
    """
    Build single instance of a class without persistence.
    
    Args:
        klass: Class to instantiate
        **kwargs: Attribute values for the instance
        
    Returns:
        Instance of klass
    """

def create(klass, **kwargs):
    """
    Create single instance of a class with persistence.
    
    Args:
        klass: Class to instantiate  
        **kwargs: Attribute values for the instance
        
    Returns:
        Persisted instance of klass
    """

def stub(klass, **kwargs):
    """
    Create stub object with attributes only (no persistence).
    
    Args:
        klass: Class to use as model reference
        **kwargs: Attribute values for the stub
        
    Returns:
        StubObject with specified attributes
    """

def generate(klass, strategy, **kwargs):
    """
    Generate instance using specified strategy.
    
    Args:
        klass: Class to instantiate
        strategy (str): 'build', 'create', or 'stub'
        **kwargs: Attribute values for the instance
        
    Returns:
        Instance created with specified strategy
    """

def simple_generate(klass, create, **kwargs):
    """
    Generate instance with boolean create flag.
    
    Args:
        klass: Class to instantiate
        create (bool): True for create strategy, False for build
        **kwargs: Attribute values for the instance
        
    Returns:
        Instance created with specified strategy
    """

Usage Examples

from factory.helpers import build, create, stub, generate, simple_generate

# Direct object creation without factory classes
user = build(User, name='Test User', email='test@example.com')
user = create(User, name='Persistent User', email='persist@example.com')
user = stub(User, name='Stub User', email='stub@example.com')

# Using strategy parameter
user = generate(User, 'build', name='Generated User')
user = simple_generate(User, create=False, name='Simple User')

Batch Object Creation Functions

Functions for creating multiple objects at once without factory classes.

def build_batch(klass, size, **kwargs):
    """
    Build multiple instances without persistence.
    
    Args:
        klass: Class to instantiate
        size (int): Number of instances to create
        **kwargs: Attribute values for all instances
        
    Returns:
        List of instances
    """

def create_batch(klass, size, **kwargs):
    """
    Create multiple instances with persistence.
    
    Args:
        klass: Class to instantiate
        size (int): Number of instances to create
        **kwargs: Attribute values for all instances
        
    Returns:
        List of persisted instances
    """

def stub_batch(klass, size, **kwargs):
    """
    Create multiple stub objects.
    
    Args:
        klass: Class to use as model reference
        size (int): Number of stubs to create
        **kwargs: Attribute values for all stubs
        
    Returns:
        List of StubObjects
    """

def generate_batch(klass, strategy, size, **kwargs):
    """
    Generate multiple instances using specified strategy.
    
    Args:
        klass: Class to instantiate
        strategy (str): 'build', 'create', or 'stub'
        size (int): Number of instances to create
        **kwargs: Attribute values for all instances
        
    Returns:
        List of instances created with specified strategy
    """

def simple_generate_batch(klass, create, size, **kwargs):
    """
    Generate multiple instances with boolean create flag.
    
    Args:
        klass: Class to instantiate
        create (bool): True for create strategy, False for build
        size (int): Number of instances to create
        **kwargs: Attribute values for all instances
        
    Returns:
        List of instances
    """

Usage Examples

from factory.helpers import build_batch, create_batch, stub_batch

# Batch creation without factory classes
users = build_batch(User, 5, is_active=True)
users = create_batch(User, 10, department='Engineering')
stubs = stub_batch(User, 3, role='admin')

# Using strategy and simple_generate
users = generate_batch(User, 'build', 5, status='pending')
users = simple_generate_batch(User, create=True, size=3, verified=True)

Factory Creation Utilities

Functions for dynamically creating factory classes from existing classes.

def make_factory(klass, **kwargs):
    """
    Create simple factory class for given class with default attributes.
    
    Args:
        klass: Class to create factory for
        **kwargs: Default attribute values for the factory
        
    Returns:
        Factory class configured for klass
    """

Usage Examples

from factory.helpers import make_factory

# Dynamically create factory
UserFactory = make_factory(
    User,
    name='Test User',
    email=factory.Sequence(lambda n: f'user{n}@example.com'),
    is_active=True
)

# Use like any other factory
user = UserFactory()
user = UserFactory(name='Custom Name')
users = UserFactory.create_batch(5)

# With complex declarations
PostFactory = make_factory(
    Post,
    title=factory.Faker('sentence'),
    content=factory.Faker('text'),
    author=factory.SubFactory(UserFactory),
    published_at=factory.LazyFunction(lambda: timezone.now())
)

Debugging and Inspection

Tools for debugging factory behavior and understanding object creation.

def debug(logger='factory', stream=None):
    """
    Context manager for factory debugging that logs detailed creation steps.
    
    Args:
        logger (str): Logger name to use (default: 'factory')
        stream: Output stream for debug messages (default: None uses logger)
        
    Returns:
        Context manager for debugging factory operations
    """

Usage Examples

from factory.helpers import debug
import logging

# Enable debug logging
logging.basicConfig(level=logging.DEBUG)

# Debug single factory call
with debug():
    user = UserFactory()
    # Logs: Building User instance
    # Logs: Setting attribute 'name' to 'Test User'
    # Logs: Setting attribute 'email' to 'user1@example.com'
    # etc.

# Debug with custom stream
import sys
with debug(stream=sys.stdout):
    users = UserFactory.create_batch(3)

# Debug with custom logger  
with debug(logger='my_factory_debug'):
    post = PostFactory(author__name='Custom Author')

Functional Declaration Wrappers

Decorator functions that convert regular functions into factory declarations, enabling functional programming patterns.

def lazy_attribute(func):
    """
    Wrap function as LazyAttribute declaration.
    
    Args:
        func: Function that takes instance and returns attribute value
        
    Returns:
        LazyAttribute declaration
    """

def sequence(func):
    """
    Wrap function as Sequence declaration.
    
    Args:
        func: Function that takes sequence number and returns attribute value
        
    Returns:
        Sequence declaration
    """

def lazy_attribute_sequence(func):
    """
    Wrap function as LazyAttributeSequence declaration.
    
    Args:
        func: Function that takes (instance, sequence_number) and returns value
        
    Returns:
        LazyAttributeSequence declaration
    """

def container_attribute(func):
    """
    Wrap function as ContainerAttribute declaration (non-strict mode).
    
    Args:
        func: Function that takes (instance, containers) and returns value
        
    Returns:
        ContainerAttribute declaration with strict=False
    """

def post_generation(func):
    """
    Wrap function as PostGeneration declaration.
    
    Args:
        func: Function that takes (instance, create, extracted, **kwargs)
        
    Returns:
        PostGeneration declaration
    """

def iterator(func):
    """
    Turn generator function into Iterator declaration.
    
    Args:
        func: Generator function that yields values
        
    Returns:
        Iterator declaration using function output
    """

Usage Examples

from factory.helpers import (
    lazy_attribute, sequence, lazy_attribute_sequence, 
    container_attribute, post_generation, iterator
)

# Functional approach to factory definitions
@lazy_attribute
def full_name(obj):
    return f'{obj.first_name} {obj.last_name}'

@sequence
def username(n):
    return f'user_{n:04d}'

@lazy_attribute_sequence  
def email(obj, n):
    return f'{obj.username}_{n}@example.com'

@container_attribute
def parent_id(obj, containers):
    return containers[0].id if containers else None

@post_generation
def setup_profile(obj, create, extracted, **kwargs):
    if create:
        obj.create_profile()
        obj.send_welcome_email()

@iterator
def department_generator():
    departments = ['Engineering', 'Sales', 'Marketing', 'HR']
    while True:
        for dept in departments:
            yield dept

# Use in factory definition
class UserFactory(Factory):
    class Meta:
        model = User
    
    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
    full_name = full_name
    username = username
    email = email
    department = department_generator
    setup_profile = setup_profile

# Inline usage
class EmployeeFactory(Factory):
    class Meta:
        model = Employee
    
    # Direct decorator usage
    employee_id = sequence(lambda n: f'EMP{n:06d}')
    
    display_name = lazy_attribute(
        lambda obj: f'{obj.last_name}, {obj.first_name}'
    )
    
    notify_hr = post_generation(
        lambda obj, create, extracted: 
            hr_system.notify_new_employee(obj) if create else None
    )

Advanced Helper Patterns

Custom Factory Creation

def make_factory_with_traits(klass, traits=None, **defaults):
    """Custom factory creation with trait support."""
    
    class DynamicFactory(Factory):
        class Meta:
            model = klass
        
        class Params:
            pass
    
    # Add default attributes
    for key, value in defaults.items():
        setattr(DynamicFactory, key, value)
    
    # Add traits
    if traits:
        for trait_name, trait_attrs in traits.items():
            setattr(DynamicFactory.Params, trait_name, Trait(**trait_attrs))
    
    return DynamicFactory

# Usage
UserFactory = make_factory_with_traits(
    User,
    traits={
        'admin': {'is_staff': True, 'is_superuser': True},
        'inactive': {'is_active': False, 'last_login': None}
    },
    username=sequence(lambda n: f'user{n}'),
    email=lazy_attribute(lambda obj: f'{obj.username}@example.com')
)

admin_user = UserFactory(admin=True)
inactive_user = UserFactory(inactive=True)

Conditional Factory Creation

from factory.helpers import create, build

def create_user_conditionally(persist=True, **kwargs):
    """Create user with conditional persistence."""
    if persist:
        return create(User, **kwargs)
    else:
        return build(User, **kwargs)

# Usage in tests
def test_user_creation():
    # Development mode - don't persist
    user = create_user_conditionally(
        persist=settings.DEBUG,
        name='Test User'
    )

Debug-Enabled Factory Creation

def debug_factory(factory_class):
    """Decorator to add debugging to factory class."""
    
    original_create = factory_class.create
    original_build = factory_class.build
    
    @classmethod
    def debug_create(cls, **kwargs):
        with debug():
            return original_create(**kwargs)
    
    @classmethod  
    def debug_build(cls, **kwargs):
        with debug():
            return original_build(**kwargs)
    
    factory_class.create = debug_create
    factory_class.build = debug_build
    
    return factory_class

# Usage
@debug_factory
class UserFactory(Factory):
    class Meta:
        model = User
    
    name = Faker('name')

# All creation operations are now automatically debugged
user = UserFactory.create()  # Debug output included

Install with Tessl CLI

npx tessl i tessl/pypi-factory-boy

docs

core-factories.md

declarations.md

helpers-and-utilities.md

index.md

orm-integration.md

tile.json