dlt destination that loads staged Parquet into DuckHaven-governed Iceberg tables through the DuckHaven API
Project description
dlt-duckhaven
A dlt destination that loads data into DuckHaven-governed Iceberg tables through the DuckHaven API.
It is a staged-Parquet SQL destination built on the duckhaven-sql-connector, modeled
on dlt's databricks/athena destinations: dlt writes Parquet, the destination stages it
to the workspace object storage, then issues the load command (COPY/INSERT … SELECT read_parquet(...)) through the DuckHaven session API, which dispatches to an agent that
writes the Iceberg table. Control goes through the API; bulk data goes through storage
staging — the same split Databricks and MotherDuck use.
Status: alpha. The destination, its capabilities/type mapping, staged loads (
append/replace/merge), and schema evolution are implemented and tested. Loading uses the session's presigned-URL stage (POST …/sql/sessions/{id}/staging-files); a DuckHaven with that endpoint andSQL_SESSIONS_ENABLED=trueis required at runtime. SeeCHANGELOG.md.
Install
pip install dlt-duckhaven
# pip install "dlt-duckhaven[otel]" # optional per-load-job spans
No storage SDK (s3fs/adlfs) is needed — staged files are uploaded to a presigned URL over plain HTTPS.
Configure
destination="duckhaven" reads the following (via dlt.yml, .dlt/secrets.toml, or env):
[destination.duckhaven]
host = "https://duckhaven.internal"
workspace = "analytics"
agent = "…-uuid-…" # optional; omit to let the API pick compute
catalog = "raw"
[destination.duckhaven.credentials]
token = "dh_pat_…" # a DuckHaven Personal Access Token (service account)
import dlt
pipeline = dlt.pipeline(
pipeline_name="ingest",
destination="duckhaven",
dataset_name="analytics", # the Iceberg schema/namespace within `catalog`
)
pipeline.run(my_resource)
dataset_name is the Iceberg schema; catalog.dataset_name.table is the fully-qualified
relation. Auth is a DuckHaven service-account PAT — every statement is authorized and
audited at the API, so a dlt load is fully governed.
Config reference
| Field | Required | Description |
|---|---|---|
host |
yes | DuckHaven API base URL (https://…). |
workspace |
yes | Workspace slug the session opens in. |
credentials.token |
yes | A DuckHaven service-account PAT (dh_pat_…). May also be passed as the credentials value directly. |
catalog |
recommended | DuckHaven (Polaris) catalog that qualifies loaded tables. |
agent |
no | Explicit compute (an agent UUID); omit to let the API auto-pick. |
Write dispositions
append— stages Parquet and loads it into the table.replace—insert-from-staging(default) swaps via a staging dataset;truncate-and-insertclears the table first. Iceberg has no cheapTRUNCATE, so truncation is aDELETE FROM … WHERE 1=1.merge— delete-insert upsert against a staging dataset; set aprimary_key(and/ormerge_key). A second run with the same key updates in place rather than appending.
Tables are stored as Iceberg (via the attached Polaris catalog); the type mapper
constrains dlt types to Iceberg-safe DuckDB types (JSON → VARCHAR, microsecond
timestamps, no 128-bit integers). Schema evolution (new columns on a later run) is applied
with ALTER TABLE … ADD COLUMN.
Reading values back
DuckHaven returns rows as JSON, so temporal values arrive as ISO-8601 strings and are
converted back to datetime on the way out. Which columns get converted is decided from
the column types the server reports, so a VARCHAR column that happens to hold an
ISO-8601-looking string stays the string it is. Against a server that reports no column
types the destination falls back to recognizing datetimes by their shape, which can
misread such a VARCHAR — the reason the typed path exists.
Observability
With the otel extra, each load job and staging upload emits an OpenTelemetry span
(dlt_duckhaven.load_job, dlt_duckhaven.stage). Because the connector injects a W3C
traceparent on every request, those spans parent the connector's HTTP spans and the
server trace, so a dlt load traces end-to-end (client → API → agent). Without the extra the
instrumentation is a no-op.
Governance & staging
Bulk Parquet is staged to the workspace object storage via a presigned-URL stage — the
session's staging-files endpoint returns a short-lived put_url (upload) and get_url
(read) per file, scoped to the session's staging prefix. The client uploads to put_url
with a plain HTTP PUT; the agent reads get_url over httpfs. No storage credentials live
on the client or the agent — all backend-specific signing (S3/MinIO SigV4, Azure SAS)
happens in the API, which already owns the storage integration. Every load statement is
authorized and audited at the API, so a dlt load is fully governed.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dlt_duckhaven-0.2.0.tar.gz.
File metadata
- Download URL: dlt_duckhaven-0.2.0.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79f7c5217664304e6cb10285d429620c12ce1199aa503647a8ee638bc0702f58
|
|
| MD5 |
b1d9f4576910e84d97ac4c1135bf8d53
|
|
| BLAKE2b-256 |
934049483000d23b5af1ebfc528c363730436ae9b5aa3d5dc94b2ff359ac5d0c
|
Provenance
The following attestation bundles were made for dlt_duckhaven-0.2.0.tar.gz:
Publisher:
release.yml on tamasmrtn/duckhaven-clients
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dlt_duckhaven-0.2.0.tar.gz -
Subject digest:
79f7c5217664304e6cb10285d429620c12ce1199aa503647a8ee638bc0702f58 - Sigstore transparency entry: 2226942732
- Sigstore integration time:
-
Permalink:
tamasmrtn/duckhaven-clients@8f57bff3202bcbe9f42aa37e9136be81f2c94a11 -
Branch / Tag:
refs/tags/dlt-duckhaven-v0.2.0 - Owner: https://github.com/tamasmrtn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8f57bff3202bcbe9f42aa37e9136be81f2c94a11 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dlt_duckhaven-0.2.0-py3-none-any.whl.
File metadata
- Download URL: dlt_duckhaven-0.2.0-py3-none-any.whl
- Upload date:
- Size: 22.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c123322b75dac60d6afd86cb6a1ab7052e4296c5bfa01c95e39a8c42f6a12e62
|
|
| MD5 |
c399ab8d7c27300da0188812e14969fc
|
|
| BLAKE2b-256 |
e0f3cd6d6ecc6ebb911ab4bc52591a5171859559a0bef4bebfa81de21b43d86a
|
Provenance
The following attestation bundles were made for dlt_duckhaven-0.2.0-py3-none-any.whl:
Publisher:
release.yml on tamasmrtn/duckhaven-clients
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dlt_duckhaven-0.2.0-py3-none-any.whl -
Subject digest:
c123322b75dac60d6afd86cb6a1ab7052e4296c5bfa01c95e39a8c42f6a12e62 - Sigstore transparency entry: 2226943012
- Sigstore integration time:
-
Permalink:
tamasmrtn/duckhaven-clients@8f57bff3202bcbe9f42aa37e9136be81f2c94a11 -
Branch / Tag:
refs/tags/dlt-duckhaven-v0.2.0 - Owner: https://github.com/tamasmrtn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8f57bff3202bcbe9f42aa37e9136be81f2c94a11 -
Trigger Event:
push
-
Statement type: