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"}

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.1.0.tar.gz (17.1 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.1.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sqlalchemy_seedling-0.1.0.tar.gz
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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.1.0.tar.gz
Algorithm Hash digest
SHA256 409be3af1ee1e94a3a2769356fbde0fdd8ca8230f52dbabcbc7f0783b14f91d2
MD5 630ac316f3103374a4997da4590bf8fa
BLAKE2b-256 9d46ce4028a0dd18ad3bf59393edc3f5177fc75596f0cbf41e812e707128de6b

See more details on using hashes here.

File details

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

File metadata

  • Download URL: sqlalchemy_seedling-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c42b5f652eb9aada1114f61a22da83643c139058dbd73036f4c276e22f07b180
MD5 d2d86e00a1cc3ffe84eaa35a20fa0b6d
BLAKE2b-256 4ccdf40e9038ffe83e3b0d7e79ffdaa99e0a015b0be562a2f3c26a0e2f8a7b73

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