In jeder Arbeit steht eine Zahl, die anderswo berechnet wurde – in einem Skript, einem Notebook, einer Tabellenkalkulation – und danach von Hand in den Text getippt wurde. Wird das Skript geändert, wird die Zahl im Text stillschweigend zur Unwahrheit. PythonTeX schließt diese Lücke: Das Paket führt den Python-Code, der in der LaTeX-Quelle steht, während des Satzes aus und setzt, was zurückkommt. Geschrieben hat es Geoffrey M. Poore; entgegen dem Namen steuert es außerdem Ruby, Julia, R, Octave, Bash, Rust, Perl und JavaScript an. Diese Seite führt von \usepackage{pythontex} über die \py-Befehlsfamilie und den dreistufigen Build, an dem sich alle einmal stoßen, bis zu dem einen Fall, in dem etwas anderes die bessere Wahl ist.
Code setzen oder Code ausführen: PythonTeX gegenüber listings und minted
listings und minted setzen Code genau so, wie er aussieht, und führen keine einzige Zeile aus. PythonTeX unterscheidet sich darin, dass es den Code ausführt und die zurückgelieferte Zeichenkette setzt. Steht \py{2**10} im Text, erscheint dort nicht die Zeichenfolge 2**10, sondern das Ergebnis 1024. Geladen wird das Paket mit einer Zeile, \usepackage{pythontex}; für den Betrieb müssen neben der TeX-Distribution Python selbst und für die Syntaxhervorhebung Pygments installiert sein.
\documentclass{article}
\usepackage{pythontex}
\begin{document}
% executed, but nothing is typeset from this block itself
\begin{pycode}
from math import sqrt
radius = 2.5
area = 3.14159 * radius**2
\end{pycode}
A circle of radius \py{radius} has area \py{round(area, 2)}.
\[ 2^{10} = \py{2**10}, \qquad \sqrt{3^2+4^2} = \py{sqrt(3**2 + 4**2)} \]
\end{document}Dieses Dokument setzt „A circle of radius 2.5 has area 19.63.“, gefolgt von 2¹⁰ = 1024 und √(3²+4²) = 5.0. Entscheidend ist: Die Zahl 19.63 steht nirgends in der Quelle. Wird radius auf 3.0 geändert und neu gebaut, ziehen Radius und Fläche im Fließtext von selbst nach. Bei handgetippten Zahlen bleibt immer eine übrig, die vergessen wird; hier gibt es nichts zu vergessen. Nur wenige Techniken sichern derart billig zu, dass die Zahlen einer Arbeit dem Code, der sie erzeugt hat, nicht widersprechen können.
Die Idee selbst ist nicht neu. WEB, das Werkzeug, das Donald Knuth 1984 für das von ihm so genannte literate programming schuf, erlaubte es, Prosa in ein Pascal-Programm zu schreiben: tangle zog das Pascal heraus, weave das TeX. PythonTeX kehrt das um. Das führende Dokument bleibt LaTeX, und das Programm zieht bei ihm ein. In beiden Richtungen ist der Beweggrund derselbe – liegen Erklärung und Implementierung in getrennten Dateien, driften sie früher oder später auseinander.
\py, \pyc, pycode, pyblock: die Wahl über das Suffix
Diese Namen muss man nicht auswendig lernen; zwei Fragen legen sie fest. Wird der Code ausgeführt? Wird er auf der Seite gezeigt? Die Kombination beider Antworten ist das Suffix. Beim Basisnamen py gilt: ohne Zusatz wird der Wert eines Ausdrucks gesetzt, c (code) führt nur aus, v (verb) setzt nur, b (block) tut beides. Im Fließtext dient die Befehlsform (\pyc{…}), für mehrere Zeilen die gleichnamige Umgebung (pycode).
| Befehl | Zugehörige Umgebung | Ausführen / Setzen |
|---|---|---|
\py | — | führt einen Ausdruck aus und setzt nur dessen Stringform |
\pyc | pycode | führt aus, setzt nichts; print-Ausgabe wird automatisch übernommen |
\pyv | pyverbatim | führt nicht aus; setzt den Code unverändert |
\pyb | pyblock | führt aus und setzt; print-Ausgabe wird nicht automatisch übernommen |
\pys | pysub | ersetzt jedes !{expr} durch seinen Wert und liest das Ergebnis als LaTeX |
\pycon | pyconsole | bildet die interaktive Konsole nach und setzt >>> samt Ein- und Ausgabe |
Das Argument eines Inline-Befehls verhält sich wie bei \verb: Es müssen keine geschweiften Klammern sein. Jedes Paar identischer Zeichen genügt, also bedeuten \py{2**10}, \py#2**10# und \py@2**10@ dasselbe – ein nützlicher Ausweg, wenn der Code selbst Klammern enthält. Genau eine Einschränkung ist zu beachten: \py fügt einen Wert ein und verträgt daher keine Zuweisung. Das Handbuch erklärt \py{a=1} ausdrücklich für ungültig, weil eine Zuweisung keine Stringdarstellung besitzt. Variablen anzulegen ist Aufgabe von pycode; \py{a} holt sie nur wieder hervor.
Die Behandlung von print kehrt sich um, je nachdem ob der Code gezeigt wird, wie die Tabelle andeutet. Bleibt der Code verborgen – pycode, \pyc –, sorgt die Paketoption autoprint (standardmäßig aktiv) dafür, dass die Ausgabe an Ort und Stelle einfließt. Wird der Code gezeigt – pyblock, \pyb –, entfällt das Einfügen, weil eine Ausgabe unmittelbar unter dem erzeugenden Listing selten erwünscht ist. An der gewünschten Stelle hilft \printpythontex (oder \stdoutpythontex). Ebenso lässt sich die Ausgabe mit \saveprintpythontex{name} unter einem Namen ablegen und weit entfernt mit \useprintpythontex{name} wieder abrufen.
Lehrmaterial und Fachtexte brauchen ständig eine nachgestellte interaktive Sitzung. Die Umgebung pyconsole behandelt ihren Inhalt so, als wäre er in einen Interpreter getippt worden, und verschränkt mithilfe von Pythons eigenem Modul code Eingabe und Ausgabe. Das folgende Beispiel ergibt drei Zeilen – >>> a = 1, >>> a + 3, 4 – und diese 4 stammt nicht aus der Quelle, sondern aus dem Build. Bei mehrzeiligen Konstrukten wie einer Funktionsdefinition kann nach der letzten Zeile eine Leerzeile nötig sein. Zur selben Familie gehören außerdem \pyconv / pyconverbatim, die eine eingefügte Sitzung setzen ohne sie auszuführen, sowie \pyconc / pyconcode, die ausführen ohne zu setzen.
\begin{pyconsole}
a = 1
a + 3
\end{pyconsole}
% typeset result:
% >>> a = 1
% >>> a + 3
% 4Der dreistufige Build – und warum -shell-escape entfällt
Ein PythonTeX-Dokument entsteht in drei Läufen: LaTeX, dann pythontex, dann wieder LaTeX. Der erste LaTeX-Lauf führt nichts aus, sondern extrahiert den Code lediglich in eine externe Datei namens <jobname>.pytxcode. Anschließend führt das Programm pythontex diesen Code aus und speichert die Ergebnisse; der zweite LaTeX-Lauf holt sie herein und erzeugt die PDF. Wird die Engine nur einmal gestartet, erscheinen die sorgfältig geschriebenen Werte schlicht nicht – der klassische erste Stolperstein.
pdflatex document.tex # 1) LaTeX extracts the code to document.pytxcode
pythontex document.tex # 2) a separate program runs it and caches the results
pdflatex document.tex # 3) LaTeX pulls the results back into the documentHier folgt die Tatsache, die alle überrascht, die minted kennen: PythonTeX braucht kein -shell-escape. minted startet mitten im Satzlauf ein externes Programm und bricht deshalb ohne Erlaubnis mit ! Package minted Error: You must invoke LaTeX with the -shell-escape flag. ab (siehe „Quellcode-Listings“). Bei PythonTeX führt dagegen nicht LaTeX den Code aus, sondern ein eigenständiges Programm zwischen den beiden LaTeX-Läufen. LaTeX schreibt nur die .pytxcode und liest später die Ergebnisse zurück. Tatsächlich enthält pythontex.sty keine einzige Verwendung von \write18.
Dieses „dazwischen“ hat noch einen angenehmen Nebeneffekt. Die Datei .pytxcode hält nicht nur jeden Codeblock fest, sondern auch, aus welcher Zeile der .tex-Datei er stammt. Stolpert Python, meldet pythontex daher die Zeilennummer des Manuskripts und nicht die der erzeugten .py. Ein undefinierter Name in einem pycode-Block liefert * PythonTeX stderr - error on line 8: und darunter NameError: name 'nosuchname' is not defined – und diese 8 ist Zeile 8 der .tex. Kein Öffnen der generierten Datei, kein Zeilenzählen von Hand.
Drei Befehle jedes Mal von Hand einzutippen ist unpraktisch, daher übernimmt in der Praxis latexmk die Arbeit. Die im Handbuch angegebene Konfiguration meldet die Datei mit dem extrahierten Code, .pytxcode, als Abhängigkeit an und startet pythontex, sobald sie sich ändert; schreibt pythontex seine Ausgabedateien neu, bemerkt latexmk das und übersetzt selbsttätig erneut. Auch hier spielt shell escape keine Rolle – latexmk ruft pythontex schlicht als gewöhnlichen externen Befehl auf.
# run pythontex whenever the extracted code changes
add_cus_dep('pytxcode', 'tex', 0, 'pythontex');
sub pythontex { return system("pythontex \"$_[0]\""); }Die Engine spielt keine Rolle. Wird pdflatex durch lualatex oder xelatex ersetzt, in japanischen Dokumenten durch platex, bleibt die Dreistufigkeit unverändert. Nicht-ASCII-Zeichen im Code verlangen allerdings eine passende Einrichtung des Dokuments, und das Handbuch wird konkret: unter pdfLaTeX \usepackage[T1]{fontenc} samt \usepackage[utf8]{inputenc}, unter LuaLaTeX \usepackage{fontspec}, unter XeLaTeX dasselbe zuzüglich \defaultfontfeatures{Ligatures=TeX}. Eine Falle betrifft nur XeLaTeX: Enthält der Code Tabulatoren, ist mit -8bit zu übersetzen, sonst landen die Tabulatoren als Zeichenfolge ^^I in der Datei.
Warum erneute Builds schnell bleiben: Cache, Sessions und --rerun
Unveränderter Code wird nicht ausgeführt. Genau das macht aus der scheinbar waghalsigen Idee, schwere Rechnungen in ein Dokument einzubetten, etwas Brauchbares. pythontex legt seine Ergebnisse unter pythontex-files-<jobname>/ ab – der Cache selbst steckt in pythontex_data.pkl – und führt beim nächsten Lauf nur die geänderten Blöcke aus. Ein korrigierter Tippfehler in einem Absatz startet die dreißig Sekunden lange Simulation nicht erneut.
Was als „geändert“ gilt, lässt sich über --rerun einstellen; dazu gibt es die gleichwertige Paketoption \usepackage[rerun=…]{pythontex}. Voreingestellt ist errors: alles Geänderte plus alles, was beim letzten Mal einen Fehler erzeugt hat. Deshalb wird ein fehlschlagender Block beim Debuggen erneut versucht, ohne dass man ihn anfassen muss. Die Schwellen bilden eine Skala.
never– nichts ausführen; bei geändertem Code lediglich warnen.modified– nur geänderte Blöcke ausführen (oder solche mit geänderten Abhängigkeiten).errors– Voreinstellung. Alles Geänderte sowie alles, was zuletzt fehlschlug.warnings– zusätzlich alles erneut ausführen, was zuletzt eine Warnung erzeugte.always– jedes Mal alles ausführen; im Wesentlichen gleichbedeutend mit--runall.
Die Schwachstelle des Caches ist Code, der sich nicht geändert hat, aber Daten liest, die sich geändert haben. Auf der Python-Seite genügt pytex.add_dependencies('data.csv'), damit der Block genau dann erneut läuft, wenn diese Datei aktualisiert wurde – standardmäßig anhand der Änderungszeit, mit --hashdependencies anhand eines Hashes. Erzeugte Dateien lassen sich mit pytex.add_created() registrieren und werden später mit aufgeräumt. Zu beachten ist außerdem: Sessions laufen parallel. Mit \begin{pycode}[sessionname] getrennte Sessions werden zu eigenen Prozessen; die Zahl gleichzeitiger Prozesse entspricht voreingestellt der Anzahl der CPU-Kerne (--jobs ändert das). Geht die Rechnung dennoch nicht auf, lautet das letzte Mittel des Handbuchs: pythontex-files-<jobname>/ vollständig löschen und neu bauen.
matplotlib-Abbildungen und SymPy-Formeln ins Dokument holen
Abbildungen zu erzeugen ist erfreulich direkt: matplotlib in einem pycode-Block savefig aufrufen lassen und die Datei danach mit \includegraphics einbinden. Voreingestellt landet sie neben der .tex, sodass kein Pfad zu bedenken ist (\setpythontexworkingdir ändert das bei Bedarf). Interessant wird es danach: Mit \setpythontexcontext{textwidth=\the\textwidth} wandern die Maße von LaTeX zu Python hinüber und sind dort als pytex.context.textwidth lesbar; nach der Umrechnung mit pytex.pt_to_in() lässt sich eine Abbildung genau in Satzspiegelbreite erzeugen. Da nachträglich nichts skaliert wird, erscheint die Beschriftung in der Abbildung so groß wie der umgebende Text.
\documentclass{article}
\usepackage{graphicx}
\usepackage{pythontex}
\setpythontexcontext{textwidth=\the\textwidth}
\begin{document}
\begin{pycode}
import matplotlib
matplotlib.use('pgf')
import matplotlib.pyplot as plt
import numpy as np
width = pytex.pt_to_in(pytex.context.textwidth)
x = np.linspace(0, 2*np.pi, 200)
fig, ax = plt.subplots(figsize=(width, 0.4*width))
ax.plot(x, np.sin(x))
fig.savefig('wave.pdf', bbox_inches='tight')
\end{pycode}
\includegraphics{wave.pdf}
\end{document}Und hier lauert das Schlagloch, das der erste Build fast immer trifft. Beim ersten LaTeX-Lauf existiert wave.pdf noch nicht, also erscheint ! Package pdftex.def Error: File 'wave.pdf' not found: using draft setting. Nichts ist kaputt – die Abbildung entsteht erst in der zweiten Stufe, in pythontex; sind alle drei Schritte durchlaufen, findet der zweite LaTeX-Lauf sie. Bei dieser einen Zeile nicht umzukehren im Glauben, etwas falsch konfiguriert zu haben, ist der erste Kniff, den man kennen sollte.
Für Mathematik gibt es eigens gebaute Familien. Wird der Basisname py ersetzt, steht dieselbe Aufstellung erneut bereit: \sympy, sympycode, sympyblock sowie \pylab, pylabcode, pylabblock. Unterschiedlich sind nur der einleitende Import und die Art, wie das Ergebnis dargestellt wird.
- Die sympy-Familie – lädt die Computeralgebra-Bibliothek SymPy mit
from sympy import *. Ein mit\sympyeingefügter Ausdruck durchläuft SymPysLatexPrinterund wird kontextgerecht als LaTeX formatiert, je nachdem ob im Text oder abgesetzt. Erst das ermöglicht Kunststücke wie eine komplett erzeugte Tabelle von Ableitungen und Integralen. - Die pylab-Familie – lädt matplotlibs Modul
pylabmitfrom pylab import *und bringt Plotten und NumPy in einen Namensraum. Wer die Importe lieber selbst schreibt, wie im Beispiel oben, kommt mit der schlichtenpy-Familie aus.
Wenn der Verlag es nicht bauen kann: depythontex und die Sicherheitsfrage
Hier liegt die eigentliche Beschränkung von PythonTeX. Eine Verarbeitungskette, die nur eine LaTeX-Engine startet, bringt dieses Dokument nie zu Ende. Es fehlt nicht die Erlaubnis für shell escape, sondern der dazwischenliegende pythontex-Lauf selbst. Das Handbuch räumt genau das ein: Dokumente mit PythonTeX eignen sich schlechter als reine LaTeX-Dokumente für Einreichung, Weitergabe und Umwandlung in andere Formate. Dafür gibt es depythontex. Wird mit \usepackage[depythontex]{pythontex} gebaut, entsteht die Hilfsdatei <jobname>.depytx; das Skript depythontex gleicht sie mit der Originalquelle ab und schreibt eine zweite .tex, in der jeder PythonTeX-Befehl und jede Umgebung durch den gesetzten Code und dessen Ausgabe ersetzt ist – gewöhnliches LaTeX mit eingebrannten Ergebnissen, ganz ohne Abhängigkeit von PythonTeX.
# 1) run the usual three steps, with the depythontex package option on
pdflatex document.tex
pythontex document.tex
pdflatex document.tex
# 2) write the static, PythonTeX-free copy
depythontex -o document-plain.tex document.tex
# code display in the output can be switched to another package
depythontex --listing minted -o document-plain.tex document.tex--listing leistet unauffällig gute Dienste. Damit lässt sich wählen, wie Code in der statischen Fassung dargestellt wird – verbatim, fancyvrb, listings, minted oder pythontex –, sodass auch eine Einreichungsvorgabe, die listings verlangt, kein Hindernis ist (siehe „Quellcode-Listings“). Es gibt noch einen leichteren Weg: Laut Handbuch genügt es, wenn das Dokument nur an Mitautorinnen und Mitautoren weitergereicht werden soll, pythontex.sty zusammen mit dem Ausgabeverzeichnis mitzuliefern. Die Empfangenden können dann alles außer dem Python-Teil wie ein gewöhnliches LaTeX-Dokument bearbeiten, ohne je Python zu starten.
Zum Schluss der Punkt, den das Handbuch eigens in einen Warnkasten setzt. Ein Dokument mit PythonTeX zu übersetzen bedeutet, tatsächlich Python – und unter Umständen weitere Programme – auf dem eigenen Rechner auszuführen. Zu übersetzen sind daher nur Dokumente aus vertrauenswürdiger Quelle. Dass kein -shell-escape nötig ist, macht die Sache nicht sicherer: Der Code läuft genauso, nur eben außerhalb von LaTeX statt darin.