This release is a pre-release and may not be stable for production use.
chtypes — Python SDK
2.0.0-dev: UNSTABLE, staging only, not for production. This is the ABI v2 development binding (public issue #511). It speaks ABI v2's unstable description, pins its dev fingerprint and refuses a library with any other ("update your dev SDK"). It fetches only from the staging dev channel (
https://registry-staging.wavehouse.dev/chtypes/v2-dev) and trusts only the staging key;CHTYPES_ARTIFACTS_URL,CHTYPES_TRUSTED_KEYSandCHTYPES_ALLOW_UNSIGNED, and thebases,trusted_keysandallow_unsignedfetch options, are ignored, each with one warning;--lock,--frozenand--update, and thefrozen,lock_path,lock_writeandupdateoptions, are refused, because a dev build is replaceable and a superseded one expires after 14 days. Its cache is${XDG_CACHE_HOME:-~/.cache}/chtypes/v2-dev, or<CHTYPES_CACHE>/v2-devunder an explicit cache, which no 1.x SDK reads. A dev SDK prefers the newest build of its own fingerprint: it resolves<tag>--fp-<its fingerprint>first and the tag only when no such build exists, and its cache lookups ignore another dev SDK's builds in a shared cache, so a newer dev fingerprint never strands it (§3 ofdocs/guides/fetch-v1.md). Every vocabulary keeps a value it does not list as itsunknown(n)member (Outcome("x"), whoseknownisFalse) instead of failing the document. The rules are r1 to r6 ofdocs/reference/abi-v2.md. For production, use the 1.x package:pip install "chtypes<2".An explicit cache directory gets the
v2-dev builds before the one that carries this contract (its release notice names it) can answer `ok` with `t` verdicts after a refused row. On those builds, when a body or block holds more than one row, treat every verdict as `d` if `errors` is non-empty.v2-devsubroot whether it comes fromCHTYPES_CACHEor fromFetchOptions(cache_dir=...): the layout is under<cache_dir>/v2-dev, never in the directory itself, so code that inspects or pre-populates a cache looks there;chtypes.cache_rootandchtypes.search_dirsreturn the resolved paths.CHTYPES_OFFLINE=1is the environment twin ofFetchOptions(offline=True)and--offline: the cache only, no request.
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>=2.0.0.dev0" # or: pip install "chtypes>=2.0.0.dev0"
uv add chtypes and pip install chtypes never select a pre-release on their own: the specifier names a dev version, which is what allows one.
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, chtypes where, chtypes resolve and chtypes prune complete the six 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 2.0.0.dev8
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-2.0.0.dev8.tar.gz | 261.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chtypes-2.0.0.dev8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 409.4 kB
Release files / chtypes-2.0.0.dev8.tar.gz
| Download URL | chtypes-2.0.0.dev8.tar.gz |
|---|---|
| Size | 261.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d46498532e4b975132a9e106611b00a764005689cfb83063001075948d297c6a
|
|
BLAKE2b-256 checksum How to use checksums |
d782b86169b58671fb1565209f3cbfc9cee53e54d0260daa7435e73842865b95
|
| 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 11, 2026.
Transparency logRelease files / chtypes-2.0.0.dev8-py3-none-any.whl
| Download URL | chtypes-2.0.0.dev8-py3-none-any.whl |
|---|---|
| Size | 148.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
52ac1899d0761b92d5a773ce5b30ea166113aa4f298d9976b239c95a604e65c7
|
|
BLAKE2b-256 checksum How to use checksums |
ef2be4c479e5b8876c1263041c7e4954c483a46f66b8208264f418d3fa6f47e7
|
| 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 11, 2026.
Transparency log