etlantic-fastapi 0.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ .eggs/
7
+ dist/
8
+ build/
9
+ site/
10
+ .venv/
11
+ venv/
12
+ .env
13
+
14
+ # Tools
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .mypy_cache/
18
+ .coverage
19
+ htmlcov/
20
+ # macOS
21
+ .DS_Store
22
+ **/.DS_Store
23
+ ._*
24
+ **/._*
25
+
26
+ examples/_file_storage_out/
27
+ examples/_generated_*.py
28
+ tmp_cli_contracts/
29
+ tmp_/
30
+
31
+ # Local durable workspace (reports, artifacts, schema history)
32
+ .etlantic/
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: etlantic-fastapi
3
+ Version: 0.24.0
4
+ Summary: Thin FastAPI reference adapter for ETLantic 0.24 authoring/service contracts.
5
+ Project-URL: Homepage, https://github.com/eddiethedean/etlantic
6
+ Project-URL: Documentation, https://etlantic.readthedocs.io/
7
+ Project-URL: Repository, https://github.com/eddiethedean/etlantic
8
+ Project-URL: Issues, https://github.com/eddiethedean/etlantic/issues
9
+ Author-email: Odo Matthews <odosmatthews@gmail.com>
10
+ License-Expression: MIT
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: etlantic<0.25,>=0.24.0
21
+ Requires-Dist: fastapi<1,>=0.115
22
+ Requires-Dist: pydantic<3,>=2.12
23
+ Provides-Extra: test
24
+ Requires-Dist: httpx<1,>=0.27; extra == 'test'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # etlantic-fastapi
28
+
29
+ Thin FastAPI reference adapter for the ETLantic 0.24 authoring and service
30
+ contract. Not a production control plane (see 1.1 FastAPI Integration Plan).
31
+
32
+ ```bash
33
+ pip install etlantic-fastapi
34
+ ```
35
+
36
+ ```python
37
+ from etlantic_fastapi import create_reference_app
38
+
39
+ app = create_reference_app()
40
+ ```
@@ -0,0 +1,14 @@
1
+ # etlantic-fastapi
2
+
3
+ Thin FastAPI reference adapter for the ETLantic 0.24 authoring and service
4
+ contract. Not a production control plane (see 1.1 FastAPI Integration Plan).
5
+
6
+ ```bash
7
+ pip install etlantic-fastapi
8
+ ```
9
+
10
+ ```python
11
+ from etlantic_fastapi import create_reference_app
12
+
13
+ app = create_reference_app()
14
+ ```
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "etlantic-fastapi"
3
+ version = "0.24.0"
4
+ description = "Thin FastAPI reference adapter for ETLantic 0.24 authoring/service contracts."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.11"
8
+ authors = [{ name = "Odo Matthews", email = "odosmatthews@gmail.com" }]
9
+ classifiers = [
10
+ "Development Status :: 4 - Beta",
11
+ "Intended Audience :: Developers",
12
+ "License :: OSI Approved :: MIT License",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
17
+ "Typing :: Typed",
18
+ ]
19
+ dependencies = [
20
+ "etlantic>=0.24.0,<0.25",
21
+ "fastapi>=0.115,<1",
22
+ "pydantic>=2.12,<3",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ test = ["httpx>=0.27,<1"]
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "httpx>=0.27,<1",
31
+ "pytest>=8,<9",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/eddiethedean/etlantic"
36
+ Documentation = "https://etlantic.readthedocs.io/"
37
+ Repository = "https://github.com/eddiethedean/etlantic"
38
+ Issues = "https://github.com/eddiethedean/etlantic/issues"
39
+
40
+ [build-system]
41
+ requires = ["hatchling"]
42
+ build-backend = "hatchling.build"
43
+
44
+ [tool.hatch.build.targets.wheel]
45
+ packages = ["src/etlantic_fastapi"]
@@ -0,0 +1,116 @@
1
+ """Thin FastAPI reference adapter for ETLantic authoring/service contracts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from etlantic.service import AuthoringService, PolicyContext
10
+ from fastapi import FastAPI, HTTPException
11
+
12
+ __version__ = "0.24.0"
13
+
14
+
15
+ class DefinitionDocument(BaseModel):
16
+ document: dict[str, Any]
17
+ idempotency_key: str | None = None
18
+
19
+
20
+ class EditRequest(BaseModel):
21
+ command: dict[str, Any]
22
+ expected_token: str | None = None
23
+
24
+
25
+ class RunSubmitRequest(BaseModel):
26
+ idempotency_key: str | None = None
27
+
28
+
29
+ def create_reference_app(
30
+ *,
31
+ service: AuthoringService | None = None,
32
+ title: str = "ETLantic Authoring Reference",
33
+ version: str = "0.24.0",
34
+ ) -> FastAPI:
35
+ """Create a FastAPI app exposing the public authoring/service facade."""
36
+ svc = service or AuthoringService(policy=PolicyContext())
37
+ app = FastAPI(title=title, version=version)
38
+ app.state.service = svc
39
+
40
+ @app.get("/negotiation")
41
+ def negotiation() -> dict[str, Any]:
42
+ return svc.negotiation()
43
+
44
+ @app.get("/catalog")
45
+ def catalog(definition_id: str | None = None) -> dict[str, Any]:
46
+ return svc.catalog(definition_id)
47
+
48
+ @app.put("/pipelines/{definition_id}")
49
+ def put_pipeline(definition_id: str, body: DefinitionDocument) -> dict[str, Any]:
50
+ try:
51
+ return svc.put_definition(
52
+ definition_id,
53
+ body.document,
54
+ idempotency_key=body.idempotency_key,
55
+ )
56
+ except Exception as exc:
57
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
58
+
59
+ @app.get("/pipelines/{definition_id}")
60
+ def get_pipeline(definition_id: str) -> dict[str, Any]:
61
+ try:
62
+ return svc.get_definition(definition_id)
63
+ except KeyError as exc:
64
+ raise HTTPException(status_code=404, detail="definition not found") from exc
65
+
66
+ @app.post("/pipelines/{definition_id}/edits")
67
+ def edit_pipeline(definition_id: str, body: EditRequest) -> dict[str, Any]:
68
+ try:
69
+ return svc.apply_edit(
70
+ definition_id, body.command, expected_token=body.expected_token
71
+ )
72
+ except Exception as exc:
73
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
74
+
75
+ @app.post("/pipelines/{definition_id}/validate")
76
+ def validate_pipeline(definition_id: str) -> dict[str, Any]:
77
+ try:
78
+ return svc.validate(definition_id)
79
+ except KeyError as exc:
80
+ raise HTTPException(status_code=404, detail="definition not found") from exc
81
+
82
+ @app.post("/pipelines/{definition_id}/plan")
83
+ def plan_pipeline(definition_id: str) -> dict[str, Any]:
84
+ try:
85
+ return svc.plan(definition_id)
86
+ except KeyError as exc:
87
+ raise HTTPException(status_code=404, detail="definition not found") from exc
88
+
89
+ @app.post("/pipelines/{definition_id}/runs")
90
+ def submit_run(
91
+ definition_id: str, body: RunSubmitRequest | None = None
92
+ ) -> dict[str, Any]:
93
+ body = body or RunSubmitRequest()
94
+ try:
95
+ return svc.submit_run(definition_id, idempotency_key=body.idempotency_key)
96
+ except KeyError as exc:
97
+ raise HTTPException(status_code=404, detail="definition not found") from exc
98
+
99
+ @app.get("/runs/{job_id}")
100
+ def run_status(job_id: str) -> dict[str, Any]:
101
+ try:
102
+ return svc.job_status(job_id)
103
+ except KeyError as exc:
104
+ raise HTTPException(status_code=404, detail="job not found") from exc
105
+
106
+ @app.post("/runs/{job_id}/cancel")
107
+ def cancel_run(job_id: str) -> dict[str, Any]:
108
+ try:
109
+ return svc.cancel_run(job_id)
110
+ except KeyError as exc:
111
+ raise HTTPException(status_code=404, detail="job not found") from exc
112
+
113
+ return app
114
+
115
+
116
+ __all__ = ["AuthoringService", "PolicyContext", "create_reference_app"]
@@ -0,0 +1,41 @@
1
+ """FastAPI reference adapter OpenAPI + service fixture (no examples import)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pytest
6
+
7
+ from etlantic.authoring import (
8
+ definition_from_pipeline,
9
+ pipeline_to_dict,
10
+ )
11
+ from etlantic.authoring.resolve import callable_registry
12
+
13
+ fastapi = pytest.importorskip("fastapi")
14
+ etlantic_fastapi = pytest.importorskip("etlantic_fastapi")
15
+ from examples.memory_customers import ( # noqa: E402
16
+ CustomerPipeline,
17
+ normalize_customers,
18
+ )
19
+
20
+ from etlantic_fastapi import create_reference_app # noqa: E402
21
+
22
+
23
+ def test_openapi_and_service_fixture() -> None:
24
+ defn = definition_from_pipeline(CustomerPipeline)
25
+ callable_registry().register(
26
+ defn.transformations[0].identity, "local", normalize_customers
27
+ )
28
+ app = create_reference_app()
29
+ schema = app.openapi()
30
+ assert "/catalog" in schema["paths"]
31
+ assert "/pipelines/{definition_id}" in schema["paths"]
32
+ assert "/negotiation" in schema["paths"]
33
+
34
+ svc = app.state.service
35
+ assert "document_versions" in svc.negotiation()
36
+ assert svc.negotiation().get("run_model") == "synchronous_reference"
37
+ put = svc.put_definition("demo", pipeline_to_dict(defn))
38
+ assert put["fingerprint"]
39
+ assert "entries" in svc.catalog("demo")
40
+ assert "diagnostics" in svc.validate("demo")
41
+ assert "plan" in svc.plan("demo")