├── README.rst ├── example.tex ├── pytex.vim ├── python.sty └── runpy.py /README.rst: -------------------------------------------------------------------------------- 1 | Python in Latex 2 | =============== 3 | 4 | This package enables you to embed Python code (www.python.org) in LaTeX and insert the output into your LaTeX document. 5 | 6 | Installing 7 | ---------- 8 | 9 | Copy `python.sty` and `runpy.py` side by side with your document. 10 | 11 | 12 | Using 13 | ----- 14 | 15 | In you LaTeX document insert:: 16 | 17 | \usepackage{python} 18 | ... 19 | \begin{python} 20 | print("42") 21 | \end{python} 22 | 23 | Compile the document with the shell escape option and of course Python installed:: 24 | 25 | $ latex -shell-escape document.tex 26 | 27 | or insert/change "shell_escape = t" in your texmf.cnf 28 | 29 | **Note**: By default LaTeX and its variants disallowing calling of arbitrary shell commands. python.sty requires unrestricted 30 | to the shell in order to execute embedded Python scripts. When running python.sty you must execute ``latex`` or ``pdftex`` with 31 | either the ``-enable-write18`` or ``-shell-escape`` command line argument to enabled access to the Python executable. 32 | 33 | 34 | Package options 35 | --------------- 36 | 37 | The package takes an optional key-value option (`bin`) that can be used to specify the 38 | python binary to use. (If not present `python` is used):: 39 | 40 | \usepackage[bin=python2.6]{python} 41 | 42 | 43 | Python scripts, output, error and return files are saved by default in the same folder as the documents and the folder gets crowded quite easily, If the word `subfolder` is 44 | added to the options, these files will be served to a subfolder named `py`:: 45 | 46 | \usepackage[subfolder]{python} 47 | 48 | 49 | Package content 50 | --------------- 51 | 52 | Original discussion and examples at http://web.archive.org/web/20120423051102/http://pycurious.org/2011/12/the-ultimate-python-latex-environment/ 53 | 54 | example.tex 55 | Example usage of python.sty. 56 | 57 | pytex.vim 58 | A Vim syntax highlighting file to correctly highlight python embedded in 59 | LaTeX documents. 60 | 61 | python.sty 62 | A LaTeX package that allows direct embedding of python scripts in LaTeX 63 | documents. 64 | 65 | runpy.py 66 | A helper python script. 67 | -------------------------------------------------------------------------------- /example.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage{python} 4 | \usepackage{amsmath} 5 | 6 | \title{Example Use of python.sty} 7 | \author{James Brotchie \emph{j.brotchie@gmail.com}} 8 | \begin{document} 9 | \maketitle 10 | 11 | $N \times N$ element identity matrices for $N \in \{1,2,\ldots,5\}$: 12 | 13 | \begin{python} 14 | def identity(n): 15 | """ 16 | Generates and returns the LaTeX code for 17 | a n x n identity matrix. 18 | 19 | """ 20 | return '\n'.join([ 21 | r'\left[', 22 | r'\begin{array}{%s}' % (n*'c',), 23 | '\\\\'.join('&'.join('1' if i==j else '0' for j in range(n)) 24 | for i in range(n)), 25 | r'\end{array}', 26 | r'\right]', 27 | ]) 28 | 29 | # Displays identity matrices for 30 | # n \in {1, 2, ..., 5}. 31 | print '\n'.join([ 32 | r'\begin{equation*}', 33 | r'\begin{array}{%s}' % (5*'c',), 34 | '&'.join(identity(i) for i in range(1,6)), 35 | r'\end{array}.', 36 | r'\end{equation*}', 37 | ]) 38 | \end{python} 39 | 40 | \begin{python} 41 | # Create a deliberate exception. 42 | print 'This text will be displayed.' 43 | print 1/0 44 | print 'This text won\'t be displayed.' 45 | \end{python} 46 | 47 | \end{document} 48 | -------------------------------------------------------------------------------- /pytex.vim: -------------------------------------------------------------------------------- 1 | " Syntax for LaTeX files with embedded Python 2 | " environments. 3 | let b:current_syntax = '' 4 | unlet b:current_syntax 5 | runtime! syntax/tex.vim 6 | 7 | let b:current_syntax = '' 8 | unlet b:current_syntax 9 | syntax include @TeX syntax/tex.vim 10 | 11 | let b:current_syntax = '' 12 | unlet b:current_syntax 13 | syntax include @Python syntax/python.vim 14 | syntax region pythonCode matchgroup=Snip start="\\begin{python}" end="\\end{python}" containedin=@TeX contains=@Python 15 | 16 | hi link Snip SpecialComment 17 | let b:current_syntax = 'pytex' 18 | -------------------------------------------------------------------------------- /python.sty: -------------------------------------------------------------------------------- 1 | %% This program is free software; you can redistribute it and/or 2 | %% modify it under the terms of the GNU General Public License 3 | %% as published by the Free Software Foundation; either version 2 4 | %% of the License, or (at your option) any later version. 5 | %% 6 | %% This program is distributed in the hope that it will be useful, 7 | %% but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | %% GNU General Public License for more details. 10 | %% 11 | %% You should have received a copy of the GNU General Public License 12 | %% along with this program; if not, write to the Free Software 13 | %% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 14 | %% 15 | 16 | %% 0.4 Version by Hernán Grecco 17 | %% 0.3 Version by James Brotchie 18 | %% 19 | %% Author: Martin R. Ehmsen, ehmsen@imada.sdu.dk. 20 | %% Department of Mathematics and Computer Science, 21 | %% University of Southern Denmark, DK 22 | %% 23 | 24 | %% You can find an online copy of the GPL at 25 | %% http://www.gnu.org/copyleft/gpl.html . 26 | %% 27 | %% Note: shell-escape needs to be activated for this to work. 28 | %% This can either be done by passing -shell-escape as an option to 29 | %% latex or by adding/changing "shell_escape = t" in your texmf.cnf . 30 | 31 | 32 | % Python-sty Changelog 33 | % ==================== 34 | % 35 | % 36 | % 0.4 (2013-11-28) 37 | % ---------------- 38 | % - Python code is only executed if it has changed. 39 | % - Option to save auxiliary files in a subfolder. 40 | % - Option to choose the python binary. 41 | % - Code refactoring. 42 | % - UTF-8 support. 43 | % 44 | % 45 | % 0.3 (2011-12-22) 46 | % ---------------- 47 | % 48 | % - Intermediate files are now stored with different filenames. 49 | % - The return code of each Python shell execution is stored 50 | % in an .rc file. 51 | % - Any stderr output of a failed Python shell execution is 52 | % inserted as a red verbatim in the resulting document. 53 | % -- James Brotchie 54 | % 55 | % 0.21 56 | % ---- 57 | % 58 | % - Moved \newwrite\@module from \@writemodule and out, since 59 | % no more than 15 \newwrites are allowed (and the previous 60 | % version created a new every time \@writemodule was called. 61 | % 62 | % 63 | 64 | \NeedsTeXFormat{LaTeX2e}[1994/12/01] 65 | \ProvidesPackage{python}[2013/11/17 v0.4 Python in LaTeX] 66 | \RequirePackage{etoolbox} 67 | \RequirePackage{verbatim} 68 | \RequirePackage{color} 69 | \RequirePackage{ifplatform} 70 | \RequirePackage{fancyvrb} 71 | \RequirePackage{inputenc} 72 | \RequirePackage{kvoptions} 73 | 74 | % Put the resulting Python code in separate files. 75 | \newcommand{\@PYT@outname}{\jobname\arabic{@PythonEnvironmentCounter}} 76 | \newcounter{@PythonEnvironmentCounter} 77 | \setcounter{@PythonEnvironmentCounter}{1} 78 | 79 | % Package Options 80 | \SetupKeyvalOptions{ 81 | family=PYT, 82 | prefix=PYT@ 83 | } 84 | 85 | \DeclareVoidOption{subfolder}{ 86 | \renewcommand{\@PYT@outname}{py/\jobname\arabic{@PythonEnvironmentCounter}} 87 | } 88 | 89 | \DeclareStringOption[python]{bin}[python] 90 | 91 | \ProcessKeyvalOptions* 92 | 93 | \newcommand{\@pythonbin}{\PYT@bin \space runpy.py \space} 94 | 95 | \typeout{PYTHON: Binary \@pythonbin} 96 | 97 | \newread\@PYT@retcode 98 | \newread\@PYT@diff 99 | 100 | \newcommand{\@PYT@copytocache}{ 101 | \ifwindows 102 | \immediate\write18{copy \@PYT@outname.py \@PYT@outname.py.cache} 103 | \else 104 | \immediate\write18{cp \@PYT@outname.py \@PYT@outname.py.cache} 105 | \fi 106 | } 107 | 108 | \newcommand{\@PYT@deletescript}{ 109 | \ifwindows 110 | \immediate\write18{del \@PYT@outname.py} 111 | \else 112 | \immediate\write18{rm \@PYT@outname.py} 113 | \fi 114 | } 115 | 116 | \newcommand{\@PYT@comparefiles}{ 117 | \ifwindows 118 | \immediate\write18{fc \@PYT@outname.py \@PYT@outname.py.cache & call echo ^\@percentchar ERRORLEVEL ^\@percentchar > \@PYT@outname.cmp.rc} 119 | \else 120 | \immediate\write18{cmp \@PYT@outname.py \@PYT@outname.py.cache; echo $? > \@PYT@outname.cmp.rc} 121 | \fi 122 | } 123 | 124 | \newcommand{\@PYT@executescript}{ 125 | \typeout{PYTHON: Running file \@PYT@outname.py} 126 | \immediate\write18{\@pythonbin \space\@PYT@outname.py} 127 | 128 | % Copy to the current script to keep a cache. 129 | \@PYT@copytocache 130 | \@PYT@deletescript 131 | 132 | } 133 | 134 | \newcommand{\@PYT@returncode}{ 135 | \inputencoding{utf8} 136 | \input{\@PYT@outname} 137 | 138 | % Read the return code of the executed Python script. 139 | \immediate\openin\@PYT@retcode=\@PYT@outname.py.rc 140 | \immediate\read\@PYT@retcode to \rc 141 | \immediate\closein\@PYT@retcode 142 | 143 | % If the return code isn't zero then include 144 | % the traceback. 145 | \ifnumequal{\rc}{0}{ 146 | \typeout{PYTHON: Run was successful} 147 | }{% 148 | \typeout{PYTHON: Run failed} 149 | \begingroup 150 | \color{red} 151 | \verbatiminput{\@PYT@outname.py.err} 152 | \endgroup 153 | } 154 | } 155 | 156 | \newenvironment{python} 157 | { 158 | \typeout{PYTHON: Writing file \@PYT@outname.py} 159 | \@PYT@deactivateeightbit\VerbatimOut{\@PYT@outname.py}} 160 | { 161 | \endVerbatimOut 162 | 163 | \@PYT@comparefiles 164 | \immediate\openin\@PYT@diff=\@PYT@outname.cmp.rc 165 | \immediate\read\@PYT@diff to \rc 166 | \immediate\closein\@PYT@diff 167 | 168 | \ifnumequal{\rc}{0}{ 169 | % Old file and new file are identical 170 | \typeout{PYTHON: No need to run the script again} 171 | }{ 172 | % Old file and new file are different or old is not present 173 | \@PYT@executescript 174 | } 175 | \@PYT@returncode 176 | 177 | \immediate\stepcounter{@PythonEnvironmentCounter} 178 | } 179 | 180 | \newcommand{\@PYT@deactivateeightbit}{% 181 | \count@=127 182 | \loop 183 | \catcode\count@=12 184 | \ifnum\count@<255 185 | \advance\count@\@ne 186 | \repeat 187 | } 188 | 189 | 190 | -------------------------------------------------------------------------------- /runpy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | 5 | try: 6 | reload(sys).setdefaultencoding("UTF-8") 7 | except: 8 | pass 9 | 10 | 11 | filename = sys.argv[1] 12 | 13 | with open(filename[:-3] + '.tex', "w") as fout: 14 | sys.stdout = fout 15 | with open(filename + '.err', "w") as ferr: 16 | with open(filename + '.rc', 'w') as frc: 17 | with open(filename) as f: 18 | try: 19 | code = compile(f.read(), filename, 'exec') 20 | exec(code, {'print': fout.write}) 21 | frc.write('0') 22 | except Exception as e: 23 | frc.write('1') 24 | import traceback 25 | ferr.write(traceback.format_exc()) 26 | raise e 27 | --------------------------------------------------------------------------------