interlaced 2.0.0a3__tar.gz → 2.0.2__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.
- interlaced-2.0.2/MANIFEST.in +2 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/PKG-INFO +84 -37
- {interlaced-2.0.0a3 → interlaced-2.0.2}/README.md +70 -28
- {interlaced-2.0.0a3 → interlaced-2.0.2}/pyproject.toml +18 -12
- interlaced-2.0.2/src/interlace/__init__.py +26 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/cli/main.py +319 -40
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/config/config.py +27 -1
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/dsl/decorators.py +81 -16
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/dsl/discovery.py +25 -8
- interlaced-2.0.0a3/src/interlace/engines/postgres.py → interlaced-2.0.2/src/interlace/engines/adbc.py +63 -61
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/engines/base.py +10 -1
- interlaced-2.0.2/src/interlace/engines/bigquery.py +45 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/engines/duckdb.py +106 -38
- interlaced-2.0.2/src/interlace/engines/postgres.py +73 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/engines/quack.py +4 -1
- interlaced-2.0.2/src/interlace/engines/redshift.py +29 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/engines/registry.py +1 -4
- interlaced-2.0.2/src/interlace/engines/snowflake.py +41 -0
- interlaced-2.0.2/src/interlace/engines/spark.py +160 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/exceptions.py +0 -12
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/graph/column_lineage.py +43 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/graph/dag.py +0 -3
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/graph/project.py +52 -17
- interlaced-2.0.2/src/interlace/graph/selectors.py +87 -0
- interlaced-2.0.2/src/interlace/ir/__init__.py +5 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/ir/canonicalize.py +11 -5
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/ir/fingerprint.py +2 -2
- interlaced-2.0.2/src/interlace/ir/relation.py +43 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/plan/apply.py +250 -98
- interlaced-2.0.2/src/interlace/plan/differ.py +386 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/plan/plan.py +38 -21
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/plan/resolve.py +4 -0
- interlaced-2.0.2/src/interlace/plan/run.py +125 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/project.py +46 -22
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/runtime/python_model.py +9 -4
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/scheduler/worker.py +54 -1
- interlaced-2.0.2/src/interlace/service/app.py +1565 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/service/auth.py +3 -2
- interlaced-2.0.2/src/interlace/service/ui/app.css +356 -0
- interlaced-2.0.2/src/interlace/service/ui/favicon.svg +1 -0
- interlaced-2.0.2/src/interlace/service/ui/index.html +65 -0
- interlaced-2.0.2/src/interlace/service/ui/js/api.js +113 -0
- interlaced-2.0.2/src/interlace/service/ui/js/app.js +274 -0
- interlaced-2.0.2/src/interlace/service/ui/js/dag.js +433 -0
- interlaced-2.0.2/src/interlace/service/ui/js/ui.js +209 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/checks.js +0 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/environments.js +231 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/lineage.js +118 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/models.js +313 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/overview.js +93 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/plan.js +181 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/query.js +242 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/runs.js +264 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/streams.js +202 -0
- interlaced-2.0.2/src/interlace/service/ui/js/views/system.js +294 -0
- interlaced-2.0.2/src/interlace/sinks.py +49 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/state/interval.py +14 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/state/janitor.py +77 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/state/snapshot.py +0 -4
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/state/store.py +215 -19
- interlaced-2.0.2/src/interlace/strategies/__init__.py +79 -0
- interlaced-2.0.2/src/interlace/strategies/append.py +46 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/strategies/base.py +7 -2
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/strategies/full_merge.py +3 -4
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/strategies/incremental_by_time.py +2 -3
- interlaced-2.0.2/src/interlace/strategies/merge.py +115 -0
- interlaced-2.0.0a3/src/interlace/strategies/full.py → interlaced-2.0.2/src/interlace/strategies/replace.py +9 -5
- interlaced-2.0.2/src/interlace/strategies/replace_in_place.py +48 -0
- interlaced-2.0.2/src/interlace/strategies/scd.py +203 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/strategies/view.py +2 -3
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/streaming/log.py +84 -57
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/streaming/materializer.py +43 -13
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/streaming/schema.py +15 -4
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlaced.egg-info/PKG-INFO +84 -37
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlaced.egg-info/SOURCES.txt +30 -49
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlaced.egg-info/requires.txt +15 -7
- interlaced-2.0.0a3/src/interlace/__init__.py +0 -26
- interlaced-2.0.0a3/src/interlace/exports.py +0 -145
- interlaced-2.0.0a3/src/interlace/graph/selectors.py +0 -45
- interlaced-2.0.0a3/src/interlace/ir/__init__.py +0 -24
- interlaced-2.0.0a3/src/interlace/ir/relation.py +0 -71
- interlaced-2.0.0a3/src/interlace/ir/schema.py +0 -23
- interlaced-2.0.0a3/src/interlace/plan/differ.py +0 -211
- interlaced-2.0.0a3/src/interlace/plan/run.py +0 -79
- interlaced-2.0.0a3/src/interlace/service/app.py +0 -836
- interlaced-2.0.0a3/src/interlace/strategies/__init__.py +0 -64
- interlaced-2.0.0a3/src/interlace/strategies/merge_by_key.py +0 -69
- interlaced-2.0.0a3/src/interlace/strategies/scd_type_2.py +0 -122
- interlaced-2.0.0a3/tests/test_apply.py +0 -199
- interlaced-2.0.0a3/tests/test_checks.py +0 -189
- interlaced-2.0.0a3/tests/test_cli.py +0 -102
- interlaced-2.0.0a3/tests/test_cli_inspect.py +0 -163
- interlaced-2.0.0a3/tests/test_column_lineage.py +0 -73
- interlaced-2.0.0a3/tests/test_compile.py +0 -74
- interlaced-2.0.0a3/tests/test_contracts.py +0 -35
- interlaced-2.0.0a3/tests/test_dag.py +0 -48
- interlaced-2.0.0a3/tests/test_differ.py +0 -112
- interlaced-2.0.0a3/tests/test_discovery.py +0 -63
- interlaced-2.0.0a3/tests/test_dsl.py +0 -73
- interlaced-2.0.0a3/tests/test_duckdb_adapter.py +0 -119
- interlaced-2.0.0a3/tests/test_ephemeral.py +0 -81
- interlaced-2.0.0a3/tests/test_example.py +0 -46
- interlaced-2.0.0a3/tests/test_example_benchmark.py +0 -44
- interlaced-2.0.0a3/tests/test_example_platform_tour.py +0 -64
- interlaced-2.0.0a3/tests/test_exports.py +0 -91
- interlaced-2.0.0a3/tests/test_fingerprint.py +0 -42
- interlaced-2.0.0a3/tests/test_forward_only.py +0 -207
- interlaced-2.0.0a3/tests/test_incremental.py +0 -170
- interlaced-2.0.0a3/tests/test_incremental_python.py +0 -225
- interlaced-2.0.0a3/tests/test_init.py +0 -52
- interlaced-2.0.0a3/tests/test_interval.py +0 -74
- interlaced-2.0.0a3/tests/test_janitor.py +0 -154
- interlaced-2.0.0a3/tests/test_multi_engine.py +0 -203
- interlaced-2.0.0a3/tests/test_postgres_engine.py +0 -198
- interlaced-2.0.0a3/tests/test_python_models.py +0 -197
- interlaced-2.0.0a3/tests/test_rebuild_skip.py +0 -160
- interlaced-2.0.0a3/tests/test_run.py +0 -108
- interlaced-2.0.0a3/tests/test_scd2.py +0 -109
- interlaced-2.0.0a3/tests/test_scheduler.py +0 -120
- interlaced-2.0.0a3/tests/test_schema_evolution.py +0 -122
- interlaced-2.0.0a3/tests/test_selectors.py +0 -53
- interlaced-2.0.0a3/tests/test_service.py +0 -346
- interlaced-2.0.0a3/tests/test_sql_config.py +0 -66
- interlaced-2.0.0a3/tests/test_state_store.py +0 -97
- interlaced-2.0.0a3/tests/test_storage.py +0 -145
- interlaced-2.0.0a3/tests/test_strategies.py +0 -107
- interlaced-2.0.0a3/tests/test_streaming.py +0 -230
- interlaced-2.0.0a3/tests/test_table_sinks.py +0 -169
- interlaced-2.0.0a3/tests/test_transfers.py +0 -201
- interlaced-2.0.0a3/tests/test_warehouse_config.py +0 -259
- interlaced-2.0.0a3/tests/test_worker_leases.py +0 -175
- {interlaced-2.0.0a3 → interlaced-2.0.2}/LICENSE +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/setup.cfg +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/checks/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/checks/builtin.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/checks/runner.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/checks/spec.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/cli/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/config/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/contracts.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/dsl/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/dsl/sql_config.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/engines/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/graph/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/plan/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/py.typed +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/runtime/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/runtime/handles.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/scaffold.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/scheduler/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/scheduler/engine.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/scheduler/triggers.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/service/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/state/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlace/streaming/__init__.py +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlaced.egg-info/dependency_links.txt +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlaced.egg-info/entry_points.txt +0 -0
- {interlaced-2.0.0a3 → interlaced-2.0.2}/src/interlaced.egg-info/top_level.txt +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: interlaced
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Python/SQL-first data platform: transformation, built-in orchestration, and durable streaming ingestion
|
|
5
5
|
Author-email: Mark <mark@interlace.sh>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Keywords: data,pipeline,orchestration,transformation,etl,streaming,dbt,sqlmesh,duckdb
|
|
8
|
-
Classifier: Development Status ::
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
9
|
Classifier: Intended Audience :: Developers
|
|
10
10
|
Classifier: Topic :: Software Development :: Build Tools
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -13,27 +13,31 @@ Classifier: Programming Language :: SQL
|
|
|
13
13
|
Requires-Python: >=3.12
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: sqlglot<
|
|
16
|
+
Requires-Dist: sqlglot<29.0,>=25.0
|
|
17
17
|
Requires-Dist: duckdb>=1.5.3
|
|
18
18
|
Requires-Dist: pyarrow>=17.0
|
|
19
|
-
Requires-Dist: msgspec<1.0,>=0.18
|
|
20
19
|
Requires-Dist: pydantic<3.0,>=2.5
|
|
21
20
|
Requires-Dist: typer<1.0,>=0.12
|
|
22
21
|
Requires-Dist: rich<15.0,>=13.0
|
|
23
22
|
Requires-Dist: cronsim<3.0,>=2.5
|
|
24
23
|
Requires-Dist: tenacity<10.0,>=8.2
|
|
25
|
-
Requires-Dist: structlog<26.0,>=24.0
|
|
26
24
|
Requires-Dist: pyyaml<7.0,>=6.0
|
|
27
25
|
Provides-Extra: service
|
|
28
26
|
Requires-Dist: litestar<3.0,>=2.12; extra == "service"
|
|
29
27
|
Requires-Dist: uvicorn<1.0,>=0.30; extra == "service"
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist: argon2-cffi<26.0,>=23.1; extra == "service"
|
|
32
|
-
Requires-Dist: joserfc<2.0,>=1.0; extra == "service"
|
|
33
|
-
Requires-Dist: watchfiles<2.0,>=0.22; extra == "service"
|
|
28
|
+
Requires-Dist: msgspec<1.0,>=0.18; extra == "service"
|
|
34
29
|
Provides-Extra: adbc
|
|
35
30
|
Requires-Dist: adbc-driver-manager<2.0,>=1.2; extra == "adbc"
|
|
36
31
|
Requires-Dist: adbc-driver-postgresql<2.0,>=1.2; extra == "adbc"
|
|
32
|
+
Provides-Extra: adbc-snowflake
|
|
33
|
+
Requires-Dist: interlaced[adbc]; extra == "adbc-snowflake"
|
|
34
|
+
Requires-Dist: adbc-driver-snowflake<2.0,>=1.2; extra == "adbc-snowflake"
|
|
35
|
+
Provides-Extra: adbc-bigquery
|
|
36
|
+
Requires-Dist: interlaced[adbc]; extra == "adbc-bigquery"
|
|
37
|
+
Requires-Dist: adbc-driver-bigquery<2.0,>=1.2; extra == "adbc-bigquery"
|
|
38
|
+
Provides-Extra: spark
|
|
39
|
+
Requires-Dist: pyspark<4.1,>=4.0; extra == "spark"
|
|
40
|
+
Requires-Dist: delta-spark<4.1,>=4.0; extra == "spark"
|
|
37
41
|
Provides-Extra: postgres
|
|
38
42
|
Requires-Dist: psycopg[binary]<4.0,>=3.1; extra == "postgres"
|
|
39
43
|
Provides-Extra: polars
|
|
@@ -44,6 +48,7 @@ Provides-Extra: all
|
|
|
44
48
|
Requires-Dist: interlaced[adbc,polars,postgres,service]; extra == "all"
|
|
45
49
|
Provides-Extra: dev
|
|
46
50
|
Requires-Dist: pytest<10.0,>=8.0; extra == "dev"
|
|
51
|
+
Requires-Dist: httpx<1.0,>=0.27; extra == "dev"
|
|
47
52
|
Requires-Dist: pytest-asyncio<2.0,>=1.0; extra == "dev"
|
|
48
53
|
Requires-Dist: ruff<1.0,>=0.6; extra == "dev"
|
|
49
54
|
Requires-Dist: black<27.0,>=24.0; extra == "dev"
|
|
@@ -60,11 +65,12 @@ Models are `.sql` files or Python functions; state is versioned snapshots with v
|
|
|
60
65
|
environments and a terraform-style plan/apply; everything runs in a single daemon on
|
|
61
66
|
DuckDB + DuckLake by default.
|
|
62
67
|
|
|
63
|
-
> **Status:
|
|
64
|
-
>
|
|
68
|
+
> **Status: 1.0.** Requires Python 3.12+.
|
|
69
|
+
> The package is published to PyPI as **`interlaced`**; the import name and CLI are `interlace`.
|
|
65
70
|
|
|
66
71
|
```bash
|
|
67
|
-
|
|
72
|
+
pip install 'interlaced[service]' # the CLI + daemon; core CLI only: pip install interlaced
|
|
73
|
+
# more extras: [adbc] postgres/redshift · [spark] · [polars] · [all]
|
|
68
74
|
```
|
|
69
75
|
|
|
70
76
|
## Sixty seconds
|
|
@@ -73,7 +79,7 @@ uv pip install "interlaced[service]" # or from source: "interlaced[service] @ g
|
|
|
73
79
|
interlace init my-project && cd my-project
|
|
74
80
|
interlace plan # terraform-style preview: added / breaking / non-breaking / reuse
|
|
75
81
|
interlace apply # build changed models, run checks, promote the environment
|
|
76
|
-
interlace serve # the daemon: HTTP API + scheduler +
|
|
82
|
+
interlace serve # the daemon: web UI (/ui) + HTTP API + scheduler + streams, one process
|
|
77
83
|
```
|
|
78
84
|
|
|
79
85
|
Every model builds into a fingerprinted physical table (`interlace__main.orders__a1b2c3`);
|
|
@@ -89,7 +95,7 @@ prod; pass `--env dev` while developing.
|
|
|
89
95
|
|
|
90
96
|
```sql
|
|
91
97
|
/* interlace:
|
|
92
|
-
strategy:
|
|
98
|
+
strategy: scd
|
|
93
99
|
key: customer_id
|
|
94
100
|
schedule: {cron: "0 * * * *"}
|
|
95
101
|
checks:
|
|
@@ -105,7 +111,7 @@ SELECT customer_id, name, tier FROM raw_customers
|
|
|
105
111
|
```python
|
|
106
112
|
from interlace import model
|
|
107
113
|
|
|
108
|
-
@model(strategy="
|
|
114
|
+
@model(strategy="merge", key="order_id", cursor="updated_at")
|
|
109
115
|
def orders(cursor, this):
|
|
110
116
|
"""Incremental API extract: `cursor` is max(updated_at) already in the
|
|
111
117
|
warehouse (None on first run); `this` is the previous materialisation."""
|
|
@@ -113,9 +119,9 @@ def orders(cursor, this):
|
|
|
113
119
|
return pyarrow.Table.from_pylist(rows) # or RecordBatchReader / generator of batches
|
|
114
120
|
```
|
|
115
121
|
|
|
116
|
-
**Strategies:** `
|
|
122
|
+
**Strategies:** `replace`, `view`, `ephemeral` (CTE-inlined), `merge` (upsert),
|
|
117
123
|
`full_merge` (full-state source applied as a minimal diff), `incremental_by_time`
|
|
118
|
-
(windowed, interval-ledger backfill/catchup), `
|
|
124
|
+
(windowed, interval-ledger backfill/catchup), `scd` (history with validity windows).
|
|
119
125
|
|
|
120
126
|
## Plan / apply
|
|
121
127
|
|
|
@@ -126,22 +132,31 @@ $ interlace plan
|
|
|
126
132
|
order_stats modified non_breaking reuse <- output provably identical: not rebuilt
|
|
127
133
|
```
|
|
128
134
|
|
|
129
|
-
- Changes classify **breaking / non-breaking / forward-only**;
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
- Changes classify **breaking / non-breaking / forward-only**; a plan with breaking changes
|
|
136
|
+
refuses to apply without `--force`. Downstream models whose output is provably identical
|
|
137
|
+
(column-pruned impact analysis) **reuse their existing tables** instead of rebuilding — an
|
|
138
|
+
improvement over model-granular invalidation.
|
|
132
139
|
- `apply --forward-only` lets history-keeping models (scd2/merge/incremental) survive a
|
|
133
|
-
definition change: the
|
|
140
|
+
definition change: the existing table is copied to the new version, the new logic applies to
|
|
141
|
+
the copy going forward, and checks gate before views move.
|
|
134
142
|
- **Checks gate promotion**: 10 built-in types (not_null, unique, accepted_values, row_count,
|
|
135
143
|
freshness, expression, relationships, pattern, range, sql) plus `@check` Python functions —
|
|
136
|
-
an error-severity failure blocks before the environment view moves.
|
|
137
|
-
-
|
|
138
|
-
|
|
144
|
+
an error-severity failure blocks before the environment view moves. `interlace checks run`
|
|
145
|
+
re-runs them ad hoc against any environment's promoted tables.
|
|
146
|
+
- **`--select state:modified`** scopes a plan/apply to models whose fingerprint drifted from the
|
|
147
|
+
target environment, plus everything downstream — the CI diff, one flag. **`interlace impact
|
|
148
|
+
model.column`** shows the column-level blast radius of a change.
|
|
149
|
+
- **`interlace env rollback`** repoints an environment's views at any earlier promotion — nothing
|
|
150
|
+
rebuilds, the views move; every apply records a generation, so a bad deploy reverts in one
|
|
151
|
+
command. `interlace gc` removes snapshots no environment references (reference-aware: tables
|
|
152
|
+
shared through reuse survive).
|
|
139
153
|
|
|
140
154
|
## Streaming
|
|
141
155
|
|
|
142
|
-
Declare a stream; POST to it; rows are durable before the 200, deduplicated by
|
|
143
|
-
key, and materialized exactly-once into `streams.<name>` —
|
|
144
|
-
|
|
156
|
+
Declare a stream; POST to it; rows are durable (SQLite WAL log) before the 200, deduplicated by
|
|
157
|
+
idempotency key, and materialized exactly-once into `streams.<name>` — a micro-batch flusher
|
|
158
|
+
commits the data and the watermark in one warehouse transaction, and SQL models just read the
|
|
159
|
+
table. A flush triggers the models that consume the stream.
|
|
145
160
|
|
|
146
161
|
```python
|
|
147
162
|
from interlace import stream
|
|
@@ -156,7 +171,8 @@ curl -X POST localhost:8000/streams/orders -d '{"order_id": "o1", "total": 49.5}
|
|
|
156
171
|
```
|
|
157
172
|
|
|
158
173
|
Schema drift is yours to choose: `reject` (400), `evolve` (new columns appear), or
|
|
159
|
-
`quarantine` (bad events divert to `<stream>__quarantine`).
|
|
174
|
+
`quarantine` (bad events divert to `<stream>__quarantine`). When the warehouse falls behind,
|
|
175
|
+
publishes get **429 backpressure** instead of unbounded backlog.
|
|
160
176
|
|
|
161
177
|
## Reverse ETL
|
|
162
178
|
|
|
@@ -170,18 +186,49 @@ attach:
|
|
|
170
186
|
```
|
|
171
187
|
|
|
172
188
|
```sql
|
|
173
|
-
/* interlace: {export: {to: table, target: crm.public.accounts, mode:
|
|
189
|
+
/* interlace: {export: {to: table, target: crm.public.accounts, mode: merge, key: id}} */
|
|
174
190
|
SELECT id, tier, lifetime_value FROM account_summary
|
|
175
191
|
```
|
|
176
192
|
|
|
177
|
-
File exports (`to: parquet|csv|json`) work the same way.
|
|
193
|
+
File exports (`to: parquet|csv|json`) work the same way. Sinks are **environment-gated**: by
|
|
194
|
+
default the side effect fires only from prod — a dev apply never writes to a live external
|
|
195
|
+
table (opt in with `environments: [dev, prod]`).
|
|
196
|
+
|
|
197
|
+
## Multi-engine
|
|
198
|
+
|
|
199
|
+
Models run on **named engines**: DuckDB/DuckLake by default, Postgres natively over ADBC
|
|
200
|
+
(`pip install 'interlaced[adbc]'`), Spark (beta, `[spark]` extra), plus alpha adapters for
|
|
201
|
+
MotherDuck, Redshift, Snowflake and BigQuery (wired and dialect-correct, not yet run against a
|
|
202
|
+
live account), with per-model pinning:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
engines:
|
|
206
|
+
pg: {type: postgres, database: "${PG_DSN}"}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```sql
|
|
210
|
+
/* interlace: {engine: pg, strategy: merge, key: id} */
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Strategies execute *inside* the pinned engine (no DuckDB middleman); cross-engine dependencies
|
|
214
|
+
appear as explicit **transfer** lines in the plan and move as Arrow (or a federated `ATTACH`
|
|
215
|
+
fast lane when possible). Contract: `docs/architecture/MULTI_ENGINE.md`.
|
|
178
216
|
|
|
179
217
|
## The daemon
|
|
180
218
|
|
|
181
|
-
`interlace serve` runs
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
219
|
+
`interlace serve` runs everything in one process:
|
|
220
|
+
|
|
221
|
+
- the **web UI** at `/ui` (in-package, zero build step) — ten views: overview, lineage canvas
|
|
222
|
+
with column-level tracing, models, plan/apply with SQL diffs, live runs, query console,
|
|
223
|
+
streams, checks, environments, and system — live over SSE;
|
|
224
|
+
- the **HTTP API** (Litestar + msgspec, OpenAPI at `/schema/scalar`) with the same surface as
|
|
225
|
+
the CLI: plan/apply, runs, checks, streams, engines, schedules, lineage, query, gc;
|
|
226
|
+
- the **scheduler**: cron/interval triggers enqueue onto a **durable run queue** (leases,
|
|
227
|
+
retries, cooperative cancellation — `interlace cancel <id>` or `POST /runs/{id}/cancel`);
|
|
228
|
+
- **stream ingestion** and retention.
|
|
229
|
+
|
|
230
|
+
Scoped API keys (`interlace apikey create ci --scope read`) lock it down; a durable event log
|
|
231
|
+
backs `GET /events/stream` (SSE with `Last-Event-ID` replay).
|
|
185
232
|
|
|
186
233
|
Add `--quack quack:localhost:4213` to serve the warehouse itself over DuckDB's quack protocol —
|
|
187
234
|
other processes (CLI runs, ad-hoc DuckDB clients) then share it concurrently by setting
|
|
@@ -198,7 +245,7 @@ other processes (CLI runs, ad-hoc DuckDB clients) then share it concurrently by
|
|
|
198
245
|
warehouse transaction — exactly-once without distributed coordination.
|
|
199
246
|
- No Jinja, no pandas in core, no external orchestrator.
|
|
200
247
|
|
|
201
|
-
The full design rationale lives in `docs/architecture/
|
|
248
|
+
The full design rationale lives in `docs/architecture/architecture.md`.
|
|
202
249
|
|
|
203
250
|
## Development
|
|
204
251
|
|
|
@@ -208,9 +255,9 @@ Toolchain is pinned with [proto](https://moonrepo.dev/proto), tasks run via
|
|
|
208
255
|
```bash
|
|
209
256
|
proto install
|
|
210
257
|
moon run interlace:sync # install deps
|
|
211
|
-
moon run interlace:test #
|
|
258
|
+
moon run interlace:test # 350+ tests
|
|
212
259
|
moon run interlace:check # black + ruff (CI equivalent)
|
|
213
|
-
moon run interlace:typecheck # mypy
|
|
260
|
+
moon run interlace:typecheck # mypy
|
|
214
261
|
```
|
|
215
262
|
|
|
216
263
|
MIT licensed.
|
|
@@ -8,11 +8,12 @@ Models are `.sql` files or Python functions; state is versioned snapshots with v
|
|
|
8
8
|
environments and a terraform-style plan/apply; everything runs in a single daemon on
|
|
9
9
|
DuckDB + DuckLake by default.
|
|
10
10
|
|
|
11
|
-
> **Status:
|
|
12
|
-
>
|
|
11
|
+
> **Status: 1.0.** Requires Python 3.12+.
|
|
12
|
+
> The package is published to PyPI as **`interlaced`**; the import name and CLI are `interlace`.
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
|
|
15
|
+
pip install 'interlaced[service]' # the CLI + daemon; core CLI only: pip install interlaced
|
|
16
|
+
# more extras: [adbc] postgres/redshift · [spark] · [polars] · [all]
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
## Sixty seconds
|
|
@@ -21,7 +22,7 @@ uv pip install "interlaced[service]" # or from source: "interlaced[service] @ g
|
|
|
21
22
|
interlace init my-project && cd my-project
|
|
22
23
|
interlace plan # terraform-style preview: added / breaking / non-breaking / reuse
|
|
23
24
|
interlace apply # build changed models, run checks, promote the environment
|
|
24
|
-
interlace serve # the daemon: HTTP API + scheduler +
|
|
25
|
+
interlace serve # the daemon: web UI (/ui) + HTTP API + scheduler + streams, one process
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
Every model builds into a fingerprinted physical table (`interlace__main.orders__a1b2c3`);
|
|
@@ -37,7 +38,7 @@ prod; pass `--env dev` while developing.
|
|
|
37
38
|
|
|
38
39
|
```sql
|
|
39
40
|
/* interlace:
|
|
40
|
-
strategy:
|
|
41
|
+
strategy: scd
|
|
41
42
|
key: customer_id
|
|
42
43
|
schedule: {cron: "0 * * * *"}
|
|
43
44
|
checks:
|
|
@@ -53,7 +54,7 @@ SELECT customer_id, name, tier FROM raw_customers
|
|
|
53
54
|
```python
|
|
54
55
|
from interlace import model
|
|
55
56
|
|
|
56
|
-
@model(strategy="
|
|
57
|
+
@model(strategy="merge", key="order_id", cursor="updated_at")
|
|
57
58
|
def orders(cursor, this):
|
|
58
59
|
"""Incremental API extract: `cursor` is max(updated_at) already in the
|
|
59
60
|
warehouse (None on first run); `this` is the previous materialisation."""
|
|
@@ -61,9 +62,9 @@ def orders(cursor, this):
|
|
|
61
62
|
return pyarrow.Table.from_pylist(rows) # or RecordBatchReader / generator of batches
|
|
62
63
|
```
|
|
63
64
|
|
|
64
|
-
**Strategies:** `
|
|
65
|
+
**Strategies:** `replace`, `view`, `ephemeral` (CTE-inlined), `merge` (upsert),
|
|
65
66
|
`full_merge` (full-state source applied as a minimal diff), `incremental_by_time`
|
|
66
|
-
(windowed, interval-ledger backfill/catchup), `
|
|
67
|
+
(windowed, interval-ledger backfill/catchup), `scd` (history with validity windows).
|
|
67
68
|
|
|
68
69
|
## Plan / apply
|
|
69
70
|
|
|
@@ -74,22 +75,31 @@ $ interlace plan
|
|
|
74
75
|
order_stats modified non_breaking reuse <- output provably identical: not rebuilt
|
|
75
76
|
```
|
|
76
77
|
|
|
77
|
-
- Changes classify **breaking / non-breaking / forward-only**;
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
- Changes classify **breaking / non-breaking / forward-only**; a plan with breaking changes
|
|
79
|
+
refuses to apply without `--force`. Downstream models whose output is provably identical
|
|
80
|
+
(column-pruned impact analysis) **reuse their existing tables** instead of rebuilding — an
|
|
81
|
+
improvement over model-granular invalidation.
|
|
80
82
|
- `apply --forward-only` lets history-keeping models (scd2/merge/incremental) survive a
|
|
81
|
-
definition change: the
|
|
83
|
+
definition change: the existing table is copied to the new version, the new logic applies to
|
|
84
|
+
the copy going forward, and checks gate before views move.
|
|
82
85
|
- **Checks gate promotion**: 10 built-in types (not_null, unique, accepted_values, row_count,
|
|
83
86
|
freshness, expression, relationships, pattern, range, sql) plus `@check` Python functions —
|
|
84
|
-
an error-severity failure blocks before the environment view moves.
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
+
an error-severity failure blocks before the environment view moves. `interlace checks run`
|
|
88
|
+
re-runs them ad hoc against any environment's promoted tables.
|
|
89
|
+
- **`--select state:modified`** scopes a plan/apply to models whose fingerprint drifted from the
|
|
90
|
+
target environment, plus everything downstream — the CI diff, one flag. **`interlace impact
|
|
91
|
+
model.column`** shows the column-level blast radius of a change.
|
|
92
|
+
- **`interlace env rollback`** repoints an environment's views at any earlier promotion — nothing
|
|
93
|
+
rebuilds, the views move; every apply records a generation, so a bad deploy reverts in one
|
|
94
|
+
command. `interlace gc` removes snapshots no environment references (reference-aware: tables
|
|
95
|
+
shared through reuse survive).
|
|
87
96
|
|
|
88
97
|
## Streaming
|
|
89
98
|
|
|
90
|
-
Declare a stream; POST to it; rows are durable before the 200, deduplicated by
|
|
91
|
-
key, and materialized exactly-once into `streams.<name>` —
|
|
92
|
-
|
|
99
|
+
Declare a stream; POST to it; rows are durable (SQLite WAL log) before the 200, deduplicated by
|
|
100
|
+
idempotency key, and materialized exactly-once into `streams.<name>` — a micro-batch flusher
|
|
101
|
+
commits the data and the watermark in one warehouse transaction, and SQL models just read the
|
|
102
|
+
table. A flush triggers the models that consume the stream.
|
|
93
103
|
|
|
94
104
|
```python
|
|
95
105
|
from interlace import stream
|
|
@@ -104,7 +114,8 @@ curl -X POST localhost:8000/streams/orders -d '{"order_id": "o1", "total": 49.5}
|
|
|
104
114
|
```
|
|
105
115
|
|
|
106
116
|
Schema drift is yours to choose: `reject` (400), `evolve` (new columns appear), or
|
|
107
|
-
`quarantine` (bad events divert to `<stream>__quarantine`).
|
|
117
|
+
`quarantine` (bad events divert to `<stream>__quarantine`). When the warehouse falls behind,
|
|
118
|
+
publishes get **429 backpressure** instead of unbounded backlog.
|
|
108
119
|
|
|
109
120
|
## Reverse ETL
|
|
110
121
|
|
|
@@ -118,18 +129,49 @@ attach:
|
|
|
118
129
|
```
|
|
119
130
|
|
|
120
131
|
```sql
|
|
121
|
-
/* interlace: {export: {to: table, target: crm.public.accounts, mode:
|
|
132
|
+
/* interlace: {export: {to: table, target: crm.public.accounts, mode: merge, key: id}} */
|
|
122
133
|
SELECT id, tier, lifetime_value FROM account_summary
|
|
123
134
|
```
|
|
124
135
|
|
|
125
|
-
File exports (`to: parquet|csv|json`) work the same way.
|
|
136
|
+
File exports (`to: parquet|csv|json`) work the same way. Sinks are **environment-gated**: by
|
|
137
|
+
default the side effect fires only from prod — a dev apply never writes to a live external
|
|
138
|
+
table (opt in with `environments: [dev, prod]`).
|
|
139
|
+
|
|
140
|
+
## Multi-engine
|
|
141
|
+
|
|
142
|
+
Models run on **named engines**: DuckDB/DuckLake by default, Postgres natively over ADBC
|
|
143
|
+
(`pip install 'interlaced[adbc]'`), Spark (beta, `[spark]` extra), plus alpha adapters for
|
|
144
|
+
MotherDuck, Redshift, Snowflake and BigQuery (wired and dialect-correct, not yet run against a
|
|
145
|
+
live account), with per-model pinning:
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
engines:
|
|
149
|
+
pg: {type: postgres, database: "${PG_DSN}"}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```sql
|
|
153
|
+
/* interlace: {engine: pg, strategy: merge, key: id} */
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Strategies execute *inside* the pinned engine (no DuckDB middleman); cross-engine dependencies
|
|
157
|
+
appear as explicit **transfer** lines in the plan and move as Arrow (or a federated `ATTACH`
|
|
158
|
+
fast lane when possible). Contract: `docs/architecture/MULTI_ENGINE.md`.
|
|
126
159
|
|
|
127
160
|
## The daemon
|
|
128
161
|
|
|
129
|
-
`interlace serve` runs
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
162
|
+
`interlace serve` runs everything in one process:
|
|
163
|
+
|
|
164
|
+
- the **web UI** at `/ui` (in-package, zero build step) — ten views: overview, lineage canvas
|
|
165
|
+
with column-level tracing, models, plan/apply with SQL diffs, live runs, query console,
|
|
166
|
+
streams, checks, environments, and system — live over SSE;
|
|
167
|
+
- the **HTTP API** (Litestar + msgspec, OpenAPI at `/schema/scalar`) with the same surface as
|
|
168
|
+
the CLI: plan/apply, runs, checks, streams, engines, schedules, lineage, query, gc;
|
|
169
|
+
- the **scheduler**: cron/interval triggers enqueue onto a **durable run queue** (leases,
|
|
170
|
+
retries, cooperative cancellation — `interlace cancel <id>` or `POST /runs/{id}/cancel`);
|
|
171
|
+
- **stream ingestion** and retention.
|
|
172
|
+
|
|
173
|
+
Scoped API keys (`interlace apikey create ci --scope read`) lock it down; a durable event log
|
|
174
|
+
backs `GET /events/stream` (SSE with `Last-Event-ID` replay).
|
|
133
175
|
|
|
134
176
|
Add `--quack quack:localhost:4213` to serve the warehouse itself over DuckDB's quack protocol —
|
|
135
177
|
other processes (CLI runs, ad-hoc DuckDB clients) then share it concurrently by setting
|
|
@@ -146,7 +188,7 @@ other processes (CLI runs, ad-hoc DuckDB clients) then share it concurrently by
|
|
|
146
188
|
warehouse transaction — exactly-once without distributed coordination.
|
|
147
189
|
- No Jinja, no pandas in core, no external orchestrator.
|
|
148
190
|
|
|
149
|
-
The full design rationale lives in `docs/architecture/
|
|
191
|
+
The full design rationale lives in `docs/architecture/architecture.md`.
|
|
150
192
|
|
|
151
193
|
## Development
|
|
152
194
|
|
|
@@ -156,9 +198,9 @@ Toolchain is pinned with [proto](https://moonrepo.dev/proto), tasks run via
|
|
|
156
198
|
```bash
|
|
157
199
|
proto install
|
|
158
200
|
moon run interlace:sync # install deps
|
|
159
|
-
moon run interlace:test #
|
|
201
|
+
moon run interlace:test # 350+ tests
|
|
160
202
|
moon run interlace:check # black + ruff (CI equivalent)
|
|
161
|
-
moon run interlace:typecheck # mypy
|
|
203
|
+
moon run interlace:typecheck # mypy
|
|
162
204
|
```
|
|
163
205
|
|
|
164
206
|
MIT licensed.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "interlaced"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.2"
|
|
8
8
|
description = "Python/SQL-first data platform: transformation, built-in orchestration, and durable streaming ingestion"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -14,7 +14,7 @@ authors = [
|
|
|
14
14
|
]
|
|
15
15
|
keywords = ["data", "pipeline", "orchestration", "transformation", "etl", "streaming", "dbt", "sqlmesh", "duckdb"]
|
|
16
16
|
classifiers = [
|
|
17
|
-
"Development Status ::
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
18
|
"Intended Audience :: Developers",
|
|
19
19
|
"Topic :: Software Development :: Build Tools",
|
|
20
20
|
"Programming Language :: Python :: 3.12",
|
|
@@ -22,18 +22,16 @@ classifiers = [
|
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
# Core: the IR + engine + state + plan spine (Phase 1). Everything is Arrow- and
|
|
25
|
-
# sqlglot-native. See docs/architecture/
|
|
25
|
+
# sqlglot-native. See docs/architecture/architecture.md.
|
|
26
26
|
dependencies = [
|
|
27
|
-
"sqlglot>=25.0,<
|
|
27
|
+
"sqlglot>=25.0,<29.0", # canonical IR, transpilation, semantic diff, column lineage
|
|
28
28
|
"duckdb>=1.5.3", # default engine + federation hub; DuckLake storage + quack serving
|
|
29
29
|
"pyarrow>=17.0", # the wire format: RecordBatchReader everywhere
|
|
30
|
-
"msgspec>=0.18,<1.0", # ingest validation + fast (de)serialisation
|
|
31
30
|
"pydantic>=2.5,<3.0", # config + manifest validation (cold paths only)
|
|
32
31
|
"typer>=0.12,<1.0", # CLI
|
|
33
32
|
"rich>=13.0,<15.0", # display, strictly an event subscriber
|
|
34
33
|
"cronsim>=2.5,<3.0", # cron parsing for the trigger engine
|
|
35
34
|
"tenacity>=8.2,<10.0", # retries (tasks, DuckLake commit conflicts, transfers)
|
|
36
|
-
"structlog>=24.0,<26.0", # structured logging
|
|
37
35
|
"pyyaml>=6.0,<7.0", # project config (config + env overlays)
|
|
38
36
|
]
|
|
39
37
|
|
|
@@ -45,22 +43,26 @@ interlace = "interlace.cli.main:main"
|
|
|
45
43
|
service = [
|
|
46
44
|
"litestar>=2.12,<3.0",
|
|
47
45
|
"uvicorn>=0.30,<1.0",
|
|
48
|
-
"
|
|
49
|
-
"argon2-cffi>=23.1,<26.0",
|
|
50
|
-
"joserfc>=1.0,<2.0",
|
|
51
|
-
"watchfiles>=0.22,<2.0",
|
|
46
|
+
"msgspec>=0.18,<1.0", # the wire types (litestar serialises msgspec structs natively)
|
|
52
47
|
]
|
|
53
|
-
# Remote engines via Arrow-native transfer (
|
|
48
|
+
# Remote engines via Arrow-native ADBC transfer. postgres (+ redshift, same wire)
|
|
49
|
+
# are the tested transport; snowflake/bigquery are ALPHA (wired, not run live).
|
|
54
50
|
adbc = [
|
|
55
51
|
"adbc-driver-manager>=1.2,<2.0",
|
|
56
52
|
"adbc-driver-postgresql>=1.2,<2.0",
|
|
57
53
|
]
|
|
54
|
+
adbc-snowflake = ["interlaced[adbc]", "adbc-driver-snowflake>=1.2,<2.0"]
|
|
55
|
+
adbc-bigquery = ["interlaced[adbc]", "adbc-driver-bigquery>=1.2,<2.0"]
|
|
56
|
+
# Spark engine: PySpark session transport (Arrow-native), Delta for mutating strategies.
|
|
57
|
+
# Pinned to the Spark 4.0 / Delta 4.0 pair (Delta lags the latest Spark minor).
|
|
58
|
+
spark = ["pyspark>=4.0,<4.1", "delta-spark>=4.0,<4.1"]
|
|
58
59
|
postgres = ["psycopg[binary]>=3.1,<4.0"]
|
|
59
60
|
polars = ["polars>=1.0,<2.0"]
|
|
60
61
|
pandas = ["pandas>=2.0,<4.0"]
|
|
61
62
|
all = ["interlaced[service,adbc,postgres,polars]"]
|
|
62
63
|
dev = [
|
|
63
64
|
"pytest>=8.0,<10.0",
|
|
65
|
+
"httpx>=0.27,<1.0", # litestar's TestClient transport
|
|
64
66
|
"pytest-asyncio>=1.0,<2.0",
|
|
65
67
|
"ruff>=0.6,<1.0",
|
|
66
68
|
"black>=24.0,<27.0",
|
|
@@ -71,7 +73,7 @@ dev = [
|
|
|
71
73
|
where = ["src"]
|
|
72
74
|
|
|
73
75
|
[tool.setuptools.package-data]
|
|
74
|
-
interlace = ["py.typed"]
|
|
76
|
+
interlace = ["py.typed", "service/ui/*", "service/ui/**/*"]
|
|
75
77
|
|
|
76
78
|
[tool.black]
|
|
77
79
|
line-length = 120
|
|
@@ -116,6 +118,10 @@ module = [
|
|
|
116
118
|
"sqlglot.*",
|
|
117
119
|
"pyarrow.*",
|
|
118
120
|
"yaml",
|
|
121
|
+
"adbc_driver_snowflake.*", # optional 'adbc-snowflake' extra — absent in the base env
|
|
122
|
+
"adbc_driver_bigquery.*", # optional 'adbc-bigquery' extra — absent in the base env
|
|
123
|
+
"pyspark.*", # optional 'spark' extra — absent in the base env
|
|
124
|
+
"delta.*", # optional 'spark' extra (delta-spark) — absent in the base env
|
|
119
125
|
]
|
|
120
126
|
ignore_missing_imports = true
|
|
121
127
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Interlace — Python/SQL-first data platform.
|
|
2
|
+
|
|
3
|
+
Transformation (sqlmesh-grade snapshots, virtual environments, plan/apply),
|
|
4
|
+
built-in orchestration (durable work queue + unified triggers), and durable
|
|
5
|
+
streaming ingestion — in one process. See docs/architecture/architecture.md.
|
|
6
|
+
|
|
7
|
+
The public surface is the ``@model`` / ``@stream`` / ``@check`` decorators.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
13
|
+
|
|
14
|
+
from interlace.dsl.decorators import check, model, stream
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
__version__ = version("interlaced")
|
|
18
|
+
except PackageNotFoundError: # running from a source tree without an install
|
|
19
|
+
__version__ = "0+unknown"
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"__version__",
|
|
23
|
+
"check",
|
|
24
|
+
"model",
|
|
25
|
+
"stream",
|
|
26
|
+
]
|