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 onPATH, the build downloads a self-contained binary into a temp folder and reuses it.inkscape—SVGimage 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
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b01b4b812140cbc958a229277c99dee253873c733a3e8bb7fde57699704d98c
|
|
| MD5 |
6a761d6529935174a12930b202cb27ca
|
|
| BLAKE2b-256 |
d8f1f9e97b35487952d20cf45eb12c5752557f7c6ee3a9332bfdafbf76924bbb
|
Provenance
The following attestation bundles were made for pytex_preprocessor-0.2.0.tar.gz:
Publisher:
release.yml on frederikbeimgraben/PyTeX-Preprocessor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytex_preprocessor-0.2.0.tar.gz -
Subject digest:
0b01b4b812140cbc958a229277c99dee253873c733a3e8bb7fde57699704d98c - Sigstore transparency entry: 1702101278
- Sigstore integration time:
-
Permalink:
frederikbeimgraben/PyTeX-Preprocessor@1dd89befe8226960f065a9c4770b8cf0656cbfee -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/frederikbeimgraben
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1dd89befe8226960f065a9c4770b8cf0656cbfee -
Trigger Event:
push
-
Statement type:
File details
Details for the file pytex_preprocessor-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pytex_preprocessor-0.2.0-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2f8e30f794e246441046a122fe7783f6a7380451f3742f552f469a9ff87998e
|
|
| MD5 |
79836f14d9f728b8ffc1c5c2b43cbd00
|
|
| BLAKE2b-256 |
444c8901fdb1def742c7b6f8dac7a4cb52bd778eaef8132796e776442e397192
|
Provenance
The following attestation bundles were made for pytex_preprocessor-0.2.0-py3-none-any.whl:
Publisher:
release.yml on frederikbeimgraben/PyTeX-Preprocessor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytex_preprocessor-0.2.0-py3-none-any.whl -
Subject digest:
d2f8e30f794e246441046a122fe7783f6a7380451f3742f552f469a9ff87998e - Sigstore transparency entry: 1702101295
- Sigstore integration time:
-
Permalink:
frederikbeimgraben/PyTeX-Preprocessor@1dd89befe8226960f065a9c4770b8cf0656cbfee -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/frederikbeimgraben
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1dd89befe8226960f065a9c4770b8cf0656cbfee -
Trigger Event:
push
-
Statement type: