deltaforge-adbc 1.0.5__py3-none-win_amd64.whl
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.
- deltaforge_adbc/__init__.py +205 -0
- deltaforge_adbc/lib/.gitkeep +3 -0
- deltaforge_adbc/lib/deltaforge_adbc.dll +0 -0
- deltaforge_adbc-1.0.5.dist-info/METADATA +103 -0
- deltaforge_adbc-1.0.5.dist-info/RECORD +7 -0
- deltaforge_adbc-1.0.5.dist-info/WHEEL +5 -0
- deltaforge_adbc-1.0.5.dist-info/licenses/LICENSE +22 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""DeltaForge ADBC driver: Arrow-native read and write for Delta tables.
|
|
2
|
+
|
|
3
|
+
This package bundles the native DeltaForge ADBC driver and exposes a small,
|
|
4
|
+
ergonomic surface over ``adbc_driver_manager`` so you can connect, run queries,
|
|
5
|
+
and write a DataFrame straight into a Delta table without per-row marshalling.
|
|
6
|
+
|
|
7
|
+
Quick start
|
|
8
|
+
-----------
|
|
9
|
+
import deltaforge_adbc as df
|
|
10
|
+
|
|
11
|
+
conn = df.connect(
|
|
12
|
+
control_plane="https://control.example.com",
|
|
13
|
+
token="df_pat_...", # personal access token
|
|
14
|
+
compute="https://compute.example.com",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Read into a pyarrow.Table (or .to_pandas() / .to_polars()).
|
|
18
|
+
table = df.read_table(conn, "SELECT * FROM sales.public.orders LIMIT 1000")
|
|
19
|
+
|
|
20
|
+
# Write a DataFrame (pandas, polars, or pyarrow) into a Delta table.
|
|
21
|
+
df.write_dataframe(conn, "sales.public.orders", my_dataframe, mode="append")
|
|
22
|
+
|
|
23
|
+
conn.close()
|
|
24
|
+
|
|
25
|
+
The driver carries Arrow record batches end to end, so ``write_dataframe`` is
|
|
26
|
+
the preferred bulk path for pandas / polars / pyarrow data.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import os
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import Any, Optional
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"driver_path",
|
|
38
|
+
"connect",
|
|
39
|
+
"read_table",
|
|
40
|
+
"write_dataframe",
|
|
41
|
+
"DeltaForgeAdbcError",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class DeltaForgeAdbcError(RuntimeError):
|
|
46
|
+
"""Raised for configuration problems before a request reaches the driver."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def driver_path() -> str:
|
|
50
|
+
"""Absolute path to the bundled native ADBC driver shared library.
|
|
51
|
+
|
|
52
|
+
The wheel ships exactly one library, named per platform. Returns the path
|
|
53
|
+
so it can be handed to ``adbc_driver_manager`` as the ``driver`` option.
|
|
54
|
+
"""
|
|
55
|
+
lib_dir = Path(__file__).resolve().parent / "lib"
|
|
56
|
+
candidates = [
|
|
57
|
+
"libdeltaforge_adbc.so",
|
|
58
|
+
"libdeltaforge_adbc.dylib",
|
|
59
|
+
"deltaforge_adbc.dll",
|
|
60
|
+
]
|
|
61
|
+
for name in candidates:
|
|
62
|
+
p = lib_dir / name
|
|
63
|
+
if p.exists():
|
|
64
|
+
return str(p)
|
|
65
|
+
# Allow an explicit override (useful for local driver builds / debugging).
|
|
66
|
+
override = os.environ.get("DELTAFORGE_ADBC_PATH")
|
|
67
|
+
if override and Path(override).exists():
|
|
68
|
+
return override
|
|
69
|
+
raise DeltaForgeAdbcError(
|
|
70
|
+
f"no DeltaForge ADBC driver found in {lib_dir}. The installed wheel may "
|
|
71
|
+
f"not match this platform ({sys.platform}); reinstall with a matching "
|
|
72
|
+
f"wheel, or set DELTAFORGE_ADBC_PATH to a local driver build."
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def connect(
|
|
77
|
+
*,
|
|
78
|
+
control_plane: Optional[str] = None,
|
|
79
|
+
token: Optional[str] = None,
|
|
80
|
+
compute: Optional[str] = None,
|
|
81
|
+
**db_kwargs: Any,
|
|
82
|
+
):
|
|
83
|
+
"""Open a DB-API 2.0 connection to a DeltaForge compute node over ADBC.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
control_plane:
|
|
88
|
+
Control-plane URL. Defaults to ``$DELTAFORGE_CONTROL_PLANE_URL`` then
|
|
89
|
+
``http://localhost:3000``.
|
|
90
|
+
token:
|
|
91
|
+
Session token or personal access token (``df_...`` / ``df_pat_...``).
|
|
92
|
+
Defaults to ``$DELTAFORGE_SESSION_TOKEN``.
|
|
93
|
+
compute:
|
|
94
|
+
Optional compute-node URL. Defaults to ``$DELTAFORGE_COMPUTE_URL`` when
|
|
95
|
+
set; otherwise the control plane selects a healthy node.
|
|
96
|
+
db_kwargs:
|
|
97
|
+
Extra ADBC database options passed through verbatim.
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
import adbc_driver_manager.dbapi as dbapi
|
|
101
|
+
except ImportError as exc: # pragma: no cover - dependency declared in pyproject
|
|
102
|
+
raise DeltaForgeAdbcError(
|
|
103
|
+
"adbc_driver_manager is required (pip install adbc-driver-manager)"
|
|
104
|
+
) from exc
|
|
105
|
+
|
|
106
|
+
cp = control_plane or os.environ.get(
|
|
107
|
+
"DELTAFORGE_CONTROL_PLANE_URL", "http://localhost:3000"
|
|
108
|
+
)
|
|
109
|
+
tok = token or os.environ.get("DELTAFORGE_SESSION_TOKEN")
|
|
110
|
+
if not tok:
|
|
111
|
+
raise DeltaForgeAdbcError(
|
|
112
|
+
"no token: pass token=... or set DELTAFORGE_SESSION_TOKEN"
|
|
113
|
+
)
|
|
114
|
+
comp = compute or os.environ.get("DELTAFORGE_COMPUTE_URL")
|
|
115
|
+
|
|
116
|
+
kwargs = {
|
|
117
|
+
"driver": driver_path(),
|
|
118
|
+
"entrypoint": "AdbcDriverInit",
|
|
119
|
+
"uri": cp,
|
|
120
|
+
"adbc.deltaforge.session_token": tok,
|
|
121
|
+
}
|
|
122
|
+
if comp:
|
|
123
|
+
kwargs["adbc.deltaforge.compute_url"] = comp
|
|
124
|
+
kwargs.update(db_kwargs)
|
|
125
|
+
return dbapi.connect(db_kwargs=kwargs)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def read_table(conn, sql: str):
|
|
129
|
+
"""Execute ``sql`` and return the full result as a ``pyarrow.Table``.
|
|
130
|
+
|
|
131
|
+
Use ``.to_pandas()`` or ``polars.from_arrow(...)`` on the result for a
|
|
132
|
+
DataFrame.
|
|
133
|
+
"""
|
|
134
|
+
with conn.cursor() as cur:
|
|
135
|
+
cur.execute(sql)
|
|
136
|
+
return cur.fetch_arrow_table()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _to_arrow(data):
|
|
140
|
+
"""Coerce pandas / polars / pyarrow input into a pyarrow Table or batch."""
|
|
141
|
+
import pyarrow as pa
|
|
142
|
+
|
|
143
|
+
if isinstance(data, (pa.Table, pa.RecordBatch)):
|
|
144
|
+
return data
|
|
145
|
+
# polars
|
|
146
|
+
if data.__class__.__module__.startswith("polars"):
|
|
147
|
+
return data.to_arrow()
|
|
148
|
+
# pandas
|
|
149
|
+
if data.__class__.__module__.startswith("pandas"):
|
|
150
|
+
return pa.Table.from_pandas(data, preserve_index=False)
|
|
151
|
+
# Anything implementing the Arrow C stream / __arrow_c_stream__ protocol.
|
|
152
|
+
if hasattr(data, "__arrow_c_stream__") or hasattr(data, "__arrow_c_array__"):
|
|
153
|
+
return pa.table(data)
|
|
154
|
+
raise DeltaForgeAdbcError(
|
|
155
|
+
f"unsupported DataFrame type {type(data)!r}; pass pandas, polars, or "
|
|
156
|
+
f"pyarrow data"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def write_dataframe(
|
|
161
|
+
conn,
|
|
162
|
+
table: str,
|
|
163
|
+
data,
|
|
164
|
+
*,
|
|
165
|
+
mode: str = "append",
|
|
166
|
+
idempotency_key: Optional[str] = None,
|
|
167
|
+
) -> None:
|
|
168
|
+
"""Write a DataFrame into a Delta table via Arrow bulk ingest.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
table:
|
|
173
|
+
Fully qualified target table (``zone.schema.table``). It must already
|
|
174
|
+
exist; this call does not create it.
|
|
175
|
+
data:
|
|
176
|
+
pandas / polars / pyarrow data. Converted to Arrow once, then streamed.
|
|
177
|
+
mode:
|
|
178
|
+
``append`` (default), ``replace`` (overwrite), or ``upsert``.
|
|
179
|
+
idempotency_key:
|
|
180
|
+
Optional dedupe key. Re-sending the same batch with the same key is a
|
|
181
|
+
no-op rather than a duplicate insert.
|
|
182
|
+
"""
|
|
183
|
+
arrow = _to_arrow(data)
|
|
184
|
+
valid = {"append", "replace", "upsert", "create", "create_append"}
|
|
185
|
+
if mode not in valid:
|
|
186
|
+
raise DeltaForgeAdbcError(f"mode must be one of {sorted(valid)}, got {mode!r}")
|
|
187
|
+
|
|
188
|
+
with conn.cursor() as cur:
|
|
189
|
+
if idempotency_key is None and mode in {"append", "replace", "create", "create_append"}:
|
|
190
|
+
cur.adbc_ingest(table, arrow, mode=mode)
|
|
191
|
+
return
|
|
192
|
+
# upsert and idempotent paths ride on the df.ingest.* statement options.
|
|
193
|
+
cur.adbc_statement.set_options(
|
|
194
|
+
**{
|
|
195
|
+
"adbc.ingest.target_table": table,
|
|
196
|
+
"df.ingest.mode": mode,
|
|
197
|
+
**(
|
|
198
|
+
{"df.ingest.idempotency_key": idempotency_key}
|
|
199
|
+
if idempotency_key
|
|
200
|
+
else {}
|
|
201
|
+
),
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
cur.adbc_statement.bind(arrow)
|
|
205
|
+
cur.adbc_statement.execute_update()
|
|
Binary file
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deltaforge-adbc
|
|
3
|
+
Version: 1.0.5
|
|
4
|
+
Summary: DeltaForge ADBC driver: Arrow-native read and write for Delta Lake and Apache Iceberg, carrying record batches end-to-end so BI tools skip row-by-row conversion
|
|
5
|
+
Project-URL: Homepage, https://deltaforge.org
|
|
6
|
+
Project-URL: Documentation, https://deltaforge.org/docs
|
|
7
|
+
Project-URL: Issues, https://github.com/deltaforge-org/delta-forge-adbc/issues
|
|
8
|
+
Author: DeltaForge
|
|
9
|
+
License: LicenseRef-DeltaForge-Proprietary
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: adbc,arrow,delta lake,deltaforge,lakehouse
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: Other/Proprietary License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Database
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Requires-Dist: adbc-driver-manager>=1.0
|
|
18
|
+
Requires-Dist: pyarrow>=14.0
|
|
19
|
+
Provides-Extra: pandas
|
|
20
|
+
Requires-Dist: pandas>=1.5; extra == 'pandas'
|
|
21
|
+
Provides-Extra: polars
|
|
22
|
+
Requires-Dist: polars>=0.20; extra == 'polars'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<img src="https://deltaforge.org/assets/favicon/favicon-512.png" alt="DeltaForge" width="96" height="96">
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
<h1 align="center">deltaforge-adbc</h1>
|
|
30
|
+
|
|
31
|
+
<p align="center"><strong>ADBC driver: Arrow-native read and write for Delta Lake and Apache Iceberg from Python</strong></p>
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
<a href="https://deltaforge.org">deltaforge.org</a> ·
|
|
35
|
+
<a href="https://deltaforge.org/pages/adbc.html">ADBC driver</a> ·
|
|
36
|
+
<a href="https://github.com/deltaforge-org/delta-forge-adbc/issues">Issues</a>
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
Arrow-native read and write for Delta tables from Python, via the DeltaForge
|
|
40
|
+
ADBC driver. The driver carries Arrow record batches end to end, so it is the
|
|
41
|
+
preferred connector for wide-column scans and for writing DataFrames straight
|
|
42
|
+
into Delta tables.
|
|
43
|
+
|
|
44
|
+
DeltaForge is commercial software with a free Community license. See
|
|
45
|
+
[deltaforge.org/pricing](https://deltaforge.org/pricing).
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install deltaforge-adbc
|
|
51
|
+
# optional DataFrame integrations:
|
|
52
|
+
pip install "deltaforge-adbc[pandas]" # or [polars]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The wheel bundles the native driver for your platform. No separate driver
|
|
56
|
+
install or `unixODBC` setup is required.
|
|
57
|
+
|
|
58
|
+
## Connect
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import deltaforge_adbc as df
|
|
62
|
+
|
|
63
|
+
conn = df.connect(
|
|
64
|
+
control_plane="https://control.example.com",
|
|
65
|
+
token="df_pat_...", # personal access token
|
|
66
|
+
compute="https://compute.example.com", # optional; auto-selected if omitted
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Connection parameters also fall back to environment variables:
|
|
71
|
+
`DELTAFORGE_CONTROL_PLANE_URL`, `DELTAFORGE_SESSION_TOKEN`,
|
|
72
|
+
`DELTAFORGE_COMPUTE_URL`.
|
|
73
|
+
|
|
74
|
+
## Read
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
table = df.read_table(conn, "SELECT * FROM sales.public.orders LIMIT 1000")
|
|
78
|
+
pdf = table.to_pandas() # pandas
|
|
79
|
+
# import polars as pl; pl.from_arrow(table) # polars
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Write a DataFrame
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import pandas as pd
|
|
86
|
+
|
|
87
|
+
frame = pd.DataFrame({"id": [1, 2, 3], "region": ["us", "eu", "us"], "qty": [10, 20, 30]})
|
|
88
|
+
|
|
89
|
+
# Append (default). Also: mode="replace" (overwrite), mode="upsert".
|
|
90
|
+
df.write_dataframe(conn, "sales.public.orders", frame, mode="append")
|
|
91
|
+
|
|
92
|
+
# Idempotent append: re-sending the same key is a no-op, not a duplicate.
|
|
93
|
+
df.write_dataframe(conn, "sales.public.orders", frame, mode="append",
|
|
94
|
+
idempotency_key="nightly-2026-05-31")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
pandas, polars, and pyarrow inputs are all accepted; the target table must
|
|
98
|
+
already exist.
|
|
99
|
+
|
|
100
|
+
## Runnable examples
|
|
101
|
+
|
|
102
|
+
See [`examples/`](examples/): `read.py` and `write_dataframe.py` are
|
|
103
|
+
self-contained scripts driven by the environment variables above.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
deltaforge_adbc/__init__.py,sha256=jTnPrEJbO2Wc3hLA0fZxl-FoDCq4oE7wZTJ4Vx9SNjQ,6816
|
|
2
|
+
deltaforge_adbc/lib/.gitkeep,sha256=CxIOZrBkT4sfT0xZvSxBdQYfGSgqkRYE-1ozzC11_TQ,217
|
|
3
|
+
deltaforge_adbc/lib/deltaforge_adbc.dll,sha256=sAHBGv9B-wCm_wQziX24FEk7Jl5XAD0tgzreOsqZs0s,1162904
|
|
4
|
+
deltaforge_adbc-1.0.5.dist-info/METADATA,sha256=xRfnwuT924sQiGlmnd8g4RJZRPWLQaNbcn0_to-ACAk,3535
|
|
5
|
+
deltaforge_adbc-1.0.5.dist-info/WHEEL,sha256=pp_iTzO0EBcCvlZZV2dJYp6L2tdDWBsn1ceo50wEt8Q,94
|
|
6
|
+
deltaforge_adbc-1.0.5.dist-info/licenses/LICENSE,sha256=StCqCRJOqCkwuP7_gJA7lYqUANhupDcIbKav3ryrLjI,909
|
|
7
|
+
deltaforge_adbc-1.0.5.dist-info/RECORD,,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
DeltaForge Software License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 DeltaForge. All rights reserved.
|
|
4
|
+
|
|
5
|
+
DeltaForge is commercial software. This package contains a compiled,
|
|
6
|
+
redistributable client component (the DeltaForge ADBC driver). Use is
|
|
7
|
+
governed by the DeltaForge license terms.
|
|
8
|
+
|
|
9
|
+
* A free Community license is available for individuals and single-node
|
|
10
|
+
use, and ships the full platform.
|
|
11
|
+
* Paid Standard, Professional, and Enterprise tiers add scale, included
|
|
12
|
+
capacity, and support.
|
|
13
|
+
|
|
14
|
+
Tiers and details: https://deltaforge.org/pricing
|
|
15
|
+
Full license terms: https://deltaforge.org/terms-of-service
|
|
16
|
+
|
|
17
|
+
The DeltaForge source code is proprietary and is NOT licensed or distributed
|
|
18
|
+
under this agreement. Only the compiled client component in this package is
|
|
19
|
+
redistributable.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED. SEE THE FULL LICENSE TERMS FOR THE GOVERNING CONDITIONS.
|