Claude Code for factory_boy: Test Object Factories — Claude Skills 360 Blog
Blog / AI / Claude Code for factory_boy: Test Object Factories
AI

Claude Code for factory_boy: Test Object Factories

Published: December 20, 2027
Read time: 5 min read
By: Claude Skills 360

factory_boy generates test objects with realistic data. pip install factory-boy. import factory. Define: class UserFactory(factory.Factory): class Meta: model = User; name = factory.Sequence(lambda n: f"user-{n}"); email = factory.LazyAttribute(lambda o: f"{o.name}@example.com"). Create: user = UserFactory(). Override: UserFactory(name="Alice"). Multiple: UserFactory.create_batch(5). Build (no save): UserFactory.build(). Stub (no model): UserFactory.stub(). SubFactory: class OrderFactory: user = factory.SubFactory(UserFactory). LazyAttribute: factory.LazyAttribute(lambda o: f"{o.first_name}.{o.last_name}@co.com"). LazyFunction: factory.LazyFunction(lambda: datetime.utcnow()). Sequence: factory.Sequence(lambda n: f"user{n}@example.com"). Faker: factory.Faker("email"), factory.Faker("first_name"). factory.Faker("random_int", min=1, max=100). Trait: class Meta: ... ; class Params: admin = factory.Trait(role="admin", is_staff=True)UserFactory(admin=True). PostGeneration: @factory.post_generation def password(self, create, extracted, **kwargs): self.set_password(extracted or "password123"). RelatedFactory: class UserFactory: profile = factory.RelatedFactory(ProfileFactory, factory_related_name="user"). create_batch(3, is_active=True). Django: class UserFactory(factory.django.DjangoModelFactory): class Meta: model = "auth.User"; django_get_or_create = ("username",). SQLAlchemy: class Meta: model = User; sqlalchemy_session = session. class Meta: exclude = ["_password"] — exclude computed fields. DjangoOptions.skip_postgeneration_save = True. factory.Iterator(["a","b","c"]) — cycles through values. factory.Maybe("is_active", yes_declaration=..., no_declaration=...). Claude Code generates factory_boy factory hierarchies, trait patterns, and pytest fixture integration.

CLAUDE.md for factory_boy

## factory_boy Stack
- Version: factory-boy >= 3.3 | pip install factory-boy
- Base: factory.Factory (plain) | DjangoModelFactory | SQLAlchemyModelFactory
- Field: Sequence | LazyAttribute | LazyFunction | Faker | SubFactory
- Variants: Trait (class Params) | Maybe | Iterator
- Create: Factory() | .build() (no save) | .create_batch(n) | .stub()
- Hooks: @factory.post_generation | RelatedFactory for reverse FK
- Pytest: wrap factories in fixtures using Factory.create / build

factory_boy Test Factory Pipeline

# tests/factories.py — factory_boy definitions for test object generation
from __future__ import annotations

import decimal
import random
from datetime import datetime, timedelta, timezone

import factory
from factory import Faker, LazyAttribute, LazyFunction, Sequence, SubFactory
from factory.fuzzy import FuzzyChoice, FuzzyDecimal, FuzzyInteger, FuzzyText


# ── 0. Data models (plain Python — no ORM dependency for examples) ────────────

class Address:
    def __init__(self, street, city, state, postal_code, country="US"):
        self.street      = street
        self.city        = city
        self.state       = state
        self.postal_code = postal_code
        self.country     = country


class User:
    def __init__(self, id, first_name, last_name, email, role,
                 is_active, created_at, address=None):
        self.id         = id
        self.first_name = first_name
        self.last_name  = last_name
        self.email      = email
        self.role       = role
        self.is_active  = is_active
        self.created_at = created_at
        self.address    = address
        self._password_hash = ""

    @property
    def full_name(self):
        return f"{self.first_name} {self.last_name}"

    def set_password(self, raw: str) -> None:
        self._password_hash = f"hashed:{raw}"

    def check_password(self, raw: str) -> bool:
        return self._password_hash == f"hashed:{raw}"


class Product:
    def __init__(self, id, name, sku, price, stock, category, is_active):
        self.id        = id
        self.name      = name
        self.sku       = sku
        self.price     = price
        self.stock     = stock
        self.category  = category
        self.is_active = is_active


class OrderLine:
    def __init__(self, product, quantity, unit_price):
        self.product    = product
        self.quantity   = quantity
        self.unit_price = unit_price

    @property
    def subtotal(self):
        return self.quantity * self.unit_price


class Order:
    def __init__(self, id, user, lines, status, created_at):
        self.id         = id
        self.user       = user
        self.lines      = lines
        self.status     = status
        self.created_at = created_at

    @property
    def total(self):
        return sum(line.subtotal for line in self.lines)


# ── 1. Address factory ────────────────────────────────────────────────────────

class AddressFactory(factory.Factory):
    class Meta:
        model = Address

    street      = Faker("street_address")
    city        = Faker("city")
    state       = Faker("state_abbr")
    postal_code = Faker("postcode")
    country     = "US"


# ── 2. User factory with Sequence, LazyAttribute, SubFactory, Trait ───────────

class UserFactory(factory.Factory):
    class Meta:
        model = User

    # Unique incrementing ID
    id = Sequence(lambda n: n + 1)

    # Realistic names from Faker
    first_name = Faker("first_name")
    last_name  = Faker("last_name")

    # Derived from other fields
    email = LazyAttribute(
        lambda o: f"{o.first_name.lower()}.{o.last_name.lower()}@example.com"
    )

    role      = FuzzyChoice(["user", "moderator"])
    is_active = True
    created_at = LazyFunction(lambda: datetime.now(timezone.utc))

    # Optional nested object
    address = SubFactory(AddressFactory)

    class Params:
        # Trait: UserFactory(admin=True) → role="admin", is_active=True
        admin = factory.Trait(
            role="admin",
            is_active=True,
        )

        # Trait: UserFactory(inactive=True)
        inactive = factory.Trait(
            is_active=False,
        )

    @factory.post_generation
    def password(self, create, extracted, **kwargs):
        """
        UserFactory(password="mypass") → hashes it.
        UserFactory() → uses default "testpass123".
        """
        raw = extracted or "testpass123"
        self.set_password(raw)


# ── 3. Product factory with FuzzyDecimal and FuzzyInteger ────────────────────

CATEGORIES = ["Electronics", "Clothing", "Books", "Home & Garden", "Sports"]


class ProductFactory(factory.Factory):
    class Meta:
        model = Product

    id       = Sequence(lambda n: n + 100)
    name     = Faker("catch_phrase")
    sku      = LazyAttribute(lambda o: f"SKU-{abs(hash(o.name)) % 100000:05d}")
    price    = FuzzyDecimal(0.99, 499.99, precision=2)
    stock    = FuzzyInteger(0, 500)
    category = FuzzyChoice(CATEGORIES)
    is_active = True

    class Params:
        out_of_stock = factory.Trait(stock=0)
        premium = factory.Trait(
            price=FuzzyDecimal(200.00, 999.99, precision=2),
            category="Electronics",
        )


# ── 4. OrderLine and Order with RelatedFactory ────────────────────────────────

class OrderLineFactory(factory.Factory):
    class Meta:
        model = OrderLine

    product    = SubFactory(ProductFactory)
    quantity   = FuzzyInteger(1, 5)
    unit_price = LazyAttribute(lambda o: o.product.price)


class OrderFactory(factory.Factory):
    class Meta:
        model   = Order
        exclude = ["_line_count"]

    _line_count = 2   # internal parameter

    id     = Sequence(lambda n: n + 1000)
    user   = SubFactory(UserFactory)
    status = FuzzyChoice(["pending", "processing", "shipped", "delivered"])
    created_at = LazyFunction(lambda: datetime.now(timezone.utc))

    @factory.lazy_attribute
    def lines(self):
        return OrderLineFactory.build_batch(self._line_count)

    class Params:
        large_order = factory.Trait(_line_count=10)
        single_item = factory.Trait(_line_count=1)


# ── 5. Iterator and Maybe ─────────────────────────────────────────────────────

class RoundRobinUserFactory(factory.Factory):
    """Users cycle through roles: user → moderator → admin → user ..."""
    class Meta:
        model = User

    id         = Sequence(lambda n: n + 1)
    first_name = Faker("first_name")
    last_name  = Faker("last_name")
    email      = LazyAttribute(lambda o: f"{o.first_name.lower()}@test.com")
    role       = factory.Iterator(["user", "moderator", "admin"])
    is_active  = True
    created_at = LazyFunction(lambda: datetime.now(timezone.utc))

    @factory.post_generation
    def password(self, create, extracted, **kwargs):
        self.set_password(extracted or "testpass123")


# ── Demo functions ─────────────────────────────────────────────────────────────

def demo_factories():
    print("=== UserFactory ===")
    alice = UserFactory(first_name="Alice", last_name="Smith")
    print(f"  {alice.full_name} <{alice.email}> | role={alice.role}")
    print(f"  check_password: {alice.check_password('testpass123')}")

    admin = UserFactory(admin=True)
    print(f"\n  Admin: {admin.full_name} | role={admin.role}")

    print("\n=== ProductFactory ===")
    products = ProductFactory.build_batch(3)
    for p in products:
        print(f"  [{p.sku}] {p.name[:40]!r} ${p.price} stock={p.stock}")

    premium = ProductFactory(premium=True)
    print(f"\n  Premium: {premium.name!r} ${premium.price}")

    print("\n=== OrderFactory ===")
    order = OrderFactory()
    print(f"  Order #{order.id} for {order.user.full_name}")
    print(f"  {len(order.lines)} lines | total=${order.total:.2f} | status={order.status}")

    big_order = OrderFactory(large_order=True)
    print(f"\n  Large order: {len(big_order.lines)} lines | total=${big_order.total:.2f}")

    print("\n=== Round-robin roles ===")
    users = [RoundRobinUserFactory() for _ in range(6)]
    for u in users:
        print(f"  {u.first_name:12} role={u.role}")


# ── pytest fixture integration ────────────────────────────────────────────────

# conftest.py pattern:
CONFTEST_EXAMPLE = """
import pytest
from tests.factories import UserFactory, ProductFactory, OrderFactory

@pytest.fixture
def user():
    return UserFactory()

@pytest.fixture
def admin_user():
    return UserFactory(admin=True)

@pytest.fixture
def product():
    return ProductFactory()

@pytest.fixture
def order(user, product):
    # Pass existing objects to avoid creating duplicates
    return OrderFactory(user=user)

@pytest.fixture
def product_catalog():
    return ProductFactory.build_batch(10)
"""


if __name__ == "__main__":
    demo_factories()

For the pytest fixtures with hard-coded dicts alternative — hand-writing {"id": 1, "name": "Alice", "email": "[email protected]", "role": "user", ...} in every test file means 20 fields to maintain across 50 test files when a model changes, while UserFactory() generates a complete valid object from one definition, UserFactory(role="admin") overrides only the field being tested, and UserFactory.create_batch(100) generates load-test data in one line with unique emails from Sequence. For the model_bakery (Django alternative) — model_bakery auto-fills all required fields using defaults without any factory definition, but field values are random and not reproducible, while factory_boy’s Sequence(lambda n: f"user{n}") and Faker.seed(42) produce deterministic data across test runs, SubFactory builds the full object graph in one call, and Trait lets a single factory express admin, inactive, and premium variants without separate classes. The Claude Skills 360 bundle includes factory_boy skill sets covering Factory and DjangoModelFactory, Sequence for unique fields, LazyAttribute for derived values, SubFactory for related objects, Trait for behavior variants, post_generation for password hashing, create_batch and build_batch, Iterator and FuzzyChoice, pytest fixture integration, and SQLAlchemy session-scoped factories. Start with the free tier to try test factory code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free