pyharfrust2 — HarfRust Trace Binding
Step-by-step (per-lookup / per-stage) shaping trace for HarfRust — the HarfBuzz Rust port — exposed through a Python (PyO3) binding.
The trace output is aligned with HarfBuzz's buffer message output (as produced by uharfbuzz), so consumers that already render HarfBuzz traces (e.g. BabelMap's OpenType Test timeline) can render it without changes.
Relationship to HarfRust
This repository is built on top of harfrust — HarfBuzz's official pure-Rust port — and does not reimplement any shaping. All glyph substitution and positioning comes straight from HarfRust:
crates/harfrust-forkis a snapshot of upstream harfrust v0.13.3 (which tracks HarfBuzz v14.3.1), vendored as a workspace member. The only additions are an optionalShapeOptions::tracecallback, alookup_map_t.feature_tagfield (which upstream HarfBuzz already has), andsrc/hb/trace.rs. With no callback the fork behaves exactly like upstream.crates/hr-traceis our thin layer: it runs HarfRust shaping with the trace callback installed and collects the per-step event sequence (TraceStep { event, glyphs }).crates/pyharfrust2+python/pyharfrust2is the PyO3 Python binding exposing this aspyharfrust2.shape_trace.
Keeping the fork small and isolated means it can be refreshed from upstream and
the trace patch re-applied, or dropped entirely once upstream gains its own
trace support — hr-trace/pyharfrust2 would then simply point at the
harfrust crate instead.
Layout
Cargo.toml # workspace
crates/
harfrust-fork/ # upstream harfrust v0.13.3 + minimal trace hooks
hr-trace/ # thin wrapper: shape_trace() -> event sequence
pyharfrust2/ # PyO3 cdylib: Python binding
python/pyharfrust2/ # Python package (maturin layout)
tests/ # Python tests + test font generator
pyproject.toml # maturin backend
The fork adds an optional trace callback to three shaping sites
(ot_shape.rs, ot_layout.rs, ot_shape_normalize.rs) plus a
lookup_map_t.feature_tag field (matching upstream HarfBuzz) and a
ShapeOptions::trace option. With no callback the behaviour is identical to
upstream and there is no overhead.
Python API
import pyharfrust2
stages = pyharfrust2.shape_trace(
font_bytes, # bytes of a TTF/OTF font
"ffi", # text to shape
direction="auto", # auto | ltr | rtl | ttb | btt
script="", # ISO 15924, e.g. "Arab"
language="",
features=None, # "+kern,-liga" (hb-shape syntax)
variations=None, # "wght=400" (comma separated)
face_index=0,
)
for stage in stages:
print(stage["m"], stage["glyphs"])
Each stage:
{
"m": "start lookup 5 feature 'liga'",
"glyphs": [
{"g": gid, "cl": cluster, "dx": dx, "dy": dy, "ax": ax, "ay": ay, "flags": flags},
...,
],
"depth": 0,
"effective": True,
}
Build & test
uv venv .venv --python 3.13
uv pip install --python .venv maturin uharfbuzz pytest
.venv/Scripts/maturin build --release # produces a wheel
uv pip install --python .venv <wheel path>
.venv/Scripts/python -m pytest tests/
Rust side:
cargo test -p harfrust-fork --lib # upstream tests still pass (no-trace unchanged)
cargo test -p hr-trace # trace event model tests
cargo run -p hr-trace --example dump_trace -- ffi
Platforms
Pure Rust with no system libraries. The Python wheel is built with
abi3-py311 (cp311-abi3), so a single wheel per OS covers Python 3.11+.
CI builds and tests on Windows, Linux and macOS, and publishes a macOS
universal2 (x86_64 + arm64) wheel. The harfrust-fork crate also compiles
without std:
cargo check -p harfrust-fork --no-default-features --features libm
Quality gates
The same checks run in CI (.github/workflows/build.yml, lint job):
.venv/Scripts/ruff check . && .venv/Scripts/ruff format --check . # Python lint/format
npx pyright@latest # Pylance type check
cargo fmt --check # Rust format
cargo clippy --workspace --all-targets -- -D warnings # Rust lint
cargo test --workspace # Rust tests
.venv/Scripts/python -m pytest tests/ # Python tests
Generate the test font
python tests/generate_test_font.py # -> tests/data/test_liga.ttf
License
MIT. The harfrust-fork crate is upstream harfrust (MIT) with a small,
upstreamable trace patch.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
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 pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 512.1 kB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76f298af62ec63bd2f0b458e0db90027858bd71a77c67eda258150882ff80d31
|
|
| MD5 |
b1c7673f97009173506f3b8d3cbaa3da
|
|
| BLAKE2b-256 |
9fe556801fe0d5b0fea441e6d178bcf11988488204378caea227b0c283c36529
|
Provenance
The following attestation bundles were made for pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl:
Publisher:
release.yml on Kushim-Jiang/pyharfrust2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl -
Subject digest:
76f298af62ec63bd2f0b458e0db90027858bd71a77c67eda258150882ff80d31 - Sigstore transparency entry: 2671397892
- Sigstore integration time:
-
Permalink:
Kushim-Jiang/pyharfrust2@87dc36ba23cebfd30ee63cce839f6264cf63e432 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Kushim-Jiang
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87dc36ba23cebfd30ee63cce839f6264cf63e432 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 694.5 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
937f8c7f97a156ab3715c58ecae07efb0daa890bb0346d68fd6e7ccabf3e8844
|
|
| MD5 |
7dd80c072235e8528506d6c6aa989d30
|
|
| BLAKE2b-256 |
676d61960c680f07681f3fc0b45bc069ae7c70d778df58873b4ce63b1044d787
|
Provenance
The following attestation bundles were made for pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl:
Publisher:
release.yml on Kushim-Jiang/pyharfrust2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl -
Subject digest:
937f8c7f97a156ab3715c58ecae07efb0daa890bb0346d68fd6e7ccabf3e8844 - Sigstore transparency entry: 2671397917
- Sigstore integration time:
-
Permalink:
Kushim-Jiang/pyharfrust2@87dc36ba23cebfd30ee63cce839f6264cf63e432 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Kushim-Jiang
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87dc36ba23cebfd30ee63cce839f6264cf63e432 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyharfrust2-0.1.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.
File metadata
- Download URL: pyharfrust2-0.1.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.11+, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c033c46fafb41d2193e802f5cc8b14acd37d0d9aabbaf49443eb01eabed02b7
|
|
| MD5 |
bdb9f0a9fef9959d96cdf5dd33e4de1e
|
|
| BLAKE2b-256 |
049bdeb6173d52c468381bfe51a5d3a9cc7c0d91d15e3357d9be5353fa0f4d12
|
Provenance
The following attestation bundles were made for pyharfrust2-0.1.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:
Publisher:
release.yml on Kushim-Jiang/pyharfrust2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyharfrust2-0.1.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl -
Subject digest:
2c033c46fafb41d2193e802f5cc8b14acd37d0d9aabbaf49443eb01eabed02b7 - Sigstore transparency entry: 2671397935
- Sigstore integration time:
-
Permalink:
Kushim-Jiang/pyharfrust2@87dc36ba23cebfd30ee63cce839f6264cf63e432 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Kushim-Jiang
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87dc36ba23cebfd30ee63cce839f6264cf63e432 -
Trigger Event:
push
-
Statement type: