Skip to main content

Type-safe LaTeX document generation with Python

Project description

PyTeX

Type-safe LaTeX document generation with Python. Build a document as a tree of typed TeX nodes and render it to a .tex file, or drop inline Python expressions into an existing .tex source and have them evaluated at render time. Requires Python 3.13+.

A TeX node is an immutable dataclass with a .rendered property. The public API mirrors LaTeX control sequences as PascalCase factories (Section, Bold, Frac, Title, ...), so a document reads like the LaTeX it produces while staying checkable by a type checker. Nodes track their package requirements, so the preamble is assembled automatically from what the body uses.

Install

To use the pytex command anywhere, install it as an isolated tool with pipx:

pipx install pytex-preprocessor

It is also available via plain pip install pytex-preprocessor.

For development, work in a virtualenv with an editable install instead:

python -m venv venv && . venv/bin/activate
pip install -e .            # add [dev] for pytest, ruff, basedpyright

External tools, each needed only for the matching feature:

  • tectonic — compile to PDF (--build). If not on PATH, the build downloads a self-contained binary into a temp folder and reuses it.
  • inkscapeSVG image conversion.
  • makeindex (from a TeX distribution, e.g. TeX Live) — resolve glossaries/acronyms.

Quick start

A .tex.py file is plain Python exposing a module-level __pytex__ that holds a TeX node:

from pytex.commands.builtin import Bold, Emph, Section, Title, MakeTitle
from pytex.model.concat import Concat
from pytex.model.document import Document
from pytex.model.math import DisplayMath, Frac

__pytex__ = Document(
    preamble=Title("PyTeX Example"),
    body=Concat(
        MakeTitle(),
        Section("Text"),
        "A paragraph with ", Bold("bold"), " and ", Emph("emphasised"), " words.",
        Section("Math"),
        DisplayMath(Concat("x = ", Frac("-b", "2a"))),
    ),
)
pytex example.tex.py          # render -> build/example.out.tex
pytex example.tex.py --build  # render + compile -> build/example.out.pdf

Bare strings are coerced to text nodes and LaTeX-escaped.

The pytex command

The input file is dispatched by extension:

Extension Handling
.py imported as a module; its __pytex__ node is rendered. Convention: name it <doc>.tex.py.
.tex wrapped in IncludeTeX; inline \iffalse{pytex(...)}\fi markers are evaluated, then rendered. Convention: <doc>.py.tex.
.md / .markdown converted to nodes via IncludeMarkdown. Frontmatter with gremium: or typ: protokoll routes to the protocol renderer instead.

Inline replacements in .tex

Any registered factory is in scope inside a marker. The \iffalse ... \fi pair is a LaTeX no-op, so the source still compiles as-is without PyTeX:

Today is \iffalse{pytex(Today())}\fi.
A fraction: $\iffalse{pytex(Frac("1", "2"))}\fi$.
Plain Python works too: $3^2 = \iffalse{pytex(3 ** 2)}\fi$.

Options

Flag Default Meaning
-o, --output <build-dir>/<input>.out.tex rendered LaTeX output path
-b, --build off compile the rendered .tex to PDF with tectonic
--build-dir DIR build directory for artifacts and tectonic output
--no-shell-escape shell-escape on disable shell-escape

Shell-escape is on by default because inline images decode their base64 payloads at compile time. The build runs tectonic, then makeindex (for glossaries/acronyms), then reruns tectonic when an index changed.

Output is minimal and color-tagged (==>, note:, warning:, error:), following tectonic's style; on failure it points at the likely cause and the log file. Set NO_COLOR to disable color.

Packages

pytex is the core; the rest are optional and build on it.

Package Provides
pytex core node model, Document, math, tables, graphics, and factories for the common LaTeX packages (biblatex, cleveref, glossaries, hyperref, listings, ...).
pytex_koma KOMA-Script classes and commands (Addchap, Minisec, KOMAoptions, ...).
pytex_tikz TikZ pictures and primitives (TikzPicture, Draw, Node, Circle, ...).
pytex_markdown Markdown -> native TeX conversion (see below).
pytex_hsrtreport HSRT report document class, colored callout boxes, title pages, glossary/citation helpers.
pytex_protocol STUPA/AStA meeting minutes from Markdown, built on pytex_hsrtreport.

Markdown

pytex_markdown converts Markdown to native TeX nodes (via marko):

from pytex_markdown import Markdown, IncludeMarkdown

body = Markdown("# Title\n\nText with **bold**, `code`, [a link](https://x).")
body = IncludeMarkdown("notes.md", base_level=-1)   # base_level=-1: # -> \chapter

Headings, emphasis, inline/fenced code, lists, links, images, block quotes and thematic breaks map to the standard pytex library; text is LaTeX-escaped. GitHub-style callouts become HSRT colored boxes (so the module depends on pytex_hsrtreport):

> [!NOTE]      -> InfoBox        > [!IMPORTANT] -> ImportantBox
> [!TIP]       -> SuccessBox     > [!WARNING]   -> WarningBox

Both factories are registered, so they work in \iffalse{pytex(...)}\fi replacements in .tex sources too.

Examples

See examples/ for one minimal input per kind (.tex.py, .py.tex, .md, mixed, and a full HSRT report). Run from the repository root so relative paths resolve:

pytex examples/document.tex.py --build
pytex examples/replacements.py.tex --build
pytex examples/notes.md --build

Project details


Download files

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

Source Distribution

pytex_preprocessor-0.2.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

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

pytex_preprocessor-0.2.0-py3-none-any.whl (1.1 MB view details)

Uploaded Python 3

File details

Details for the file pytex_preprocessor-0.2.0.tar.gz.

File metadata

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

File hashes

Hashes for pytex_preprocessor-0.2.0.tar.gz
Algorithm Hash digest
SHA256 0b01b4b812140cbc958a229277c99dee253873c733a3e8bb7fde57699704d98c
MD5 6a761d6529935174a12930b202cb27ca
BLAKE2b-256 d8f1f9e97b35487952d20cf45eb12c5752557f7c6ee3a9332bfdafbf76924bbb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytex_preprocessor-0.2.0.tar.gz:

Publisher: release.yml on frederikbeimgraben/PyTeX-Preprocessor

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

File details

Details for the file pytex_preprocessor-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytex_preprocessor-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d2f8e30f794e246441046a122fe7783f6a7380451f3742f552f469a9ff87998e
MD5 79836f14d9f728b8ffc1c5c2b43cbd00
BLAKE2b-256 444c8901fdb1def742c7b6f8dac7a4cb52bd778eaef8132796e776442e397192

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytex_preprocessor-0.2.0-py3-none-any.whl:

Publisher: release.yml on frederikbeimgraben/PyTeX-Preprocessor

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