Metadata-Version: 2.4
Name: dlt
Version: 1.30.0a0
Summary: dlt is an open-source python-first scalable data loading library that does not require any backend to run.
Project-URL: Homepage, https://github.com/dlt-hub
Project-URL: Repository, https://github.com/dlt-hub/dlt
Author-email: "dltHub Inc." <services@dlthub.com>
Maintainer-email: Marcin Rudolf <marcin@dlthub.com>, Adrian Brudaru <adrian@dlthub.com>, Anton Burnashev <anton@dlthub.com>, David Scharf <david@dlthub.com>
License-Expression: Apache-2.0
License-File: LICENSE.txt
Keywords: etl
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: <3.15,>=3.10
Requires-Dist: click>=7.1
Requires-Dist: fsspec>=2022.4.0
Requires-Dist: gitpython>=3.1.42
Requires-Dist: giturlparse>=0.10.0
Requires-Dist: humanize>=4.4.0
Requires-Dist: jsonpath-ng>=1.8.0
Requires-Dist: orjson!=3.10.1,!=3.9.11,!=3.9.12,!=3.9.13,!=3.9.14,<4,>=3.6.7; platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'
Requires-Dist: orjson>=3.10.1; platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'
Requires-Dist: orjson>=3.11.0; python_version > '3.13'
Requires-Dist: packaging>=21.1
Requires-Dist: pathvalidate>=2.5.2
Requires-Dist: pendulum>=2.1.2
Requires-Dist: pendulum>=3.0.0; python_version > '3.13'
Requires-Dist: pluggy>=1.3.0
Requires-Dist: pytz>=2022.6
Requires-Dist: pywin32>=306; sys_platform == 'win32'
Requires-Dist: pyyaml>=5.4.1
Requires-Dist: requests>=2.26.0
Requires-Dist: requirements-parser>=0.5.0
Requires-Dist: rich-argparse>=1.6.0
Requires-Dist: semver>=3.0.0
Requires-Dist: setuptools>=65.6.0
Requires-Dist: simplejson>=3.17.5
Requires-Dist: sqlglot>=26.32.0
Requires-Dist: tenacity>=8.0.2
Requires-Dist: tomlkit>=0.11.3
Requires-Dist: typing-extensions>=4.8.0
Requires-Dist: tzdata>=2022.1
Requires-Dist: win-precise-time>=1.4.2; os_name == 'nt' and python_version < '3.13'
Provides-Extra: athena
Requires-Dist: botocore>=1.28; extra == 'athena'
Requires-Dist: pyarrow>=16.0.0; extra == 'athena'
Requires-Dist: pyathena>=2.9.6; extra == 'athena'
Requires-Dist: s3fs>=2022.4.0; extra == 'athena'
Provides-Extra: az
Requires-Dist: adlfs>=2024.7.0; extra == 'az'
Provides-Extra: bigquery
Requires-Dist: db-dtypes>=1.2.0; extra == 'bigquery'
Requires-Dist: gcsfs>=2022.4.0; extra == 'bigquery'
Requires-Dist: google-cloud-bigquery>=2.26.0; extra == 'bigquery'
Requires-Dist: grpcio>=1.50.0; extra == 'bigquery'
Requires-Dist: pyarrow>=16.0.0; extra == 'bigquery'
Provides-Extra: cli
Requires-Dist: cron-descriptor>=1.2.32; extra == 'cli'
Requires-Dist: pip>=23.0.0; extra == 'cli'
Requires-Dist: pipdeptree<2.10,>=2.9.3; extra == 'cli'
Provides-Extra: clickhouse
Requires-Dist: adlfs>=2024.7.0; extra == 'clickhouse'
Requires-Dist: clickhouse-connect>=0.7.7; extra == 'clickhouse'
Requires-Dist: clickhouse-driver>=0.2.7; extra == 'clickhouse'
Requires-Dist: gcsfs>=2022.4.0; extra == 'clickhouse'
Requires-Dist: pyarrow>=16.0.0; extra == 'clickhouse'
Requires-Dist: s3fs>=2022.4.0; extra == 'clickhouse'
Provides-Extra: databricks
Requires-Dist: databricks-sdk>=0.38.0; extra == 'databricks'
Requires-Dist: databricks-sql-connector>=2.9.3; (python_version <= '3.12') and extra == 'databricks'
Requires-Dist: databricks-sql-connector>=3.6.0; (python_version >= '3.13') and extra == 'databricks'
Requires-Dist: databricks-zerobus-ingest-sdk>=1.2.0; ((platform_system == 'Linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')) or (platform_system == 'Windows' and (platform_machine == 'AMD64' or platform_machine == 'x86_64'))) and extra == 'databricks'
Provides-Extra: dbml
Requires-Dist: pydbml; extra == 'dbml'
Provides-Extra: deltalake
Requires-Dist: deltalake>=0.25.1; extra == 'deltalake'
Requires-Dist: pyarrow>=16.0.0; extra == 'deltalake'
Provides-Extra: dremio
Requires-Dist: pyarrow>=16.0.0; extra == 'dremio'
Provides-Extra: duckdb
Requires-Dist: duckdb>=0.9; extra == 'duckdb'
Provides-Extra: ducklake
Requires-Dist: duckdb>=1.2.0; extra == 'ducklake'
Requires-Dist: pyarrow>=16.0.0; extra == 'ducklake'
Provides-Extra: fabric
Requires-Dist: adlfs>=2024.7.0; extra == 'fabric'
Requires-Dist: pyarrow>=16.0.0; extra == 'fabric'
Requires-Dist: pyodbc>=4.0.39; extra == 'fabric'
Provides-Extra: filesystem
Requires-Dist: botocore>=1.28; extra == 'filesystem'
Requires-Dist: s3fs>=2022.4.0; extra == 'filesystem'
Provides-Extra: gcp
Requires-Dist: db-dtypes>=1.2.0; extra == 'gcp'
Requires-Dist: gcsfs>=2022.4.0; extra == 'gcp'
Requires-Dist: google-cloud-bigquery>=2.26.0; extra == 'gcp'
Requires-Dist: grpcio>=1.50.0; extra == 'gcp'
Provides-Extra: gs
Requires-Dist: gcsfs>=2022.4.0; extra == 'gs'
Provides-Extra: hf
Requires-Dist: huggingface-hub>=1.4.1; extra == 'hf'
Requires-Dist: pyarrow>=21.0.0; extra == 'hf'
Provides-Extra: http
Requires-Dist: aiohttp>3.9.0; extra == 'http'
Provides-Extra: hub
Requires-Dist: dlthub-client>=0.28.1; extra == 'hub'
Requires-Dist: dlthub<0.31,>=0.29.0; extra == 'hub'
Provides-Extra: lance
Requires-Dist: duckdb>=1.4.3; extra == 'lance'
Requires-Dist: ibis-framework>=12.0.0; extra == 'lance'
Requires-Dist: lancedb>=0.33.0; extra == 'lance'
Requires-Dist: pyarrow>=16.0.0; extra == 'lance'
Requires-Dist: pylance<8,>=6.0.1; extra == 'lance'
Provides-Extra: lancedb
Requires-Dist: duckdb>=1.4.3; extra == 'lancedb'
Requires-Dist: ibis-framework>=12.0.0; extra == 'lancedb'
Requires-Dist: lancedb>=0.22.0; extra == 'lancedb'
Requires-Dist: pyarrow>=16.0.0; extra == 'lancedb'
Provides-Extra: motherduck
Requires-Dist: duckdb>=0.9; extra == 'motherduck'
Requires-Dist: pyarrow>=16.0.0; extra == 'motherduck'
Provides-Extra: mssql
Requires-Dist: pyodbc>=4.0.39; extra == 'mssql'
Provides-Extra: oracle
Requires-Dist: oracledb>=3.4.1; extra == 'oracle'
Provides-Extra: parquet
Requires-Dist: pyarrow>=16.0.0; extra == 'parquet'
Provides-Extra: polars
Requires-Dist: polars>=1.0.0; extra == 'polars'
Provides-Extra: postgis
Requires-Dist: psycopg2-binary>=2.9.1; extra == 'postgis'
Provides-Extra: postgres
Requires-Dist: psycopg2-binary>=2.9.1; extra == 'postgres'
Provides-Extra: pyiceberg
Requires-Dist: pyarrow>=16.0.0; extra == 'pyiceberg'
Requires-Dist: pyiceberg-core>=0.6.0; extra == 'pyiceberg'
Requires-Dist: pyiceberg>=0.9.1; extra == 'pyiceberg'
Requires-Dist: sqlalchemy>=1.4; extra == 'pyiceberg'
Provides-Extra: qdrant
Requires-Dist: qdrant-client>=1.8; (python_version > '3.13') and extra == 'qdrant'
Requires-Dist: qdrant-client[fastembed]>=1.8; (python_version <= '3.13') and extra == 'qdrant'
Provides-Extra: redshift
Requires-Dist: psycopg2-binary>=2.9.1; extra == 'redshift'
Provides-Extra: s3
Requires-Dist: botocore>=1.28; extra == 's3'
Requires-Dist: s3fs>=2022.4.0; extra == 's3'
Provides-Extra: sftp
Requires-Dist: paramiko<5,>=3.3.0; extra == 'sftp'
Provides-Extra: snowflake
Requires-Dist: snowflake-connector-python>=3.5.0; extra == 'snowflake'
Requires-Dist: snowflake-connector-python>=4.4.0; (python_version >= '3.14') and extra == 'snowflake'
Provides-Extra: sql-database
Requires-Dist: sqlalchemy>=1.4; extra == 'sql-database'
Provides-Extra: sqlalchemy
Requires-Dist: alembic>1.10.0; extra == 'sqlalchemy'
Requires-Dist: sqlalchemy>=1.4; extra == 'sqlalchemy'
Provides-Extra: synapse
Requires-Dist: adlfs>=2024.7.0; extra == 'synapse'
Requires-Dist: pyarrow>=16.0.0; extra == 'synapse'
Requires-Dist: pyodbc>=4.0.39; extra == 'synapse'
Provides-Extra: weaviate
Requires-Dist: weaviate-client<5.0.0,>=4.0.0; extra == 'weaviate'
Description-Content-Type: text/markdown

<h1 align="center">
    <strong>data load tool (dlt) — the open-source Python library that automates all your tedious data loading tasks</strong>
</h1>
<p align="center">
Be it a Google Colab notebook, AWS Lambda function, an Airflow DAG, your local laptop,<br/>or an AI coding agent—<strong>dlt</strong> can be dropped in anywhere.
</p>


<h3 align="center">

🚀 Join our thriving community of likeminded developers and build the future together!

</h3>

<div align="center">
  <a target="_blank" href="https://dlthub.com/community" style="background:none">
    <img src="https://img.shields.io/badge/slack-join-dlt.svg?labelColor=191937&color=6F6FF7&logo=slack" style="width: 260px;"  />
  </a>
</div>
<div align="center">
  <a target="_blank" href="https://pypi.org/project/dlt/" style="background:none">
    <img src="https://img.shields.io/pypi/v/dlt?labelColor=191937&color=6F6FF7">
  </a>
  <a target="_blank" href="https://pypi.org/project/dlt/" style="background:none">
    <img src="https://img.shields.io/pypi/pyversions/dlt?labelColor=191937&color=6F6FF7">
  </a>
  <a target="_blank" href="https://pypi.org/project/dlt/" style="background:none">
    <img src="https://img.shields.io/pypi/dm/dlt?labelColor=191937&color=6F6FF7">
  </a>
</div>

## Installation

dlt supports Python 3.10 through Python 3.14. Note that some optional extras are not yet available for Python 3.14, so support for this version is considered experimental.

```sh
pip install dlt
```

Add the extras you need for your sources and destinations, for example:

```sh
pip install "dlt[duckdb]"        # local DuckDB destination
pip install "dlt[bigquery]"      # or snowflake, postgres, redshift, databricks, athena, ...
pip install "dlt[s3]"            # or gs, az for cloud filesystems
pip install "dlt[sql_database]"  # read from any SQL database
pip install "dlt[hub]"           # data quality, transformations, and AI (see below)
```

Prefer [uv](https://docs.astral.sh/uv/)? `uv add "dlt[duckdb]"`.

## Quick Start

Describe an API declaratively and load it into DuckDB — dlt handles requests, pagination, schema inference, and typing for you:

```python
import dlt
from dlt.sources.rest_api import rest_api_source

# 1. Describe the API declaratively
source = rest_api_source({
    "client": {"base_url": "https://pokeapi.co/api/v2/"},
    "resources": [
        {"name": "pokemon", "endpoint": {"path": "pokemon", "params": {"limit": 1000}}},
    ],
})

# 2. Point a pipeline at any destination
pipeline = dlt.pipeline(
    pipeline_name="pokemon",
    destination="duckdb",
    dataset_name="pokemon_data",
)

# 3. Extract, normalize, and load
print(pipeline.run(source))

# 4. ...and read it straight back as a DataFrame
print(pipeline.dataset().pokemon.df())
```

...or load any Python iterable — a [resource](https://dlthub.com/docs/general-usage/resource) is just a generator, and dlt infers the schema, types the columns, and writes the table:

```python
import dlt

@dlt.resource(table_name="players", primary_key="id", write_disposition="merge")
def players():
    yield {"id": 1, "name": "Magnus", "rating": 2839}
    yield {"id": 2, "name": "Pragg", "rating": 2758}

dlt.pipeline(destination="duckdb", dataset_name="chess").run(players())
```

Check out a super simple demo in **[Colab](https://colab.research.google.com/drive/1NfSB1DpwbbHX9_t5vlalBTf13utwpMGx?usp=sharing)** or a more advanced [Hugging Face demo with Marimo notebooks](https://molab.marimo.io/github/marimo-team/gallery-examples/blob/main/notebooks/external/dlthub-huggingface.py).

## Why dlt

**dlt** loads data from messy, often unstructured sources into well-structured, typed datasets. It's a **library, not a platform** — you `pip install` it into your existing code and keep your workflow and the other tools you already use. No black boxes: clean Pythonic interfaces, human-readable file formats, schemas you can inspect, no hidden side effects.

dlt and its docs are **built from the ground up for LLMs and coding agents**. Pair the typed, declarative primitives below with [dlthub.com/context](https://dlthub.com/context) and the [LLM-native workflow](https://dlthub.com/docs/dlt-ecosystem/llm-tooling/llm-native-workflow) to go from prompt to working pipeline — across [5000+ sources](https://dlthub.com/workspace) — often in a single shot.

## Extract from any source

**REST APIs** — describe the endpoints declaratively; filter, map, and flatten records right at the source ([docs](https://dlthub.com/docs/tutorial/rest-api)):

```python
from dlt.sources.rest_api import rest_api_source

source = rest_api_source({
    "client": {
        "base_url": "https://api.example.com/v1",
        "paginator": {"type": "cursor", "cursor_path": "next_cursor"},
    },
    "resources": [
        {
            "name": "guests",
            "endpoint": {"path": "events/guests"},
            "processing_steps": [
                {"filter": lambda r: r["approval_status"] == "approved"},
                {"map": lambda r: {**r, "email": r["email"].lower()}},
            ],
        },
    ],
})
```

**SQL databases** — reflect tables and types straight from the database ([docs](https://dlthub.com/docs/tutorial/sql-database)):

```python
from dlt.sources.sql_database import sql_database

source = sql_database("mysql+pymysql://user:pass@host/db")
```

**Files in any bucket** — list, then parse CSV / JSONL / Parquet from local disk, S3, GCS, or Azure ([docs](https://dlthub.com/docs/tutorial/filesystem)):

```python
from dlt.sources.filesystem import filesystem, read_csv_duckdb

source = (
    filesystem(bucket_url="s3://my-bucket/data", file_glob="*.csv")
    | read_csv_duckdb()
).with_name("events")
```

**DataFrames & Arrow** — pandas, Polars, and Arrow tables load directly; Arrow-backed frames move with zero copies:

```python
import dlt
import pandas as pd

df = pd.DataFrame({"event": ["dlt summit", "DuckCon"], "signups": [1240, 860]})
dlt.pipeline(destination="duckdb", dataset_name="events").run(df, table_name="events")
```

See [many more sources](https://dlthub.com/docs/dlt-ecosystem/verified-sources) in the ecosystem.

## Load to 20+ destinations — swap one string

The same resource runs anywhere. Change the `destination` string and dlt takes care of credentials, DDL in the target dialect, staging, and schema drift:

```python
pipeline = dlt.pipeline(
    pipeline_name="luma",
    destination="duckdb",       # → snowflake, bigquery, postgres, redshift, databricks,
    dataset_name="luma_data",   #   athena, clickhouse, motherduck, filesystem (S3/GCS/Azure),
)                               #   iceberg, delta, ... and custom reverse-ETL destinations
pipeline.run(source)
```

dlt handles the parts you'd rather not:

- **Credentials** → `secrets.toml` / env vars, injected automatically
- **DDL** → `CREATE TABLE` in the target's dialect
- **Type mapping** → source types converted to the destination's types
- **Staging** → S3 / GCS for warehouses that need it
- **Schema drift** → `ALTER TABLE` on the fly

Browse all [supported destinations](https://dlthub.com/docs/dlt-ecosystem/destinations/), or build a [custom one](https://dlthub.com/docs/dlt-ecosystem/destinations/destination).

## Declare intent with decorators

Decorators let you declare *what* you want — incremental loading, merge strategies, schema contracts, column hints — instead of hand-rolling it. Every knob can be overridden at runtime ([docs](https://dlthub.com/docs/general-usage/resource)):

```python
import dlt

@dlt.resource(
    primary_key="id",
    write_disposition="merge",                       # upsert on the primary key
    columns={"email": {"x-annotation-pii": True}},   # type and annotate columns
    schema_contract={"columns": "freeze"},           # reject unexpected columns
)
def events(
    updated_at=dlt.sources.incremental("updated_at"),  # load only new/changed rows
):
    yield from fetch_events(since=updated_at.last_value)


@dlt.source
def luma(api_key: str = dlt.secrets.value):
    return events(), guests()   # group one or more resources behind shared config/auth
```

[**Schema contracts**](https://dlthub.com/docs/general-usage/schema-contracts) enforce the shape at the gate, with three modes — `evolve` (accept and adapt the schema), `freeze` (reject the record), and `discard` (drop the offending row/column) — applied independently to `tables`, `columns`, and `data_type`. You also get [schema inference](https://dlthub.com/docs/general-usage/schema), [normalization of nested data](https://dlthub.com/docs/general-usage/schema/#data-normalizer), [incremental loading](https://dlthub.com/docs/general-usage/incremental-loading), and [secrets & config injection](https://dlthub.com/docs/general-usage/credentials) out of the box.

## Read your data back: the Dataset API

A pipeline is durable. Reconnect to one by name with `dlt.attach` and read any table back in the shape that fits your tool ([docs](https://dlthub.com/docs/general-usage/dataset-access/)):

```python
import dlt

pipeline = dlt.attach(pipeline_name="luma", destination="duckdb", dataset_name="luma_data")

dataset = pipeline.dataset()
dataset.tables               # ['events', 'guests', ...]

guests = dataset.guests      # a lazy dlt.Relation
guests.df()                  # pandas DataFrame
guests.arrow()               # pyarrow.Table (zero-copy)
guests.to_ibis()             # ibis expression — lazy, composable
```

## Transform with Ibis — Python in, SQL out

Lift any loaded table into an [Ibis](https://ibis-project.org/) expression, compose group-bys, joins, and window functions in Python, and let dlt compile it to SQL in the destination's dialect. Nothing runs until you ask for the result:

```python
import ibis

guests = pipeline.dataset().guests.to_ibis()

guests_by_event = (
    guests
    .group_by("event_id")
    .aggregate(n_guests=ibis._.api_id.count())
)

guests_by_event.to_pyarrow()   # compiles to SQL and runs on the destination
```

dlt also supports [Python and SQL data access](https://dlthub.com/docs/general-usage/dataset-access/), [transformations](https://dlthub.com/docs/dlt-ecosystem/transformations), [pipeline inspection](https://dlthub.com/docs/general-usage/dashboard), and [visualizing data in Marimo notebooks](https://dlthub.com/docs/general-usage/dataset-access/marimo).

## Documentation

For detailed usage and configuration, please refer to the [official documentation](https://dlthub.com/docs).

## Examples

You can find examples for various use cases in the [examples](docs/examples) folder, or in the [code examples section](https://dlthub.com/docs/examples) of our docs page.

## Adding as dependency

`dlt` follows the semantic versioning with the [`MAJOR.MINOR.PATCH`](https://peps.python.org/pep-0440/#semantic-versioning) pattern.

* `major` means breaking changes and removed deprecations
* `minor` new features, sometimes automatic migrations
* `patch` bug fixes

We suggest that you allow only `patch` level updates automatically using the [Compatible Release Specifier](https://packaging.python.org/en/latest/specifications/version-specifiers/#compatible-release). For example **dlt~=1.23.0** allows only versions **>=1.23.0** and less than **<1.24.0**

Please also see our [release notes](https://github.com/dlt-hub/dlt/releases) for notable changes between versions.

## Get Involved

The dlt project is quickly growing, and we're excited to have you join our community! Here's how you can get involved:

- **Connect with the Community**: Join other dlt users and contributors on our [Slack](https://dlthub.com/community)
- **Report issues and suggest features**: Please use the [GitHub Issues](https://github.com/dlt-hub/dlt/issues) to report bugs or suggest new features. Before creating a new issue, make sure to search the tracker for possible duplicates and add a comment if you find one.
- **Track progress of our work and our plans**: Please check out our [public Github project](https://github.com/orgs/dlt-hub/projects/9)
- **Improve documentation**: Help us enhance the dlt documentation.

## Contribute code
Please read [CONTRIBUTING](CONTRIBUTING.md) before you make a PR.

- 📣 **New destinations are unlikely to be merged** due to high maintenance cost (but we are happy to improve SQLAlchemy destination to handle more dialects)
- Significant changes require tests and docs and in many cases writing tests will be more laborious than writing code
- Bugfixes and improvements are welcome! You'll get help with writing tests and docs + a decent review.

## Sponsors

<p>
  <a href="https://blacksmith.sh/?utm_source=dlt&utm_medium=readme&utm_campaign=sponsorship" target="_blank">
    <img src=".github/assets/blacksmith-logo.svg" alt="Blacksmith" width="240" />
  </a>
</p>

[Blacksmith](https://blacksmith.sh/?utm_source=dlt&utm_medium=readme&utm_campaign=sponsorship) is a drop-in replacement for GitHub-hosted runners that speed up our CI/CD pipelines by 2x and up to 75% cheaper. We're grateful to Blacksmith for sponsoring us with free CI/CD minutes--which helps us keep builds fast and our costs lower.

## License

`dlt` is released under the [Apache 2.0 License](LICENSE.txt).
