Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

UseCaseCore

The standard runtime for application use cases.

CI PyPI Python License

UseCaseCore gives business actions one explicit, typed, transactional execution model across validation, state loading, policy checks, transitions, audit, idempotency, events, and side effects.

Why

Your API layer is standardized. Your data layer is standardized. Your service layer is still where business logic leaks into routes, model methods, jobs, and helpers.

UseCaseCore standardizes that missing layer without replacing FastAPI, SQLModel, SQLAlchemy, Postgres, Alembic, Oso, pytransitions, Temporal, or the stack you already use.

FastAPI standardizes the API layer. SQLAlchemy standardizes persistence. UseCaseCore standardizes the business action boundary.

The command layer Python apps keep rebuilding by accident. A standard execution spine for Python backend mutations.

Install

pip install usecasecore==0.1.0a3

Core path

command
  -> validate
  -> check idempotency
  -> load state
  -> check policy
  -> check transitions
  -> open transaction
  -> apply changes
  -> write audit
  -> emit events
  -> queue side effects
  -> return result

Before / After: the route handler problem

Stop hiding business mutations in FastAPI routes.

Without a use-case boundary, a route handler for something like MoveInventory tends to collect every operational concern in one place:

  • request validation
  • business validation
  • database session access
  • row loading and locking
  • permission checks
  • state transition checks
  • balance mutation
  • movement history
  • audit logging
  • event publishing
  • job enqueueing
  • idempotency handling
  • response shaping
@app.post("/inventory/move")
def move_inventory(request: MoveInventoryRequest, session: Session = Depends(get_session)):
    # validate request
    # load source and destination balances
    # check permissions
    # check inventory invariants
    # update balances
    # create movement history
    # write audit
    # publish event
    # enqueue low-stock job
    # remember idempotency
    # return response

With UseCaseCore, the route becomes transport glue:

@app.post("/inventory/move")
def move_inventory(request: MoveInventoryRequest):
    command = request.to_command()
    result = move_inventory_use_case.execute(command)
    return MoveInventoryResponse.from_result(result)

The use case owns the authoritative business mutation boundary:

validate -> idempotency -> load state -> policy -> transitions -> transaction -> apply -> audit -> events -> jobs -> result

Real backend example

The FastAPI + SQLAlchemy inventory example shows the same MoveInventory action inside a realistic Python backend stack:

FastAPI route
  -> Pydantic request
  -> MoveInventoryCommand
  -> MoveInventoryUseCase
  -> SQLAlchemy repository
  -> transaction
  -> inventory_movements + audit_records + outbox_records + idempotency_records
  -> Pydantic response

The FastAPI route is transport glue. The use case is the business mutation boundary. SQLAlchemy owns persistence. UseCaseCore owns the action lifecycle:

validate -> idempotency -> load state -> policy -> transitions -> transaction -> apply -> audit -> outbox -> jobs -> result

Quick example

from examples.move_inventory import (
    InMemoryInventoryRepository,
    MoveInventoryCommand,
    MoveInventoryUseCase,
)
from usecasecore import InMemoryIdempotencyStore

repo = InMemoryInventoryRepository()
repo.set_balance(product_id="sku-1", bin_id="A", qty=10)
repo.set_balance(product_id="sku-1", bin_id="B", qty=1)

use_case = MoveInventoryUseCase(
    repository=repo,
    idempotency_store=InMemoryIdempotencyStore(),
)

result = use_case.execute(
    MoveInventoryCommand(
        request_id="req-1",
        idempotency_key="move-sku-1-A-B-4",
        product_id="sku-1",
        from_bin_id="A",
        to_bin_id="B",
        qty=4,
        moved_by_user_id="user-1",
        reason="rebalancing",
    )
)

assert result.success is True
assert result.source_qty_after == 6
assert result.dest_qty_after == 5

Current v0.1.0 surface

  • UseCase execution shell with validation, state loading, policy checks, transitions, transactions, audit, events, jobs, and idempotency.
  • Result wrapper for use cases that want to return metadata for default audit/event/job dispatch.
  • In-memory audit, event, job, and idempotency implementations for examples and tests.
  • Adapter protocols for policy engines, state machines, workflow engines, event buses, and job queues.
  • Canonical MoveInventory example with validation, repository state loading, policy checks, invariant checks, audit, events, jobs, and idempotency replay.

Where it fits

FastAPI
  -> Command model
  -> UseCaseCore
  -> Repositories / Session
  -> SQLModel / SQLAlchemy
  -> Postgres

Alembic evolves schema.

What it is not

  • not an API framework
  • not an ORM
  • not a database
  • not a migration tool
  • not a BPM suite
  • not a no-code workflow builder
  • not a universal rules engine

Repository layout

src/usecasecore/          core package
src/usecasecore/adapters/ adapter protocols
examples/move_inventory/ canonical example
examples/fastapi_sqlalchemy_inventory/
                          FastAPI + SQLAlchemy example
docs/                     documentation stubs
tests/                    lifecycle and example tests
index.html                homepage

Docs and Examples

Release Process

Publishing is manual for now. Do not upload to PyPI until CI is green.

Build and check the package:

rm -rf build dist src/usecasecore.egg-info
python3 -m build
python3 -m twine check dist/*

For TestPyPI, upload with a TestPyPI token:

python3 -m twine upload --repository testpypi dist/*

Then verify install in a clean environment:

python3 -m venv /tmp/ucc-test
source /tmp/ucc-test/bin/activate
python3 -m pip install \
  --index-url https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple \
  usecasecore==0.1.0a3
python3 -c "from usecasecore import Command, Result, ExecutionContext, UseCase; print('OK')"
deactivate

Only publish to PyPI after the TestPyPI install works.

Status

Early alpha. The current package release is 0.1.0a3; the core abstractions are intentionally small while the execution model settles.

Metadata

Release files for usecasecore 0.1.0a3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for usecasecore 0.1.0a3
File Size Uploaded
usecasecore-0.1.0a3.tar.gz 14.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for usecasecore 0.1.0a3
File Interpreter ABI Platform
usecasecore-0.1.0a3-py3-none-any.whl Python 3 none any Details

Total release size: 28.8 kB

Release files / usecasecore-0.1.0a3.tar.gz

Download URL usecasecore-0.1.0a3.tar.gz
Size 14.5 kB
Tags Source
SHA-256 checksum
How to use checksums
dd2a679fb3ee88b75b493f4c1c3fee411cb72469e2a6091af3c78bfe71d5a225
BLAKE2b-256 checksum
How to use checksums
0676433bc12a170930ae408b17d9605d109f5e7c7386b437a279a4f9944f2128
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / usecasecore-0.1.0a3-py3-none-any.whl

Download URL usecasecore-0.1.0a3-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3b62ee59be39b926302f563db03e5483259f21d7beb2c264fb8722794976b0cb
BLAKE2b-256 checksum
How to use checksums
fb073b530ca71a85120b88664f863a4bf355503795eea881d8d5ba569dd4327a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.1.0a3 This release

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