Skip to main content

Async-native seeder and factory library for SQLAlchemy

Project description

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 factoriesFactory[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 trackingseedling_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 powerAutoFactory[Model] with mapper introspection, declarative Trait classes, @post_generation hooks, RelatedFactory, and bulk insert. Coming in 0.4.
  • Scaffoldingseed 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlalchemy_seedling-0.5.0.tar.gz (53.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlalchemy_seedling-0.5.0-py3-none-any.whl (32.4 kB view details)

Uploaded Python 3

File details

Details for the file sqlalchemy_seedling-0.5.0.tar.gz.

File metadata

  • Download URL: sqlalchemy_seedling-0.5.0.tar.gz
  • Upload date:
  • Size: 53.9 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for sqlalchemy_seedling-0.5.0.tar.gz
Algorithm Hash digest
SHA256 a46ddd1fbe1fa11a22c314232334d34f58f60ea2ee3424ed1203a69a4dc89b3e
MD5 89dff4a20fe18598cd935faced9b7e23
BLAKE2b-256 7632f6dfdcd27723303ba42c6c2a26cc8752aa991d7960fdcd3287a56a8ca393

See more details on using hashes here.

File details

Details for the file sqlalchemy_seedling-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: sqlalchemy_seedling-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 32.4 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for sqlalchemy_seedling-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 39b02604e3ef4f956b36b7521629f0011232bef439037f30ef1281f1e4ae09e2
MD5 60d78a7fe188be219045de2e0e01a878
BLAKE2b-256 e7621fe77705d539688e19c03757c1018c58945d0038861a62911a4c25292619

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page