Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Merman For Python

PyPI Python License: MIT License: Apache-2.0

Parse, analyze, lay out, and render Mermaid diagrams from Python without a browser or JavaScript runtime. The package ships Merman's Rust engine and exposes it through UniFFI.

Alpha: Python and native APIs may break before the stable release. Version 0.8.0a7 targets direct UniFFI binding API 7, which is independent from the C ABI and text-measurement protocol. Install the Python wheel and native library as one artifact rather than mixing releases.

Install

Install the exact version documented here:

python -m pip install 'merman==0.8.0a7'

For source work, build the wheel and native library from the exact reviewed commit and keep those artifacts paired with the same binding contract.

Published wheels currently target CPython-compatible Python 3.9+ on macOS arm64, manylinux x86_64, and Windows x86_64. A platform without a listed wheel is not an officially packaged target; supporting another target requires a native-port contribution rather than only a local pip build.

Render A Diagram

import merman

client = merman.Merman()

source = "flowchart TD\nA[Hello] --> B[World]"
svg = client.render_svg(source, None)
print(svg[:4])  # <svg

The same one-shot facade exposes render_png, render_jpeg, render_pdf, render_ascii, parse_json, layout_json, analyze_json, validate, theme and lint metadata, ASCII support grades, and the complete diagram-family capability catalog. The default wheel supports SVG, ASCII, semantic/layout operations, analysis, validation, and document analysis. Math-bearing SVG and PNG, JPEG, or PDF methods remain available for custom current-contract libraries; the default wheel raises MermanError.Binding with MISSING_CAPABILITY and the exact capability ID. MermanOperationRequestV4 plus client.execute() is the generic, descriptor-owned form of those named methods and returns binary-safe data with media type and typed operation metadata. Generic options belong in MermanOperationRequestV4.options_json; execute() has no separate options argument. The alpha.7 binding API is 7; MermanOperationRequestV4 retains its record name and carries an optional MermanOperationControl for cooperative cancellation and relative deadlines. ASCII capability records expose layout/width/encoding/fallback admission arrays, and ASCII output plans use schema 3 with explicit encoding, requested/effective layouts, and Compact-attempt information.

Reuse An Engine

Construct MermanEngine directly when calls share baseline options:

engine = merman.MermanEngine(
    options_json='{"svg":{"pipeline":"readable"}}',
    services=None,
)
svg = engine.render_svg(source, '{"svg":{"diagram_id":"preview"}}')
facts = engine.analyze_document_facts_json(
    "```mermaid\n" + source + "\n```",
    "file:///workspace/README.md",
    None,
)
engine.close()

options_json is optional and follows the versioned binding options schema. Invalid options and engine failures raise typed MermanError variants. Reusable request options deeply merge over the construction baseline for one operation without mutating it. They cannot change the constructor-owned runtime_policy. MermanError.Binding.kind distinguishes UNKNOWN_OPERATION from MISSING_CAPABILITY; only the latter carries a non-null, descriptor-owned capability_id.

Release wheels use deterministic runtime state and do not bundle native clock, time-zone, or random adapters. A custom source build may enable the atomic native-runtime feature and then select {"runtime_policy":"native"}. The default wheel raises the generated unsupported-operation error when native policy is requested, and runtime discovery reports concrete adapter IDs only when they are present.

Choose a profile from the shared resource decision table, then use the generated builder:

from merman import ResourceOptionsBuilder, ResourceOverrideId, ResourceProfile

resource_options = (
    ResourceOptionsBuilder()
    .profile(ResourceProfile.CONSTRAINED)
    .limit(ResourceOverrideId.MAX_SOURCE_BYTES, 4 * 1024 * 1024)
    .build()
    .to_options_json()
)
svg = client.render_svg(source, resource_options)

Use CONSTRAINED for untrusted, public, or multi-tenant input; INTERACTIVE is for cooperative local editing. Leave the profile unset when a reusable request must inherit its constructor ceiling. The native CLI's default is intentionally separate (trusted-native).

Call client.runtime_catalog_json() to inspect the loaded runtime catalog and exact resource profile values instead of duplicating limits in application code. Decode client.presentation_catalog_json() for the open-ended theme preset, presentation profile, aspect, and capability-availability catalog. merman.get_runtime_catalog(client) strictly validates its flat schema 1 artifact facts, package identity, transport API, supported options/payload schema IDs, named metadata IDs, sorted stable IDs, and local output/operation relations as one atomic response. New stable IDs remain forward compatible. This direct binding API version is 7 and is independent from native C ABI and the text-measurement protocol version.

API 7 adds requested_layout_profile and compact_attempted to the schema-3 ASCII output plan. The effective layout_profile remains Canonical or Compact. Replace binding_api_version_v6() with binding_api_version_v7() and regenerate the package and native library together; published alpha.6 wheels retain API 6.

Diagnostics use schema 1 and parser facts use schema 2, independently of UniFFI binding API 7. Other facts versions are rejected at the boundary; consumers of the removed TextScan shape and Flowchart-only rich graph must migrate to generic parser-backed items and explicit unavailable bodies.

For generic operations, construct MermanOperationControl(timeout_ms=...), retain it in the host, and put it in MermanOperationRequestV4.control. Calling cancel() from another thread requests cooperative termination. MermanError.Binding.cancellation reports the reason and observed phase; resource failures continue to use the separate resource field. Opaque callbacks may complete before the next checkpoint, so hard preemption requires a worker or process boundary.

Text Measurement

Merman owns a deterministic, font-agnostic text measurer by default. Keep it for servers, CLIs, CI, and documentation builds.

GUI, browser automation, and WebView hosts can implement MermanTextMeasurer, start with MermanEngineServices(), call with_text_measurer(...), and pass the returned immutable bundle to MermanEngine(options_json, services). The original bundle remains unchanged, and the callback is immutable for that engine; construct a different engine to change or remove it. Text-measurement protocol 1 exposes 19 exact operations (0..18), and each handled MermanTextMeasureResult must use the MermanTextMeasurementResultKind required by request.operation. Return None for operations that cannot be measured synchronously and faithfully. Invalid results and Python exceptions delivered through UniFFI's generated callback trampoline fall back for that operation; Merman does not claim to catch arbitrary foreign unwinds outside that generated boundary.

Use a real font API from the surface that displays the SVG rather than estimating width from character counts. Keep callbacks fast and do not re-enter the same reusable engine while its callback is active. Callback-free engines allow concurrent operations; callback engines serialize admission and report typed BUSY to a competing caller, while same-engine callback reentry reports REENTRANT_CALL. The host measurement guide documents every operation and fallback; the repository's Python smoke example demonstrates one representative callback path while owner-local tests enforce the complete protocol.

The generated callback is measure(self, request), not measure_text. One-shot and reusable operations accept request-local options_json; reusable values deeply merge over the construction baseline for that call. The wheel builder executes the linked smoke example against the installed final wheel, so it is the authoritative copy-paste reference.

Output And Platform Limits

  • SVG may contain styles, markers, and foreignObject HTML labels; the final viewer must support the selected SVG pipeline.
  • All APIs are synchronous. Run expensive rendering outside a GUI event loop.
  • Wheels bundle a platform-specific native library and are not portable across operating systems or CPU families.
  • Merman targets structural and semantic Mermaid compatibility; browser font rendering and DOM measurements can still differ unless the host provides matching metrics.

Query diagram_family_capabilities() and ascii_capabilities() at runtime instead of assuming that every build profile or output format supports every family.

Custom artifacts with binary exports expose MermanOutputPlan as an open record. Switch on kind, inspect raster, pdf_filter_images, or ascii for known plans, and retain raw_json so a newer native library can report a future plan without forcing Python into a closed enum. The ASCII plan records the selected projection, encoding, emitted dimensions, and viewport fallback outcome.

Local Development

Build the descriptor-owned native library, regenerate bindings, assemble a wheel, install it into an isolated environment, and run the smoke test with:

python3 scripts/build-python-uniffi-wheel.py --run-smoke

The helper resolves the python-uniffi-native artifact recipe and chooses the platform library name (.dylib, .so, or .dll). The bundled release library excludes binding-generation; only source generation enables that feature. It also embeds the checked-in Rust dependency license report for the selected target rather than the union of every published wheel target. For manual binding generation, follow the UniFFI maintainer guide.

Documentation And Releases

PyPI is the supported registry channel for the Python package. Release wheels are also attached to the corresponding GitHub release; this README does not imply support for platforms without a listed wheel.

License And Notices

This package is available under MIT or Apache-2.0. The installed distribution carries the exact release license, notices, and upstream texts under its .dist-info/licenses/ directory. Online copies live in the repository's Python package directory.

Metadata

Release files for merman 0.8.0a7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for merman 0.8.0a7
File Interpreter ABI Platform
merman-0.8.0a7-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
merman-0.8.0a7-py3-none-manylinux_2_35_x86_64.whl Python 3 none Linux glibc 2.35+ x86-64 Details
merman-0.8.0a7-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 23.6 MB

Release files / merman-0.8.0a7-py3-none-win_amd64.whl

Download URL merman-0.8.0a7-py3-none-win_amd64.whl
Size 8.0 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
b63b5c3a408227e324acc247533625c5dcc770df3d6aa5a5ac63b7081c83d9bf
BLAKE2b-256 checksum
How to use checksums
79b4c7c420b0f62ce5965504d5ee7a9ae6886a91e153ea89167bf6083aa1715f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release files / merman-0.8.0a7-py3-none-manylinux_2_35_x86_64.whl

Download URL merman-0.8.0a7-py3-none-manylinux_2_35_x86_64.whl
Size 8.1 MB
Tags Linux glibc 2.35+ x86-64 Python 3
SHA-256 checksum
How to use checksums
86d8746c40ac653027e23eca55c9a4adea4c2484956c4022955ce81857670398
BLAKE2b-256 checksum
How to use checksums
f68f9174d8b46dcfa4e3577dec677547a95140d4e6bef37fa92e92f314763b94
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release files / merman-0.8.0a7-py3-none-macosx_11_0_arm64.whl

Download URL merman-0.8.0a7-py3-none-macosx_11_0_arm64.whl
Size 7.4 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
f95dac42a0cab7076234b541da41ace3753a90206ea53e6afb367501bf64f35a
BLAKE2b-256 checksum
How to use checksums
d8c263b771e72ac4e9e66d32174474b6bd80e3d4593a3149df336bea529b927f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log
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