Skip to main content

pygraphite2

Cross-platform, fully typed Python binding for SIL Graphite2 text shaping.

pygraphite2 shapes complex scripts (Myanmar, Tai, many of the world's orthographies that need smart-font rules) using the Graphite rendering technology. It is a pure-Python package — it wraps SIL's official ctypes binding and loads the native libgraphite2 at runtime, so there is no C/C++ compilation and no build toolchain required to install it.

import pygraphite2

font = open("Padauk-Regular.ttf", "rb").read()
glyphs = pygraphite2.shape(font, "မြန်မာ")
for g in glyphs:
    print(f"gid={g.gid} cluster={g.cluster} advance={g.x_advance:.1f}")

Features

  • Fully typed — ships a py.typed marker and complete inline annotations (mypy --strict clean on the package).
  • Cross-platform — Windows / macOS / Linux. The native library is discovered in a documented order (env var → system library → wheel-bundled → vendored), with Windows DLL-directory handling for MSYS2 runtime dependencies.
  • No temp files — fonts are loaded fully in memory through a native table callback; nothing is ever written to disk.
  • Rich, ergonomic API — glyph runs with advances/clusters, RTL support, script & language selection, feature overrides, and font metadata (units-per-em, glyph count, languages, feature enumeration).
  • Graceful degradation — the pure-Python helpers (is_graphite_font, has_table, upem_from_ttf) work even without the native library; shaping calls raise a clear, actionable pygraphite2.LibraryNotFound.

Installation

pip install pygraphite2        # or: uv add pygraphite2

The wheel is a universal (py3-none-any) pure-Python wheel. It does not bundle the native library by default; you must make libgraphite2 available (see Native library). Platform-specific wheels that bundle the library are planned for a future release (the loader already supports them via pygraphite2/_lib/).

For development from source:

uv sync --extra dev          # or: pip install -e ".[dev]"
pytest
ruff check .
mypy src

Native library

pygraphite2 locates libgraphite2 at runtime in this order (first hit wins):

# Source How
1 pygraphite2.configure(path) explicit programmatic override
2 PYGRAPHITE2_LIBRARY_PATH env var path to a file or a directory
3 System library ctypes.util.find_library("graphite2")
4 Wheel-bundled pygraphite2/_lib/ future platform wheels
5 Vendored checkout vendor/graphite2/ developer convenience

Per-OS ways to obtain the library:

  • Debian/Ubuntu: sudo apt install libgraphite2-3
  • conda-forge: conda install graphite2
  • macOS: brew install graphite2 (if a formula is available) or conda-forge
  • Windows: MSYS2 package mingw-w64-x86_64-graphite2 (drop graphite2.dll plus its runtime DLLs into vendor/graphite2/), or conda-forge

Check what is loaded with pygraphite2.library_info():

>>> import pygraphite2
>>> pygraphite2.library_info()
'graphite2 v1.3.14 (D:\\...\\libgraphite2.dll)'

API

Shaping

  • pygraphite2.shape(font, text, *, direction="ltr", script=None, lang=None, features=None) -> list[Glyph] — one-shot shaping; returns the glyph run.
  • pygraphite2.shape_segment(...) -> ShapedText — same, but returns the full run (glyphs + advance_x/advance_y + metadata).
  • pygraphite2.GraphiteFont(font, *, options=0) / from_bytes / from_path — a reusable font object; the recommended API when shaping many runs with the same font. Usable as a context manager.

font may be raw bytes or a path to a font file.

Glyph & ShapedText

Glyph is a NamedTuple:

field meaning
gid glyph id in the font
cluster source character index this glyph is associated with
x_advance / y_advance advances in font units (from slot origins, matching gr2fonttest)
x_offset / y_offset offsets in font units
before / after source character range covered (inclusive/exclusive)
slot_index slot index within the segment

ShapedText adds advance_x, advance_y, text, direction, script.

Font inspection (pure Python — no native lib needed)

  • pygraphite2.is_graphite_font(font) -> bool — has a Silf table?
  • pygraphite2.has_table(font, tag) -> bool
  • pygraphite2.upem_from_ttf(font) -> int
  • pygraphite2.read_font_bytes(font) -> bytes

Font metadata (needs the native lib)

On a GraphiteFont instance: upem, num_glyphs, languages, feature_refs() (returns tuple[Feature, ...], each with tag and values).

Example with features and RTL

with pygraphite2.GraphiteFont.from_path("MyGraphite.ttf") as font:
    shaped = font.shape(
        "\u0645\u0627",
        direction="rtl",
        script="arab",
        lang="urd",
        features={"StylSet": 1},
    )
    print(shaped.advance_x)

Per-pass shaping trace (needs a tracing-enabled binary)

pygraphite2.shape_trace(font, text, ...) / GraphiteFont.shape_trace(...) return a step-by-step shaping trace — one TraceStage per Graphite pass, each a snapshot of the glyph run, bookended by "Start of shaping" (input glyphs) and "End of shaping" (final glyphs). This is directly renderable by Crowbar-style shaping debuggers (e.g. BabelMap's OpenType Test dialog):

import pygraphite2 as pg

trace = pg.shape_trace(open("Padauk-Regular.ttf", "rb").read(), "မြန်မာ", script="mymr")
for stage in trace.stages:
    print(stage.m, [g.gid for g in stage.glyphs])
# Start of shaping [305, 392, 290, 383, 305, 354]
# Pass 1 ...
# ... the pass where reordering happens ...
# End of shaping [392, 305, 290, 383, 305, 354]
  • TraceStage.to_dict() / ShapedTrace.stages_to_dicts() serialize to the {m, glyphs, depth, effective} / {g, cl, dx, dy, ax, ay, flags} schema used by shaping-debug UIs.
  • Requires a graphite2 binary built with tracing support (GRAPHITE2_NTRACING off). GraphiteFont.tracing_supported() reports whether the loaded binary can trace; otherwise shape_trace raises TracingUnavailable. vendor/graphite2/ ships tracing-enabled binaries for Windows and Linux, and .github/workflows/build-native.yml builds + verifies tracing on macOS too — see vendor/graphite2/README.md.
  • Lower-level control: GraphiteFont.start_logging(path) / stop_logging() wrap graphite2's Segment-JSON logging directly.

Error handling

All exceptions derive from pygraphite2.GraphiteError:

  • LibraryNotFound — no native library could be located/loaded.
  • GraphiteFontError — invalid font data, missing Silf table, unknown feature.
  • ShapingError — the native shaper failed.
  • TracingUnavailable — a trace was requested but the binary has no tracing support.

Development

  • Tests: pytest — native tests auto-skip when the library is missing; golden tests auto-skip when the Padauk test font is missing (place Padauk-Regular.ttf in vendor/fonts/).
  • Lint: ruff check .   Format: ruff format .
  • Types: mypy src (strict)
  • CI: .github/workflows/ci.yml runs the test matrix on Ubuntu/macOS/Windows and multiple Python versions; .github/workflows/build-native.yml builds a tracing-enabled graphite2 from the pinned upstream source and verifies shape_trace on all three OSes; .github/workflows/publish.yml publishes to PyPI via trusted publishing on version tags.

Licensing & attribution

  • pygraphite2's own code is MIT-licensed.
  • The vendored ctypes binding (src/pygraphite2/_binding.py) is © 2013 SIL International and is distributed under its original multi-license (MIT OR MPL-2.0 OR GPL-2.0-or-later). See NOTICE.md.

The project's SPDX license expression is therefore MIT OR MPL-2.0 OR GPL-2.0-or-later.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygraphite2-0.3.0.tar.gz (461.8 kB view details)

Uploaded Source

Built Distribution

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

pygraphite2-0.3.0-py3-none-any.whl (29.8 kB view details)

Uploaded Python 3

File details

Details for the file pygraphite2-0.3.0.tar.gz.

File metadata

  • Download URL: pygraphite2-0.3.0.tar.gz
  • Upload date:
  • Size: 461.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pygraphite2-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2feacac8b14e0a4a5631761a4dda16a77c8ab9938eae4901661e5d9e2594a91a
MD5 cc267b0679bccae7eababcacb098b622
BLAKE2b-256 eb5d40d5b253e0c627847c9f504269e0d087667783feb95f22bf9f3c8dc83695

See more details on using hashes here.

Provenance

The following attestation bundles were made for pygraphite2-0.3.0.tar.gz:

Publisher: publish.yml on Kushim-Jiang/pygraphite2

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

File details

Details for the file pygraphite2-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pygraphite2-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 29.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pygraphite2-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c2a66d6eced80dd89542596200b01e4c4687bba6c923b01ba52c4ddb44093f9e
MD5 d963c01b5039a126dd7305bccf52f2e3
BLAKE2b-256 e0c075f8003ebb7103b0476c4276936cd64d7b6df43018e407708025ed4349bc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pygraphite2-0.3.0-py3-none-any.whl:

Publisher: publish.yml on Kushim-Jiang/pygraphite2

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

Release history Release notifications | RSS feed

0.4.0

2 files

This release

0.3.0 This release

2 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