arrowbricks
Databricks SQL to Arrow, with a Rust core.
Runs SQL against a Databricks SQL warehouse and hands you the result as Arrow -- a Cursor shaped like databricks-sql-python's (execute, fetchone/fetchmany/fetchall, fetchall_arrow/fetchmany_arrow), or stream_query_json for streaming NDJSON. Talks to Databricks over Thrift by default (protocol="thrift"), or the REST Statement Execution API if you prefer (protocol="sea") -- see below.
- Rust core. Statement submit/poll, bounded-concurrency chunk fetch, the reorder buffer, and Arrow-IPC decode all run in a PyO3/arrow-rs extension bundled in this same package -- 1.6x-2.5x faster than a pure-Python/asyncio client on a multi-chunk result, scaling further with chunk count and concurrency where asyncio+GIL plateaus.
- Thrift by default, SEA/REST as a fully-supported alternative (
protocol="sea"onconnect()/DatabricksClient(...)). Thrift speaks the same HiveServer2-compatible protocoldatabricks-sql-connectoruses by default -- measurably faster for small results (a statement's data can come back inline in the very same call that submits it, instead of SEA's separate poll-then-fetch round trip), and on par with SEA for a large, multi-chunk result too (its chunk downloads fan out concurrently across the whole result, same as SEA's own bounded-concurrency fetch, not serialized batch by batch) -- never slower than SEA on any query shape tested. Confirmed against a real production warehouse; seeAGENTS.md's design-invariant entry for the benchmarking history behind the switch. - Compressed cloud-fetch transport by default. Every statement requests LZ4-compressed chunk downloads (same default as the official
databricks-sql-connector) and decompresses them in Rust before you ever see the bytes -- less data over the wire, which matters more than local decode speed for a large result. Measured ~2x faster chunk-fetch time against a real 120-column/100k-row table. Disable per-client withcompress_results=False(connect()/DatabricksClient(...)) if your link to the warehouse is fast enough that decompression CPU time stops paying for itself. - Zero required dependencies.
pip install arrowbricksand go. - Bring-your-own-auth -- a static token or your own token-refresh callable. No cloud-SDK dependency baked in.
- Result order preserved even though chunks can complete out of order over the network.
- Lazy fetching -- chunks are pulled only as
fetchone/fetchmany/fetchallactually need them, not all upfront. - Heartbeats between slow chunks (
execute_streamed/stream_query_json), so a caller streaming this over e.g. SSE never goes silent during a cold warehouse start.
Install
pip install arrowbricks
Ships as precompiled platform wheels (Linux/macOS/Windows) -- no Rust toolchain needed, and nothing else to install for most of the API. Row-tuple fetches (fetchone/fetchmany/fetchall) need one optional extra: pip install arrowbricks[arro3] -- see Arrow vs. row-tuple fetches below.
Quickstart
import asyncio
from arrowbricks import connect
async def main():
conn = connect(
host="adb-1234567890.1.azuredatabricks.net",
warehouse_id="abcd1234efgh5678",
token="dapi...", # or token_provider=... -- see Auth below
)
cursor = conn.cursor()
await cursor.execute("SELECT * FROM my_catalog.my_schema.my_table LIMIT 100")
async for row in cursor:
print(row)
await cursor.execute("SELECT * FROM my_catalog.my_schema.my_table LIMIT 100")
table = await cursor.fetchall_arrow() # an Arrow table (arro3/pyarrow/DuckDB-compatible)
asyncio.run(main())
For streaming NDJSON (e.g. a FastAPI SSE endpoint, first row out as soon as its chunk arrives):
from arrowbricks import HEARTBEAT, DatabricksClient
client = DatabricksClient(host=..., warehouse_id=..., token=...)
async for item in client.stream_query_json("SELECT * FROM my_catalog.my_schema.big_table"):
if item is HEARTBEAT:
continue # forward as an SSE keep-alive comment, e.g.
print(item) # one ready-to-send JSON string per row
See examples/basic.py for a runnable version,
examples/cursor_paging.py for paging a large
result with fetchmany/fetchmany_arrow without buffering it all upfront, or
examples/azure_auth.py for a caching
token_provider built on Azure AD (DefaultAzureCredential).
FastAPI SSE example
stream_query_json is the full-speed way to serve a query over HTTP: the first row reaches the client after roughly one chunk's fetch/decode time, not the whole query's -- the Rust core is fetching, decoding, and reordering chunks concurrently the entire time, and the HEARTBEATs keep the connection alive through a slow cold warehouse start instead of the client just seeing dead air:
import os
from collections.abc import AsyncIterator
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from arrowbricks import HEARTBEAT, DatabricksClient
app = FastAPI()
client = DatabricksClient(
host=os.environ["DATABRICKS_HOST"],
warehouse_id=os.environ["DATABRICKS_WAREHOUSE_ID"],
token=os.environ["DATABRICKS_TOKEN"],
)
async def _sse(sql: str) -> AsyncIterator[str]:
async for item in client.stream_query_json(sql, total_timeout_s=300):
if item is HEARTBEAT:
yield ": keep-alive\n\n" # SSE comment line -- clients ignore it, it just keeps the connection open
else:
yield f"data: {item}\n\n"
@app.get("/query")
async def query(sql: str) -> StreamingResponse:
return StreamingResponse(_sse(sql), media_type="text/event-stream")
uvicorn app:app --reload
curl -N "http://localhost:8000/query?sql=SELECT+*+FROM+range(1000000)"
This example takes sql straight from the request for brevity -- arrowbricks does no SQL validation by design, so a real deployment must validate/allowlist it (or accept fixed query names + params) before exposing a route like this publicly. See examples/fastapi_sse.py for the runnable version, examples/fastapi_sse_pivot.py for the same over a buffered Cursor.fetchall_streamed result with one combined heartbeat/timeout budget across both the wait and the download, or examples/fastapi_sse_validated.py for one way to do that validation, using sqlglot to require a single read-only SELECT against an allowlist of fully-qualified tables.
Auth
connect/DatabricksClient take either:
token: str-- a static personal access token or pre-issued OAuth token, ortoken_provider-- a callable (sync or async) returning a token string, called on every request.
arrowbricks has no opinion on how you get a token and no cloud-SDK dependency of its own. If your provider is expensive to call, cache/refresh inside it -- arrowbricks does no caching on your behalf.
conn = connect(host=..., warehouse_id=..., token_provider=my_token_provider)
API
connect(host, warehouse_id, *, token=None, token_provider=None, ...) -> ConnectionConnection.cursor() -> CursorConnection.client -> DatabricksClient-- the same clientcursor()uses, for lower-level access (e.g.stream_query_json,upload_volume_file).Cursor.execute(sql, parameters=None, *, row_limit=None, offset=None, catalog=None, schema=None, total_timeout_s=None, prefer_inline=False) -> Cursor-- submits and waits for the statement, like a real DB-API cursor.parameters, if given, is Databricks' own named-parameter format --[{"name": ..., "value": ..., "type": ...}]bound against:namemarkers insql.prefer_inline=Truetries fetching a small result (well under Databricks' 25 MiB inline cap) in the same round trip as the submission itself, skipping the chunk-fetch entirely -- if the result turns out too big, or has a column type this can't convert (nested ARRAY/MAP/STRUCT, VARIANT), it transparently re-runs the query the normal way, so a caller who sets this without actually expecting a small result pays for the query twice. Leave it off unless you know the result is small.Cursor.execute_streamed(...)-- same args, but an async generator yieldingHEARTBEATwhile waiting on a slow cold start, then the readyCursor-- for bridging e.g. an SSE connection. Its timeout/heartbeats stop the moment the statement is ready, before any chunk has been downloaded -- seefetchall_streamedbelow for the download phase itself.Cursor.fetchone() -> tuple | None,Cursor.fetchmany(size) -> list[tuple],Cursor.fetchall() -> list[tuple], and iterating aCursordirectly -- row tuples; needs thearro3extra.Cursor.fetchmany_arrow(size) -> Table,Cursor.fetchall_arrow() -> Table-- an Arrow table (implements__arrow_c_stream__, so arro3/pyarrow/DuckDB can all consume it directly, zero-copy).Cursor.fetchall_streamed(*, total_timeout_s=None)/Cursor.fetchall_arrow_streamed(*, total_timeout_s=None)-- likefetchall()/fetchall_arrow(), but yieldHEARTBEATwhile pulling chunks instead of blocking silently, then the final rows/Table -- for a caller downloading a large result over SSE who needs heartbeats (and a timeout) through the download, not just the initial wait. Compose withexecute_streamedand a shared deadline if you want one combined budget across both phases (seeexamples/fastapi_sse_pivot.py).Cursor.description-- DB-API-style[(name, type_name, None, None, None, None, None), ...]afterexecute().client.stream_query_json(sql, **kwargs)(or the equivalent free functionstream_query_json(client, sql, **kwargs)) -- yieldsHEARTBEAT, then each row as a JSON string, as soon as its chunk arrives. Timestamps come out as full ISO-8601, every column key is always present ("col":nullfor a null value, never an omitted key). JSON has no literal for NaN/Infinity/-Infinity, so those come back as"col":nullby default -- passnon_finite_floats="string"to get"col":"NaN"/"col":"Infinity"/"col":"-Infinity"instead if you need to tell them apart from a real NULL.DatabricksClient(host, warehouse_id, *, token=None, token_provider=None, protocol="thrift", ...)-- the lower-level clientConnectionwraps.client.upload_volume_file(volume_path, data)/client.delete_volume_file(volume_path)for the Files API. Passprotocol="sea"to opt into the REST Statement Execution API backend instead of the default Thrift one (see above) --prefer_inline(SEA-only) has no effect underprotocol="thrift"(silent no-op, not an error), since Thrift's own inline-result mechanism already covers that case.write_ipc_stream(table, buf)-- writes any Arrow-C-Data-Interface-compatible object as an uncompressed Arrow-IPC stream (see below).ReplayableArrowChunk(data: bytes, chunk_index, declared_row_count=None)-- wraps raw Arrow-IPC stream bytes (e.g. previously downloaded and stored) so they can be read more than once via__arrow_c_stream__(a schema peek, then the actual scan -- DuckDB's registration path does this), and.to_table()for a one-shot parse. No extra dependency needed.
Cursor.execute/execute_streamed/stream_query_json all accept catalog, schema, row_limit, offset, and total_timeout_s.
Arrow vs. row-tuple fetches
Everything above works with zero dependencies installed except row-tuple fetches. fetchall_arrow/fetchmany_arrow return an Arrow table straight from the Rust core -- the faster path if your code can consume Arrow directly (DuckDB, pyarrow, polars, a Parquet writer, ...):
import duckdb
table = await cursor.fetchall_arrow()
duckdb.sql("SELECT count(*) FROM table").show() # DuckDB reads it zero-copy
fetchone/fetchmany/fetchall (and iterating a Cursor directly) materialize actual Python tuples instead -- ("id", "label")-style rows you can index into, print, or pass to code that doesn't know about Arrow at all. That conversion needs arro3-core (pip install arrowbricks[arro3]):
await cursor.execute("SELECT id, label FROM my_catalog.my_schema.my_table")
async for row in cursor: # or: rows = await cursor.fetchall()
print(row[0], row[1])
Calling a row-tuple method without arro3-core installed raises a ModuleNotFoundError naming the exact install command, rather than failing silently or with a confusing traceback.
Using with DuckDB
Anything arrowbricks hands back as Arrow (fetchall_arrow/fetchmany_arrow, ReplayableArrowChunk) implements __arrow_c_stream__, so DuckDB can register and query it directly -- zero-copy, no intermediate materialization, and no arro3-core/pyarrow install needed on top:
import duckdb
from arrowbricks import connect
conn = connect(host=..., warehouse_id=..., token=...)
cursor = conn.cursor()
await cursor.execute("SELECT * FROM my_catalog.my_schema.my_table LIMIT 100")
table = await cursor.fetchall_arrow()
con = duckdb.connect()
con.register("my_table", table)
con.sql("SELECT count(*) FROM my_table").show()
ReplayableArrowChunk works the same way for Arrow-IPC bytes you fetched and stored earlier (e.g. a raw chunk's bytes, cached in Redis/a file/wherever) -- DuckDB's registration path calls __arrow_c_stream__ twice (a schema peek, then the actual scan), which is exactly what ReplayableArrowChunk exists to support:
from arrowbricks import ReplayableArrowChunk
chunk = ReplayableArrowChunk(stored_bytes, chunk_index=0)
con.register("my_table", chunk)
con.sql("SELECT * FROM my_table WHERE id = 42").show()
Rust core
rust/arrowbricks_core is the crate implementing the hot path above, built into this same arrowbricks wheel as a compiled submodule -- not a separate PyPI package. See its own README for the crate-level design, plus standalone DuckDB and FastAPI SSE examples against the compiled extension directly.
Why not databricks-sql-connector?
The official driver 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.
A note on Arrow IPC compression
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.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 arrowbricks-3.0.1.tar.gz.
File metadata
- Download URL: arrowbricks-3.0.1.tar.gz
- Upload date:
- Size: 161.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5ccb215a4376d519d19545b68ece78e71795943948b8ee7c815eebdbad28f12
|
|
| MD5 |
c0af5eef81bd8f163beed2851bce617e
|
|
| BLAKE2b-256 |
c4b7e272c390c151e1fbc969f4c842174c2c9a0d1765496f413e71cc5e7a6278
|
Provenance
The following attestation bundles were made for arrowbricks-3.0.1.tar.gz:
Publisher:
release.yml on bmsuisse/arrowbricks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arrowbricks-3.0.1.tar.gz -
Subject digest:
e5ccb215a4376d519d19545b68ece78e71795943948b8ee7c815eebdbad28f12 - Sigstore transparency entry: 2371611225
- Sigstore integration time:
-
Permalink:
bmsuisse/arrowbricks@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Branch / Tag:
refs/tags/v3.0.1 - Owner: https://github.com/bmsuisse
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Trigger Event:
push
-
Statement type:
File details
Details for the file arrowbricks-3.0.1-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: arrowbricks-3.0.1-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 5.7 MB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0add7b5f8e80d97b3451e636e72ff6901585c6866bc4c788a27de1eb8e93ee5a
|
|
| MD5 |
bc4ab617dcaa56f15b39c2839b852a4b
|
|
| BLAKE2b-256 |
9778c9343923fb564578821fe49ae5de370fe7d6f56a72f6d2f513c1095fe9dd
|
Provenance
The following attestation bundles were made for arrowbricks-3.0.1-cp311-abi3-win_amd64.whl:
Publisher:
release.yml on bmsuisse/arrowbricks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arrowbricks-3.0.1-cp311-abi3-win_amd64.whl -
Subject digest:
0add7b5f8e80d97b3451e636e72ff6901585c6866bc4c788a27de1eb8e93ee5a - Sigstore transparency entry: 2371611327
- Sigstore integration time:
-
Permalink:
bmsuisse/arrowbricks@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Branch / Tag:
refs/tags/v3.0.1 - Owner: https://github.com/bmsuisse
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Trigger Event:
push
-
Statement type:
File details
Details for the file arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 5.7 MB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6994eb3e4cd7cb4dfa96ceb1835a7db75bebcae8fb2f61a0fd0cd38979418048
|
|
| MD5 |
0d56c1dc9b66a2881ce4318dbff1b8e5
|
|
| BLAKE2b-256 |
a838e95b95ec4312f3fa2f4ae92a539937c1d2b13862cf8a86810955c135241b
|
Provenance
The following attestation bundles were made for arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on bmsuisse/arrowbricks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
6994eb3e4cd7cb4dfa96ceb1835a7db75bebcae8fb2f61a0fd0cd38979418048 - Sigstore transparency entry: 2371611412
- Sigstore integration time:
-
Permalink:
bmsuisse/arrowbricks@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Branch / Tag:
refs/tags/v3.0.1 - Owner: https://github.com/bmsuisse
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Trigger Event:
push
-
Statement type:
File details
Details for the file arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 5.2 MB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9aeab1d3d0c91d9dd705d60e562177345db66bdfa425ad59e585db52aa6fad42
|
|
| MD5 |
a854a5c4d820efc539181d85f537026f
|
|
| BLAKE2b-256 |
f50b07708e9260d9a50c6175dd07ab383d3b6bdc11014faa194a715a2d02b5e2
|
Provenance
The following attestation bundles were made for arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on bmsuisse/arrowbricks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arrowbricks-3.0.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
9aeab1d3d0c91d9dd705d60e562177345db66bdfa425ad59e585db52aa6fad42 - Sigstore transparency entry: 2371611527
- Sigstore integration time:
-
Permalink:
bmsuisse/arrowbricks@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Branch / Tag:
refs/tags/v3.0.1 - Owner: https://github.com/bmsuisse
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Trigger Event:
push
-
Statement type:
File details
Details for the file arrowbricks-3.0.1-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: arrowbricks-3.0.1-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 5.1 MB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
283a1955eeb8558f877173c8563ce54b2678767be6feaaef02eb69fe741ddaf1
|
|
| MD5 |
65a3b1945ee5049781651c03387e0169
|
|
| BLAKE2b-256 |
0295b9bca1331e9063f165d35dcc6c0c02dc856e932fa299d12ce74c8f03a7e9
|
Provenance
The following attestation bundles were made for arrowbricks-3.0.1-cp311-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on bmsuisse/arrowbricks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arrowbricks-3.0.1-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
283a1955eeb8558f877173c8563ce54b2678767be6feaaef02eb69fe741ddaf1 - Sigstore transparency entry: 2371611582
- Sigstore integration time:
-
Permalink:
bmsuisse/arrowbricks@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Branch / Tag:
refs/tags/v3.0.1 - Owner: https://github.com/bmsuisse
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Trigger Event:
push
-
Statement type:
File details
Details for the file arrowbricks-3.0.1-cp311-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: arrowbricks-3.0.1-cp311-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.11+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c57c0b1122ec048f35019e5ff047790a1523222b88aaf31f267e2713fbc3e1be
|
|
| MD5 |
1bcd6f23cdc4ec98ed1647a66e9b49de
|
|
| BLAKE2b-256 |
51154edb0cc1d3c9987c590a6879f0a3a34629e05163319696db1ee1bda5e78b
|
Provenance
The following attestation bundles were made for arrowbricks-3.0.1-cp311-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on bmsuisse/arrowbricks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
arrowbricks-3.0.1-cp311-abi3-macosx_10_12_x86_64.whl -
Subject digest:
c57c0b1122ec048f35019e5ff047790a1523222b88aaf31f267e2713fbc3e1be - Sigstore transparency entry: 2371611677
- Sigstore integration time:
-
Permalink:
bmsuisse/arrowbricks@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Branch / Tag:
refs/tags/v3.0.1 - Owner: https://github.com/bmsuisse
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57fee17e0f3d05d5d5866171bf21bc20ef68102e -
Trigger Event:
push
-
Statement type: