Skip to main content

sqlalchemy-seedling

Async-native seeder and factory library for SQLAlchemy. Dependency-aware runners, declarative factories, and a CLI — Laravel-style ergonomics for the Python async ecosystem.

PyPI version Python versions License: MIT CI


Why seedling?

  • Dependency-aware — declare depends_on between seeders and the runner resolves the correct execution order automatically (Kahn's topological sort).
  • Async-native — built for async/await and SQLAlchemy's async session from the ground up; no sync wrappers.
  • Declarative factories — Factory[T] with LazyAttribute, Sequence, SubFactory, and as_trait() for composable test data.
  • Environment filtering — tag seeders with environments = {DEV, TEST, PROD} and the runner skips what doesn't belong.
  • Zero boilerplate CLI — one line in pyproject.toml and you get seed run, seed fresh, and seed list.

Installation

pip install sqlalchemy-seedling
# or
uv add sqlalchemy-seedling

Requires Python 3.11+ and SQLAlchemy 2.0+.


Quick start

1. Define seeders

# myapp/seeders/user_seeder.py
from seedling import Seeder, DEV_AND_TEST
from sqlalchemy.ext.asyncio import AsyncSession
from myapp.models import User

class UserSeeder(Seeder):
    environments = DEV_AND_TEST

    async def run(self, session: AsyncSession) -> None:
        session.add(User(email="admin@example.com", name="Admin"))
        await session.commit()

    async def truncate(self, session: AsyncSession) -> None:
        await session.execute(delete(User))
        await session.commit()


# myapp/seeders/post_seeder.py
from seedling import Seeder, DEV_AND_TEST

class PostSeeder(Seeder):
    depends_on = [UserSeeder]       # runs after UserSeeder automatically
    environments = DEV_AND_TEST

    async def run(self, session: AsyncSession) -> None:
        ...

2. Create a runner factory

# myapp/seeders/__init__.py
from seedling import SeederRunner
from myapp.db import async_session_maker
from myapp.seeders.user_seeder import UserSeeder
from myapp.seeders.post_seeder import PostSeeder

def create_runner(env: str = "development") -> SeederRunner:
    runner = SeederRunner(session_factory=async_session_maker, env=env)
    runner.register(UserSeeder, PostSeeder)
    return runner

3. Configure the CLI

# pyproject.toml
[tool.seedling]
runner = "myapp.seeders:create_runner"

4. Run

seed run                        # run all seeders for the default env
seed run UserSeeder             # run a specific seeder (+ its dependencies)
seed fresh                      # truncate then re-seed
seed list                       # print execution order without running
seed run --env production       # target a different environment

Factories

Use Factory[T] to build and persist model instances with minimal boilerplate.

from seedling import Factory, LazyAttribute, Sequence, SubFactory, faker
from myapp.models import User, Post

class UserFactory(Factory[User]):
    model = User
    email = LazyAttribute(lambda f: faker.unique.email())
    name  = Sequence(lambda n: f"User {n}")

class PostFactory(Factory[Post]):
    model = Post
    author = SubFactory(UserFactory)       # creates a User row automatically
    title  = LazyAttribute(lambda f: faker.sentence())
# In tests or seeders:
user = await UserFactory.create(session)
posts = await PostFactory.create_batch(session, 5)

# build() never touches the DB — useful in pure unit tests:
user = UserFactory.build(email="test@example.com")

# Traits for scenario-specific variants:
AdminUser = UserFactory.as_trait(is_superuser=True)
admin = await AdminUser.create(session)

Helpers

from seedling import upsert

# Idempotent insert — ON CONFLICT DO NOTHING (PostgreSQL) / INSERT OR IGNORE (SQLite)
await upsert(session, MyModel, {"id": 1, "name": "Foo"})
await upsert(session, MyModel, {"id": 1, "name": "Foo"}, constraint="uq_mymodel_name")

Environment constants

from seedling import DEV, TEST, PROD, ALL, DEV_AND_TEST
Constant Value
DEV "development"
TEST "test"
PROD "production"
DEV_AND_TEST {"development", "test"}
ALL {"development", "test", "production"}

On the horizon

  • State tracking — seedling_state table records every run with timestamps, status, and a content hash for drift detection. seed status and --new-only flag coming in 0.3.
  • Factory power — AutoFactory[Model] with mapper introspection, declarative Trait classes, @post_generation hooks, RelatedFactory, and bulk insert. Coming in 0.4.
  • Scaffolding — seed init, seed make:seeder, seed make:factory, and a transactional pytest fixture. Coming in 0.5.

See ROADMAP.md for the full plan.


License

MIT — see LICENSE.

Release files for sqlalchemy-seedling 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sqlalchemy-seedling 0.5.0
File Size Uploaded
sqlalchemy_seedling-0.5.0.tar.gz 53.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sqlalchemy-seedling 0.5.0
File Interpreter ABI Platform
sqlalchemy_seedling-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 86.3 kB

Release files / sqlalchemy_seedling-0.5.0.tar.gz

Download URL sqlalchemy_seedling-0.5.0.tar.gz
Size 53.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a46ddd1fbe1fa11a22c314232334d34f58f60ea2ee3424ed1203a69a4dc89b3e
BLAKE2b-256 checksum
How to use checksums
7632f6dfdcd27723303ba42c6c2a26cc8752aa991d7960fdcd3287a56a8ca393
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / sqlalchemy_seedling-0.5.0-py3-none-any.whl

Download URL sqlalchemy_seedling-0.5.0-py3-none-any.whl
Size 32.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
39b02604e3ef4f956b36b7521629f0011232bef439037f30ef1281f1e4ae09e2
BLAKE2b-256 checksum
How to use checksums
e7621fe77705d539688e19c03757c1018c58945d0038861a62911a4c25292619
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page