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.
Why seedling?
- Dependency-aware — declare
depends_onbetween seeders and the runner resolves the correct execution order automatically (Kahn's topological sort). - Async-native — built for
async/awaitand SQLAlchemy's async session from the ground up; no sync wrappers. - Declarative factories —
Factory[T]withLazyAttribute,Sequence,SubFactory, andas_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.tomland you getseed run,seed fresh, andseed 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_statetable records every run with timestamps, status, and a content hash for drift detection.seed statusand--new-onlyflag coming in 0.3. - Factory power —
AutoFactory[Model]with mapper introspection, declarativeTraitclasses,@post_generationhooks,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)
| File | Size | Uploaded | |
|---|---|---|---|
| sqlalchemy_seedling-0.5.0.tar.gz | 53.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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}
|