alembic-adapter-sdk (python)
a small, dependency-free sdk for writing alembic external adapters in python.
network engineering lives in python, so adapters should be writable there too. alembic delegates backend i/o to external adapters: standalone programs the alembic host spawns as subprocesses, exchanging one json request and one json response over stdin/stdout. this sdk handles that protocol so you only write the backend logic.
the import package is alembic_adapter. (the pypi distribution is
alembic-adapter-sdk; the bare name alembic belongs to sqlalchemy's migration
tool and is unrelated.)
install
pip install alembic-adapter-sdk
or, from a checkout:
pip install -e .
the sdk has no runtime dependencies; it speaks json with the stdlib.
writing an adapter
subclass Adapter, implement the methods your backend needs, and call run:
from alembic_adapter import Adapter, ApplyReport, AppliedOp, Create, run
class MyAdapter(Adapter):
def setup(self, config):
# `config` is the parsed `setup:` block from the backend config.
self.host = (config or {}).get("host", "http://localhost:8080")
def read(self, schema, types, state):
# observe backend state -> list[ExternalObject]; the engine diffs it
# against the desired inventory to build a plan. emit-only adapters
# return [] (the default).
return []
def write(self, schema, ops, state):
# apply create/update/delete ops, then report what was applied.
report = ApplyReport()
for op in ops:
if isinstance(op, Create):
... # create op.desired on the backend
report.applied.append(AppliedOp(uid=op.uid, type_name=op.type_name))
return report
if __name__ == "__main__":
run(MyAdapter())
run reads one request from stdin, dispatches it, and writes a
newline-terminated json response to stdout. any exception your adapter raises is
turned into a well-formed {"ok": false, "error": ...} response.
see examples/example_adapter.py for a copyable
starting point, and examples/json_store_adapter.py
for a finished adapter: it keeps objects in a json file, implements every method
of the contract, and converges under alembic plan/apply.
the protocol
every request carries version (currently 1) and a method. the sdk parses
the payload into typed objects and serializes your results back:
| method | you receive | you return |
|---|---|---|
read |
schema, types, state |
list[ExternalObject] |
write |
schema, ops, state |
ApplyReport |
ensure_schema |
schema |
ProvisionReport |
preview_schema |
schema |
ProvisionReport or None |
capabilities |
nothing | Capabilities |
preview_schema is called at plan time to show what ensure_schema would
provision without writing; return None (the default) if your adapter cannot
preview.
capabilities reports the adapter's role: adapter (read+write, the default),
emitter (write-only), or observer (read-only), so the host can reject
import/apply up front instead of calling into a side that does nothing.
setup is the setup: block from the backend config (parsed json, usually a
dict); Adapter.setup is called once before each request.
the model mirrors alembic's ir:
OpisCreate,Update, orDelete(dispatch withisinstance).CreateandUpdatecarry the full desiredObject;Updatealso carrieschangesandbackend_id;Deletecarrieskeyandbackend_id.Objecthasuid,type_name,key, andattrs.State.backend_id(type_name, uid)looks up the engine's existing backend id for an object, so renames stay stable.Schemaparses intoTypeSchema/FieldSchema/FieldType, so schema-driven adapters can, for example, find reference fields viafield.type.kind == "ref"andfield.type.target.
for the full request/response shapes, see alembic's
docs/external-adapters.md.
wiring into alembic
point a backend config at your program (see examples/backend.yaml):
backend: external
command: python3
args: ["examples/example_adapter.py"]
setup:
host: http://localhost:8080
alembic plan --backend external --backend-config examples/backend.yaml \
-f inventory.yaml -o plan.json
alembic apply --backend external --backend-config examples/backend.yaml \
-p plan.json
you can also debug the protocol by hand by piping a request into your adapter:
echo '{"version":1,"setup":{},"method":"read","schema":{"types":{}},"types":[],"state":{"mappings":{}}}' \
| python3 examples/example_adapter.py
develop
pip install -e ".[dev]"
# tests
PYTHONPATH=src python -m unittest discover -s tests
# tests with the coverage gate (fails under 100%, matching ci)
coverage run -m unittest discover -s tests
coverage report
ruff check
ruff format --check
the unit tests assert json shapes on their own, so ci also checks the sdk against the real host, pinned to one alembic release:
# protocol conformance, with the runner that ships alongside alembic
alembic-adapter-test -- python examples/example_adapter.py
# a full converge cycle driven by the alembic cli (create, re-plan, update, delete)
bash tests/e2e-alembic.sh
both need binaries from an alembic release
on your PATH; the e2e skips itself when alembic is missing.
license
Apache-2.0
Metadata
Release files for alembic-adapter-sdk 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| alembic_adapter_sdk-0.3.1.tar.gz | 24.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| alembic_adapter_sdk-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.5 kB
Release files / alembic_adapter_sdk-0.3.1.tar.gz
| Download URL | alembic_adapter_sdk-0.3.1.tar.gz |
|---|---|
| Size | 24.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4ae70e1a001282f2003435aa3cde8c6b075e2cb4d1df63480dd4f439adffe93
|
|
BLAKE2b-256 checksum How to use checksums |
eeb17607e134c8be482e7a235de68d5a1531bd5ec9aeea367dbd6e1bc3146cb0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / alembic_adapter_sdk-0.3.1-py3-none-any.whl
| Download URL | alembic_adapter_sdk-0.3.1-py3-none-any.whl |
|---|---|
| Size | 14.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2d06e5c3cb6bcbfa4535e243a4fd1db5b7f8977056e1f4ff151f5eb0e40b4ba5
|
|
BLAKE2b-256 checksum How to use checksums |
0f1c62667030ecaa16c715c862fd734ac92e5c7903bf5b36f98dd699b7865afd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency log