Pure Python wire protocol implementation for dqlite
Project description
dqlite-wire
Pure Python wire protocol implementation for dqlite, Canonical's distributed SQLite.
Installation
pip install dqlite-wire
Usage
from dqlitewire import encode_message, decode_message
from dqlitewire.messages import LeaderRequest
# Encode a message
data = encode_message(LeaderRequest())
# Decode a message
message = decode_message(data, is_request=True)
Thread-safety
ReadBuffer, WriteBuffer, MessageEncoder, and MessageDecoder
are not thread-safe. Each instance must be owned by a single
thread or a single asyncio coroutine at a time. This matches Go's
driver.Conn contract from go-dqlite.
Concurrent use of a single instance from multiple threads produces
silent data corruption — not exceptions. The is_poisoned
mechanism catches torn state from signal delivery during
single-owner execution, but it cannot detect lost-update races
between concurrent threads. Fuzz testing reliably reproduces both
duplicate message delivery and corrupt (garbage) message bytes with
no exception surfacing.
If you need concurrent access, wrap every call site in an
asyncio.Lock or threading.Lock at the layer that owns the
socket and decoder.
Protocol Reference
Based on the dqlite wire protocol specification.
Deliberate divergences from upstream
This library implements the dqlite wire protocol faithfully but adds a handful of defensive guards that the upstream C server and the canonical go-dqlite client do not. They protect a Python client running in potentially adversarial network contexts and are all opt-out-able.
Python-specific caps (not present in C or Go; None disables):
DEFAULT_MAX_TOTAL_ROWS(MessageDecoder(max_total_rows=...), default 10,000,000) — cap on rows accumulated across continuation frames for one query. Importable fromdqlitewire.DEFAULT_MAX_CONTINUATION_FRAMES(MessageDecoder(max_continuation_frames=...), default 100,000) — cap on continuation frames for one query. Importable fromdqlitewire.RowsResponse.DEFAULT_MAX_ROWS(MessageDecoder(max_rows=...), default 1,000,000) — per-frame row cap. Class-scoped, not exported at module level.ReadBuffer.DEFAULT_MAX_MESSAGE_SIZE(ReadBuffer(max_message_size=...), default 64 MiB) — envelope cap on a single frame. Class-scoped, not exported at module level._MAX_PARAM_COUNT(32,766 — matches SQLite'sSQLITE_MAX_VARIABLE_NUMBER),_MAX_COLUMN_COUNT(255 — matches the C server'sSTMT__MAX_COLUMNS),_MAX_FILE_COUNT(100),_MAX_NODE_COUNT(10,000) — internal sanity bounds on decoded tuple / response sizes.
Stricter-than-Go validations (match the C server's intent):
decode_row_headerrequires the full 8-byte marker (C definesDQLITE_RESPONSE_ROWS_DONE = 0xff..ff/_PART = 0xee..ee; go-dqlite checks only the first byte).encode_value(value, ValueType.BOOLEAN)rejects arbitrary ints (accepts onlyboolor exactly0/1).FilesResponse.encode_bodyrejects non-8-aligned file content (C'sdumpFileassertslen % 8 == 0).encode_params_tuplerejectsValueType.UNIXTIMEoutbound (C'stuple_decoder__nextcannot decode it on the server side).StmtResponserejects a 16-byte body whenschema=1(C's V1 response is 24 bytes).
Asymmetric encode/decode (decoded for proxy / recorded-traffic round-trip; encoder rejects):
ClusterRequestformat=0— V0 response shape (id + address only). Decoded byClusterRequest.decode_bodyfor proxy / replay use; encoder rejects withEncodeErrorbecause production senders always emit V1 (id + address + role).
Development
See DEVELOPMENT.md for setup and contribution guidelines.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 dqlite_wire-0.2.2.tar.gz.
File metadata
- Download URL: dqlite_wire-0.2.2.tar.gz
- Upload date:
- Size: 337.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eff65db37fdbd566d74fb4e6908fd0af8ecb596bb99d9f228af7653ed994e69a
|
|
| MD5 |
b958caeb1362240f7994fd48a5193106
|
|
| BLAKE2b-256 |
66e2205b4f9a955d9a5427a008004539e3e49555ffae5e7ccfcf5a57c31133e8
|
Provenance
The following attestation bundles were made for dqlite_wire-0.2.2.tar.gz:
Publisher:
publish-to-pypi.yml on letsdiscodev/python-dqlite-wire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dqlite_wire-0.2.2.tar.gz -
Subject digest:
eff65db37fdbd566d74fb4e6908fd0af8ecb596bb99d9f228af7653ed994e69a - Sigstore transparency entry: 1630365292
- Sigstore integration time:
-
Permalink:
letsdiscodev/python-dqlite-wire@8458bc4ffb344d32bb4d8af314fe7b3b02acc9fc -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/letsdiscodev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@8458bc4ffb344d32bb4d8af314fe7b3b02acc9fc -
Trigger Event:
push
-
Statement type:
File details
Details for the file dqlite_wire-0.2.2-py3-none-any.whl.
File metadata
- Download URL: dqlite_wire-0.2.2-py3-none-any.whl
- Upload date:
- Size: 115.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d60a17b8c6cd7bf21a95e982d9615b9f21aa7ae6aaee8700a08993c2bdbc414
|
|
| MD5 |
3f9e5f287d09641da995d8cbd149325d
|
|
| BLAKE2b-256 |
c5829415c0cfd2c795b1253272b4173525bf014a0754430c19734658a4478a3b
|
Provenance
The following attestation bundles were made for dqlite_wire-0.2.2-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on letsdiscodev/python-dqlite-wire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dqlite_wire-0.2.2-py3-none-any.whl -
Subject digest:
6d60a17b8c6cd7bf21a95e982d9615b9f21aa7ae6aaee8700a08993c2bdbc414 - Sigstore transparency entry: 1630365301
- Sigstore integration time:
-
Permalink:
letsdiscodev/python-dqlite-wire@8458bc4ffb344d32bb4d8af314fe7b3b02acc9fc -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/letsdiscodev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@8458bc4ffb344d32bb4d8af314fe7b3b02acc9fc -
Trigger Event:
push
-
Statement type: