# How to treat the arguments of a macro as literal or verbatim text?

I'm working on a package that allows Python code to be entered within certain commands and environments, saves the Python code to external files and executes it, and brings back the results via \input. Similar to SympyTeX and SageTeX, but with additional features.

As a trivial example, \pylab{print 1+1} would save the text string print 1+1 to a file, Python executes this file to obtain 2 and saves this in a second file, and this second file is brought back into the original document with \input.

This is a minimal example. (It will give errors after the first run, before Python is run to create infile.tex.)

\newcommand{\pylab}[1]{
\newwrite\outputstream
\immediate\openout\outputstream=outfile.py
\immediate\write\outputstream{#1}
\immediate\closeout\outputstream
\input{infile.tex}
}


The problem is that in more complex cases, the argument for \pylab could contain special characters, for example \pylab{print 3%2} (modulus operator). What's the best way to deal with this? Ideally, my command would act like \verb, so that it would take anything but * as the switch, so as to be able to work around almost any special code characters. I've been reading about verbatim, catcodes, \gdef, etc., but I haven't been able to get anywhere with those yet.

SympyTeX and SageTeX use

\catcode\%=12
\newcommand{\percent}{%}
\catcode\%=14


to define a replacement for %, but I want to avoid that route if possible since it means that I can't just directly paste in valid Python code.

• Hi, I don't know if it is going to help you, but perhaps you would like to have a look at python.sty. You may find the code here or at the internet archives. – pmav99 May 28 '11 at 19:28
• About your code example: \newwrite\outputstream must be outside of \pylab and only executed once. And the percent character is already defined as \@percentchar. – Martin Scharrer May 28 '11 at 19:34

You can read the argument verbatim using the follow technique. However this keeps { and } normal so they need to be matched inside the argument.

\documentclass{article}

\makeatletter
\newwrite\@pyout
\newcommand{\pylab}{%
\begingroup
% deactivate special characters
\let\do\@makeother
\dospecials
% change '{' and '}' back to normal
\catcode\{=1
\catcode\}=2
\@pylab
}
\def\@pylab#1{%
\endgroup
\immediate\openout\@pyout=\jobname.py
\immediate\write\@pyout{#1}%
\immediate\closeout\@pyout
\immediate\write18{python \jobname.py > \jobname-py.tex}%
\input{\jobname-py}%
}

\makeatother

\begin{document}

\pylab{print 3%2}

\end{document}


If you want the behavior of \verb use the following code which is inspired by the actual \verb code.

\documentclass{article}

\makeatletter

\newwrite\@pyout

\newcommand{\pylab}[1]{%
\begingroup
\verb@eol@error
\let\do\@makeother
\dospecials
\catcode#1\active
\lccode\~#1%
\lowercase{\def\@@pylab##1~}{\endgroup\@pylab{##1}}%
\@@pylab
}

\def\@pylab#1{%
\immediate\openout\@pyout=\jobname.py
\immediate\write\@pyout{#1}%
\immediate\closeout\@pyout
\immediate\write18{python \jobname.py > \jobname-py.tex}%
\input{\jobname-py}%
}

\makeatother

\begin{document}

\pylab|print 3%2|

\end{document}


### Update:

With the new version 2011/07/23 of my newverbs package you can simplify the \pylab macro to \newcommand{\pylab}{\begingroup\Collectverb{\@pylab}}.

• It's possible to avoid writing the \jobname-py.tex file by changing the two lines before the final brace into \@@input|"python \jobname.py"` (it still requires shell-escape enabled). – egreg May 28 '11 at 20:52
• Thanks! The first solution does everything I wanted--seems to handle everything I've thrown at it, and since I'm dealing with code, matched braces isn't an issue. – G.P. May 29 '11 at 3:28