Skip to main content

Local-first ETL/ELT pipelines that run on DuckDB. Headless CLI.

Project description

Duckle

Local-first ETL/ELT pipelines that run on DuckDB. Python builds the plan, DuckDB moves the rows. Your data never leaves the machine.

PyPI License GitHub

pip install duckle
Terminal: pip install duckle, then a job.py that reads a CSV, filters, derives columns and writes Parquet, running in 394 ms

That installs a ~20 MB native binary plus the DuckDB CLI. No JVM, no Docker, no server, no account.


No data passes through Python

Every method appends a node to a pipeline graph. Nothing executes until .run(), and then the whole graph is handed to the engine, compiled to SQL, and executed inside DuckDB.

That is the difference from a dataframe library: a billion-row job costs what the SQL costs, because it is SQL. There is no interpreter in the data path, and no to_pandas() escape hatch quietly pulling rows into memory.

import duckle
from duckle import col

(duckle.read_csv("orders.csv")
    .where(col.amount >= 20)
    .derive(total="round(amount * 1.2, 2)", tag="f'{region}-{id}'")
    .write_parquet("out.parquet")
    .run())

Python expressions, compiled to SQL

amount * 1.2, f'{a}-{b}', x if c else y, name.strip().upper() and email is None are translated to vectorized DuckDB SQL at plan time:

.derive(band="'high' if amount > 50 else 'low'")
# CASE WHEN ("amount" > 50) THEN 'high' ELSE 'low' END

An expression with no exact SQL equivalent is rejected with the construct named, never quietly executed somewhere slower. Comprehensions, lambda, indexing and eval are refused by name.

Prefer editor completion over strings? col builds the same tree with real operators, and fragments are reusable:

eu_only = col.region.isin(["EU", "UK"])
p.where(eu_only & (col.amount >= 20))

See exactly what will run, before it runs:

p.explain()   # prints the compiled SQL, one block per stage

359 components, not 10 file formats

Component ids map onto attribute paths, so anything in the catalog is reachable:

duckle.src.salesforce(object="Account", authMode="clientCredentials")
duckle.xf.geo.reproject(geomColumn="geom", targetCrs="EPSG:3857")
duckle.snk.salesforce.bulk(operation="upsert", externalIdField="Ext__c")

104 sources, 66 sinks and 138 transforms: Postgres, MySQL, Oracle, SQL Server, Snowflake, Databricks, Teradata, SAP OData, Salesforce (including Bulk API 2.0), Kafka, WebSocket, S3, SFTP, IMAP, LanceDB and more.

duckle.component_ids(contains="salesforce")
duckle.describe("snk.salesforce.bulk")   # settings, and which ones the engine ignores

A CI gate that needs no engine

Terminal: duckle validate reports one failing and one passing pipeline, then exits 1

duckle validate compiles every pipeline without opening a source or writing a sink, so it needs no DuckDB, no credentials and no network. Exit codes are stable and safe to gate on:

code meaning
0 clean
1 a real finding: a pipeline failed, or did not compile
2 the runner could not start: bad usage, missing engine
duckle validate --json          # machine-readable, for a build step
duckle --pipeline my.json       # run one

Note: validate does not yet catch every missing required property, so a clean validate is not proof that a run will succeed.

Code and canvas are the same file

Pipelines are the same JSON the Duckle desktop studio reads. A pipeline written in Python opens on the canvas, and one drawn on the canvas runs from Python:

p.save("pipelines/orders.json")          # opens in the studio
duckle.from_json("pipelines/orders.json").run()

Install notes

duckle depends on duckdb-cli, published by the DuckDB Foundation, so the engine arrives with the install and works offline. To pin your own build instead, set DUCKLE_DUCKDB_BIN.

Wheels ship for Linux, macOS and Windows on x86-64 and arm64. The wheel carries a compiled Rust binary and is Python-version independent (py3-none-<platform>).


Apache-2.0  ·  GitHub  ·  duckle.org  ·  Issues

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

duckle-0.5.7-py3-none-win_arm64.whl (11.0 MB view details)

Uploaded Python 3Windows ARM64

duckle-0.5.7-py3-none-win_amd64.whl (11.6 MB view details)

Uploaded Python 3Windows x86-64

duckle-0.5.7-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl (11.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64musllinux: musl 1.2+ x86-64

duckle-0.5.7-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl (11.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64musllinux: musl 1.2+ ARM64

duckle-0.5.7-py3-none-macosx_11_0_x86_64.whl (10.7 MB view details)

Uploaded Python 3macOS 11.0+ x86-64

duckle-0.5.7-py3-none-macosx_11_0_arm64.whl (10.3 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file duckle-0.5.7-py3-none-win_arm64.whl.

File metadata

  • Download URL: duckle-0.5.7-py3-none-win_arm64.whl
  • Upload date:
  • Size: 11.0 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for duckle-0.5.7-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 03e9149ec07ac0e126f9b8bc7aeb190c784f36346fead44116dced0a3817a858
MD5 b48046fc4f9b74c0c188d812ea068b3a
BLAKE2b-256 f7308f6532b0bdad509b94928058f0d5c0713d3e5a347427f30bfb858e7baa38

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckle-0.5.7-py3-none-win_arm64.whl:

Publisher: pypi.yml on slothflowlabs/duckle

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckle-0.5.7-py3-none-win_amd64.whl.

File metadata

  • Download URL: duckle-0.5.7-py3-none-win_amd64.whl
  • Upload date:
  • Size: 11.6 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for duckle-0.5.7-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 9ad89a8d4035dc9b75d28b7a2d04a04dffea7a65a739e5857919858469fd3868
MD5 86cbd2211767929bde939003bf8e2a65
BLAKE2b-256 180dfc6b16b41861cd00b6cccda5e6573fbc31c2faf029d66d7f20ea90d4e683

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckle-0.5.7-py3-none-win_amd64.whl:

Publisher: pypi.yml on slothflowlabs/duckle

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckle-0.5.7-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for duckle-0.5.7-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 eabfd79859576d48ffe7b72f0160633376a59c12f99337c7ac91c0ef1c3f1ef9
MD5 a001e9c2470b2d76896f69db2c11abb5
BLAKE2b-256 22b59457bebbd65d57bc1e864cdf1d4d502a79748caf9678936dd629ced76e54

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckle-0.5.7-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl:

Publisher: pypi.yml on slothflowlabs/duckle

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckle-0.5.7-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for duckle-0.5.7-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 7993829fd843d020d60dafd5449ae24b034375e8c258649f8daf39062fbe8c40
MD5 dca57eb13136f888c408e6b049a71fba
BLAKE2b-256 008bffa8691868212f99a3749193e16548b8d7964625e91b7018d53efa9c3dcb

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckle-0.5.7-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl:

Publisher: pypi.yml on slothflowlabs/duckle

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckle-0.5.7-py3-none-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for duckle-0.5.7-py3-none-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 3e8b9b1baac3bb2d5e066d2acd901b1bb8252a71b2be083bf91f2e2f27ca7407
MD5 75e9ef8ec26718c4d34da85c7f5d0bdb
BLAKE2b-256 8ea4cc625e302c10134e7bcf7837a8ec82663a2d8a4ed3188aaec0c1cfc3bdd1

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckle-0.5.7-py3-none-macosx_11_0_x86_64.whl:

Publisher: pypi.yml on slothflowlabs/duckle

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckle-0.5.7-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for duckle-0.5.7-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 83bd2bf5fe1ca6f102213c39560ed8e76aaeb660d1b3ec6c628538e9cb239c4e
MD5 b6ef171e20260507133c1065909813d9
BLAKE2b-256 2013890829202c4cd3933e9ae566860bb263cbb5b0240beac04d9b60932559da

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckle-0.5.7-py3-none-macosx_11_0_arm64.whl:

Publisher: pypi.yml on slothflowlabs/duckle

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page