chtypes — Python SDK
If this row were inserted into this table on this ClickHouse version, what would happen? chtypes answers with ClickHouse's own code: the real C++ type machinery, vendored per release into a native library behind the frozen chs_* C ABI and reached here through stdlib ctypes. Nothing semantic is reimplemented, so "what does ClickHouse do with 256 into a UInt8?" is answered by ClickHouse rather than by a model of it. One peer binding among {go, python, ts, rust} — no language is privileged, and all four give one answer.
Pure ctypes: no compiler, no build step. The only dependency is a zstd decompressor for the artifact layer, which is the standard library's own from Python 3.14 and the backports.zstd package before that.
Install
Two things: this package, and at least one artifact — the per-version native library it dlopens at runtime. The registry fetches the artifact on first use when autofetch is on (Registry(autofetch=True) or CHTYPES_AUTOFETCH=1), after verifying its signature and every byte against the signed statement; with autofetch off it answers only from what is already installed.
uv add chtypes # or: pip install chtypes
Quickstart
import chtypes
from chtypes import Format, Registry
chtypes.setup(timezone="UTC") # once, before the first open (optional)
registry = Registry(autofetch=True)
library = registry.for_version("26.8") # a release line or an exact version
ddl = b"CREATE TABLE t (x UInt8, ts DateTime DEFAULT now()) ENGINE = Memory"
with library.compile_table(ddl) as schema:
batch = schema.rows(Format.JSON_EACH_ROW, b'{"x":256}\n')
row = batch.rows[0]
print(batch.outcome) # accepted
print(row.values[0].text) # b'0' what would actually be stored
print(row.transformed[0].reason) # overflow_wrap which is the product
The row is accepted and 256 is silently stored as 0. That report — transformed — is why chtypes exists. Names, SQL, messages and renderings come back as bytes, never decoded for you: a column name that is not valid UTF-8 round-trips exactly.
A column whose DEFAULT calls a random or UUID generator is drawn by the library (Source.DEFAULT_GENERATED). Ask rows for an export and insert its payload, never the original body, or the server draws a different value than the one previewed.
Errors
A bad row is a verdict, not an exception: outcome becomes Outcome.REJECTED with ClickHouse's own code. Exceptions are for the call and for the machinery. Every call error carries status, ch_code, ch_name, message (bytes) and column (bytes).
SchemaError— the server itself would refuse this, and.ch_codeis a real ClickHouse code.UnsupportedError— this build declines to answer, and a real server might well have accepted. Fall back to the server; never tell a user they are wrong on the strength of a decline.UsageError— a misuse: a closed object, a conflictingsetup, a zone given twice.InternalError— a library bug.UnsupportedErroris a peer ofSchemaError, not a subclass, soexcept SchemaErrornever catches a decline. CatchCallErrorfor all four, deliberately.ArtifactErrorand its subclasses cover fetching and loading:ArtifactCorruptError,ArtifactIncompatibleError,ArtifactMissingErrorand the rest, one class per code.
Documentation
| Quickstart | the same program in all four languages |
| Python API reference | every symbol, the C entry point under it, what it returns and what it raises |
| Artifacts | getting one, where it lands, verifying and pinning it |
| Batches | always rows, and the two bad-row policies |
| Transformations | the silent-change report, and the DEFAULTs you must echo back |
| Settings · Discovery | the four channels; asking a real server what profile to validate under |
| Filters · Multi-version | boolean expressions over rows; several ClickHouse versions in one process |
| Support matrix · Limitations | what works where; what chtypes declines to answer |
Fetching from the command line
chtypes fetch 26.8 (or python -m chtypes fetch 26.8) resolves, verifies and installs a build into the per-user cache; chtypes verify, chtypes list and chtypes where complete the four commands. --lock FILE records what was installed and --frozen fetches only what the lock pins. See the Python API reference.
Things specific to this binding
A settings value is a string, and only a string. settings={"flatten_nested": "0"}, never 0: a non-string value is a TypeError, and nothing rewrites one for you.
ctypes releases the GIL for the whole of a foreign call, so calls on compiled handles run in parallel across threads. The package takes no lock around a call; it keeps a close guard per handle and one setup guard.
The INSERT column list is a keyword-only columns on schema.row, schema.rows and schema.parse_block: schema.row(Format.JSON_EACH_ROW, body, columns=["id", "e"]). None or an empty sequence is the no-list shape; a list makes the data supply exactly those columns, with a listed EPHEMERAL value read and in scope for the DEFAULTs that reference it but never stored.
Known gaps in 1.0 are listed, with workarounds, in docs/limitations.md.
Tests
uv run pytest -q. Tests that need an artifact skip loudly by name without a registry on the search path, and a suite that ran nothing fails. The fetch conformance suite runs offline against the repository's tests/fixtures/fetch-v1/ cases, served by a loopback registry the suite starts itself, under the fixture test key (docs/guides/fetch-v1.md §10).
License
Apache 2.0. The artifacts this package loads are Elastic License 2.0 — a separate license, shipped inside each artifact release.
Metadata
Release files for chtypes 1.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| chtypes-1.0.4.tar.gz | 181.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chtypes-1.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 289.2 kB
Release files / chtypes-1.0.4.tar.gz
| Download URL | chtypes-1.0.4.tar.gz |
|---|---|
| Size | 181.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6c5b6f0958e681bcca63af1676e85c1caeb8117f1ca63d12171d2a0e49816698
|
|
BLAKE2b-256 checksum How to use checksums |
e2619b8342851ea3bea0056cbf5d42a5b4129bff3dfc36318a333a910a4fc141
|
| 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 / chtypes-1.0.4-py3-none-any.whl
| Download URL | chtypes-1.0.4-py3-none-any.whl |
|---|---|
| Size | 107.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c3aa7e34d82d70752afd76f41ac6bf340abe492eedbfd61a9b2fa2b3f2da26db
|
|
BLAKE2b-256 checksum How to use checksums |
0b3075b82c262a57e2679b954d1c3c14f473c2b41c64b4dc8d7c0c112ac9afcf
|
| 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 log