End-to-end integration testbed and executable demo for the datacoolie ETL framework.
Exercises every combination of {polars, spark} × {file, database, api} metadata
sources × {local, aws} storage platforms, plus lakehouse maintenance
(compact / cleanup). A companion docker-compose stack provides realistic
backends (Postgres/MySQL/MSSQL/Oracle, MinIO, Iceberg REST, Trino, a mock REST
API, and a metadata REST API).
Examples use PowerShell syntax. Bash users: drop the leading
.\on venv paths and swap\for/in file arguments. All commands assume the working directory isdatacoolie/(repo:datacoolie/datacoolie/).
- Library under test: the
datacooliepackage indatacoolie/src/datacoolie/. - What it exercises: 24 named scenarios that combine 2 engines, 3 metadata sources, 2 storage platforms, and lakehouse maintenance.
- Why it exists: one-command regression coverage for ETL behaviour across the supported matrix, plus a teaching surface for new contributors.
| Requirement | Version | Notes |
|---|---|---|
| Python | ≥ 3.11 | Tested on 3.11.9 (Windows) |
| Virtualenv | — | Recommended at the active checkout root as .venv |
datacoolie extras |
[polars,spark] |
Installed editable from repo root |
| Docker Desktop | optional | Only required for P1 / P2 scenarios |
| Java 17 | for Spark | Only required for spark_* scenarios |
Install into a fresh checkout-root venv:
# From the checkout root
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .\datacoolie[polars,spark]usecase-sim/
├── scripts/ # Bootstrap + reset entrypoints (7 scripts + _common.py)
├── runner/ # ETL runners (run.py, maintenance.py) + dispatcher (run_scenario.py)
├── scenarios/ # scenarios.json (multi entries) + SCENARIOS.md (field reference)
├── metadata/
│ ├── file/ # JSON use-case files (local, aws, perf) + generated yaml/xlsx
│ ├── database/ # DDL per dialect + verify_metadata.py
│ └── api/ # Standalone dev metadata server (reads JSON)
├── docker/ # docker-compose.yml, mock_api_server.py, pg_api_metadata_server.py
├── functions/ # Custom Python source functions (sources.py)
├── data/ # Generated inputs/outputs (gitignored)
├── logs/ # Framework logs (system_logs/, etl_logs/) + scenarios/ console logs (gitignored)
└── platforms/
├── databricks/ # DEFERRED
└── fabric/ # Prepared metadata + notebook samples (runner integration deferred)
The simplest reliable path: bring up the entire stack, seed every metadata target, generate every input dataset, and run every scenario. Takes a few minutes cold but has no "is service X up?" guesswork.
# From the inner package directory
cd datacoolie
# 1. Start all 10 containers and wait for ports (≈ 60 s cold, 10 s warm)
python usecase-sim/scripts/setup_platform.py
# 2. Seed metadata into file + every DB dialect + api-db
python usecase-sim/scripts/setup_metadata.py `
--targets file,db:sqlite,db:postgresql,db:mysql,db:mssql,db:oracle `
--truncate
# 3. Generate 30-row sample inputs across every target
python usecase-sim/scripts/generate_data.py
# 4. Run every scenario
python usecase-sim/runner/run_scenario.py --allExpected result (≈ a few minutes, depending on cold/warm JVM):
Total: 24 | PASS: 24 | FAIL: 0
Or, for a first sanity check after step 3:
python usecase-sim/runner/run_scenario.py --scenario local_polars_file
# ETL complete — Success: 121, Failed: 0, Skipped: 0
# Total: 1 | PASS: 1 | FAIL: 0Outputs land in usecase-sim/data/output/ (Delta tables, Parquet, JSON, …)
and watermarks in usecase-sim/metadata/file/watermarks/.
Tear everything down:
python usecase-sim/scripts/setup_platform.py --down --volumesOnce the full path works, you can trim. Minimum required services per scenario tier:
| Tier | Services |
|---|---|
P0 *_file (polars / spark) |
minio + iceberg-rest (+ mock-api if not skipping API sources) |
| P1 database — SQLite | none |
P1 database — postgres / mysql / mssql / oracle |
the matching container |
| P1 api | postgres + metadata-api |
| P1 / P2 iceberg maintenance | minio + iceberg-rest |
P2 aws_* |
minio + iceberg-rest |
The runner eagerly builds an Iceberg REST catalog for every Polars
*_filescenario, soiceberg-restandminioare hard requirements even when no Iceberg stage runs. If you want a smaller stack, target a different scenario family (database / api / maintenance).
setup_metadata.pywith no args defaults tofile,db:sqlite,db:postgresqland therefore needs thepostgrescontainer. Narrow--targetswhen running it standalone against a smaller stack.
flowchart LR
A[scenarios.json] -->|--scenario / --priority| B[run_scenario.py]
B -->|metadata_type == maintenance| C[maintenance.py]
B -->|otherwise| D[run.py]
D --> E[DataCoolieDriver.run]
C --> F[DataCoolieDriver.run_maintenance]
# Single scenario
python usecase-sim/runner/run_scenario.py --scenario local_polars_file
# All scenarios at a given priority
python usecase-sim/runner/run_scenario.py --priority P0
# Everything (long; P1/P2 need Docker)
python usecase-sim/runner/run_scenario.py --all| Concern | Handling |
|---|---|
| Spark JVM cooldown | 6 s pause + stale spark-warehouse/ + metastore_db/ wipe between Spark scenarios |
| Timeouts | 300 s (spark), 180 s (polars), 600 s (maintenance); override per scenario via "timeout_seconds" |
| Exit code | 0 iff every scenario passed |
When debugging one metadata row, bypass the dispatcher and call run.py
directly — all flags documented in section 7.
python usecase-sim/runner/run.py `
--engine polars --metadata-source file --platform local `
--metadata-path usecase-sim/metadata/file/local_use_cases.json `
--stage local_csv2parquetFull field-level reference: scenarios/SCENARIOS.md.
| Key | Engine | Source | Notes |
|---|---|---|---|
local_polars_file |
polars | file (JSON) | all stages including transform_filter |
local_polars_file_yaml |
polars | file (YAML) | |
local_polars_file_excel |
polars | file (XLSX) | |
local_spark_file |
spark | file (JSON) | api-source dataflows skipped |
local_polars_replay |
polars | file (JSON) | replay mode — run twice to test window replace |
local_spark_replay |
spark | file (JSON) | replay mode — api-source dataflows skipped |
| Key | Engine | Source | Requires |
|---|---|---|---|
local_polars_database |
polars | database (SQLite) | — |
local_polars_database_postgres |
polars | database | postgres |
local_polars_database_mysql |
polars | database | mysql |
local_polars_database_mssql |
polars | database | mssql |
local_polars_database_oracle |
polars | database | oracle |
local_spark_database |
spark | database (SQLite) | — |
local_polars_api |
polars | api | metadata-api |
local_spark_api |
spark | api | metadata-api |
local_polars_delta_maintenance |
polars | maintenance | — |
local_polars_iceberg_maintenance |
polars | maintenance | minio + iceberg-rest |
local_spark_delta_maintenance |
spark | maintenance | — |
local_spark_iceberg_maintenance |
spark | maintenance | minio + iceberg-rest |
| Key | Engine | Source | Requires |
|---|---|---|---|
aws_polars_file |
polars | file | minio + iceberg-rest |
aws_spark_file |
spark | file | minio + iceberg-rest |
aws_polars_delta_maintenance |
polars | maintenance | minio |
aws_polars_iceberg_maintenance |
polars | maintenance | minio + iceberg-rest |
aws_spark_delta_maintenance |
spark | maintenance | minio |
aws_spark_iceberg_maintenance |
spark | maintenance | minio + iceberg-rest |
All four P0 scenarios require
minio+iceberg-restbecause the Polars runner eagerly builds an Iceberg REST catalog.local_polars_fileandlocal_polars_file_yamladditionally needmock-apion port 8082 for their API-source dataflows; the_exceland_spark_filevariants setskip_api_sources: trueand therefore avoid that dependency.
Two runner scripts replace what used to be eight. They are thin shells over
DataCoolieDriver from the library.
Unified ETL runner. Dispatches any (engine × metadata-source) combination.
| Flag | Req | Default | Purpose |
|---|---|---|---|
--engine |
✓ | — | polars | spark |
--metadata-source |
✓ | — | file | database | api |
--platform |
local |
local | aws (chooses LocalPlatform or AWSPlatform) |
|
--metadata-path |
file | — | .json | .yaml | .xlsx |
--metadata-db-connection-string |
db | — | SQLAlchemy URL |
--metadata-api-url |
api | — | Base URL of metadata API |
--metadata-api-key |
"" |
Optional API key | |
--metadata-workspace-id |
db/api | — | Workspace ID |
--stage |
✓ | — | Stage name(s); "" runs all stages |
--column-name-mode |
lower |
lower | snake |
|
--dry-run |
off | Skip writes | |
--storage-options KEY=VALUE |
[] |
Repeatable; passed to Polars / object store | |
--iceberg-catalog-uri |
None |
Override Iceberg REST URI | |
--catalog-preset |
local |
local | unity_catalog |
|
--uc-token / --uc-credential |
"" |
Unity Catalog auth | |
--log-path |
None |
Directory for framework logs; driver writes system_logs/ and etl_logs/ under it |
|
--max-workers |
None |
Parallel dataflow workers | |
--skip-api-sources |
off | Skip dataflows with connection_type=api |
|
--app-name |
spark | DataCoolie-UseCase |
Spark app name |
--spark-config KEY=VALUE |
spark | [] |
Extra Spark configs |
--replay-start |
None |
Inclusive replay range start (ISO date/datetime or int); activates replay mode | |
--replay-end |
None |
Exclusive replay range end | |
--replay-chunk-interval KEY=VALUE |
[] |
Repeatable; e.g. days=1. Empty = single-shot replay |
|
--replay-save-watermark |
off | Save watermark after each chunk (init/crash-resume mode) | |
--replay-chunk-column |
None |
Override auto-resolved chunk column |
Compact + cleanup for Delta and Iceberg tables.
| Flag | Req | Default | Purpose |
|---|---|---|---|
--engine |
✓ | — | polars | spark |
--platform |
local |
local | aws |
|
--metadata-path |
✓ | — | Path to metadata file |
--connection |
None |
Filter to a single connection name | |
--do-compact / --no-compact |
on | Enable/disable compaction | |
--do-cleanup / --no-cleanup |
on | Enable/disable cleanup | |
--retention-hours |
168 |
File retention window | |
--dry-run |
off | Dry-run mode | |
--storage-options KEY=VALUE |
[] |
Repeatable | |
--catalog-preset |
local |
local | unity_catalog |
|
--iceberg-catalog-uri |
None |
Override Iceberg REST URI | |
--uc-token / --uc-credential |
"" |
Unity Catalog auth | |
--log-path |
None |
Directory for framework logs (same layout as run.py) |
|
--skip-api-sources |
off | Skip api-source dataflows | |
--app-name |
spark | DataCoolie-Maintenance |
Spark app name |
--spark-config KEY=VALUE |
spark | [] |
Extra Spark configs |
| Flag | Default | Purpose |
|---|---|---|
--scenario NAME |
— | Single scenario key |
--all |
off | Run every scenario |
--priority P0|P1|P2 |
— | Run every scenario at a priority tier |
--scenarios-path PATH |
scenarios/scenarios.json |
Override scenarios file |
The dispatcher writes three kinds of logs under usecase-sim/logs/:
logs/system_logs/andlogs/etl_logs/— driver output (forwarded via--log-path).logs/scenarios/run_scenario.log— dispatcher's own log (which scenarios ran, commands, pass/fail summary).logs/scenarios/<name>.console.log— full stdout+stderr tee of each scenario's child process (also streamed live to the terminal).
Shared factory module. Key exports:
build_spark_session(...)— picks Scala 2.12 / 2.13, injects Delta + Iceberg + S3A + JDBC drivers.build_iceberg_rest_catalog(...)— builds apyicebergREST catalog for Polars.setup_platform(is_aws, storage_opts, logger)— returnsLocalPlatformorAWSPlatform.run_and_report(driver, stage, ...)— runs the driver, logs the result, optionally stops Spark.replay_and_report(driver, stage, ..., replay_start, replay_end, replay_chunk_interval, ...)— runsdriver.run_replay()with aReplayConfigbuilt from the supplied arguments.
Three catalog presets are supported:
| Preset | --iceberg-catalog-uri default |
Auth |
|---|---|---|
local |
http://localhost:8181 (tabulario/iceberg-rest) |
none |
unity_catalog (OSS) |
http://<host>:8080/api/2.1/unity-catalog/iceberg |
--uc-credential client_id:secret |
unity_catalog (Databricks) |
https://<ws>.azuredatabricks.net/api/2.1/unity-catalog/iceberg |
--uc-token <pat> |
All scripts live in scripts/ and import shared helpers from
scripts/_common.py. Run from the datacoolie/ directory.
python usecase-sim/scripts/setup_platform.py # up all, wait for ports
python usecase-sim/scripts/setup_platform.py --services postgres minio
python usecase-sim/scripts/setup_platform.py --down --volumes # tear down + wipe data| Flag | Default | Purpose |
|---|---|---|
--down |
off | Stop the stack (docker compose down) |
--volumes |
off | With --down, also remove named volumes |
--services s1 s2 … |
all | Bring up/down a subset |
--timeout SECONDS |
180 |
Port-readiness poll timeout |
--no-wait |
off | Skip readiness polling |
# Default: file + db:sqlite + db:postgresql (local workspace)
python usecase-sim/scripts/setup_metadata.py
# Seed every dialect, truncating first
python usecase-sim/scripts/setup_metadata.py `
--targets file,db:postgresql,db:mysql,db:mssql,db:oracle --truncate
# AWS workspace into postgres
python usecase-sim/scripts/setup_metadata.py `
--json usecase-sim/metadata/file/aws_use_cases.json `
--workspace-id aws-workspace --targets db:postgresql --truncate| Flag | Default | Purpose |
|---|---|---|
--json PATH |
local_use_cases.json |
Source JSON file |
--workspace-id STR |
local-workspace |
Workspace ID written into DB rows |
--targets LIST |
file,db:sqlite,db:postgresql |
Comma-separated targets |
--truncate |
off | Truncate tables before seeding |
--db-url DIALECT=URL |
[] |
Override the default SQLAlchemy URL per dialect |
Targets: file, db:sqlite, db:postgresql, db:mysql, db:mssql,
db:oracle, api-db (alias for db:postgresql).
30-row sample dataset into every requested target. Replaces the old
generate_sample_data.py + bootstrap_{postgres,mysql,mssql,oracle,minio}.py.
| Flag | Default | Purpose |
|---|---|---|
--targets LIST |
all reachable | local, minio, pg, mysql, mssql, oracle |
python usecase-sim/scripts/generate_data.py --targets local,minio
python usecase-sim/scripts/generate_data.py --targets pg,mysql| Flag | Default | Purpose |
|---|---|---|
--dry-run |
off | Report without deleting |
--skip-local / --skip-minio / --skip-db |
off | Skip individual stores |
--dialects D1 D2 … |
all 5 | DB dialects to target |
--db-url DIALECT=URL |
[] |
Override SQLAlchemy URL |
Wipes data/output/, drops MinIO output + iceberg-warehouse prefixes, drops
the Iceberg default namespace, and calls reset_watermarks.py.
| Flag | Default | Purpose |
|---|---|---|
--dry-run |
off | Report without deleting |
--local-only |
off | Skip MinIO + Iceberg + DB cleanup |
--dialects D1 D2 … |
all 5 | DB dialects for watermark cleanup |
| Flag | Default | Purpose |
|---|---|---|
--sizes LIST |
all 8 | 10k,50k,100k,500k,1m,5m,10m,50m |
--formats LIST |
all | jsonl,parquet,delta,iceberg |
--targets LIST |
all | local,minio,iceberg |
--iceberg-uri URL |
http://localhost:8181 |
Iceberg REST URI |
Notes:
- JSONL inputs are only generated through
1mrows. The script skips JSONL for5m,10m, and50m. miniois skipped automatically whenlocalhost:9000is unavailable.icebergrequires the local REST catalog and is skipped when the catalog is unavailable.
| Flag | Default | Purpose |
|---|---|---|
--all |
off | Also reset inputs (data/perf/input/ + perf_src namespace) |
--dry-run |
off | Report without deleting |
usecase-sim/docker/docker-compose.yml brings up a 10-service stack. All
credentials are hardcoded — intended for local dev only.
| Service | Port(s) | Credentials | Purpose |
|---|---|---|---|
postgres |
5432 | datacoolie/datacoolie |
Metadata DB + Iceberg JDBC catalog |
mysql |
3306 | datacoolie/datacoolie |
Metadata DB variant |
mssql |
1433 | sa / Datacoolie@1 |
Metadata DB variant |
oracle |
1521 | datacoolie/datacoolie, service FREEPDB1 |
Metadata DB variant |
minio |
9000 / 9001 | minioadmin/minioadmin |
S3-compatible object store |
iceberg-rest |
8181 | — | Tabular Iceberg REST catalog |
trino |
8080 | — | SQL engine over Iceberg |
mock-api |
8082 | env-configured | Simulates REST API sources |
metadata-api |
8000 | via DATABASE_URL |
Flask API over postgres metadata |
sqlpad |
3000 | admin@datacoolie.local / admin |
Web SQL editor |
spark |
— | — | Containerised PySpark (Linux); avoids Windows Spark issues |
- MinIO console: http://localhost:9001
- Trino UI: http://localhost:8080
- SQLPad: http://localhost:3000
- Mock REST API: http://localhost:8082
- Metadata REST API: http://localhost:8000
# P1 database scenario on postgres only
python usecase-sim/scripts/setup_platform.py --services postgres
# P2 AWS iceberg scenario
python usecase-sim/scripts/setup_platform.py --services minio iceberg-rest
# P1 metadata-api scenario (postgres + api server)
python usecase-sim/scripts/setup_platform.py --services postgres metadata-apiRunning PySpark natively on Windows is fragile (JVM temp-dir cleanup,
winutils.exe, Python-path resolution). The spark Docker service solves
this by running Spark in local[*] mode inside a Linux container. Input and
output data are shared through a volume mount — no path changes needed.
Start the service (same pattern as any other service):
# From the datacoolie/ directory — build image + start dependencies + spark
python usecase-sim/scripts/setup_platform.py --services minio iceberg-rest sparkOn first start the container runs pip install -e /datacoolie --no-deps
automatically via its entrypoint (all deps are pre-baked into the image, so
this is fast). No separate setup script needed.
Generate input data on the host (once per reset):
python usecase-sim/scripts/generate_data.py --targets localRun any Spark scenario via docker exec:
# Single stage
docker exec datacoolie-spark python usecase-sim/runner/run.py `
--engine spark --metadata-source file --platform local `
--metadata-path ./usecase-sim/metadata/file/local_use_cases.json `
--stage load_delta --column-name-mode lower --skip-api-sources
# All stages
docker exec datacoolie-spark python usecase-sim/runner/run.py `
--engine spark --metadata-source file --platform local `
--metadata-path ./usecase-sim/metadata/file/local_use_cases.json `
--stage "" --column-name-mode lower --skip-api-sources
# Interactive shell for debugging
docker exec -it datacoolie-spark bashAll relative paths (./usecase-sim/data/...) resolve correctly because the
container's WORKDIR is /datacoolie (the mounted package directory).
Output tables written inside the container appear on the host immediately.
| What works | Notes |
|---|---|
| P0 file scenarios (Delta, Parquet, CSV, Iceberg) | ✅ Full support — minio + iceberg-rest reached by container name |
| P0 replay scenarios | ✅ |
| P1 database scenarios | ⚠ localhost in metadata JSON resolves to the container, not the host. Use docker exec ... --metadata-source database only after verifying connectivity. |
| P1 API scenarios | ⚠ Same localhost caveat; pass --skip-api-sources to avoid. |
The SQL Server password Datacoolie@1 must be URL-encoded in SQLAlchemy URLs
as Datacoolie%401. The default URL in scenarios.json already handles this.
Three interchangeable ways of providing the same connection + dataflow + schema hint definitions.
Primary sources: local_use_cases.json,
aws_use_cases.json,
perf_test.json. Running
setup_metadata.py --targets file emits YAML and XLSX siblings used by the
*_yaml / *_excel scenarios.
Schema files per dialect: metadata/database/schema.sql (SQLite),
schema_postgres.sql, schema_mysql.sql, schema_mssql.sql,
schema_oracle.sql. All create the same five dc_framework_* tables.
Seeded by setup_metadata.py --targets db:<dialect>.
Verify DB matches JSON source:
python usecase-sim/metadata/database/verify_metadata.py `
--json-path usecase-sim/metadata/file/local_use_cases.json `
--connection-string "postgresql+psycopg2://datacoolie:datacoolie@localhost:5432/datacoolie" `
--workspace-id local-workspace- Containerized (recommended):
docker/pg_api_metadata_server.py, running in themetadata-apiservice on port 8000. Reads from postgres. - Standalone dev:
metadata/api/api_metadata_server.py— reads a JSON file directly; useful when you don't want Docker.
Both serve the same REST contract consumed by APIClient.
functions/sources.py hosts Python functions that are
callable from metadata via source.python_function dotted paths. Current
function:
sql_query_orders(engine, source, watermark)— queries Delta tables via SQL; registers tables for Polars, queries the metastore for Spark. Supports Local, AWS, Fabric, and Databricks platforms viabase_pathlookups.
To add your own, define a function in functions/sources.py and reference it
from the metadata JSON:
{
"source": {
"type": "python_function",
"python_function": "sources.my_custom_reader"
}
}Maintenance scenarios call DataCoolieDriver.run_maintenance(...) to compact
(optimize file layout) and cleanup (vacuum expired files) Delta and Iceberg
tables listed in the metadata.
python usecase-sim/runner/run_scenario.py --scenario local_polars_delta_maintenance
python usecase-sim/runner/run_scenario.py --scenario local_spark_iceberg_maintenanceOr directly:
python usecase-sim/runner/maintenance.py `
--engine polars --platform local `
--metadata-path usecase-sim/metadata/file/local_use_cases.json `
--connection local_delta_dest `
--retention-hours 168Known sharp edge. Two maintenance dataflows writing to the same physical
Delta path (e.g. both pointing at orders_schema_evolve) can race and surface
as "concurrent transaction deleted the same data your transaction deletes".
This is a concurrency property of the lakehouse format, not a usecase-sim
bug — serialise such jobs or point them at distinct paths.
# Generate full benchmark inputs.
# JSONL is only generated through 1m; parquet/delta/iceberg go through 50m.
python usecase-sim/scripts/generate_perf_data.py
# Run each engine from a clean output state for a fair comparison.
python usecase-sim/runner/run_perf_benchmark.py --engine polars --max-size 50m --reset
python usecase-sim/runner/run_perf_benchmark.py --engine spark --max-size 50m --reset
# Regenerate the final merged report from the two JSON result files.
python usecase-sim/runner/run_perf_benchmark.py --report-onlyNotes:
- Run all benchmark commands from the inner
datacoolie/directory. --resetcallsusecase-sim/scripts/reset_perf_data.pyand clears perf outputs only. It does not delete generated inputs orbenchmark_results/.- Each engine run writes one JSON file to
./benchmark_results/and also regeneratesperf_report.mdfrom whatever result files already exist. --report-onlyis the clean way to rebuild the final comparison after both engine runs finish.- If you want to regenerate inputs as well, use
python usecase-sim/scripts/reset_perf_data.py --allbeforegenerate_perf_data.py. - If Docker-backed services are unavailable, use
--no-icebergand keep--max-size 1mbecause JSONL inputs stop at1m.
| Symptom | Fix |
|---|---|
ERROR DerbyLockFile on second Spark run |
run_scenario.py auto-wipes spark-warehouse/ + metastore_db/; if running run.py directly, delete them between runs |
BucketAlreadyOwnedByYou on MinIO |
Benign; _common.ensure_bucket is idempotent |
psycopg2 / pymssql / oracledb import error |
Install the corresponding extra: pip install psycopg2-binary pymssql oracledb |
MSSQL auth fails with Datacoolie@1 |
Use URL-encoded form Datacoolie%401 in SQLAlchemy URLs |
MSSQL Login failed for user 'sa' with state 38 |
The datacoolie user database is missing — the MSSQL image has no auto-create env var. setup_platform.py creates it after the container is up; to do it manually: docker exec datacoolie-mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'Datacoolie@1' -No -Q "IF DB_ID('datacoolie') IS NULL CREATE DATABASE datacoolie;" |
API-source dataflows fail in local_polars_file |
mock-api container is down; either setup_platform.py --services mock-api or use --skip-api-sources |
Iceberg scenarios fail with connection refused on :8181 |
iceberg-rest container is down: setup_platform.py --services iceberg-rest |
json.decoder.JSONDecodeError loading scenarios.json |
File likely corrupted; reseed from git and reapply edits |
Databricks runner integration is planned but not implemented in this testbed. Fabric runner integration is also deferred, but prepared Fabric assets are now available in this repository.
Fabric assets:
platforms/fabric/README.mdplatforms/fabric/fabric_use_cases.jsonplatforms/fabric/sample_fabric_spark.ipynbplatforms/fabric/sample_fabric_polars.ipynb
Deferred status details:
AGPL-3.0-or-later — same as the parent datacoolie package. See ../LICENSE.