Skip to main content

sqlalchemy-seedling logo

sqlalchemy-seedling

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

PyPI version Python versions License: MIT CI Coverage Downloads Stable since 2026-10-01


Why seedling?

  • Async-native — built for async/await and SQLAlchemy 2.0's async session from day one. No sync wrappers, no thread-pool shims.
  • Dependency-aware — declare depends_on between seeders; the runner topologically sorts them and runs independent seeders in parallel via asyncio.gather.
  • Rich factories — Factory[T] with Faker, LazyAttribute, Sequence, SubFactory, declarative Trait classes, @post_generation hooks, and AutoFactory[T] for mapper-introspected defaults.
  • State tracking — every run is recorded in a seedling_state table: append-only audit log, drift detection via content hash, and a --new-only skip flag.
  • Full CLI — seed run, seed fresh, seed status, seed validate, seed graph, seed export, seed restore, and scaffolding commands.
  • Framework-agnostic — works with FastAPI, Litestar, or a plain script; no framework coupling.

Installation

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

Optional YAML fixture support:

pip install sqlalchemy-seedling[yaml]

Requires Python 3.11+ and SQLAlchemy 2.0+.


Quick start

Scaffold the project layout

seed init

Creates seeders/ and factories/ packages and appends [tool.seedling] to pyproject.toml.

Define seeders

# seeders/users.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
    models = [User]
    tags = {"demo"}

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


# seeders/posts.py
from seedling import Seeder, DEV_AND_TEST
from seeders.users import UserSeeder


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

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

Create a runner factory

# seeders/__init__.py
from seedling import SeederRunner
from myapp.db import async_session_maker
from .users import UserSeeder
from .posts import PostSeeder


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

Configure the CLI

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

Run

seed run                          # run all seeders for development
seed run --tag demo               # run only seeders tagged "demo"
seed fresh                        # truncate then re-seed
seed status                       # latest run per seeder + drift detection
seed list                         # print execution order without running

Factories

from seedling import Factory, Faker, LazyAttribute, Sequence, SubFactory, Trait


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

    class admin(Trait):
        is_superuser = True


class PostFactory(Factory[Post]):
    model = Post
    author = SubFactory(UserFactory)
    title = Faker("sentence")
# In-memory — no DB required
user = UserFactory.build(admin=True)

# Persisted
user = await UserFactory.create(session)
posts = await PostFactory.create_batch(session, 5)

# Fast bulk insert — no hooks fired, no SubFactory resolution
rows = await UserFactory.create_batch(session, 10_000, bulk=True)

AutoFactory[T] generates sensible defaults from mapper introspection, with name-based smart defaults (email → faker.email(), phone → faker.phone_number(), etc.):

class UserFactory(AutoFactory[User]):
    model = User

Helpers

from seedling import upsert, truncate_tables, reset_sequences, deferred_constraints

await upsert(session, User, {"id": 1, "email": "a@b.com"})  # idempotent insert
await truncate_tables(session, User, Post, cascade=True)  # dialect-aware TRUNCATE
await reset_sequences(session, User)  # PostgreSQL: reset SERIAL

async with deferred_constraints(session):  # PostgreSQL: defer FKs
    ...

State tracking

seed status                       # show last run per seeder + drift flag
seed run --new-only               # skip seeders whose source hasn't changed
seed run --force                  # force re-run even if --new-only would skip

Disable per-project:

[tool.seedling]
state_tracking = false

pytest integration

# conftest.py
@pytest.fixture(scope="session")
def seedling_session_factory():
    engine = create_async_engine("sqlite+aiosqlite:///:memory:")
    return async_sessionmaker(engine, expire_on_commit=False)
from seedling.pytest_plugin import seed


@seed(UserSeeder)
async def test_with_user(seedling_transactional_session):
    # UserSeeder ran before the test body (committed by the runner);
    # anything done through this session is rolled back after the test
    ...

CLI reference

Command Description
seed run Run seeders in dependency order
seed fresh Truncate then re-seed
seed list Print resolved execution order
seed status Latest run per seeder with drift detection
seed validate Static checks: cycles, missing deps, empty envs
seed graph Dependency graph (Graphviz DOT or Mermaid)
seed export Dump seeded rows to JSON or YAML
seed restore Load a fixture file back into the database
seed init Scaffold seeders/ and factories/
seed make:seeder <Name> Generate a seeder stub
seed make:factory <module:ClassName> Generate a factory stub

See the CLI reference for full options and flags.


Stability

From 1.0.0 onward, seedling follows Semantic Versioning: breaking changes only on major version bumps.


Documentation

Full docs: https://arthurvasconcelos.github.io/seedling


License

MIT — see LICENSE.

Metadata

Release files for sqlalchemy-seedling 1.0.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 1.0.0
File Size Uploaded
sqlalchemy_seedling-1.0.0.tar.gz 61.6 kB Details

Built distribution (wheel)

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

Total release size: 95.8 kB

Release files / sqlalchemy_seedling-1.0.0.tar.gz

Download URL sqlalchemy_seedling-1.0.0.tar.gz
Size 61.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9d77da628c05423546a9ae3a6f7acc2d6223722fc6c1336c62586a33d62d317c
BLAKE2b-256 checksum
How to use checksums
61e9f74ae039652b04b1c0493209801872c2af5cff0d379e3456ca90f7f66f7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","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-1.0.0-py3-none-any.whl

Download URL sqlalchemy_seedling-1.0.0-py3-none-any.whl
Size 34.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
068a1ad7e01d09bba7b967cf7a726b642e1dd5add75f7f79c1e83c6616fd87be
BLAKE2b-256 checksum
How to use checksums
60374798afac363dd5d04b676b84ca12d61fcb801814310422a23b1188a69fc2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","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

1.0.0 This release

2 release files

0.5.0

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