arrowbricks 3.0.2__tar.gz → 3.0.4__tar.gz

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.
Files changed (36) hide show
  1. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/PKG-INFO +28 -1
  2. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/README.md +27 -0
  3. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/pyproject.toml +1 -1
  4. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/Cargo.lock +88 -306
  5. arrowbricks-3.0.4/rust/arrowbricks_core/Cargo.toml +108 -0
  6. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/src/client.rs +49 -14
  7. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/src/pipeline.rs +28 -3
  8. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/src/arrowbricks/client.py +3 -1
  9. arrowbricks-3.0.2/rust/arrowbricks_core/Cargo.toml +0 -79
  10. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/LICENSE +0 -0
  11. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/.gitignore +0 -0
  12. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/README.md +0 -0
  13. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/examples/duckdb_query.py +0 -0
  14. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/examples/fastapi_sse.py +0 -0
  15. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/rustfmt.toml +0 -0
  16. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/src/heartbeat.rs +0 -0
  17. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/src/json_convert.rs +0 -0
  18. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/src/lib.rs +0 -0
  19. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/src/thrift.rs +0 -0
  20. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests/wiremock_pipeline.rs +0 -0
  21. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests/wiremock_thrift.rs +0 -0
  22. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests/wiremock_volume_files.rs +0 -0
  23. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/conftest.py +0 -0
  24. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_ipc_stream.py +0 -0
  25. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_parameters.py +0 -0
  26. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_stream_ndjson_lines.py +0 -0
  27. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_streaming.py +0 -0
  28. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_thrift.py +0 -0
  29. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_token_provider.py +0 -0
  30. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/test_volume_files.py +0 -0
  31. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/rust/arrowbricks_core/tests_py/thrift_mock.py +0 -0
  32. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/src/arrowbricks/__init__.py +0 -0
  33. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/src/arrowbricks/_core.pyi +0 -0
  34. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/src/arrowbricks/_streaming.py +0 -0
  35. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/src/arrowbricks/cursor.py +0 -0
  36. {arrowbricks-3.0.2 → arrowbricks-3.0.4}/src/arrowbricks/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arrowbricks
3
- Version: 3.0.2
3
+ Version: 3.0.4
4
4
  Requires-Dist: arro3-core>=0.8 ; extra == 'arro3'
5
5
  Provides-Extra: arro3
6
6
  License-File: LICENSE
@@ -210,6 +210,33 @@ con.sql("SELECT * FROM my_table WHERE id = 42").show()
210
210
 
211
211
  The [official driver](https://github.com/databricks/databricks-sql-python) is the right choice if you need full DB-API 2.0 compatibility. If you just want a query result as Arrow/JSON in your own async app, it drags in a lot for that: `pandas`, `thrift`, `openpyxl`, `pybreaker`, `pyjwt`, `oauthlib`, `lz4`, `requests`, `urllib3` as hard dependencies. arrowbricks speaks the same wire protocols (Thrift by default, or the REST Statement Execution API via `protocol="sea"`) with a hand-rolled Rust implementation instead, and zero required dependencies of its own. The `Cursor` API is deliberately shaped like the official driver's so switching between them is mostly a constructor change, but arrowbricks is async throughout (`execute`, `fetchone`, etc. are all coroutines) -- there's no sync escape hatch.
212
212
 
213
+ ## Benchmarks
214
+
215
+ Measured against a real Databricks SQL warehouse (Azure Databricks, `2X-Small` **Pro** serverless warehouse, Photon on, 1-4 auto-scaling clusters -- the smallest/cheapest warehouse tier, deliberately: a bigger warehouse would narrow the gap by making the query itself slower and the client-side overhead this compares proportionally smaller). Query: `SELECT id, id * 2 AS doubled, CAST(id AS STRING) AS label FROM range(200000)` (200k rows, 3 columns), 3 timed runs after 1 discarded warm-up run, one connection reused per library:
216
+
217
+ | | avg | stdev | range | peak RSS during the query |
218
+ |---|---|---|---|---|
219
+ | `databricks-sql-connector` | 0.88s | 0.06s | 0.83s - 0.95s | 16 MB |
220
+ | arrowbricks | 0.50s | 0.02s | 0.48s - 0.52s | 16 MB |
221
+
222
+ **arrowbricks: ~1.8x faster**, same order-of-magnitude peak memory *for this query size* -- at 200k rows the Python interpreter's own baseline footprint dominates over the actual result data for both libraries, so this particular number doesn't show a difference. The real memory/footprint difference is in what gets installed, not what a single small query allocates:
223
+
224
+ | | installed size (package + all required deps) |
225
+ |---|---|
226
+ | `databricks-sql-connector` | 71 MB (pulls in `pandas`, `numpy`, `thrift`, `oauthlib`, `lz4`, `requests`, `urllib3`, `openpyxl`, ... as hard dependencies -- `pandas`+`numpy` alone are 61 MB of that) |
227
+ | arrowbricks | 9 MB (zero required runtime dependencies -- the whole thing is one compiled Rust extension, built with `opt-level="s"`, `ring` instead of the heavier default TLS crypto backend, and no unused HTTP/2 support -- see `rust/arrowbricks_core/Cargo.toml`'s own `[profile.release]` and `rustls`/`hyper-rustls` comments for the measurements behind those choices) |
228
+
229
+ Run it yourself: [`examples/benchmark_vs_connector.py`](examples/benchmark_vs_connector.py) (needs both packages installed: `pip install arrowbricks databricks-sql-connector`). Reads `DATABRICKS_HOST`/`DATABRICKS_WAREHOUSE_ID`/`DATABRICKS_TOKEN` from the environment or a `.env` file (never commit one with a real token in it) and runs each library in its own subprocess so peak memory reflects that library alone:
230
+
231
+ ```bash
232
+ DATABRICKS_HOST=adb-1234567890.1.azuredatabricks.net \
233
+ DATABRICKS_WAREHOUSE_ID=abcd1234efgh5678 \
234
+ DATABRICKS_TOKEN=dapiXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
235
+ python examples/benchmark_vs_connector.py
236
+ ```
237
+
238
+ `BENCHMARK_SQL` overrides the query, `BENCHMARK_RUNS` (default 3) controls how many timed runs to average.
239
+
213
240
  ## A note on Arrow IPC compression
214
241
 
215
242
  `write_ipc_stream` (and everything in this package that serializes Arrow-IPC bytes) always writes **uncompressed** bodies. A compressed body (arro3's own default is `compression="LZ4"`) is transparently decompressed by some Arrow readers (e.g. DuckDB's) but not necessarily by every other Arrow IPC reader -- notably, `duckdb-wasm`'s browser-side decoder silently fails to parse LZ4-compressed bodies. Since arrowbricks' bytes might end up read by anything, plain uncompressed is the safe default.
@@ -198,6 +198,33 @@ con.sql("SELECT * FROM my_table WHERE id = 42").show()
198
198
 
199
199
  The [official driver](https://github.com/databricks/databricks-sql-python) is the right choice if you need full DB-API 2.0 compatibility. If you just want a query result as Arrow/JSON in your own async app, it drags in a lot for that: `pandas`, `thrift`, `openpyxl`, `pybreaker`, `pyjwt`, `oauthlib`, `lz4`, `requests`, `urllib3` as hard dependencies. arrowbricks speaks the same wire protocols (Thrift by default, or the REST Statement Execution API via `protocol="sea"`) with a hand-rolled Rust implementation instead, and zero required dependencies of its own. The `Cursor` API is deliberately shaped like the official driver's so switching between them is mostly a constructor change, but arrowbricks is async throughout (`execute`, `fetchone`, etc. are all coroutines) -- there's no sync escape hatch.
200
200
 
201
+ ## Benchmarks
202
+
203
+ Measured against a real Databricks SQL warehouse (Azure Databricks, `2X-Small` **Pro** serverless warehouse, Photon on, 1-4 auto-scaling clusters -- the smallest/cheapest warehouse tier, deliberately: a bigger warehouse would narrow the gap by making the query itself slower and the client-side overhead this compares proportionally smaller). Query: `SELECT id, id * 2 AS doubled, CAST(id AS STRING) AS label FROM range(200000)` (200k rows, 3 columns), 3 timed runs after 1 discarded warm-up run, one connection reused per library:
204
+
205
+ | | avg | stdev | range | peak RSS during the query |
206
+ |---|---|---|---|---|
207
+ | `databricks-sql-connector` | 0.88s | 0.06s | 0.83s - 0.95s | 16 MB |
208
+ | arrowbricks | 0.50s | 0.02s | 0.48s - 0.52s | 16 MB |
209
+
210
+ **arrowbricks: ~1.8x faster**, same order-of-magnitude peak memory *for this query size* -- at 200k rows the Python interpreter's own baseline footprint dominates over the actual result data for both libraries, so this particular number doesn't show a difference. The real memory/footprint difference is in what gets installed, not what a single small query allocates:
211
+
212
+ | | installed size (package + all required deps) |
213
+ |---|---|
214
+ | `databricks-sql-connector` | 71 MB (pulls in `pandas`, `numpy`, `thrift`, `oauthlib`, `lz4`, `requests`, `urllib3`, `openpyxl`, ... as hard dependencies -- `pandas`+`numpy` alone are 61 MB of that) |
215
+ | arrowbricks | 9 MB (zero required runtime dependencies -- the whole thing is one compiled Rust extension, built with `opt-level="s"`, `ring` instead of the heavier default TLS crypto backend, and no unused HTTP/2 support -- see `rust/arrowbricks_core/Cargo.toml`'s own `[profile.release]` and `rustls`/`hyper-rustls` comments for the measurements behind those choices) |
216
+
217
+ Run it yourself: [`examples/benchmark_vs_connector.py`](examples/benchmark_vs_connector.py) (needs both packages installed: `pip install arrowbricks databricks-sql-connector`). Reads `DATABRICKS_HOST`/`DATABRICKS_WAREHOUSE_ID`/`DATABRICKS_TOKEN` from the environment or a `.env` file (never commit one with a real token in it) and runs each library in its own subprocess so peak memory reflects that library alone:
218
+
219
+ ```bash
220
+ DATABRICKS_HOST=adb-1234567890.1.azuredatabricks.net \
221
+ DATABRICKS_WAREHOUSE_ID=abcd1234efgh5678 \
222
+ DATABRICKS_TOKEN=dapiXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
223
+ python examples/benchmark_vs_connector.py
224
+ ```
225
+
226
+ `BENCHMARK_SQL` overrides the query, `BENCHMARK_RUNS` (default 3) controls how many timed runs to average.
227
+
201
228
  ## A note on Arrow IPC compression
202
229
 
203
230
  `write_ipc_stream` (and everything in this package that serializes Arrow-IPC bytes) always writes **uncompressed** bodies. A compressed body (arro3's own default is `compression="LZ4"`) is transparently decompressed by some Arrow readers (e.g. DuckDB's) but not necessarily by every other Arrow IPC reader -- notably, `duckdb-wasm`'s browser-side decoder silently fails to parse LZ4-compressed bodies. Since arrowbricks' bytes might end up read by anything, plain uncompressed is the safe default.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arrowbricks"
3
- version = "3.0.2"
3
+ version = "3.0.4"
4
4
  description = "Runs SQL against a Databricks SQL warehouse via the Statement Execution API and hands you the result as Arrow -- a DB-API-ish Cursor (fetchone/fetchmany/fetchall/fetchall_arrow) or NDJSON streaming. Rust/PyO3 core throughout -- zero required runtime dependencies."
5
5
  readme = "README.md"
6
6
  license = "MIT"