quickhouse
Move tables from PostgreSQL, MySQL, BigQuery, or ClickHouse into ClickHouse or BigQuery — fast, in one function call.
quickhouse is a small, typed Python API on top of a native Rust engine. You hand it a source, a destination, and a table name; it figures out the schema, creates the destination table, streams the rows across in parallel, and keeps memory flat the whole way. The heavy lifting never touches Python objects — each database's native wire protocol flows straight into Apache Arrow and out the other side.
import quickhouse
src = quickhouse.Postgres("postgresql://user:pw@localhost:5432/shop")
dst = quickhouse.ClickHouse("http://localhost:8123", database="analytics")
result = quickhouse.sync(src, dst, dest_table="orders",
source_table="orders", mode="full", key=["id"])
print(result) # rows_read, rows_written, bytes_written, duration_secs, new_watermark
Status: pre-1.0. quickhouse is used against real production data and is covered by an integration test suite, but the Python API may still change between minor versions before 1.0. Pin a compatible range (e.g.
quickhouse~=0.7) and watch the CHANGELOG. A few knobs are marked experimental in the API docs — those may change without a major bump.
When to use quickhouse
Reach for it when you want to move whole tables — full refresh or incremental — from PostgreSQL/MySQL/BigQuery/ClickHouse into ClickHouse or BigQuery, fast, from your own Python jobs with almost no setup. It fits cron/Airflow/Dagster tasks and one-off backfills well.
Look elsewhere when you need in-warehouse SQL transformations (use dbt), change-data-capture or streaming (use Debezium/Kafka), a large catalog of SaaS connectors (use Airbyte / Fivetran / dlt), or arbitrary source↔destination pairs — quickhouse deliberately supports a focused, fast set:
Supported sources and destinations
| Source | → ClickHouse | → BigQuery |
|---|---|---|
| PostgreSQL | ✅ | ✅ |
| MySQL | ✅ | ✅ |
| BigQuery | ✅ | ✅ |
| ClickHouse | ✅ | ✅ |
| CleverTap (HTTP API) | ✅ | ✅ |
| AppsFlyer (HTTP API) | ✅ | ✅ |
| pandas / polars / pyarrow DataFrame | ✅ | ✅ |
BigQuery and ClickHouse are each both a source and a destination — so a
cross-cluster ClickHouse copy, or publishing a ClickHouse mart into BigQuery,
is an ordinary sync(). Some knobs are engine-specific: column_transforms /
read_max_rows_per_sec apply to the PostgreSQL, MySQL and ClickHouse sources;
merge_prune_partition_by /
delete_stale_in_window apply to BigQuery-destination incremental syncs.
Why quickhouse
-
It's fast. Rows are decoded straight off the wire into Arrow, in Rust — no per-row Python, no intermediate DataFrame. Tables are split into ranges and read in parallel, and decoding overlaps uploading. On a laptop-class box a 1M-row, 20-column full refresh runs at hundreds of thousands of rows per second, and memory is bounded by
max_memory_bytesrather than by table size. Reproduce it withpython benchmarks/bench_transfer.py. -
It's one function call.
sync()replaces the cursor loop, manual batching, retry logic, andCREATE TABLEyou'd otherwise write by hand. Defaults handle table creation, type mapping, parallelism, and batching, and a typed stub gives you autocomplete on every argument. -
It's safe with real, messy data. Full refreshes swap in atomically, so a crash never leaves a half-written table. Incremental syncs are idempotent — safe to re-run or retry. Transient network blips retry automatically. And legacy quirks like MySQL zero-dates or out-of-range timestamps are coerced to
NULLwith a warning instead of aborting the run. -
It's gentle on a small production database. Set
read_max_rows_per_secand quickhouse paces the read to that aggregate rate across all partitions; becauseCOPY/streaming results only produce as fast as the client consumes, the source scan itself backs off — you're throttling the database's work, not just your own. Combine it withparallelism=1(one connection), incremental mode (only new rows), and astatement_timeout_secs, point it at a read replica, and a bulk export stops competing with your app. The Postgres connection also shows up asapplication_name = 'quickhouse'inpg_stat_activity, so a DBA can see and kill it. -
There's nothing to stand up.
pip install quickhouseand you're done — no JVM, no Spark cluster, no separate service. It's an ordinary Python dependency that runs wherever your jobs already run: cron, Airflow, Dagster, a Lambda, or a plain script.
Install
pip install quickhouse
pip install "quickhouse[progress]" # adds a ready-made tqdm progress bar
Prebuilt wheels ship for Python 3.9+ on Linux (x86_64), macOS (Apple
Silicon), and Windows (x64) — no Rust toolchain needed. On other platforms
(Intel macOS, Linux aarch64) pip builds from the source distribution, which
needs a Rust toolchain (see CONTRIBUTING.md).
Using it
A fuller call, with the options you'll reach for most:
import quickhouse as qh
src = qh.Postgres("postgresql://user:pw@localhost:5432/shop")
dst = qh.ClickHouse("http://localhost:8123", database="analytics")
qh.sync(
src, dst,
dest_table="orders",
source_table="orders", # or source_query="SELECT ..."
mode="incremental", # or "full"
watermark="updated_at", # required for incremental
key=["id"], # dedup key / ORDER BY
parallelism=8,
exclude=["internal_notes"],
rename={"amount": "amt"},
on_progress=lambda p: print(f"{p.rows_written:,} rows @ {p.rows_per_sec:,.0f}/s"),
)
Sources and destinations
Pick a source and a destination by constructing the matching object —
everything else about sync() stays the same:
# sources
qh.Postgres("postgresql://user:pw@host:5432/db")
qh.MySQL("mysql://user:pw@host:3306/db", require_tls=True)
qh.BigQuery("my-gcp-project") # source_table="dataset.table"
qh.ClickHouse("http://ch-a:8123", database="raw") # ClickHouse reads too
# destinations
qh.ClickHouse("http://host:8123", database="analytics")
qh.BigQuery("my-gcp-project", dataset_id="analytics")
BigQuery authenticates with a service-account key (credentials_file=...) or
Application Default Credentials. As a destination it also takes
write_method: the default "storage_write" (the gRPC Storage Write API — free
up to 2 TiB/month and higher-throughput) or the legacy "insert_all"
(tabledata.insertAll, billed at roughly double and slower).
DataFrames — from_pandas
A frame you already hold in memory goes in through from_pandas rather than
sync (pip install 'quickhouse[pandas]'):
qh.from_pandas(df, dst, dest_table="orders", mode="full", key=["id"])
# Upsert on key — and unlike every other source, no watermark is needed.
# A database source needs one to know where to resume reading; you already
# hold every row, so the frame IS the delta.
qh.from_pandas(df, dst, dest_table="orders", mode="incremental", key=["id"])
The conversion is Arrow, so pandas is the headline rather than the requirement:
a pyarrow.Table, a polars.DataFrame, a DuckDB relation, or anything exposing
__arrow_c_stream__ all work. Every other sync() argument is forwarded
unchanged. Categoricals, nullable Int64, Decimal objects and tz-aware
timestamps are handled; nanosecond precision, nested columns and out-of-range
dates are refused by column name rather than silently coerced. See the
DataFrames guide.
HTTP API sources — CleverTap, AppsFlyer & generic HTTP
These pull directly from HTTP APIs into either destination (BigQuery or
ClickHouse): purpose-built CleverTap and AppsFlyer sources, plus a generic
HttpApi source for any other REST/JSON or CSV endpoint. API data has no
catalog, so you declare the schema: each column's name, its BigQuery-style
type, and — for nested JSON — a dotted path into the record. The declared type
drives the destination table; the watermark's from/to date window drives
incremental pulls.
# CleverTap Data Export API (events) -> BigQuery.
# region MUST match your CleverTap account's region (sg1 / us1 / eu1 / in1 / aps3 / mec1);
# it selects the API host, and the wrong region silently returns no data.
qh.sync(
qh.CleverTap(
account_id="...", passcode="...", # or load from a secret manager
event_name="App Launched", region="sg1",
columns=[
("identity", "STRING", "profile.identity"), # dotted path into the record
("email", "STRING", "profile.email"),
("ts", "TIMESTAMP"), # packed yyyyMMddHHmmSS int (parsed as UTC)
("app_ver", "STRING", "profile.app_version"),
],
from_date="2026-07-01", # window start (first-run floor for incremental)
),
qh.BigQuery("my-gcp-project", dataset_id="analytics"),
dest_table="clevertap_app_launched",
mode="incremental", watermark="ts", key=["identity"],
)
# AppsFlyer raw-data Pull API (CSV report) -> BigQuery. columns map to CSV headers.
qh.sync(
qh.AppsFlyer(
api_token="...", app_id="id123456789", report_type="installs_report",
columns={"install_time": "TIMESTAMP", "media_source": "STRING", "campaign": "STRING"},
from_date="2026-07-01",
),
qh.BigQuery("my-gcp-project", dataset_id="analytics"),
dest_table="af_installs", mode="full",
)
# Generic HTTP source — any REST/JSON or CSV endpoint. Auth goes in headers;
# records_path locates the JSON array; cursor pagination is optional.
qh.sync(
qh.HttpApi(
"https://api.example.com/v1/events?since={from}",
columns=[("id", "INTEGER"), ("ts", "TIMESTAMP"), ("name", "STRING", "attrs.name")],
headers={"Authorization": "Bearer ..."},
records_path="data.items", # JSON array location
next_cursor_path="paging.next", cursor_param="cursor", # follow the cursor
from_date="2026-07-01",
),
qh.ClickHouse("http://localhost:8123", database="analytics"), # or BigQuery
dest_table="events", mode="incremental", watermark="ts", key=["id"],
)
Notes: incremental re-pulls the boundary day each run, so key is required
(BigQuery MERGE dedups it). NUMERIC is delivered exactly (declare it only for
values sent as JSON strings/integers); BIGNUMERIC is lossy. CleverTap's
top-level ts is a packed yyyyMMddHHmmSS integer (not epoch seconds) — declare
it TIMESTAMP/DATETIME/DATE and it's parsed as UTC civil time. Nested
RECORD/STRUCT types can't be declared in bq_type; point a JSON (or
STRING) column at a nested object/array via its path and it lands as compact
JSON text. AppsFlyer's Pull API has hard daily-call/row caps — for high volume
use its Data Locker (files in a bucket) instead. A full-refresh (mode="full",
the default) REPLACES the destination; since these sources are day/event-scoped,
prefer mode="incremental" for an existing table (a shrinking full swap is
warned about but still executes).
Three knobs tune the incremental behavior for these sources:
lookback_days=N— on each resume, re-pull a rollingN-day window before the cursor so late-arriving/restated events past the boundary day aren't missed (both APIs restate history; AppsFlyer attribution updates for days). MERGE-on-key dedups the overlap in incremental mode.mode="append"— a bronze-landing write: insert each window's rows straight into the destination with no staging/merge/swap and no dedup, running your own consolidation MERGE downstream.watermarkdrives the resume window;keyisn't required. Avoids per-run table-metadata churn (BigQuery's ~5-ops/10s/table limit) since there's no staging create/swap. API sources only.delete_stale_in_window=True(BigQuery incremental) — alsoDELETEdestination rows inside the merged window that are absent from the source pull ("replace this window"; a NULL merge key nets to a replace instead of duplicating). Requiresmerge_prune_partition_by— the DELETE is scoped to that immutable column's staging range, so it never touches history outside the batch (a hard error otherwise).
Backup to cloud storage during the transfer
Either destination can also archive every synced batch to Google Cloud Storage or S3 as a data lake — a secondary, best-effort-free backup independent of the destination's own retention:
dst = qh.ClickHouse(
"http://host:8123", database="analytics",
archive=qh.backup(destination="gcs", format="parquet",
bucket="my-data-lake", prefix="quickhouse"),
)
qh.sync(src, dst, dest_table="orders", source_table="orders", mode="full", key=["id"])
backup() is a thin factory over the two descriptors, which you can also name
directly — qh.GcsArchive(bucket=...) and qh.S3Archive(bucket=...). Parquet
is the only supported format; any other value is rejected at the call.
This streams Parquet — one file per parallel partition (per chunk, with
chunk_rows), never fully buffered in memory — to gs:// or
s3://{bucket}/{prefix}/{dest_table}/dt=<date>/ run=<id>/part-<partition>.parquet, a Hive-style layout directly queryable by
BigQuery external tables, Athena, Spark, or DuckDB. It works for every
source and both destinations, so a CleverTap pull or a from_pandas()
frame is archived the same way a Postgres table is.
GCS credentials fall back to Application Default Credentials and the standard
SERVICE_ACCOUNT/GOOGLE_SERVICE_ACCOUNT environment, exactly like the
BigQuery descriptor; pass credentials_file= or credentials_json= to
override. S3 falls back to the standard AWS chain (env vars, IAM role); pass
endpoint= for an S3-compatible service like MinIO.
A persistent upload failure fails the whole sync() call, same as a
destination insert failure — the archive never silently falls behind. Set
archive= on the destination descriptor: one set on the source does
nothing, and says so with an ignored_source_archive warning. Storage and
request costs are billed by Google/AWS as usual (free on a self-hosted
MinIO).
The DDL knobs (engine, partition_by, order_by, primary_key, key) are
interpreted per destination — for ClickHouse they shape the MergeTree
DDL; for BigQuery they map to partitioning and clustering. quickhouse creates
the table for you (create_if_missing=True by default) with a sensible schema
derived from the source.
Full vs. incremental
Full reloads the whole table into a staging table, then swaps it into place
atomically — a crash mid-run never leaves the destination partial. For a
BigQuery destination that swap runs as a query (a billed scan of the staged
data), not a free copy job — BigQuery's copy jobs can silently skip rows still
sitting in a table's streaming buffer, so a real query is what keeps this
correct rather than just fast. One accepted tradeoff on the ClickHouse path:
an insert retried after a lost acknowledgment (not after a crash — the
transfer is still running) can duplicate one batch's rows in the staging
table, since mode="full" has no engine-level dedup like ReplacingMergeTree
— rare, and harmless for key-based incremental syncs, but worth knowing if
you see an unexpected small over-count on a full-refresh right after a
transient network blip.
Incremental tracks a high-water mark (the watermark column) in a small
state table in the destination and copies only newer rows. Updated rows are
deduplicated on key — via ClickHouse's ReplacingMergeTree, or a MERGE
upsert on BigQuery (where key is therefore required). Re-running with no new
data does nothing.
Both modes stage through a per-run-unique table ({dest}_quickhouse_tmp_<id>)
that's dropped when the run finishes, including on failure. The unique name is
what makes rapid re-runs and whole-call retries safe on BigQuery, whose
streaming ingestion rejects writes into a table recently recreated under the
same name.
For daily syncs that need to catch late-arriving or edited rows, set
lookback_seconds to re-scan a trailing window (e.g. 3 * 86400 for the last
three days) — the dedup above keeps that overlap from creating duplicates.
Cursor control. A few knobs make the incremental cursor robust in the real world:
state_keypins the cursor's identity. By default it's keyed by the source table (or query text) + destination — so editing asource_query'sWHEREwould silently start a fresh full pull, and two syncs into one destination tracking differentwatermarkcolumns would clobber each other's cursor. Setstate_key="orders:updated_at"to give each a stable, distinct identity.skip_to_max=True(orseed_watermark="<value>") seeds the cursor on the first run only, then self-retires. Use it when the destination already holds complete data from a previous pipeline and a full first pull would be a waste — it starts the cursor at the source's current max instead of scanning everything.advance_watermark=Falsereads and merges a window without moving the cursor — for loading a historical backfill without rewinding your regular schedule.
MERGE cost on large BigQuery tables. By default an incremental MERGE
scans the whole destination table (it joins on key only), so upserting a few
delta rows into a huge partitioned table bills the whole table each run. Set
merge_prune_partition_by="created_at" to bound the scan to the staging
batch's range and let BigQuery prune partitions. Only do this for an
immutable column — one whose value never changes for a given key, i.e. a
created_at/inserted-at column that is also the partition column. Do not
point it at a updated_at/updated-at column: an updated row's new value lands
in a different partition than the existing row, so pruning would miss it and
insert a duplicate key instead of updating. quickhouse can't detect mutability,
so this is a deliberate opt-in; the default full scan is always correct.
Watching progress and diagnosing failures
on_progress is a plain callback you can point at anything; qh.progress_bar()
wraps tqdm for a ready-made bar. Every sync()
also logs each step to stderr (RUST_LOG=quickhouse_core=debug for the actual
SQL).
When something goes wrong, sync() raises a RuntimeError written to be
actionable on its own: it names the table involved, and for a bad config or an
unmappable column it says exactly what's wrong and how to fix it (e.g.
exclude= the column or cast it in a source_query). Underlying database
errors are surfaced verbatim rather than wrapped in something generic.
Full parameter list
| Parameter | Meaning |
|---|---|
source_table / source_query |
Read a whole table, or a custom SELECT (one required) |
dest_table |
Destination table name |
mode |
"full", "incremental" or "append" (required since 0.15.0) |
watermark |
Monotonic column for incremental (e.g. updated_at); ignored in full mode |
lookback_seconds |
Re-scan a trailing window of the watermark to catch late/edited rows; 0 disables (default) |
state_key |
Pin the incremental cursor's identity (stable across source_query edits; distinct per watermark column). Default derives it from source+dest |
seed_watermark / skip_to_max |
Seed the cursor on the first run only (explicit floor, or the source's current max) — skips a doomed first full pull; mutually exclusive |
advance_watermark |
False reads+merges a window without advancing the cursor (backfill without rewinding the schedule); default True |
merge_prune_partition_by |
BigQuery incremental: prune the MERGE's destination scan to the staging range on this column. Only safe for an immutable partition column (e.g. created_at) — never a mutable updated_at (would insert dup keys) |
chunk_rows |
Read in keyset-ordered chunks of N rows, committing the cursor per chunk so a mid-read failure resumes. Incremental only; keyset column must be a unique NOT-NULL integer. On BigQuery, one MERGE per chunk (cluster the destination by key). With source_query, see keyset_not_null. None = one read (default) |
probe_max_cost |
Skip a setup-phase watermark probe when the planner estimates it above this cost. Without an index, MAX(watermark) and the nullable-watermark count(*) are full scans on every run (measured 57s each on a 14.9 GB table). Asked via EXPLAIN, never ANALYZE. 0 = always probe (default 50000) |
read_window_rows |
Sweep an unindexed read in bounded key ranges so each piece finishes inside a hot standby's conflict window, instead of being cancelled with 40001. Activates automatically; this only sizes it (default None) |
window_target_secs |
What one windowed read should take; the sweep re-sizes itself to converge on it (default 5.0) |
retry_max_attempts |
Re-run the whole transfer on a transient source error (PG recovery-conflict/cancel; MySQL gone-away/lock-wait/deadlock). 1 = no retry (default) |
column_transforms |
Per-column SQL value transforms over source_table= (e.g. {"ts":"ts AT TIME ZONE 'UTC'"}), preserving range partitioning. Postgres/MySQL/ClickHouse only |
evolve_schema |
Auto-ADD COLUMN (Nullable) when the source has a column the destination lacks, instead of erroring. ADD-only. Default False |
key |
Dedup key (required for BigQuery incremental) |
create_if_missing |
Auto-create the destination table (default True) |
engine, order_by, partition_by, primary_key |
DDL knobs, interpreted per destination |
parallelism |
Concurrent read streams |
batch_rows / batch_bytes |
Per-batch size knobs (rows, or estimated bytes) |
max_memory_bytes |
Hard ceiling on total in-flight memory; decoding blocks when hit (default 512 MiB, 0 = unbounded) |
read_max_rows_per_sec |
Cap the aggregate source read rate to be gentle on a small DB; None = unlimited (default). Postgres/MySQL/ClickHouse only |
type_overrides |
Force a destination column type, e.g. {"qty": "Decimal(18, 3)"} |
rename, include, exclude |
Column renames and allow/deny lists |
on_progress |
Progress callback |
How types are mapped
quickhouse maps each source type to a sensible destination type automatically: integers to integers, floats to floats, text/JSON/UUID to strings, dates and timestamps across as-is, and booleans preserved. A few deliberate choices worth knowing:
- Arbitrary-precision decimals (
numeric/DECIMAL/NUMERIC) default toFloat64, since precision can't be recovered from the type alone — pin an exact type withtype_overrides(e.g."Decimal(18, 2)",P <= 38) and the value is decoded exactly (noFloat64round-trip), not just declared with the right destination type. A value that doesn't fit the declared precision, or is NaN/Infinity (PostgreSQLnumericonly), coerces toNULLwith a warning, same as the out-of-range-date handling below.P > 38(Decimal256) isn't supported yet and is rejected as a config error up front, rather than silently falling back toFloat64. TIMEcolumns transfer as canonical text into aStringcolumn (ClickHouse has no time-of-day type).- MySQL
DATETIME/TIMESTAMPmap to a UTC-aware timestamp (BigQueryTIMESTAMP, ClickHouseDateTime64(6, 'UTC')) — the wall-clock value is read as UTC, matching how aTIMESTAMPcolumn expects it. To land a column as a naive BigQueryDATETIMEinstead, opt out per-column withtype_overrides={"col": "DATETIME"}— that flips the actual encoding, not just the declared type. (PostgreSQL keeps the distinction natively:timestamptz→ UTC-aware,timestamp→ naive.) - Out-of-range dates (and MySQL zero-dates like
0000-00-00) coerce toNULLwith a warning rather than failing the transfer. - Nullable source columns stay nullable in the destination.
Arrays and composite (RECORD/STRUCT) types aren't supported yet.
Limitations
- Auth: connect with a DSN string or discrete
host/port/user/password/databasefields; add a private CA viaca_cert_file=...(e.g. AWS RDS), or client-certificate mTLS viaclient_cert_file=...+client_key_file=...(Postgres and MySQL). BigQuery acceptscredentials_file, inlinecredentials_json, or ADC. - Array / composite types aren't mapped yet.
from_pandasis not bounded-memory — the frame is in RAM by definition. Expect a transient peak of roughly 3–4x its Arrow footprint while it is converted, serialized and decoded. Reading a table back into a DataFrame (to_pandas) is not implemented yet.- BigQuery as a source reads through a single connection —
parallelismbecomes a server-side hint rather than true client-side fan-out (a limitation of the underlying crate's read API). - CDC / streaming and arbitrary in-source transforms are out of scope.
- Single table per call —
sync()moves one table; loop over a list for many.
Command-line interface
For cron/CI jobs you can drive a transfer from a TOML file instead of writing Python:
pip install "quickhouse[cli]" # the extra is only needed on Python < 3.11
quickhouse run job.toml
quickhouse --version
The job file has three tables — [source], [target], [sync]. type picks
the engine; every other key maps to that descriptor's constructor / to sync()'s
arguments, and ${ENV_VAR} is expanded so credentials stay in the environment:
[source]
type = "postgres"
dsn = "${PG_DSN}"
[target]
type = "clickhouse"
url = "http://localhost:8123"
database = "analytics"
[sync]
dest_table = "orders"
source_table = "orders"
mode = "incremental"
watermark = "updated_at"
key = ["id"]
See examples/job.toml.
Stability and versioning
quickhouse follows Semantic Versioning. It is pre-1.0:
while on 0.x, minor versions (0.7 → 0.8) may contain breaking API changes,
and patch versions (0.7.0 → 0.7.1) are backwards-compatible fixes. Every change
is recorded in the CHANGELOG; pin a compatible range (e.g.
quickhouse~=0.7).
A few surfaces are experimental and may change even in a patch release —
they're flagged in the API docstrings: chunk_rows, merge_prune_partition_by,
delete_stale_in_window, BigQuery(write_method="storage_write"), and
column_transforms. The core sync() call and the connection descriptor classes
are considered stable within a minor version.
Contributing
Bug reports, new source/type mappings, and PRs are welcome — see CONTRIBUTING.md for build steps, tests, and layout.
License
MIT
Metadata
Release files for quickhouse 0.20.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| quickhouse-0.20.6.tar.gz | 481.0 kB | With provenance | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quickhouse-0.20.6-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details |
| quickhouse-0.20.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| quickhouse-0.20.6-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 27.9 MB
Release files / quickhouse-0.20.6.tar.gz
| Download URL | quickhouse-0.20.6.tar.gz |
|---|---|
| Size | 481.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8caac2ef9608fbd6e87868544f5e7188ad1929f39fe879993c2818122ef367a8
|
|
BLAKE2b-256 checksum How to use checksums |
1275773c10e33f1ee0372bd3e827a6cd731b4803232bd620d69ed8ed59198f63
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / quickhouse-0.20.6-cp39-abi3-win_amd64.whl
| Download URL | quickhouse-0.20.6-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 9.2 MB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
e358e12bf3f94f5b22285cbdd314ceed502845e6f16870caa432fe69eb013e7c
|
|
BLAKE2b-256 checksum How to use checksums |
f09049d7c51be5ed7d462b2ec463cccb519a0e02f392c2828d3ae6d24cd1687c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / quickhouse-0.20.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | quickhouse-0.20.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 9.6 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
769248aa45f0251fd71eb15fbd16614d5716a499fe5a7f1ecdcdd696e90c5110
|
|
BLAKE2b-256 checksum How to use checksums |
791a0dab90eadc3cdf1e22ad4695728d27aeaac16d235a1f9af56e2c6f4040a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / quickhouse-0.20.6-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | quickhouse-0.20.6-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 8.6 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1d6ee5bf88160059357db6cd6d0c8f53460a80fca93d2105da23687817315d0f
|
|
BLAKE2b-256 checksum How to use checksums |
667f140ef8cba36316b85bb14c5995aaa80516e1190faa883b2ecfc754d6ac17
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logSecurity for quickhouse 0.20.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 4 files in this release have been uploaded with provenance metadata.
Attestation for quickhouse-0.20.6.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.