A pure-Python package to convert between RDF Turtle (.ttl) and HDT (.hdt):
.ttl→.hdt.hdt→.ttl- combine two or more
.hdtfiles into one
No CLI — import pyhdtkit is the interface. No Rust, no native extension.
Install
pip install pyhdtkit
pip install "pyhdtkit[fast]" # optional CRC speedup, see Performance
Dev:
pip install -e ".[dev]"
Usage
from pyhdtkit import ttl2hdt, hdt2ttl, hdtcat
ttl2hdt("graph.ttl", "graph.hdt")
hdt2ttl("graph.hdt", "graph.ttl")
hdtcat(["a.hdt", "b.hdt"], "combined.hdt")
Errors
All three functions raise ValueError for anything that goes wrong — a
missing or unreadable input file, malformed Turtle, a truncated or corrupt
.hdt file, or an unwritable output path. hdtcat additionally requires
at least 2 input paths.
Status
All three functions are implemented: a real HDT binary reader and writer
(dictionary front-coding, BitmapTriples), built from scratch — no Rust, no
C extension, no wrapping an existing HDT library. rdflib handles Turtle
parsing/serialization; everything HDT-specific is pure Python.
The read path (hdt2ttl) is verified against a real .hdt file produced
by independent hdt-cpp tooling (tests/fixtures/snikmeta.hdt), not just
against our own writer.
Performance
HDT's compactness comes from succinct bit-level structures (rank/select
bitmaps, front-coded dictionaries) that are naturally suited to compiled
languages. This is pure Python — it will be slower and more memory-hungry
than the reference C++ (hdt-cpp) or a Rust implementation, especially at
large triple counts. That's an accepted, deliberate trade-off for this
package: correctness and hackability over raw speed.
Measured on this machine (benchmarks/bench.py, synthetic triples,
default front-coding block size):
| Triples | Write | Read | Write [fast] |
Read [fast] |
File size |
|---|---|---|---|---|---|
| 1,000 | 0.01s | 0.00s | 0.00s | 0.00s | 0.01 MB |
| 10,000 | 0.05s | 0.03s | 0.04s | 0.02s | 0.07 MB |
| 100,000 | 0.60s | 0.29s | 0.53s | 0.19s | 0.79 MB |
| 1,000,000 | 7.2s | 3.2s | 6.1s | 1.9s | 8.4 MB |
Roughly linear scaling.
Optional speedup
pip install "pyhdtkit[fast]"
This pulls in google-crc32c — the [fast] columns above. HDT checksums
every section it writes, and a pure-Python CRC loop is ~2600x slower than
a compiled one, which made it the single largest cost in the read path
once everything else was tuned.
Being precise about what this is: google-crc32c wraps
google/crc32c, a compiled C++
library. It ships as a prebuilt wheel for CPython 3.9–3.14 on Windows
x64, macOS (Intel/ARM), and glibc Linux (x86_64/i686/aarch64), so you
don't need a compiler — but there is compiled C++ running under the hood,
and there is no musl wheel, so on Alpine this extra would try to build
from source.
None of that touches the default install: pip install pyhdtkit pulls
only rdflib (itself pure Python) and contains zero compiled code. The
pure-Python CRC stays the fallback, and the test suite pins the two
implementations to identical output and runs green in both modes.
Only the checksum is ever delegated — all HDT encoding and decoding is our own Python code either way.
Notes on what makes it fast
- Bit-packing streams through a small bounded buffer rather than shifting
one whole-array Python integer, which would be O(n²) (
binio.py'spack_lsb_bitfields/unpack_lsb_bitfields). - Bitmaps (1 bit per entry, the largest arrays in a typical file) get a byte-at-a-time fast path instead of a per-bit loop.
- Dictionary front-coding finds shared prefixes via a single big-integer XOR instead of comparing bytes one at a time.
No numpy or other compiled-array dependency was needed; one may get added later if profiling on a real workload shows it's worth the weight.
Metadata
Release files for pyhdtkit 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyhdtkit-0.3.2.tar.gz | 45.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyhdtkit-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.1 kB
Release files / pyhdtkit-0.3.2.tar.gz
| Download URL | pyhdtkit-0.3.2.tar.gz |
|---|---|
| Size | 45.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ef74efb6f7ecab001da68823830d42b52159cede6d8e4179527d46e039f33f66
|
|
BLAKE2b-256 checksum How to use checksums |
bfb75605172975669b53b6c2d6c9cfaf92fed3815061c0553792547167f552c7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / pyhdtkit-0.3.2-py3-none-any.whl
| Download URL | pyhdtkit-0.3.2-py3-none-any.whl |
|---|---|
| Size | 25.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
96bf724ac021c84191eba8627053f8109e95c59ee422c92ebb4c9e3d21d5cb83
|
|
BLAKE2b-256 checksum How to use checksums |
1fd4cb54da4df97b8f8e9ba843e25d9923dc95f5b3488b591cbd090c2fc316c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|