Skip to main content

Python bindings for Quillmark - format-first Markdown rendering

Project description

Quillmark — Python bindings

Python bindings for Quillmark's format-first Markdown rendering engine.

Maintained by TTQ.

Installation

pip install quillmark

Quick Start

from quillmark import Quillmark, Quill, Document, OutputFormat

engine = Quillmark()                       # backend registry + render dispatcher
quill = Quill.from_path("path/to/quill")   # engine-free, validated config data

markdown = """~~~
$quill: my_quill
$kind: main
title: Hello World
~~~

# Hello
"""

parsed = Document.from_markdown(markdown)
result = engine.render(quill, parsed, OutputFormat.PDF)
result.artifacts[0].save("output.pdf")

API surface

The Python surface mirrors the @quillmark/wasm package. Names follow snake_case conventions; the underlying concepts (and shapes of return values) are the same.

Capability principle: a Quill is engine-free, validated config data — quill.metadata is a pure, infallible snapshot of the quill: section. Backend capability (supported_formats / supports_canvas) and rendering (render / open) are resolved by the engine, against a quill; they raise QuillmarkError (UnsupportedBackend) only if the declared backend isn't registered.

Quillmark

engine = Quillmark()
engine.registered_backends()              # ['typst']
engine.render(quill, parsed, OutputFormat.PDF)   # ppi=, pages=, producer= optional
engine.open(quill, parsed)                # RenderSession
engine.supported_formats(quill)           # [OutputFormat.PDF, ...] (raises if backend unregistered)
engine.supports_canvas(quill)             # True iff backend supports canvas preview (non-raising)

Quill

quill = Quill.from_path("path/to/quill")  # pure config load — no backend resolved here

quill.backend_id            # "typst" (declared backend)
quill.blueprint             # auto-generated annotated Markdown blueprint
quill.schema                # structured dict of the quill's document schema
quill.metadata              # pure config snapshot of the quill: section (never raises)
quill.quill_ref             # "name@version"

diags   = quill.validate(parsed)          # list of validation::* diagnostic dicts ([] = valid)
seed    = quill.seed_document()           # starter Document seeded from `example:` values
main    = quill.seed_main()               # just the $kind: main card (dict, like doc.main)
card    = quill.seed_card("note")         # one starter composable card (dict), None if kind undeclared

RenderSession

session = engine.open(quill, parsed)
session.page_count
session.backend_id
session.supports_canvas
session.warnings
session.render(OutputFormat.SVG, pages=[0])

RenderResult / Artifact

result.artifacts            # [Artifact, ...]
result.warnings             # [Diagnostic, ...]
result.format               # OutputFormat
result.render_time_ms       # float

artifact.format             # OutputFormat
artifact.bytes              # bytes
artifact.mime_type          # 'application/pdf', 'image/svg+xml', ...
artifact.save("out.pdf")

Document

doc = Document.from_markdown(markdown)
emitted = doc.to_markdown()

stored   = doc.to_json()
restored = Document.from_json(stored)
maybe    = Document.try_from_json(blob)          # None when not a DTO

Document.schema_version_of(blob)                 # raw tag (incl. unknown futures)
Document.current_schema_version()                # what this build writes

doc.clone()
doc.equals(other)
doc.card_count
doc.main; doc.cards; doc.body; doc.warnings

doc.set_field("title", "New")
doc.push_card(Document.make_card("note", {"x": 1}, "..."))  # or pass a Card from cards/remove_card/seed_card
# insert_card, remove_card, move_card, set_card_kind,
# update_card_field, remove_card_field, update_card_body, ...

Schema model

A field's cell is inferred from whether the schema declares a default::

  • Unendorsed (no default:) — the blueprint renders <must-fill>. An absent Unendorsed field is a non-fatal signal (validation::field_absent) — the render path zero-fills it silently. A surviving <must-fill> sentinel is fatal (validation::must_fill_sentinel). Partial documents are first-class; engine.render(quill, doc) only raises for malformed input.
  • Endorsed (with default:) — the blueprint renders the default value with a ; delete-ok annotation, and the default is used when the document omits the field.

There is no required: axis on FieldSchema.

Error contract

A single exception type — QuillmarkError — is raised for every failure mode. Every raised exception carries a non-empty .diagnostics list of Diagnostic objects. This matches the WASM binding's contract.

try:
    Document.from_markdown(bad_md)
except QuillmarkError as exc:
    for d in exc.diagnostics:
        print(d.severity, d.code, d.message, d.path)

EditError-shaped failures (invalid field names, kind names, out-of-range indices) prefix the message with [EditError::<Variant>] — the same format WASM uses — so callers can pattern-match on the message when they need to.

Changelog

See the changelog and the GitHub Releases page for release notes and version history.

Development

uv venv
uv pip install -e ".[dev]"
uv run pytest

License

Apache-2.0

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distribution

quillmark-0.91.0.tar.gz (2.5 MB view details)

Uploaded Source

Built Distributions

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

quillmark-0.91.0-cp310-abi3-win_amd64.whl (15.1 MB view details)

Uploaded CPython 3.10+Windows x86-64

quillmark-0.91.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.3 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

quillmark-0.91.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.7 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

quillmark-0.91.0-cp310-abi3-macosx_11_0_arm64.whl (14.3 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file quillmark-0.91.0.tar.gz.

File metadata

  • Download URL: quillmark-0.91.0.tar.gz
  • Upload date:
  • Size: 2.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for quillmark-0.91.0.tar.gz
Algorithm Hash digest
SHA256 f415d09deee4383b6e20accdebbfecaf47a3c92e0915d10b99c2bae400586838
MD5 0e01b2b8ec2e7e6f13e53f231bf3528e
BLAKE2b-256 935d751b7c512719738ceb70ea4bf6e3fb7c1c66b3342d5d5c2010a19cd07f35

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillmark-0.91.0.tar.gz:

Publisher: release.yml on quillmark-org/quillmark

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

File details

Details for the file quillmark-0.91.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: quillmark-0.91.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 15.1 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for quillmark-0.91.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 49243944e137bc6a591c20b0dbd86ac6b6522dc9d3d20c74767c8bf9c116cd2f
MD5 aa86cbbcc0fcb10dba8cfc9d648b99df
BLAKE2b-256 f4a8f492d34d17a5079749c88ec70d406a08a5b41601cd291027c342db9ebb2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillmark-0.91.0-cp310-abi3-win_amd64.whl:

Publisher: release.yml on quillmark-org/quillmark

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

File details

Details for the file quillmark-0.91.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for quillmark-0.91.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d70707d204a0d6d8cbb7b47ee8bf7e7ed16593423d70b4f93d24d82ad1c95b75
MD5 759f895d3f9bd7553c3569d41e6c65b5
BLAKE2b-256 7cc01be6b3b4eb887bc35fcd4b592ef58cefa5eedfe30687a448033868be53e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillmark-0.91.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on quillmark-org/quillmark

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

File details

Details for the file quillmark-0.91.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for quillmark-0.91.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 a930844e24694c80a0d007caf0410aed3699c9397daa007cb172c06159f27700
MD5 cc18691c5cf7ca40ffb517361678ea53
BLAKE2b-256 0d2e511784d907dcf0db7931272497316a19be47e95d103271a102252277a310

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillmark-0.91.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on quillmark-org/quillmark

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

File details

Details for the file quillmark-0.91.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for quillmark-0.91.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7009d214ef5d9bc94ce56cdf9af6dcd82a29b5e3f9d376269d0be4a903cceb7d
MD5 fd4fd57b0f4197568286e93acb209e7b
BLAKE2b-256 4e8f1172ef255a461a659f07dffc5b417437e0a8e6b7335cb15deb112aee0e8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillmark-0.91.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on quillmark-org/quillmark

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page