craftainer-crud
A generic CRUD framework for FastAPI: router factories (JSON, XML, and a small web form/component set), a CRUD interface, storage-agnostic repositories (SQLAlchemy async and in-memory), and the model and view bases they build on. A host application keeps its own models, views and settings and builds each resource on top of the generic pieces here; this package imports nothing from the host.
It is an instance of
template-python-package
(so it gets the devcontainer, CI, release workflow and template sync from
there); see docs/TEMPLATE.md for the conventions shared
by every instance. The package's own layout and rules are in
src/craftainer_crud/README.md.
Install
pip install craftainer-crud # core
pip install "craftainer-crud[mqtt]" # + MQTT event sink/source (aiomqtt)
pip install "craftainer-crud[xml]" # + XML request bodies (defusedxml)
The core needs Python 3.14 or newer. Both extras are imported lazily, only
where they are used (MQTTEventSink/MQTTEventSource, and the XML codec and
XML router's body parsing), so the core imports without them and a missing
extra surfaces as an ImportError at first use. Bring your own database
driver (for example asyncpg) for SQLAlchemyRepository.
Public API overview
craftainer_crud.config:CrudConfig,MQTTConfig,configure(config, session_factory). Callconfigureonce at startup, before the first request.craftainer_crud.models: the declarativeBase/IdentifiedBase, the record-lifecycle mixins (Archivable,Draftable,Schedulable,Lockable) and the sharedRevisionmodel.craftainer_crud.views: the Pydantic view base (ORMView), bulk, revision and stats response shapes.craftainer_crud.repositories: theRepositoryprotocol,SQLAlchemyRepository,InMemoryRepositoryand the filter/sort clauses.craftainer_crud.interfaces:CRUDInterface,OwnerScope, revision and event sinks,build_repository_providerand friends.craftainer_crud.controllers:build_json_router,build_xml_router,build_web_routerandbuild_resource_router;crud_manifest_routerandapi_catalog_router(controllers.crud_manifest).craftainer_crud.manifest:ManifestRegistry,ManifestOptionsandbuild_manifest, the CRUD manifest builder.
CRUD manifest
A server describes its resources, their filters, optional routes and cache hints in
one JSON document (docs/manifest.md, schema
schemas/crud-manifest/v1.json). Wire it up once:
from craftainer_crud.controllers.crud_manifest import api_catalog_router, crud_manifest_router
from craftainer_crud.controllers.crud_router import build_resource_router
from craftainer_crud.manifest import ManifestOptions, ManifestRegistry
registry = ManifestRegistry()
router = build_resource_router(
..., # as before
manifest=ManifestOptions(
registry=registry,
name="heroes",
api_version="v2",
model=HeroModel,
owner_scoped=True,
read_roles=["viewer"],
write_roles=["editor"],
delete_roles=["maintainer"],
),
)
app.include_router(
crud_manifest_router(
registry,
service_name="my-api",
service_version="1.4.0",
stats_ttl=30,
oidc_discovery_url="https://idp/.well-known/openid-configuration",
)
) # GET /api/_crud/manifest
app.include_router(
api_catalog_router(manifest_url="/api/_crud/manifest")
) # GET /.well-known/api-catalog
The factories register what they build, so the manifest cannot list a route that
is not mounted. It is filtered to the caller by running each resource's own
read_roles dependency, and carries an ETag over that filtered body.
The catalog's service-desc link follows the serving app's openapi_url
(RFC 9727 makes the link optional): FastAPI(openapi_url=None) omits it, a custom
path is advertised as is. Pass openapi_url="/spec.json" to override, or
openapi_url=None to omit it regardless of the app.
Event stream subscriber ids
GET <prefix>/events hands each subscriber a server-minted, HMAC-signed id in its
first frame and resumes a session only for an id it minted for that resource. The
key is CrudConfig.subscriber_secret (at least 32 bytes), random per process when
unset; set the same value on every instance (and keep it across restarts) for
resume to work across workers and restarts. A forged or unknown id is not an error:
the stream starts fresh under a new id.
Model changes need an app-side migration
The package ships SQLAlchemy models (Revision, the lifecycle mixins) but no
migrations: the host's Alembic setup targets models.base.Base.metadata. A
release that changes those models therefore needs a new migration in the host
application, and the release notes say so. Migrations stay immutable once
applied (NFR-0019 in the host repository).
Versioning
SemVer, starting at 0.1.0. While the major version is
0, a minor release may break the public API; pin craftainer-crud>=0.x,<0.(x+1)
until 1.0.0. The version lives only in the git tag release.yml computes;
pyproject.toml stays at 0.0.0 and make build stamps RELEASE_VERSION
into the build. Releases go to TestPyPI first, then PyPI, through trusted
publishing (PYPI_PUBLISH repository variable: testpypi or pypi; unset
publishes nothing).
Development
Open the repository in the devcontainer (it starts a Postgres for the
integration tests), then run prek run --all-files --hook-stage manual. The
pytest hook covers tests/unit and tests/integration under one 100%
coverage gate; see tests/README.md.
License
Licensed under the GNU General Public License v3.0.
Metadata
Release files for craftainer-crud 0.3.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 | Provenance | |
|---|---|---|---|---|
| craftainer_crud-0.3.0.tar.gz | 332.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| craftainer_crud-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 460.3 kB
Release files / craftainer_crud-0.3.0.tar.gz
| Download URL | craftainer_crud-0.3.0.tar.gz |
|---|---|
| Size | 332.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6c518a269dc768d78722c59b862dbf2aa90e1c8ea32d053997e3a9103a04af52
|
|
BLAKE2b-256 checksum How to use checksums |
9ad632f45d35677188881596c6476c2ec1423eaa51d31aabea5389106f3d6e3e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / craftainer_crud-0.3.0-py3-none-any.whl
| Download URL | craftainer_crud-0.3.0-py3-none-any.whl |
|---|---|
| Size | 127.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e2c132b9509874b684b10177d1e7aab912c5e8c27821d0294e3bfc729a589699
|
|
BLAKE2b-256 checksum How to use checksums |
8814d16a24a9d4f57ebbf0280b4fe07dc29c283e1956b5e297a13a3b2b782bba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for craftainer-crud 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.