summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/pyluatex/pyluatex.tex
blob: 15e8c4f9f2834d817c5b06595bc01cae173deb24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
\documentclass{article}
\usepackage{helvet}
\usepackage{courier}
\renewcommand{\familydefault}{\sfdefault}
\usepackage[margin=2.5cm]{geometry}
\usepackage{parskip}
\linespread{1.2}
\usepackage{tabularx}
\usepackage{xcolor}
\usepackage[listings,breakable,xparse]{tcolorbox}
\tcbset{breakable,listing only,size=fbox,colframe=black!10,boxrule=3pt,colback=black!10}
\NewTotalTCBox{\inlcode}{ v }{
    on line,boxsep=0pt,left=0.5ex,right=0.5ex,top=0pt,bottom=0pt,
    boxrule=0pt}{\lstinline[style=tcblatex]|#1|\rule[-.3\baselineskip]{0pt}{0.9\baselineskip}}
\usepackage{url}
\title{The \emph{pyluatex} package}
\author{Tobias Enderle\\\url{https://github.com/tndrle/PyLuaTeX}}
\date{v0.6.3 (2024/01/10)}
\begin{document}
\maketitle
\raggedright

\textbf{Execute Python code on the fly in your \LaTeX{} documents}

PyLuaTeX allows you to execute Python code and to include the resulting output in your \LaTeX{} documents in a \textit{single compilation run}.
\LaTeX{} documents must be compiled with Lua\LaTeX{} for this to work.


\section{Example}
\begin{enumerate}
\item  \LaTeX{} document \inlcode|example.tex|\\[0.5ex]
\begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
\documentclass{article}

\usepackage{pyluatex}

\begin{python}
import math
import random

random.seed(0)

greeting = 'Hello PyLuaTeX!'
\end{python}

\newcommand{\randint}[2]{\py{random.randint(#1, #2)}}

\begin{document}
\py{greeting}

$\sqrt{371} = \py{math.sqrt(371)}$

\randint{2}{5}
\end{document}
\end{tcblisting}
\item  Compile using Lua\LaTeX{} (shell escape is required)
\begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
lualatex --shell-escape example.tex
\end{tcblisting}
\end{enumerate}
\textbf{Note:} PyLuaTeX starts Python 3 using the command \inlcode|python3| by default.
If \inlcode|python3| does not start Python 3 on your system, find the correct command
and replace \inlcode|\usepackage{pyluatex}| with \inlcode|\usepackage[executable=<your python command>]{pyluatex}|.
For example, \inlcode|\usepackage[executable=python.exe]{pyluatex}|.

\textbf{Note:} Running \LaTeX{} with the shell escape option enabled allows arbitrary code to be
executed. For this reason, it is recommended to compile trusted documents only.

\subsection{Further Examples}
The folder \inlcode|example| contains additional example documents:
\begin{itemize}
\item \inlcode|beamer.tex|\\[0.5ex]
  Demonstrates the use of PyLuaTeX environments and typesetting in \textit{BEAMER} presentations. In particular, the \inlcode|fragile| option for frames is highlighted.
\item \inlcode|data-visualization.tex|\\[0.5ex]
  Demonstrates the visualization of data using \textit{pgfplots} and \textit{pandas}
\item \inlcode|matplotlib-external.tex|\\[0.5ex]
  Demonstrates how \textit{matplotlib} plots can be generated and included in a document
\item \inlcode|matplotlib-pgf.tex|\\[0.5ex]
  Demonstrates how \textit{matplotlib} plots can be generated and included in a document using \textit{PGF}
\item \inlcode|readme-example.tex|\\[0.5ex]
  The example above
\item \inlcode|repl.tex|\\[0.5ex]
  Demonstrates how a Python console/REPL can be run and typeset
\item \inlcode|sessions.tex|\\[0.5ex]
  Demonstrates the use of different Python sessions in a document
\item \inlcode|typesetting-example.tex|\\[0.5ex]
  The code typesetting example below
\item \inlcode|typesetting-listings.tex|\\[0.5ex]
  A detailed example for typesetting code and output with the \textit{listings} package
\item \inlcode|typesetting-minted.tex|\\[0.5ex]
  A detailed example for typesetting code and output with the \textit{minted} package
\end{itemize}
\section{Installation}
PyLuaTeX is available in TeX Live, MiKTeX, and on CTAN\footnote{\url{https://ctan.org/pkg/pyluatex}} as \inlcode|pyluatex|.

To install PyLuaTeX in \textbf{TeX Live} run \inlcode|tlmgr install pyluatex|.\\[0.5ex]
In \textbf{MiKTeX}, PyLuaTeX can be installed in the \textit{MiKTeX Console}.

\section{Reference}
PyLuaTeX offers a simple set of options, macros and environments.

Most macros and environments are available as \textit{quiet} versions as well.
They have the suffix \inlcode|q| in their name, e.g. \inlcode|\pycq| or \inlcode|\pyfileq|.
The quiet versions suppress any output, even if the Python code explicitly calls \inlcode|print()|.
This is helpful if you want to process code or output further and do your own typesetting.
For an example, see the Typesetting Code section.

\subsection{Package Options}
\begin{itemize}
\item \inlcode|executable|\\[0.5ex]
  Specifies the path to the Python executable. (default: \inlcode|python3|)\\[0.5ex]
  \textit{Example:} \inlcode|\usepackage[executable=/usr/local/bin/python3]{pyluatex}|
\item \inlcode|ignoreerrors|\\[0.5ex]
  By default, PyLuaTeX aborts the compilation process when Python reports an error.
  If the \inlcode|ignoreerrors| option is set, the compilation process is not aborted.\\[0.5ex]
  \textit{Example:} \inlcode|\usepackage[ignoreerrors]{pyluatex}|
\item \inlcode|localimports|\\[0.5ex]
  If this option is set, the folder containing the TeX input file is added to the Python path. This allows local Python packages to be imported. (default: \inlcode|true|)\\[0.5ex]
  \textit{Example:} \inlcode|\usepackage[localimports=false]{pyluatex}|
\item \inlcode|shutdown|\\[0.5ex]
  Specifies when the Python process is shut down. (default: \inlcode|veryveryend|)\\[0.5ex]
  \textit{Options:} \inlcode|veryveryend|, \inlcode|veryenddocument|, \inlcode|off|\\[0.5ex]
  PyLuaTeX shuts down the Python interpreter when the compilation is done. With the option \inlcode|veryveryend|, Python is shut down in the \inlcode|enddocument/end| hook. With the option \inlcode|veryenddocument|, Python is shut down in the \inlcode|enddocument/afteraux| hook. With the option \inlcode|off|, Python is not shut down explicitly. However, the Python process will shut down when the LuaTeX process finishes even if \inlcode|off| is selected. Using \inlcode|off| on Windows might lead to problems with SyncTeX, though.\\[0.5ex]
  Before v0.6.2, PyLuaTeX used the hooks \inlcode|\AtVeryVeryEnd| and \inlcode|\AtVeryEndDocument| of the package \textit{atveryend}. The new hooks \inlcode|enddocument/end| and \inlcode|enddocument/afteraux| are equivalent to those of the \textit{atveryend} package.\\[0.5ex]
  \textit{Example:} \inlcode|\usepackage[shutdown=veryenddocument]{pyluatex}|
\item \inlcode|verbose|\\[0.5ex]
  If this option is set, Python input and output is written to the \LaTeX{} log file.\\[0.5ex]
  \textit{Example:} \inlcode|\usepackage[verbose]{pyluatex}|
\end{itemize}
The package options \inlcode|verbose| and \inlcode|ignoreerrors| can be changed in the document with the
\inlcode|\pyoption| command, e.g. \inlcode|\pyoption{verbose}{true}| or \inlcode|\pyoption{ignoreerrors}{false}|.

\subsection{Macros}
\begin{itemize}
\item \inlcode|\py{<code>}|\\[0.5ex]
  Executes (object-like) \inlcode|<code>| and writes its string representation to the document.\\[0.5ex]
  \textit{Example:} \inlcode|\py{3 + 7}|
\item \inlcode|\pyq{<code>}|\\[0.5ex]
  Executes (object-like) \inlcode|<code>|. Any output is suppressed.\\[0.5ex]
  \textit{Example:} \inlcode|\pyq{3 + 7}|
\item \inlcode|\pyc{<code>}|\\[0.5ex]
  Executes \inlcode|<code>|. Output (e.g. from a call to \inlcode|print()|) is written to the document.\\[0.5ex]
  \textit{Examples:} \inlcode|\pyc{x = 5}|, \inlcode|\pyc{print('hello')}|
\item \inlcode|\pycq{<code>}|\\[0.5ex]
  Executes \inlcode|<code>|. Any output is suppressed.\\[0.5ex]
  \textit{Example:} \inlcode|\pycq{x = 5}|
\item \inlcode|\pyfile{<path>}|\\[0.5ex]
  Executes the Python file specified by \inlcode|<path>|. Output (e.g. from a call to \inlcode|print()|) is written to the document.\\[0.5ex]
  \textit{Example:} \inlcode|\pyfile{main.py}|
\item \inlcode|\pyfileq{<path>}|\\[0.5ex]
  Executes the Python file specified by \inlcode|<path>|. Any output is suppressed.\\[0.5ex]
  \textit{Example:} \inlcode|\pyfileq{main.py}|
\item \inlcode|\pysession{<session>}|\\[0.5ex]
  Selects \inlcode|<session>| as Python session for subsequent Python code.\\[0.5ex]
  The session that is active at the beginning is \inlcode|default|.\\[0.5ex]
  \textit{Example:} \inlcode|\pysession{main}|
\item \inlcode|\pyoption{<option>}{<value>}|\\[0.5ex]
  Assigns \inlcode|<value>| to the package option \inlcode|<option>| anywhere in the document. For more information consider
  the Package Options section.\\[0.5ex]
  \textit{Example:} \inlcode|\pyoption{verbose}{true}|
\item \inlcode|\pyif{<test>}{<then clause>}{<else clause>}|\\[0.5ex]
  Evaluates the Python boolean expression \inlcode|<test>|, and then executes either the \LaTeX{} code in \inlcode|<then clause>| or the \LaTeX{} code in \inlcode|<else clause>|.\\[0.5ex]
  \textit{Example:} \inlcode|\pyif{a == 1}{$a = 1$}{$a \neq 1$}|
\end{itemize}
\subsection{Environments}
\begin{itemize}
\item \inlcode|python|\\[0.5ex]
  Executes the provided block of Python code.\\[0.5ex]
  The environment handles characters like \inlcode|_|, \inlcode|#|, \inlcode|%|, \inlcode|\|, etc.\\[0.5ex]
  Code on the same line as \inlcode|\begin{python}| is ignored, i.e., code must start on the next line.\\[0.5ex]
  If leading spaces are present they are gobbled automatically up to the first level of indentation.\\[0.5ex]
  \textit{Example:}
  \begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
\begin{python}
    x = 'Hello PyLuaTeX'
    print(x)
\end{python}
\end{tcblisting}
\item \inlcode|pythonq|\\[0.5ex]
  Same as the \inlcode|python| environment, but any output is suppressed.
\item \inlcode|pythonrepl|\\[0.5ex]
  Executes the provided block of Python code in an interactive console/REPL. Code and output are
  stored together in the output buffer and can be typeset as explained in section
  Typesetting Code or as shown in the example \inlcode|repl.tex| in the folder
  \inlcode|example|.
\end{itemize}
You can create your own environments based on the \inlcode|python|, \inlcode|pythonq| and \inlcode|pythonrepl| environments.
However, since they are verbatim environments, you have to use the macro \inlcode|\PyLTVerbatimEnv|
in your environment definition, e.g.
\begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
\newenvironment{custompy}
{\PyLTVerbatimEnv\begin{python}}
{\end{python}}
\end{tcblisting}

\subsection{Logging from Python}
\begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
tex.log(*objects, sep=' ', end='\n')
\end{tcblisting}
Writes \inlcode|objects| to the TeX log, separated by \inlcode|sep| and followed by \inlcode|end|.
All elements in \inlcode|objects| are converted to strings using \inlcode|str()|.
Both \inlcode|sep| and \inlcode|end| must be strings.

\textit{Example:}
\begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
\begin{python}
tex.log('This text goes to the TeX log.')
\end{python}
\end{tcblisting}

\section{Requirements}
\begin{itemize}
\item Lua\LaTeX{}
\item Python 3
\item Linux, macOS or Windows
\end{itemize}
\section{Typesetting Code}
Sometimes, in addition to having Python code executed and the output written to your document, you also want to show the code itself in your document.
PyLuaTeX does not offer any macros or environments that directly typeset code.
However, PyLuaTeX has a \textbf{code and output buffer} which you can use to create your own typesetting functionality.
This provides a lot of flexibility for your typesetting.

After a PyLuaTeX macro or environment has been executed, the corresponding Python code and output can be accessed via the Lua functions \inlcode|pyluatex.get_last_code()| and \inlcode|pyluatex.get_last_output()|, respectively.
Both functions return a Lua table\footnote{\url{https://www.lua.org/pil/2.5.html}} (basically an array) where each table item corresponds to a line of code or output.

A simple example for typesetting code and output using the \textit{listings} package would be:
\begin{tcblisting}{breakable,listing only,
    size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
\documentclass{article}

\usepackage{pyluatex}
\usepackage{listings}
\usepackage{luacode}

\begin{luacode}
function pytypeset()
    tex.print("\\begin{lstlisting}[language=Python]")
    tex.print(pyluatex.get_last_code())
    tex.print("\\end{lstlisting}")
    tex.print("") -- ensure newline
end
\end{luacode}

\newcommand*{\pytypeset}{%
    \noindent\textbf{Input:}
    \directlua{pytypeset()}
    \textbf{Output:}
    \begin{center}
        \directlua{tex.print(pyluatex.get_last_output())}
    \end{center}
}

\begin{document}

\begin{pythonq}
greeting = 'Hello PyLuaTeX!'
print(greeting)
\end{pythonq}
\pytypeset

\end{document}
\end{tcblisting}

Notice that we use the \inlcode|pythonq| environment, which suppresses any output.
After that, the custom macro \inlcode|\pytypeset| is responsible for typesetting the code and its output.

Using a different code listings package like \textit{minted}, or typesetting inline code is very easy.
You can also define your own environments that combine Python code and typesetting.
See the \inlcode|typesetting-*.tex| examples in the \inlcode|example| folder.

To emulate an interactive Python console/REPL, the \inlcode|pythonrepl| environment can be used.

\section{How It Works}
PyLuaTeX runs a Python \inlcode|InteractiveInterpreter|\footnote{\url{https://docs.python.org/3/library/code.html#code.InteractiveInterpreter}} (actually several if you use different sessions) in the background for on the fly code execution.
Python code from your \LaTeX{} file is sent to the background interpreter through a TCP socket.
This approach allows your Python code to be executed and the output to be integrated in your \LaTeX{} file in a single compilation run.
No additional processing steps are needed.
No intermediate files have to be written.
No placeholders have to be inserted.

\section{License}
LPPL 1.3c\footnote{\url{http://www.latex-project.org/lppl.txt}} for \LaTeX{} code and
MIT license\footnote{\url{https://opensource.org/licenses/MIT}} for Python and Lua code and other files.
\end{document}