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

orm-integration.mddocs/

ORM Integration

Specialized factory classes for popular Python ORMs providing database persistence, get-or-create behavior, and ORM-specific features. Factory Boy seamlessly integrates with Django, SQLAlchemy, MongoEngine, and Mogo.

Capabilities

Django ORM Integration

Factory classes and helpers specifically designed for Django models with built-in ORM features.

class DjangoModelFactory(Factory):
    """
    Factory for Django models with ORM integration.
    
    Meta attributes:
    - model: Django model class
    - django_get_or_create: Fields to use for get_or_create behavior (tuple/list)
    - database: Database alias to use (string)
    - strategy: Default strategy (inherited from Factory)
    """
    
    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        """Uses Django ORM create() or get_or_create() based on Meta options."""

class FileField:
    """
    Helper for populating Django FileField instances.
    
    Args:
        data (bytes, optional): Raw file content
        filename (str, optional): Name for the file
        from_path (str, optional): Path to read file content from
        from_file (file-like, optional): File object to read from
        from_func (callable, optional): Function returning file content
    """
    def __init__(self, data=None, filename=None, from_path=None, from_file=None, from_func=None): ...

class ImageField(FileField):
    """
    Helper for populating Django ImageField instances.
    
    Args:
        width (int): Image width in pixels (default: 100)
        height (int): Image height in pixels (default: 100)
        color (str): Image color (default: 'blue')
        format (str): Image format (default: 'JPEG')
        **kwargs: Additional FileField arguments
    """
    def __init__(self, width=100, height=100, color='blue', format='JPEG', **kwargs): ...

def mute_signals(*signals):
    """
    Context manager/decorator to disable Django signals during factory operations.
    
    Args:
        *signals: Django signal objects to mute
        
    Returns:
        Context manager that can also be used as decorator
    """

Usage Examples

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from factory.django import DjangoModelFactory, FileField, ImageField, mute_signals

# Django model
class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField()
    avatar = models.ImageField(upload_to='avatars/')
    resume = models.FileField(upload_to='resumes/')

# Django factory
class UserFactory(DjangoModelFactory):
    class Meta:
        model = User
        django_get_or_create = ('username',)  # Use get_or_create for username
        database = 'default'  # Optional database alias
    
    username = Sequence(lambda n: f'user{n}')
    email = LazyAttribute(lambda obj: f'{obj.username}@example.com')
    first_name = Faker('first_name')
    last_name = Faker('last_name')

class ProfileFactory(DjangoModelFactory):
    class Meta:
        model = Profile
    
    user = SubFactory(UserFactory)
    bio = Faker('text', max_nb_chars=200)
    
    # File field with custom content
    resume = FileField(
        filename='resume.pdf',
        data=b'%PDF-1.4 fake pdf content',
        from_func=lambda: generate_pdf_bytes()
    )
    
    # Image field with specifications
    avatar = ImageField(
        width=200,
        height=200,
        color='red',
        format='PNG'
    )

# Usage
user = UserFactory()  # Saved to database
profile = ProfileFactory()  # Creates user and profile

# Muting signals
with mute_signals(post_save):
    # post_save signals won't fire during this block
    users = UserFactory.create_batch(10)

# As decorator
@mute_signals(post_save)
def create_test_data():
    return UserFactory.create_batch(100)

SQLAlchemy Integration

Factory class for SQLAlchemy models with session management and persistence options.

class SQLAlchemyModelFactory(Factory):
    """
    Factory for SQLAlchemy models with session management.
    
    Meta attributes:
    - model: SQLAlchemy model class
    - sqlalchemy_session: SQLAlchemy session to use
    - sqlalchemy_session_persistence: Persistence strategy ('commit', 'flush', or None)
    
    Class attributes:
    - SESSION_PERSISTENCE_COMMIT = 'commit'
    - SESSION_PERSISTENCE_FLUSH = 'flush'
    """
    
    SESSION_PERSISTENCE_COMMIT = 'commit'
    SESSION_PERSISTENCE_FLUSH = 'flush'
    
    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        """Creates SQLAlchemy instance and manages session persistence."""

Usage Examples

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from factory.alchemy import SQLAlchemyModelFactory

# SQLAlchemy setup
Base = declarative_base()
engine = create_engine('sqlite:///test.db')
Session = sessionmaker(bind=engine)
session = Session()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))
    email = Column(String(100))

# Factory with session management
class UserFactory(SQLAlchemyModelFactory):
    class Meta:
        model = User
        sqlalchemy_session = session
        sqlalchemy_session_persistence = 'commit'  # or 'flush' or None
    
    username = Sequence(lambda n: f'user{n}')
    email = LazyAttribute(lambda obj: f'{obj.username}@example.com')

# Usage
user = UserFactory()  # Created and committed to database
users = UserFactory.create_batch(5)  # All committed

# Different persistence strategies
class FlushOnlyUserFactory(SQLAlchemyModelFactory):
    class Meta:
        model = User
        sqlalchemy_session = session
        sqlalchemy_session_persistence = SQLAlchemyModelFactory.SESSION_PERSISTENCE_FLUSH
    
    username = Sequence(lambda n: f'flush_user{n}')

# Creates and flushes but doesn't commit
user = FlushOnlyUserFactory()

MongoEngine Integration

Factory class for MongoEngine documents with automatic saving.

class MongoEngineFactory(Factory):
    """
    Factory for MongoEngine documents with automatic persistence.
    
    Meta attributes:
    - model: MongoEngine Document class
    """
    
    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        """Creates MongoEngine document and calls save() if it's a Document."""

Usage Examples

from mongoengine import Document, StringField, IntField, connect
from factory.mongoengine import MongoEngineFactory

# Connect to MongoDB
connect('test_db')

# MongoEngine model
class User(Document):
    username = StringField(required=True)
    email = StringField()
    age = IntField()

# MongoEngine factory
class UserFactory(MongoEngineFactory):
    class Meta:
        model = User
    
    username = Sequence(lambda n: f'user{n}')
    email = LazyAttribute(lambda obj: f'{obj.username}@example.com')
    age = Faker('random_int', min=18, max=65)

# Usage
user = UserFactory()  # Saved to MongoDB
users = UserFactory.create_batch(10)  # All saved to MongoDB

Mogo Integration

Factory class for Mogo (pymongo wrapper) objects.

class MogoFactory(Factory):
    """
    Factory for Mogo (pymongo wrapper) objects with automatic persistence.
    
    Meta attributes:
    - model: Mogo model class
    """
    
    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        """Creates Mogo instance and calls save() method."""

Usage Examples

from mogo import Model, Field
from factory.mogo import MogoFactory

# Mogo model (assuming mogo is configured)
class User(Model):
    username = Field()
    email = Field()
    age = Field()

# Mogo factory
class UserFactory(MogoFactory):
    class Meta:
        model = User
    
    username = Sequence(lambda n: f'user{n}')
    email = LazyAttribute(lambda obj: f'{obj.username}@example.com')
    age = Faker('random_int', min=18, max=65)

# Usage
user = UserFactory()  # Saved via mogo

Common ORM Integration Patterns

Database-Specific Factories

# Multiple database support (Django)
class PrimaryDBUserFactory(DjangoModelFactory):
    class Meta:
        model = User
        database = 'primary'

class AnalyticsDBUserFactory(DjangoModelFactory):
    class Meta:
        model = User  
        database = 'analytics'

Get-or-Create Behavior

# Django get_or_create
class CategoryFactory(DjangoModelFactory):
    class Meta:
        model = Category
        django_get_or_create = ('name',)  # Won't create duplicates by name
    
    name = Iterator(['Technology', 'Sports', 'News'])
    slug = LazyAttribute(lambda obj: slugify(obj.name))

# Always returns existing or creates new based on name
tech_category = CategoryFactory(name='Technology')  # Gets existing or creates

Transaction Management

# SQLAlchemy with custom session handling
from sqlalchemy.orm import scoped_session

class TransactionalUserFactory(SQLAlchemyModelFactory):
    class Meta:
        model = User
        sqlalchemy_session = scoped_session(sessionmaker())
        sqlalchemy_session_persistence = None  # Manual control
    
    username = Sequence(lambda n: f'user{n}')
    
    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        instance = super()._create(model_class, *args, **kwargs)
        # Custom transaction logic
        cls._meta.sqlalchemy_session.add(instance)
        return instance

File and Media Handling

# Django with custom file handling
class DocumentFactory(DjangoModelFactory):
    class Meta:
        model = Document
    
    title = Faker('sentence')
    
    # Generate PDF content dynamically
    file = FileField(
        filename=LazyAttribute(lambda obj: f'{slugify(obj.title)}.pdf'),
        from_func=lambda: generate_pdf_content()
    )
    
    # Image with dynamic dimensions
    thumbnail = ImageField(
        width=LazyFunction(lambda: random.randint(100, 300)),
        height=LazyFunction(lambda: random.randint(100, 300)),
        format='PNG'
    )

Signal Management

# Complex signal muting
from django.db.models.signals import post_save, pre_save, post_delete

@mute_signals(post_save, pre_save, post_delete)
class SilentUserFactory(DjangoModelFactory):
    class Meta:
        model = User
    
    username = Sequence(lambda n: f'silent_user{n}')

# Conditional signal muting
def create_users_silently(count):
    with mute_signals(post_save):
        return UserFactory.create_batch(count)

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