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.2.0.tar.gz (22.5 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.2.0-py3-none-any.whl (16.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sqlalchemy_seedling-0.2.0.tar.gz
  • Upload date:
  • Size: 22.5 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.2.0.tar.gz
Algorithm Hash digest
SHA256 4e8cf0e6c53962d7e90856d9abbb1ee9fec40102d8a8102b32cec271c871af35
MD5 355c7910ad3ac8f9f3fdf8c7d1c954c2
BLAKE2b-256 a7e43940d255c1e0efc88cb2f023de059883c3782e0092e433738257c5bc0651

See more details on using hashes here.

File details

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

File metadata

  • Download URL: sqlalchemy_seedling-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 16.6 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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a612fd66fcc1b16cb51a2df7ace536dba1240e44ed77c6b314735787b69ff690
MD5 58139f6de620637f69d0f9c19a62973a
BLAKE2b-256 e4984223660a1be655420038d03d5f6ed68aebac2a18a13194cf662dbbbd92a1

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