Skip to main content

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-fork is a snapshot of upstream harfrust v0.13.3 (which tracks HarfBuzz v14.3.1), vendored as a workspace member. The only additions are an optional ShapeOptions::trace callback, a lookup_map_t.feature_tag field (which upstream HarfBuzz already has), and src/hb/trace.rs. With no callback the fork behaves exactly like upstream.
  • crates/hr-trace is 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/pyharfrust2 is the PyO3 Python binding exposing this as pyharfrust2.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

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl (512.1 kB view details)

Uploaded CPython 3.11+Windows x86-64

pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl (694.5 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.34+ x86-64

pyharfrust2-0.1.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (1.3 MB view details)

Uploaded CPython 3.11+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

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

Hashes for pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 76f298af62ec63bd2f0b458e0db90027858bd71a77c67eda258150882ff80d31
MD5 b1c7673f97009173506f3b8d3cbaa3da
BLAKE2b-256 9fe556801fe0d5b0fea441e6d178bcf11988488204378caea227b0c283c36529

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyharfrust2-0.1.0-cp311-abi3-win_amd64.whl:

Publisher: release.yml on Kushim-Jiang/pyharfrust2

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for pyharfrust2-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 937f8c7f97a156ab3715c58ecae07efb0daa890bb0346d68fd6e7ccabf3e8844
MD5 7dd80c072235e8528506d6c6aa989d30
BLAKE2b-256 676d61960c680f07681f3fc0b45bc069ae7c70d778df58873b4ce63b1044d787

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

File hashes

Hashes for pyharfrust2-0.1.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 2c033c46fafb41d2193e802f5cc8b14acd37d0d9aabbaf49443eb01eabed02b7
MD5 bdb9f0a9fef9959d96cdf5dd33e4de1e
BLAKE2b-256 049bdeb6173d52c468381bfe51a5d3a9cc7c0d91d15e3357d9be5353fa0f4d12

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

3 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page