% \iffalse meta-comment
%
% Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org>% -------------------------------------------------------
%
% See the "Copying and licenses" section at the end of this file for the
% terms under which this source code and documentation may be modified
% and distributed.
%
% This package is not licensed under the LPPL, but it seems reasonable
% to say:
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Dan Drake.
%
% This work consists of the files sagetexpackage.dtx,
% sagetexpackage.ins, example.tex, and the derived files sagetex.sty,
% sagetex.py, sagetexparse.py, makestatic.py, and extractsagecode.py.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{sagetexpackage.dtx}
%</driver>%<latex>\NeedsTeXFormat{LaTeX2e}
%<latex>\ProvidesPackage{sagetex}
%<*latex>
[2009/01/27 v2.0.1 embedding Sage into LaTeX documents]
%</latex>%<*driver>
\documentclass{ltxdoc}
\usepackage{sagetex}
\usepackage{xspace}
\usepackage{tikz}
\usepackage{hyperref}
\renewcommand{\subsubsectionautorefname}{section}
\renewcommand{\subsectionautorefname}{section}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
\DocInput{sagetexpackage.dtx}
\PrintChanges
\PrintIndex
\end{document}
%</driver>% \fi
%
% \CheckSum{0}
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
% Digits \0\1\2\3\4\5\6\7\8\9
% Exclamation \! Double quote \" Hash (number) \#
% Dollar \$ Percent \% Ampersand \&% Acute accent \' Left paren \( Right paren \)
% Asterisk \* Plus \+ Comma \,
% Minus \- Point \. Solidus \/
% Colon \: Semicolon \; Less than \<% Equals \= Greater than \> Question mark \?
% Commercial at \@ Left bracket \[ Backslash \\
% Right bracket \] Circumflex \^ Underscore \_
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
% \changes{v1.0}{2008/03/03}{Initial version}
% \changes{v1.1}{2008/03/05}{Wrapped user-provided Sage code in
% try/except clauses; plotting now has optional format argument.}
% \changes{v1.2}{2008/03/07}{Imagemagick option; better documentation}
% \changes{v1.3.1}{2008/03/10}{Internal variables renamed; fixed typos}
% \changes{v1.4}{2008/03/11}{MD5 fix, percent sign macro, CTAN upload}
% \changes{v2.0}{2008/12/16}{External Python scripts for parsing
% SageTeX-ified documents, tons of documentation improvements,
% sagetex.py refactored, include in Sage as spkg}
% \changes{v2.0}{2009/01/09}{Miscellaneous fixes, final 2.0 version.}
%
% \GetFileInfo{sagetexpackage.dtx}
%
% \DoNotIndex{\newcommand,\newenvironment,\the}
%
% \newcommand{\ST}{\textsf{Sage\TeX}\xspace}
% \iffalse
% so I don't have to put \ or {} after \LaTeX:
% \fi
% \newcommand{\LTX}{\LaTeX\xspace}
%
% \newcommand{\TikZ}{Ti\emph{k}Z\xspace}
%
% \tikzstyle{box}=[draw, shape=rectangle, thick]
%
% \title{The \ST{} package\thanks{This document
% corresponds to \ST~\fileversion, dated \filedate.}}
% \author{Dan Drake (\texttt{ddrake@member.ams.org}) and others}
%
% \maketitle
%
% \section{Introduction}
%
% Why should the Haskell and R folks have all the fun?
% \href{http://www.haskell.org/haskellwiki/Literate_programming}{Literate
% Haskell} is a popular way to mix Haskell source code and \LTX
% documents. (Actually any kind of text or document, but here
% we're concerned only with \LTX.) You can even embed Haskell code in
% your document that writes part of your document for you. Similarly,
% the R statistical computing environment includes
% \href{http://tug.org/pracjourn/2008-1/zahn/}{Sweave}, which lets you
% do the same thing with R code and \LTX.
%
% The \ST package allows you to do (roughly) the same thing with the
% Sage mathematics software suite (see \url{http://sagemath.org}) and
% \LTX. (If you know how to write literate Haskell: the |\eval| command
% corresponds to |\sage|, and the |code| environment to the |sageblock|
% environment.) As a simple example, imagine in your document you are
% writing about how to count license plates with three letters and three
% digits. With this package, you can write something like this:
% \begin{quote}
% |There are $26$ choices for each letter, and $10$ choices for|\\
% |each digit, for a total of $26^3 \cdot 10^3 =|\\
% |\sage{26^3*10^3}$ license plates.|
% \end{quote}
% and it will produce
% \begin{quote}
% There are $26$ choices for each letter, and $10$ choices for each
% digit, for a total of $26^3 \cdot 10^3 = \sage{26^3 * 10^3}$ license
% plates.
% \end{quote}
% The great thing is, you don't have to do the multiplication. Sage does
% it for you. This process mirrors one of the great aspects of \LTX:
% when writing a \LTX document, you can concentrate on the logical
% structure of the document and trust \LTX and its army of packages to
% deal with the presentation and typesetting. Similarly, with \ST, you
% can concentrate on the mathematical structure (``I need the product of
% $26^3$ and $10^3$'') and let Sage deal with the base-$10$ presentation
% of the number.
%
% A less trivial, and perhaps more useful example is plotting. You can
% include a plot of the sine curve without manually producing a plot,
% saving an EPS or PDF file, and doing the |\includegraphics| business
% with the correct filename yourself. If you write this:
% \begin{quote}
% |Here is a lovely graph of the sine curve:|
%
% |\sageplot{plot(sin(x), x, 0, 2*pi)}|
% \end{quote}
% in your \LTX file, it produces
% \begin{quote}
% Here is a lovely graph of the sine curve:
%
% \sageplot{plot(sin(x), x, 0, 2*pi)}
% \end{quote}
% Again, you need only worry about the logical/mathematical structure of
% your document (``I need a plot of the sine curve over the interval
% $[0, 2\pi]$ here''), while \ST{} takes care of the gritty details of
% producing the file and sourcing it into your document.
%
% \paragraph{But \texttt{\bslash sageplot} isn't magic} I just tried to
% convince you that \ST makes putting nice graphics into your document
% very easy; let me turn around and warn you that using graphics
% \emph{well} is not easy, and no \LTX package or Python script will
% ever make it easy. What \ST does is make it easy to \emph{use Sage} to
% create graphics; it doesn't magically make your graphics good,
% appropriate, or useful. (For instance, look at the sine plot above---I
% would say that a truly lovely plot of the sine curve would not mark
% integer points on the $x$-axis, but rather $\pi/2$, $\pi$, $3\pi/2$,
% and $2\pi$.)
%
% Till Tantau has some good commentary on the use of graphics in
% \href{http://www.ctan.org/tex-archive/graphics/pgf/}{section 6 of the
% \textsc{pgf} manual}. You should always give careful thought and
% attention to creating graphics for your document; I have in mind that
% a good workflow for using \ST for plotting is something like this:
%
% \begin{enumerate}
% \item Figure out what sort of graphic you need to communicate your
% ideas or information.
% \item Fiddle around in Sage until you get a graphics object and set
% of options that produce the graphic you need.
% \item Copy those commands and options into \ST commands in your
% \LTX document.
% \end{enumerate}
%
% The \ST{} package's plotting capabilities don't help you find those
% Sage commands to make your lovely plot, but they do eliminate the need
% to muck around with saving the result to a file, remembering the
% filename, including it into your document, and so on. In
% \autoref{s:usage}, we will see what what we can do with \ST.
%
%
% \section{Installation}
% \changes{v2.0}{2009/01/14}{Fixed up installation section, final
% \emph{final} 2.0.}
%
% To install \ST, you need to do two things: make \ST known to Sage, and
% to \LTX. There are two basic methods to do those two things.
%
% \newcommand{\sageroot}{\$SAGE\_ROOT}
%
% In what follows, ``\texttt{\sageroot}'' refers to the root directory
% of your Sage installation.
%
% \subsection{As a Sage spkg}
% \label{sec:install-spkg}
%
% The easiest way to install \ST is by using Sage's own spkg
% installation facility; visit the
% \href{http://sagemath.org/packages/optional/}{optional packages page}
% and run \texttt{sage -i} with the appropriate version. This will let
% Sage know about \ST; you still need to let \LTX know about it.
%
% The simplest way to ``install'' \ST for \LTX is to copy the file
% |sagetex.sty| from \texttt{\sageroot/local/share/texmf} to the same
% directory as your document. This will always work, as \LTX always
% searches the current directory for files.
%
% Rather than make lots of copies of |sagetex.sty|, you can keep it (and
% the rest of the \ST documentation) in a |texmf| directory. The easiest
% thing to do is to create a |texmf| directory in your home directory
% and use the |texhash| utility so that your \TeX{} system can find the
% new files. See
% \href{http://www.tex.ac.uk/cgi-bin/texfaq2html?label=privinst}
% {\texttt{www.tex.ac.uk/cgi-bin/texfaq2html?label=privinst}} which
% describes the basic ideas, and also
% \href{http://www.tex.ac.uk/cgi-bin/texfaq2html?label=what-TDS}
% {\texttt{www.tex.ac.uk/cgi-bin/texfaq2html?label=what-TDS}} which has
% some information specific to MiK\TeX. Linux/Unix users can use
% |$HOME/texmf| and users of Mac\TeX{} should use |$HOME/Library/texmf|.
%
% To copy the files that \LTX needs into your |texmf| directory, simply
% do
% \begin{quote}
% \texttt{cp -r \sageroot/local/share/texmf/* \$HOMEPREFIX/texmf/}
% \end{quote}
% where |$HOMEPREFIX| is the appropriate prefix for your own |texmf|
% tree. Then you need to make \TeX{} aware of the new files by running
% \begin{quote}
% \texttt{texhash \$HOMEPREFIX/texmf/}
% \end{quote}
%
% \subsection{From CTAN}
% \label{sec:install-ctan}
%
% You can also get \ST from \href{http://tug.ctan.org/pkg/sagetex}{its
% CTAN page}. This is not the recommended way to get \ST, but it will
% work.
%
% If you get \ST from CTAN, you will need to make the |sagetex.sty| file
% available to \LTX using any of the methods described above, and you
% will also need to make |sagetex.py| known to Sage. You can either keep
% a copy of that file in the same directory as your document or put it
% where Sage will find it. You can use the |$SAGE_PATH| environment
% variable (which is analogous to the |$PYTHONPATH| variable) to tell
% Sage where the file is, or manually copy |sagetex.py| into
% \texttt{\sageroot/local/lib/python/site-packages}.
%
%
% \subsection{Using \TeX Shop}
% \label{sec:using-texshop}
% \changes{v2.0.1}{2009/03/10}{Add \TeX Shop info}
%
% Starting with version 2.25,
% \href{http://www.uoregon.edu/~koch/texshop/}{\TeX Shop} includes
% support for \ST. If you move the file |sage.engine| from
% |~/Library/TeXShop/Engines/Inactive/Sage| to
% |~/Library/TeXShop/Engines| and put the line
% \begin{quotation}
% |%!TEX TS-program = sage|
% \end{quotation}
% at the top of your document, then \TeX Shop will automatically run Sage
% for you when compiling your document.
%
% Note that you will need to make |sagetex.sty| and |sagetex.py| known
% to \LTX and Sage using any of the methods described above (although
% note that \TeX Shop includes copies of these files for you). You also
% might need to edit the |sage.engine| script to reflect the location of
% your Sage installation.
%
% \subsection{Other scripts included with \ST}
% \label{sec:inst-other-scripts}
%
% \ST includes several Python files which may be useful for working with
% ``\ST-ified'' documents: |makestatic.py| and |extractsagecode.py| are
% convenience scripts that you can use after you've written your
% document. See \autoref{sec:makestatic} and
% \autoref{sec:extractsagecode} for information on using those scripts.
% The file |sagetexparse.py| is a module used by both those scripts.
% These three files are independent of \ST. If you install from a spkg,
% these scripts can be found in \texttt{\sageroot/local/share/texmf/}.
%
% \section{Usage} \label{s:usage}
%
% Let's begin with a rough description of how \ST works. Naturally the
% very first step is to put |\usepackage{sagetex}| in the preamble of
% your document. When you use macros from this package and run \LTX on
% your file, along with the usual zoo of auxiliary files, a |.sage| file
% is written with the same basename as your document. This is a Sage
% source file that uses the Python module from this package and when you
% run Sage on that file, it will produce a |.sout| file. That file
% contains \LTX code that, when you run \LTX on your source file again,
% will pull in all the results of Sage's computation.
%
% All you really need to know is that to typeset your document, you need
% to run \LTX, then run Sage, then run \LTX again.
%
% Also keep in mind that everything you send to Sage is done within one
% Sage session. This means you can define variables and reuse them
% throughout your \LTX document; if you tell Sage that |foo| is
% $12$, then anytime afterwards you can use |foo| in your Sage code and
% Sage will remember that it's $12$---just like in a regular Sage
% session.
%
% Now that you know that, let's describe what macros \ST provides and
% how to use them. If you are the sort of person who can't be bothered
% to read documentation until something goes wrong, you can also just
% look through the |example.tex| file included with this
% package.\footnote{Then again, if you're such a person, you're probably
% not reading this, and are already fiddling with
% \texttt{example.tex}\dots}\\
%
% \noindent\fbox{\parbox{.97\textwidth}{\textbf{WARNING!} When you run
% \LTX on a file named \texttt{\meta{filename}.tex}, the file
% \texttt{\meta{filename}.sage} is created---and will be
% \emph{automatically overwritten} if it already exists. If you keep
% Sage scripts in the same directory as your \ST-ified \LTX
% documents, use a different file name!}}
%
% \paragraph{The final option} On a similar note, \ST, like many \LTX
% packages, accepts the |final| option. When passed this option, either
% directly in the |\usepackage| line, or from the |\documentclass| line,
% \ST will not write a |.sage| file. It will try to read in the |.sout|
% file so that the \ST macros can pull in their results. However, this
% will not allow you to have an independent Sage script with the same
% basename as your document, since to get the |.sout| file, you need the
% |.sage| file.
%
% \subsection{Inline Sage}
%
% \DescribeMacro{\sage}
% \fbox{\texttt{\bslash sage}\marg{Sage code}}
% takes whatever Sage code you give it, runs Sage's |latex| function on
% it, and puts the result into your document.
%
% For example, if you do |\sage{matrix([[1, 2], [3,4]])^2}|, then that
% macro will get replaced by
% \begin{quote}
% |\left(\begin{array}{rr}|\\
% |7 & 10 \\|\\
% |15 & 22|\\
% |\end{array}\right)|
% \end{quote}
% in your document---that \LTX code is exactly exactly what you get
% from doing
% \begin{center}
% |latex(matrix([[1, 2], [3,4]])^2)|
% \end{center}
% in Sage.
%
% Note that since \LTX will do macro expansion on whatever you give
% to |\sage|, you can mix \LTX variables and Sage variables! If
% you have defined the Sage variable |foo| to be $12$ (using, say, the
% |sageblock| environment), then you can do something like this:
% \begin{quote}
% |The prime factorization of the current page number plus foo|\\
% |is $\sage{factor(foo + \thepage)}$|.
% \end{quote}
% Here, I'll do just that right now: the prime factorization of the
% current page number plus $12$ is $\sage{factor(\thepage + 12)}$.
% (Wrong answer? See footnote.\footnote{Is the above factorization
% wrong? If the current page number plus $12$ is one larger than the
% claimed factorization, you need to do another Sage/\LTX cycle on
% this source file. Why? The first time you run \LTX on this file, the
% sine graph isn't available, so the text where I've talked about the
% prime factorization is back one page. Then you run Sage, and it
% creates the sine graph and does the factorization. When you run \LTX
% again, the sine graph pushes the text onto the next page, but it
% uses the Sage-computed value from the previous page. Meanwhile, the
% |.sage| file has been rewritten with the correct page number, so if
% you do another Sage/\LTX cycle, you'll get the correct value
% above.}) The |\sage| command doesn't automatically use math mode for
% its output, so be sure to use dollar signs or a displayed math
% environment
% as appropriate.\\
%
% \DescribeMacro{\percent} If you are doing modular arithmetic or string
% formatting and need a percent sign in a call to |\sage| (or
% |\sageplot|), you can use |\percent|. Using a bare percent sign won't
% work because \LTX will think you're starting a comment and get
% confused; prefixing the percent sign with a backslash won't work
% because then ``|\%|'' will be written to the |.sage| file and Sage
% will get confused. The |\percent| macro makes everyone happy.
%
% Note that using |\percent| inside the verbatim-like environments
% described in \autoref{s:codeblockenv} isn't necessary; a literal
% ``\percent'' inside such an environment will get written, uh, verbatim
% to the |.sage| file.
%
% \subsection{Graphics and plotting}
%
% \noindent \DescribeMacro{\sageplot}
% \fbox{\texttt{\bslash sageplot}\oarg{ltx opts}\oarg{fmt}\{\meta{graphics
% obj}, \meta{keyword args}\}}
% plots the given Sage graphics object and runs an
% |\includegraphics| command to put it into your document. It does not
% have to actually be a plot of a function; it can be any Sage graphics
% object. The options are described in \autoref{t:sageplotopts}.
%
% \begin{table}[h]
% \centering
% \begin{tabular}{l p{8cm}}
% Option & Description \\
% \hline
% \meta{ltx options} & Any text here is passed directly into the
% optional arguments (between the square brackets) of an
% |\includegraphics| command. If not specified,
% ``|width=.75\textwidth|'' will be used.\\
% \meta{fmt} & You can optionally specify a file extension here; Sage
% will then try to save the graphics object to a file with extension
% \emph{fmt}. If not specified, \ST\ will save to EPS and PDF files.\\
% \meta{graphics obj} & A Sage object on which you can call |.save()|
% with a graphics filename.\\
% \meta{keyword args} & Any keyword arguments you put here will
% all be put into the call to |.save()|.
% \end{tabular}
% \caption{Explanation of options for the \texttt{\bslash sageplot}
% command.}
% \label{t:sageplotopts}
% \end{table}
%
% This setup allows you to control both the Sage side of things, and the
% \LTX side. For instance, the command
% \begin{quote}
% |\sageplot[angle=30, width=5cm]{plot(sin(x), 0, pi), axes=False,|\\
% |chocolate=True}|
% \end{quote}
% will run the following command in Sage:
% \begin{quote}
% |sage: plot(sin(x), 0, pi).save(filename=autogen, axes=False,|\\
% |chocolate=True)|
% \end{quote}
% Then, in your \LTX file, the following command will be issued
% automatically:
% \begin{center}
% |\includegraphics[angle=30, width=5cm]{autogen}|
% \end{center}
% You can specify a file format if you like. This must be the
% \emph{second} optional argument, so you must use empty brackets if
% you're not passing anything to |\includegraphics|:
% \begin{center}
% |\sageplot[][png]{plot(sin(x), x, 0, pi)}|
% \end{center}
% The filename is automatically generated, and unless you specify a
% format, both EPS and PDF files will be generated. This allows you to
% freely switch between using, say, a DVI viewer (many of which have
% support for automatic reloading, source specials and make the writing
% process easier) and creating PDFs for posting on the web or emailing
% to colleagues.
%
% If you ask for, say, a PNG file, keep in mind that ordinary |latex|
% and DVI files have no support for PNG files; \ST detects this and will
% warn you that it cannot find a suitable file if using
% |latex|.\footnote{We use a typewriter font here to indicate the
% executables which produce DVI and PDF files, respectively, as
% opposed to ``\LTX'' which refers to the entire typesetting system.}
% If you use |pdflatex|, there will be no problems because PDF files can
% include PNG graphics.
%
% When \ST cannot find a graphics file, it inserts this into your
% document:
%
% \begin{center}
% \framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}
% \end{center}
%
% \noindent That's supposed to resemble the image-not-found graphics
% used by web browsers and use the traditional ``\textbf{??}'' that \LTX
% uses to indicate missing references.
%
% You needn't worry about the filenames; they are automatically
% generated and will be put into the directory
% |sage-plots-for-filename.tex|. You can safely delete that directory
% anytime; if \ST can't find the files, it will warn you to run Sage to
% regenerate them.\\
%
% \noindent\fbox{\parbox{.97\textwidth}{\textbf{WARNING!} When you run
% Sage on your |.sage| file, all files in the
% \texttt{sage-plots-for-\meta{filename}.tex} directory \emph{will be
% deleted!} Do not put any files into that directory that you do not
% want to get automatically deleted.}}
%
% \paragraph{The epstopdf option} One of the graphics-related options
% supported by \ST is |epstopdf|. This option causes \ST to use the
% |epstopdf| command to convert EPS files into PDF files. Like with the
% |imagemagick| option, it doesn't check to see if the |epstopdf|
% command exists or add options: it just runs the command. This option
% was motivated by a bug in the matplotlib PDF backend which caused it
% to create invalid PDFs. Ideally, this option should never be
% necessary; if you do need to use it, file a bug!
%
% \subsubsection{3D plotting}
%
% Right now there is, to put it nicely, a bit of tension between the
% sort of graphics formats supported by |latex| and |pdflatex|, and the
% graphics formats supported by Sage's 3D plotting systems. \LTX is
% happiest, and produces the best output, with EPS and PDF files, which
% are vector formats. Tachyon, Sage's 3D plotting system, produces
% bitmap formats like BMP and PNG.
%
% Because of this, when producing 3D plots with |\sageplot|, \emph{you
% must specify a file format}. The PNG format is compressed and lossless
% and is by far the best choice, so use that whenever possible. (Right
% now, it is always possible.) If you do not specify a file format, or
% specify one that Tachyon does not understand, it will produce files in
% the Targa format with an incorrect extension and \LTX (both |latex|
% and |pdflatex|) will be profoundly confused. Don't do that.
%
% Since |latex| does not support PNGs, when using 3D plotting (and
% therefore a bitmap format like PNG), \ST will always issue a warning
% about incompatible graphics if you use |latex|, provided you've
% processed the |.sage| file and the PNG file exists. The only exception
% is if you're using the |imagemagick| option below. (Running |pdflatex|
% on the same file will work, since PDF files can include PNG files.)
%
% \paragraph{The imagemagick option} As a response to the above issue,
% the \ST package has an |imagemagick| option. If you specify this
% option in the preamble of your document with the usual
% ``|\usepackage[imagemagick]{sagetex}|'', then when you are compiling
% your document using |latex|, any |\sageplot| command which requests a
% non-default format will cause the \ST Python script to convert the
% resulting file to EPS using the Imagemagick |convert| utility. It does
% this by executing ``|convert filename.EXT filename.eps|'' in a
% subshell. It doesn't add any options, check to see if the |convert|
% command exists or belongs to Imagemagick---it just runs the command.
%
% The resulting EPS files are not very high quality, but they will work.
% This option is not intended to produce good graphics, but to allow you
% to see your graphics when you use |latex| and DVI files while writing
% your document.
%
% \subsubsection{But that's not good enough!} \label{s:notgoodenough}
%
% The |\sageplot| command tries to be both flexible and easy to use, but
% if you are just not happy with it, you can always do things manually:
% inside a |sagesilent| environment (see the next section) you could do
% \begin{quote}
% |your special commands|\\
% |x = your graphics object|\\
% |x.save(filename=myspecialfile.ext, options, etc)|
% \end{quote}
% and then, in your source file, do your own |\includegraphics| command.
% The \ST package gives you full access to Sage and Python and doesn't
% turn off anything in \LTX, so you can always do things manually.
%
% \subsection{Verbatim-like environments}
% \label{s:codeblockenv}
%
% The \ST package provides several environments for typesetting and
% executing blocks of Sage code.\\
%
% \DescribeEnv{sageblock} Any text between |\begin{sageblock}| and
% |\end{sageblock}| will be typeset into your file, and also written into
% the |.sage| file for execution. This means you can do something like
% this:
% \begin{quote}
% |\begin{sageblock}|\\
% | var('x')|\\
% | f = sin(x) - 1|\\
% | g = log(x)|\\
% | h = diff(f(x) * g(x), x)|\\
% |\end{sageblock}|
% \end{quote}
% and then anytime later write in your source file
% \begin{quote}
% |We have $h(2) = \sage{h(2)}$, where $h$ is the derivative of|\\
% |the product of $f$ and $g$.|
% \end{quote}
% and the |\sage| call will get correctly replaced by $\sage{
% diff((sin(x) - 1)*log(x), x)(1)}$. You can use any Sage or Python
% commands inside a |sageblock|; all the commands get sent directly to
% Sage.\\
%
% \iffalse meta-comment
% Sadly, we can't use sageblock or similar environments in this file!
% If you prefix the lines inside the environment with percent signs,
% then those percent signs get written to your .sage file. If you
% *don't* prefix the lines with percent signs, those lines get written
% into the .sty or .py file. It's just too tricky to get docstrip and
% the verbatim stuff to play nicely together. I'd have to redefine how
% those environments work, and get them to strip off initial percents.
% \fi
%
% \DescribeEnv{sagesilent} This environment is like |sageblock|, but it
% does not typeset any of the code; it just writes it to the |.sage|
% file. This is useful if you have to do some setup in Sage that is not
% interesting or relevant to the document you are writing.\\
%
% \DescribeEnv{sageverbatim} This environment is the opposite of the one
% above: whatever you type will be typeset, but not written into the
% |.sage| file. This allows you to typeset psuedocode, code that will
% fail, or take too much time to execute, or whatever.\\
%
% \DescribeEnv{comment} Logically, we now need an environment that
% neither typesets nor executes your Sage code\ldots but the |verbatim|
% package, which is always loaded when using \ST, provides such an
% environment: |comment|. Another way to do this is to put stuff between
% |\iffalse| and |\fi|.\\
%
% \DescribeMacro{\sagetexindent} There is one final bit to our
% verbatim-like environments: the indentation. The \ST package defines a
% length |\sagetexindent|, which controls how much the Sage code is
% indented when typeset. You can change this length however you like
% with |\setlength|: do |\setlength{\sagetexindent}{6ex}| or whatever.
%
%
% \section{Other notes}
%
% Here are some other notes on using \ST.
%
% \paragraph{Using Beamer} The \textsc{beamer} package does not play
% nicely with verbatim-like environments unless you ask it to. To use
% code block environments in a \textsc{beamer} presentation, do:
% \begin{quote}
% |\begin{frame}[fragile]|\\
% |\begin{sageblock}|\\
% |# sage stuff|\\
% |# more stuff \end{sageblock}|\\
% |\end{frame}|\\
% \end{quote}
% For some reason, \textsc{beamer} inserts an extra line break at the
% end of the environment; if you put the |\end{sageblock}| on the same
% line as the last line of your code, it works properly. See section
% 12.9, ``Verbatim and Fragile Text'', in the \textsc{beamer} manual.
%
% Thanks to Franco Saliola for reporting this.
%
% \paragraph{Plotting from Mathematica, Maple, etc.} Sage can use
% Mathematica, Maple, and friends and can tell them to do plotting, but
% since it cannot get those plots into a Sage graphics object, you
% cannot use |\sageplot| to use such graphics. You'll need to use the
% method described in ``But that's not good enough!''
% (\hyperref[s:notgoodenough]{page~\pageref*{s:notgoodenough}}) with
% some additional bits to get the directory right---otherwise your file
% will get saved to someplace in a hidden directory.
%
% For Mathematica, you can do something like this inside a |sagesilent|
% or |sageblock| environment:
% \begin{quote}
% |mathematica('myplot = commands to make your plot')|\\
% |mathematica('Export["%s/graphicsfile.eps", myplot]' % os.getcwd())|
% \end{quote}
% then put |\includegraphics[opts]{graphicsfile}| in your file.
%
% For Maple, you'll need something like
% \begin{quote}
% |maple('plotsetup(ps, plotoutput=`%s/graphicsfile.eps`, \|\\
% | plotoptions=`whatever`);' % os.getcwd())|\\
% |maple('plot(function, x=1..whatever);')|
% \end{quote}
% and then |\includegraphics| as necessary.
%
% These interfaces, especially when plotting, can be finicky. The above
% commands are just meant to be a starting point.
%
% \subsection{Sending \ST files to others who don't use Sage}
% \label{sec:makestatic}
%
% What can you do when sending a \LTX document that uses \ST to a
% colleague who doesn't use Sage?\footnote{Or who cannot use Sage, since
% currently \ST is not very useful on Windows.} The best option is to
% bring your colleague into the light and get him or her using Sage! But
% this may not be feasible, because some (most?) mathematicians are
% fiercely crotchety about their choice of computer algebra system, or
% you may be sending a paper to a journal or the arXiv, and such places
% will not run Sage just so they can typeset your paper---at least not
% until Sage is much closer to its goal of world domination.
%
% How can you send your \ST-enabled document to someone else who doesn't
% use Sage? The easiest way is to simply include with your document the
% following files:
% \begin{enumerate}
% \item |sagetex.sty|
% \item the generated |.sout| file
% \item the \texttt{sage-plots-for-\meta{filename}.tex} directory and
% its contents
% \end{enumerate}
% As long as |sagetex.sty| is available, your document can be typeset
% using any reasonable \LTX system. Since it is very common to include
% graphics files with a paper submission, this is a solution that should
% always work. (In particular, it will work with arXiv submissions.)
%
% There is another option, and that is to use the |makestatic.py| script
% included with \ST.
%
% Use of the script is quite simple. Copy it and |sagetexparse.py| to
% the directory with your document, and run
% \begin{quote}
% |python makestatic.py inputfile [outputfile]|
% \end{quote}
% where |inputfile| is your document. (You can also set the executable
% bit of |makestatic.py| and use |./makestatic.py|.) This script needs
% the \href{http://pyparsing.wikispaces.com}{pyparsing} module to be
% installed.\footnote{If you don't have pyparsing installed, you can
% simply copy the file
% \texttt{\sageroot/local/lib/python/matplotlib/pyparsing.py} into
% your directory.} You may optionally specify |outputfile|; if you do
% so, the results will be written to that file. If the file exists, it
% won't be overwritten unless you also specify the |-o| switch.
%
% You will need to run this after you've compiled your document and run
% Sage on the |.sage| file. The script reads in the |.sout| file and
% replaces all the calls to |\sage| and |\sageplot| with their plain
% \LTX equivalent, and turns the |sageblock| and |sageverbatim|
% environments into |verbatim| environments. Any |sagesilent|
% environment is turned into a |comment| environment. The resulting
% document should compile to something identical, or very nearly so, to
% the original file.
%
% The parsing that |makestatic.py| does is pretty good, but not perfect.
% Right now it doesn't support having a comma-separated list of
% packages, so you can't have |\usepackage{sagetex, foo}|. You need to
% have just |\usepackage{sagetex}|. (Along with package options; those
% are handled correctly.) If you find other parsing errors, please let
% me know.
%
% \subsection{Extracting the Sage code from a document}
% \label{sec:extractsagecode}
%
% This next script is probably not so useful, but having done the above,
% this was pretty easy. The |extractsagecode.py| script does the
% opposite of |makestatic.py|, in some sense: given a document, it
% extracts all the Sage code and removes all the \LTX.
%
% Its usage is the same as |makestatic.py|.
%
% Note that the resulting file will almost certainly \emph{not} be a
% runnable Sage script, since there might be \LTX commands in it, the
% indentation may not be correct, and the plot options just get written
% verbatim to the file. Nevertheless, it might be useful if you just
% want to look at the Sage code in a file.
%
%
% \StopEventually{}
%
% \section{Implementation}
%
% There are two pieces to this package: a \LTX style file, and a
% Python module. They are mutually interdependent, so it makes sense to
% document them both here.
%
% \subsection{The style file}
%
% \iffalse
% tell docstrip to put code into the .sty file
%<*latex>
% \fi
%
% All macros and counters intended for use internal to this package
% begin with ``|ST@|''.
%
% \subsubsection{Initialization}
%
% Let's begin by loading some packages. The key bits of |sageblock| and
% friends are stol---um, adapted from the |verbatim| package manual. So
% grab the |verbatim| package.
% \begin{macrocode}
\RequirePackage{verbatim}
% \end{macrocode}
% Unsurprisingly, the |\sageplot| command works poorly without graphics
% support.
% \begin{macrocode}
\RequirePackage{graphicx}
% \end{macrocode}
% The |makecmds| package gives us a |\provideenvironment| which we need,
% and we use |ifpdf| and |ifthen| in |\sageplot| so we know what kind of
% files to look for.
% \begin{macrocode}
\RequirePackage{makecmds}
\RequirePackage{ifpdf}
\RequirePackage{ifthen}
% \end{macrocode}
%
% Next set up the counters and the default indent.
% \begin{macrocode}
\newcounter{ST@inline}
\newcounter{ST@plot}
\setcounter{ST@inline}{0}
\setcounter{ST@plot}{0}
\newlength{\sagetexindent}
\setlength{\sagetexindent}{5ex}
% \end{macrocode}
% Set up the file stuff, which will get run at the beginning of the
% document, after we know what's happening with the |final| option.
% First, we open the |.sage| file:
% \begin{macrocode}
\AtBeginDocument{\@ifundefined{ST@final}{%
\newwrite\ST@sf%
\immediate\openout\ST@sf=\jobname.sage%
% \end{macrocode}
% \begin{macro}{\ST@wsf}
% We will write a lot of stuff to that file, so make a convenient
% abbreviation, then use it to put the initial commands into the
% |.sage| file. The hash mark below gets doubled when written to the
% file, for some obscure reason related to parameter expansion. It's
% valid Python, though, so I haven't bothered figuring out how to get
% a single hash. We are assuming that the extension is |.tex|; see the
% |initplot| documentation on page~\pageref{initplot} for discussion
% of file extensions. The ``|(\jobname.sage)|'' business is there
% because the comment below will get pulled into the autogenerated
% |.py| file (second order autogeneration!) and I'd like to reduce
% possible confusion if someone is looking around in those files.
% \begin{macrocode}
\newcommand{\ST@wsf}[1]{\immediate\write\ST@sf{#1}}%
\ST@wsf{# This file (\jobname.sage) was *autogenerated* from the file \jobname.tex.}%
\ST@wsf{import sagetex}%
\ST@wsf{_st_ = sagetex.SageTeXProcessor('\jobname')}}%
% \end{macrocode}
% On the other hand, if the |ST@final| flag is set, don't bother with
% any of the file stuff, and make |\ST@wsf| a no-op.
% \begin{macrocode}
{\newcommand{\ST@wsf}[1]{\relax}}}
% \end{macrocode}
% \end{macro}
% Now we declare our options, which mostly just set flags that we check
% at the beginning of the document, and when running the |.sage| file.
% \changes{v2.0}{2008/04/04}{Add \texttt{epstopdf} option}
% \changes{v2.0}{2008/12/16}{Add \texttt{final} option}
%
% The |final| option controls whether or not we write the |.sage| file;
% the |imagemagick| and |epstopdf| options both want to write something
% to that same file. So we put off all the actual file stuff until the
% beginning of the document---by that time, we'll have processed the
% |final| option (or not) and can check the |\ST@final| flag to see what
% to do. (We must do this because we can't specify code that runs if an
% option \emph{isn't} defined.)
%
% For |final|, we set a flag for other guys to check, and if there's no
% |.sout| file, we warn the user that something fishy is going on.
% \begin{macrocode}
\DeclareOption{final}{%
\newcommand{\ST@final}{x}%
\IfFileExists{\jobname.sout}{}{\AtEndDocument{\PackageWarningNoLine{sagetex}%
{`final' option provided, but \jobname.sout^^Jdoesn't exist! No Sage
input will appear in your document. Remove the `final'^^Joption and
rerun LaTeX on your document}}}}
% \end{macrocode}
% For |imagemagick|, we set two flags: one for \LTX and one for Sage.
% It's important that we set |ST@useimagmagick| \emph{before} the
% beginning of the document, so that the graphics commands can check
% that. We do wait until the beginning of the document to do file
% writing stuff.
% \begin{macrocode}
\DeclareOption{imagemagick}{%
\newcommand{\ST@useimagemagick}{x}%
\AtBeginDocument{%
\@ifundefined{ST@final}{%
\ST@wsf{_st_.useimagemagick = True}}{}}}
% \end{macrocode}
% For |epstopdf|, we just set a flag for Sage. Then, process the options.
% \begin{macrocode}
\DeclareOption{epstopdf}{%
\AtBeginDocument{%
\@ifundefined{ST@final}{%
\ST@wsf{_st_.useepstopdf = True}}{}}}
\ProcessOptions\relax
% \end{macrocode}
% The |\relax| is a little incantation suggested by the ``\LaTeXe{} for
% class and package writers'' manual, section 4.7.
%
% Pull in the |.sout| file if it exists, or do nothing if it doesn't. I
% suppose we could do this inside an |AtBeginDocument| but I don't see
% any particular reason to do that. It will work whenever we load it.
% \begin{macrocode}
\InputIfFileExists{\jobname.sout}{}{}
% \end{macrocode}
%
% \subsubsection{The \texttt{\bslash sage} macro}
% \label{sec:sagemacro}
%
% \begin{macro}{\sage}
% This macro combines |\ref|, |\label|, and Sage all at once. First, we
% use Sage to get a \LTX representation of whatever you give this
% function. The Sage script writes a |\newlabel| line into the |.sout|
% file, and we read the output using the |\ref| command. Usually, |\ref|
% pulls in a section or theorem number, but it will pull in arbitrary
% text just as well.
%
% The first thing it does it write its argument into the |.sage| file,
% along with a counter so we can produce a unique label. We wrap a
% try/except around the function call so that we can provide a more
% helpful error message in case something goes wrong. (In particular, we
% can tell the user which line of the |.tex| file contains the offending
% code.) We can use |^^J| to put linebreaks into the |.sage| file, but
% \LTX wants to put a space after that, which is why we don't put the
% ``except'' on its own line here in the source.
% \begin{macrocode}
\newcommand{\sage}[1]{\ST@wsf{%
try:^^J
_st_.inline(\theST@inline, #1)^^Jexcept:^^J
_st_.goboom(\the\inputlineno)}%
% \end{macrocode}
% The |inline| function of the Python module is documented on page
% \pageref{inlinefn}.
%
% Our use of |\newlabel| and |\ref| seems awfully clever until you load
% the |hyperref| package, which gleefully tries to hyperlink the hell
% out of everything. This is great until it hits one of our special
% |\newlabel|s and gets deeply confused. Fortunately the |hyperref|
% folks are willing to accomodate people like us, and give us a
% |NoHyper| environment.
% \begin{macrocode}
\begin{NoHyper}\ref{@sageinline\theST@inline}\end{NoHyper}%
% \end{macrocode}
% Now check if the label has already been defined. (The internal
% implementation of labels in \LTX involves defining a macro called
% ``|r@@labelname|''.) If it hasn't, we set a flag so that we can tell
% the user to run Sage on the |.sage| file at the end of the run.
% Finally, step the counter.
% \begin{macrocode}
\@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{}%
\stepcounter{ST@inline}}
% \end{macrocode}
% \end{macro}
% The user might load the |hyperref| package after this one (indeed, the
% |hyperref| documentation insists that it be loaded last) or not at
% all---so when we hit the beginning of the document, provide a dummy
% |NoHyper| environment if one hasn't been defined by the |hyperref|
% package.
% \begin{macrocode}
\AtBeginDocument{\provideenvironment{NoHyper}{}{}}
% \end{macrocode}
%
% \begin{macro}{\percent}
% A macro that inserts a percent sign. This is more-or-less stolen from the
% \textsf{Docstrip} manual; there they change the catcode inside a group
% and use |gdef|, but here we try to be more \LaTeX y and use
% |\newcommand|.
% \begin{macrocode}
\catcode`\%=12
\newcommand{\percent}{%}
\catcode`\%=14
% \end{macrocode}
% \end{macro}
%
% \subsubsection{The \texttt{\bslash sageplot} macro and friends}
% \label{sec:sageplotmacro}
%
% Plotting is rather more complicated, and requires several helper
% macros that accompany |\sageplot|.
%
% \begin{macro}{\ST@plotdir}
% A little abbreviation for the plot directory. We don't use
% |\graphicspath| because it's
% \href{http://www.tex.ac.uk/cgi-bin/texfaq2html?label=graphicspath}{
% apparently slow}---also, since we know right where our plots are
% going, no need to have \LTX looking for them.
% \begin{macrocode}
\newcommand{\ST@plotdir}{sage-plots-for-\jobname.tex}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ST@missingfilebox}
% The code that makes the ``file not found'' box. This shows up in a
% couple places below, so let's just define it once.
% \begin{macrocode}
\newcommand{\ST@missingfilebox}{\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\sageplot}
% \changes{v1.3}{2008/03/08}{Iron out warnings, cool \TikZ flowchart}
% This function is similar to |\sage|. The neat thing that we take
% advantage of is that commas aren't special for arguments to \LTX
% commands, so it's easy to capture a bunch of keyword arguments that
% get passed right into a Python function.
%
% This macro has two optional arguments, which can't be defined using
% \LTX's |\newcommand|; we use Scott Pakin's brilliant
% \href{http://tug.ctan.org/tex-archive/support/newcommand/}{|newcommand|}
% package to create this macro; the options I fed to his script were
% similar to this:
%\begin{center}
% |MACRO sageplot OPT[#1={width}] OPT[#2={notprovided}] #3|
%\end{center}
% Observe that we are using a Python script to write \LTX code which
% writes Python code which writes \LTX code. Crazy!
%
% Here's the wrapper command which does whatever magic we need to get
% two optional arguments.
% \begin{macrocode}
\newcommand{\sageplot}[1][width=.75\textwidth]{%
\@ifnextchar[{\ST@sageplot[#1]}{\ST@sageplot[#1][notprovided]}}
% \end{macrocode}
% The first optional argument |#1| will get shoved right into the
% optional argument for |\includegraphics|, so the user has easy control
% over the \LTX aspects of the plotting. We define a default size of
% $3/4$ the textwidth, which seems reasonable. (Perhaps a future version
% of \ST will allow the user to specify in the package options a set of
% default options to be used throughout.) The second optional argument
% |#2| is the file format and allows us to tell what files to look for.
% It defaults to ``notprovided'', which tells the Python module to
% create EPS and PDF files. Everything in |#3| gets put into the Python
% function call, so the user can put in keyword arguments there which
% get interpreted correctly by Python.
%
% \begin{macro}{\ST@sageplot}
% \changes{v2.0}{2008/12/16}{Change to use only keyword arguments: see issue
% 2 on bitbucket tracker}
% Let's see the real code here. We write a
% couple lines to the |.sage| file, including a counter, input line
% number, and all of the mandatory argument; all this is wrapped in
% another try/except.
% \begin{macrocode}
\def\ST@sageplot[#1][#2]#3{\ST@wsf{%
try:^^J
_st_.plot(\theST@plot, format='#2', _p_=#3)^^Jexcept:^^J
_st_.goboom(\the\inputlineno)}%
% \end{macrocode}
% The Python |plot| function is documented on page~\pageref{plotfn}.
%
% Now we include the appropriate graphics file. Because the user might
% be producing DVI or PDF files, and have supplied a file format or not,
% and so on, the logic we follow is a bit complicated.
% \autoref{f:sageplottree} shows what we do; for completeness---and
% because I think drawing trees with \TikZ is really cool---we show what
% |\ST@inclgrfx| does in \autoref{f:stig}. This entire complicated
% business is intended to avoid doing an |\includegraphics| command on a
% file that doesn't exist, and to issue warnings appropriate to the
% situation.
%
% \begin{figure}
% \centering
% \begin{tikzpicture}
% \tikzstyle{level 1}=[sibling distance=6cm]
% \tikzstyle{level 2}=[sibling distance=3cm]
% \node [box] {DVI or PDF?}
% child {node [box] {Format provided?}
% child {node [box] {STig EPS}
% edge from parent node[left] {no}}
% child {node [box] {IM option set?}
% child {node [box, text width=3cm] {Warn that DVI + PNG = bad}
% edge from parent node[left] {no}}
% child {node [box] {STig EPS}
% edge from parent node[right] {yes}}
% edge from parent node[right] {yes}}
% edge from parent node[left] {DVI}}
% child {node [box] {Format provided?}
% child {node [box] {STig PDF}
% edge from parent node[left] {no}}
% child {node [box] {STig \texttt{\#2}}
% edge from parent node[right] {yes}}
% edge from parent node[right] {PDF}};
% \end{tikzpicture}
% \caption{The logic tree that \texttt{\bslash sageplot} uses to
% decide whether to run \texttt{\bslash includegraphics} or to yell at
% the user. ``Format'' is the \texttt{\#2} argument to \texttt{\bslash
% sageplot}, ``STig ext''
% means a call to \texttt{\bslash ST@inclgrfx} with ``ext'' as the
% second argument, and ``IM'' is Imagemagick.}
% \label{f:sageplottree}
% \end{figure}
%
% If we are creating a PDF, we check to see if the user asked for a
% different format, and use that if necessary:
% \begin{macrocode}
\ifpdf
\ifthenelse{\equal{#2}{notprovided}}%
{\ST@inclgrfx{#1}{pdf}}%
{\ST@inclgrfx{#1}{#2}}%
% \end{macrocode}
% Otherwise, we are creating a DVI file, which only supports EPS. If the
% user provided a format anyway, don't include the file (since it won't
% work) and warn the user about this. (Unless the file doesn't exist, in
% which case we do the same thing that |\ST@inclgrfx| does.)
% \begin{macrocode}
\else
\ifthenelse{\equal{#2}{notprovided}}%
{\ST@inclgrfx{#1}{eps}}%
% \end{macrocode}
% If a format is provided, we check to see if we're using the
% imagemagick option. If not, we're going to issue some sort of warning,
% depending on whether the file exists yet or not.
% \begin{macrocode}
{\@ifundefined{ST@useimagemagick}%
{\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}%
{\ST@missingfilebox%
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space
cannot be used with DVI output. Use pdflatex or create an EPS
file. Plot command is}}%
{\ST@missingfilebox%
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space
does not exist. Plot command is}%
\gdef\ST@rerun{x}}}%
% \end{macrocode}
% Otherwise, we are using Imagemagick, so try to include an EPS file
% anyway.
% \begin{macrocode}
{\ST@inclgrfx{#1}{eps}}}%
\fi
% \end{macrocode}
% Finally, step the counter and we're done.
% \begin{macrocode}
\stepcounter{ST@plot}}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ST@inclgrfx}
% This command includes the requested graphics file (|#2| is the
% extension) with the requested options (|#1|) if the file exists. Note
% that it just needs to know the extension, since we use a counter for
% the filename.
% \begin{macrocode}
\newcommand{\ST@inclgrfx}[2]{%
\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}%
{\includegraphics[#1]{\ST@plotdir/plot-\theST@plot.#2}}%
% \end{macrocode}
% If the file doesn't exist, we insert a little box to indicate it
% wasn't found, issue a warning that we didn't find a graphics file,
% then set a flag that, at the end of the run, tells the user to run
% Sage again.
% \begin{macrocode}
{\ST@missingfilebox%
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space does not
exist. Plot command is}%
\gdef\ST@rerun{x}}}
% \end{macrocode}
% \autoref{f:stig} makes this a bit clearer.
% \begin{figure}
% \centering
% \begin{tikzpicture}
% \tikzstyle{level 1}=[sibling distance=4cm]
% \node [box] {Does EXT file exist?}
% child {node [box, text width = 2.125cm] {Warn user to rerun Sage}
% edge from parent node[left] {no}}
% child {node [box] {Use \texttt{includegraphics}}
% edge from parent node[right] {yes}};
% \end{tikzpicture}
% \caption{The logic used by the \texttt{\bslash ST@inclgrfx}
% command.}
% \label{f:stig}
% \end{figure}
% \end{macro}
%
% \subsubsection{Verbatim-like environments}
% \label{sec:verbatim-envs}
%
% \begin{macro}{\ST@beginsfbl}
% This is ``begin |.sage| file block'', an internal-use abbreviation
% that sets things up when we start writing a chunk of Sage code to
% the |.sage| file. It begins with some \TeX{} magic that fixes
% spacing, then puts the start of a try/except block in the |.sage|
% file---this not only allows the user to indent code without
% Sage/Python complaining about indentation, but lets us tell the user
% where things went wrong. The |blockbegin| and |blockend| functions
% are documented on page~\pageref{blocksbeginend}. The last bit is some
% magic from the |verbatim| package manual that makes \LTX respect
% line breaks.
% \begin{macrocode}
\newcommand{\ST@beginsfbl}{%
\@bsphack\ST@wsf{%
_st_.blockbegin()^^Jtry:}%
\let\do\@makeother\dospecials\catcode`\^^M\active}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ST@endsfbl}
% The companion to |\ST@beginsfbl|.
% \begin{macrocode}
\newcommand{\ST@endsfbl}{%
\ST@wsf{except:^^J
_st_.goboom(\the\inputlineno)^^J_st_.blockend()}}
% \end{macrocode}
% \end{macro}
%
% Now let's define the ``verbatim-like'' environments. There are four
% possibilities, corresponding to two independent choices of typesetting
% the code or not, and writing to the |.sage| file or not.
%
% \begin{environment}{sageblock}
% This environment does both: it typesets your code and puts it into the
% |.sage| file for execution by Sage.
% \begin{macrocode}
\newenvironment{sageblock}{\ST@beginsfbl%
% \end{macrocode}
% The space between |\ST@wsf{| and |\the| is crucial! It, along with the
% ``|try:|'', is what allows the user to indent code if they like. This
% line sends stuff to the |.sage| file.
% \begin{macrocode}
\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}%
% \end{macrocode}
% Next, we typeset your code and start the verbatim environment.
% \begin{macrocode}
\hspace{\sagetexindent}\the\verbatim@line\par}%
\verbatim}%
% \end{macrocode}
% At the end of the environment, we put a chunk into the |.sage| file
% and stop the verbatim environment.
% \begin{macrocode}
{\ST@endsfbl\endverbatim}
% \end{macrocode}
% \end{environment}
%
% \begin{environment}{sagesilent}
% This is from the |verbatim| package manual. It's just like the above,
% except we don't typeset anything.
% \begin{macrocode}
\newenvironment{sagesilent}{\ST@beginsfbl%
\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}}%
\verbatim@start}%
{\ST@endsfbl\@esphack}
% \end{macrocode}
% \end{environment}
%
% \begin{environment}{sageverbatim}
% The opposite of |sagesilent|. This is exactly the same as the verbatim
% environment, except that we include some indentation to be consistent
% with other typeset Sage code.
% \begin{macrocode}
\newenvironment{sageverbatim}{%
\def\verbatim@processline{\hspace{\sagetexindent}\the\verbatim@line\par}%
\verbatim}%
{\endverbatim}
% \end{macrocode}
% \end{environment}
%
% Logically, we now need an environment which neither typesets
% \emph{nor} writes code to the |.sage| file. The verbatim package's
% |comment| environment does that.\\
%
% Now we deal with some end-of-file cleanup.
%
% We tell the Sage script to write some information to the |.sout| file,
% then check to see if |ST@rerun| ever got defined. If not, all the
% inline formulas and plots worked, so do nothing.
% \begin{macrocode}
\AtEndDocument{\ST@wsf{_st_.endofdoc()}%
\@ifundefined{ST@rerun}{}%
% \end{macrocode}
% Otherwise, we issue a warning to tell the user to run Sage on the
% |.sage| file. Part of the reason we do this is that, by using |\ref|
% to pull in the inlines, \LTX will complain about undefined references
% if you haven't run the Sage script---and for many \LTX users, myself
% included, the warning ``there were undefined references'' is a signal
% to run \LTX again. But to fix these particular undefined references,
% you need to run \emph{Sage}. We also suppressed file-not-found errors
% for graphics files, and need to tell the user what to do about that.
%
% At any rate, we tell the user to run Sage if it's necessary.
% \begin{macrocode}
{\PackageWarningNoLine{sagetex}{There were undefined Sage formulas
and/or plots.^^JRun Sage on \jobname.sage, and then run
LaTeX on \jobname.tex again}}}
% \end{macrocode}
%
%
% \subsection{The Python module}
%
% \iffalse
% Hey, docstrip! Stop putting code into the .sty file, and start
% putting it into the .py file.
%</latex>%<*python>
% Thanks.
% \fi
%
% The style file writes things to the |.sage| file and reads them from
% the |.sout| file. The Python module provides functions that help
% produce the |.sout| file from the |.sage| file.
%
% \paragraph{A note on Python and \textsf{Docstrip}} There is one tiny
% potential source of confusion when documenting Python code with
% \textsf{Docstrip}: the percent sign. If you have a long line of Python
% code which includes a percent sign for string formatting and you break
% the line with a backslash and begin the next line with a percent sign,
% that line \emph{will not} be written to the output file. This is only
% a problem if you \emph{begin} the line with a (single) percent sign;
% there are no troubles otherwise.\\
%
% On to the code:
%
% The |sagetex.py| file is intended to be used as a module and doesn't
% do anything useful when called directly, so if someone does that, warn
% them. We do this right away so that we print this and exit before
% trying to import any Sage modules; that way, this error message gets
% printed whether you run the script with Sage or with Python.
% \begin{macrocode}
import sys
if __name__ == "__main__":
print("""This file is part of the SageTeX package.
It is not meant to be called directly.
This file will be automatically used by Sage scripts generated from a
LaTeX document using the sagetex package.""")
sys.exit()
% \end{macrocode}
% Import what we need:
% \begin{macrocode}
from sage.misc.latex import latex
import os
import os.path
import hashlib
import traceback
import subprocess
import shutil
% \end{macrocode}
% We define a class so that it's a bit easier to carry around internal
% state. We used to just have some global variables and a bunch of
% functions, but this seems a bit nicer and easier.
% \begin{macrocode}
class SageTeXProcessor():
def __init__(self, jobname):
self.progress('Processing Sage code for %s.tex...' % jobname)
self.didinitplot = False
self.useimagemagick = False
self.useepstopdf = False
self.plotdir = 'sage-plots-for-' + jobname + '.tex'
self.filename = jobname
% \end{macrocode}
% Open a |.sout.tmp| file and write all our output to that. Then, when
% we're done, we move that to |.sout|. The ``autogenerated'' line is
% basically the same as the lines that get put at the top of preparsed
% Sage files; we are automatically generating a file with Sage, so it
% seems reasonable to add it.
% \begin{macrocode}
self.souttmp = open(self.filename + '.sout.tmp', 'w')
s = '% This file was *autogenerated* from the file ' + \
os.path.splitext(jobname)[0] + '.sage.\n'
self.souttmp.write(s)
% \end{macrocode}
%
% \begin{macro}{progress}
% This function just prints stuff. It allows us to not print a
% linebreak, so you can get ``|start...|'' (little time spent
% processing) ``|end|'' on one line.
% \begin{macrocode}
def progress(self, t,linebreak=True):
if linebreak:
print(t)
else:
sys.stdout.write(t)
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{initplot}
% \phantomsection\label{initplot}
% We only want to create the plots directory if the user actually plots
% something. This function creates the directory and sets the
% |didinitplot| flag after doing so. We make a directory based on the
% \LTX file being processed so that if there are multiple |.tex| files
% in a directory, we don't overwrite plots from another file.
% \begin{macrocode}
def initplot(self):
self.progress('Initializing plots directory')
% \end{macrocode}
% We hard-code the |.tex| extension, which is fine in the overwhelming
% majority of cases, although it does cause minor confusion when
% building the documentation. If it turns out lots of people use, say, a
% |ltx| extension or whatever, We could find out the correct extension,
% but it would involve a lot of irritating mucking around---on
% |comp.text.tex|, the best solution I found for finding the file
% extension is to look through the |.log| file.
% \begin{macrocode}
if os.path.isdir(self.plotdir):
shutil.rmtree(self.plotdir)
os.mkdir(self.plotdir)
self.didinitplot = True
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{inline}
% \phantomsection\label{inlinefn}
% This function works with |\sage| from the style file (see
% \autoref{sec:sagemacro}) to put Sage output into your \LTX file.
% Usually, when you use |\label|, it writes a line such as
% \begin{center}
% |\newlabel{labelname}{{section number}{page number}}|
% \end{center}
% to the |.aux| file. When you use the |hyperref| package, there are
% more fields in the second argument, but the first two are the same.
% The |\ref| command just pulls in what's in the first field of the
% second argument, so we can hijack this mechanism for our own nefarious
% purposes. The function writes a |\newlabel| line with a label made
% from a counter and the text from running Sage on |s|.
%
% We print out the line number so if something goes wrong, the user can
% more easily track down the offending |\sage| command in the source
% file.
%
% That's a lot of explanation for a very short function:
% \begin{macrocode}
def inline(self, counter, s):
self.progress('Inline formula %s' % counter)
self.souttmp.write('\\newlabel{@sageinline' + str(counter) + '}{{' + \
latex(s) + '}{}{}{}{}}\n')
% \end{macrocode}
% We are using five fields, just like |hyperref| does, because that
% works whether or not |hyperref| is loaded. Using two fields, as in
% plain \LTX, doesn't work if |hyperref| is loaded.
% \end{macro}
%
% \begin{macro}{blockbegin}
% \begin{macro}{blockend}
% \phantomsection\label{blocksbeginend}
% This function and its companion used to write stuff to the |.sout|
% file, but now they just update the user on our progress evaluating a
% code block. The verbatim-like environments of
% \autoref{sec:verbatim-envs} use these functions.
% \begin{macrocode}
def blockbegin(self):
self.progress('Code block begin...', False)
def blockend(self):
self.progress('end')
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{plot}
% \phantomsection\label{plotfn}
% I hope it's obvious that this function does plotting. It's the Python
% counterpart of |\ST@sageplot| described in \autoref{sec:sageplotmacro}. As
% mentioned in the |\sageplot| code, we're taking advantage of two
% things: first, that \LTX doesn't treat commas and spaces in macro
% arguments specially, and second, that Python (and Sage plotting
% functions) has nice support for keyword arguments. The |#3| argument
% to |\sageplot| becomes |_p_| and |**kwargs| below.
% \begin{macrocode}
def plot(self, counter, _p_, format='notprovided', **kwargs):
if not self.didinitplot:
self.initplot()
self.progress('Plot %s' % counter)
% \end{macrocode}
% If the user says nothing about file formats, we default to producing
% PDF and EPS. This allows the user to transparently switch between
% using a DVI previewer (which usually automatically updates when the
% DVI changes, and has support for source specials, which makes the
% writing process easier) and making PDFs.\footnote{Yes, there's
% \texttt{pdfsync}, but full support for that is still rare in Linux, so
% producing EPS and PDF is the best solution for now.}
% \begin{macrocode}
if format == 'notprovided':
formats = ['eps', 'pdf']
else:
formats = [format]
for fmt in formats:
% \end{macrocode}
% If we're making a PDF and have been told to use |epstopdf|, do so,
% then skip the rest of the loop.
% \begin{macrocode}
if fmt == 'pdf' and self.useepstopdf:
epsfile = os.path.join(self.plotdir, 'plot-%s.eps' % counter)
self.progress('Calling epstopdf to convert plot-%s.eps to PDF' % \
counter)
subprocess.check_call(['epstopdf', epsfile])
continue
plotfilename = os.path.join(self.plotdir, 'plot-%s.%s' % (counter, fmt))
#print(' plotting %s with args %s' % (plotfilename, kwargs))
_p_.save(filename=plotfilename, **kwargs)
% \end{macrocode}
% If the user provides a format \emph{and} specifies the |imagemagick|
% option, we try to convert the newly-created file into EPS format.
% \begin{macrocode}
if format != 'notprovided' and self.useimagemagick:
self.progress('Calling Imagemagick to convert plot-%s.%s to EPS' % \
(counter, format))
self.toeps(counter, format)
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{toeps}
% This function calls the Imagmagick utility |convert| to, well, convert
% something into EPS format. This gets called when the user has
% requested the ``|imagemagick|'' option to the \ST\ style file and is
% making a graphic file with a nondefault extension.
% \begin{macrocode}
def toeps(self, counter, ext):
subprocess.check_call(['convert',\
'%s/plot-%s.%s' % (self.plotdir, counter, ext), \
'%s/plot-%s.eps' % (self.plotdir, counter)])
% \end{macrocode}
% We are blindly assuming that the |convert| command exists and will do
% the conversion for us; the |check_call| function raises an exception
% which, since all these calls get wrapped in try/excepts in the |.sage|
% file, should result in a reasonable error message if something strange
% happens.
% \end{macro}
%
% \begin{macro}{goboom}
% When a chunk of Sage code blows up, this function bears the bad news
% to the user. Normally in Python the traceback is good enough for this,
% but in this case, we start with a |.sage| file (which is
% autogenerated) which itself autogenerates a |.py| file---and the
% tracebacks the user sees refer to that file, whose line numbers are
% basically useless. We want to tell them where in the \LTX file things
% went bad, so we do that, give them the traceback, and exit after
% removing the |.sout.tmp| file.
% \begin{macrocode}
def goboom(self, line):
print('\n**** Error in Sage code on line %s of %s.tex! Traceback\
follows.' % (line, self.filename))
traceback.print_exc()
print('\n**** Running Sage on %s.sage failed! Fix %s.tex and try\
again.' % ((self.filename,) * 2))
self.souttmp.close()
os.remove(self.filename + '.sout.tmp')
sys.exit(1)
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{endofdoc}
% When we're done processing, we have some cleanup tasks. We
% want to put the MD5 sum of the |.sage| file that produced the |.sout|
% file we're about to write into the |.sout| file, so that external
% programs that build \LTX documents can determine if they need to call Sage
% to update the |.sout| file. But there is a problem: we write line
% numbers to the |.sage| file so that we can provide useful error
% messages---but that means that adding non-\ST text to your
% source file will change the MD5 sum, and your program will think it
% needs to rerun Sage even though none of the actual \ST macros
% changed.
%
% How do we include line numbers for our error messages but still allow
% a program to discover a ``genuine'' change to the |.sage| file?
%
% The answer is to only find the MD5 sum of \emph{part} of the |.sage|
% file. By design, the source file line numbers only appear in calls to
% |goboom|, so we will strip those lines out. Basically we are doing
% \begin{center}
% \verb+grep -v '^ _st_.goboom' filename.sage | md5sum+
% \end{center}
% (In fact, what we do below produces exactly the same sum.)
% \begin{macrocode}
def endofdoc(self):
sagef = open(self.filename + '.sage', 'r')
m = hashlib.md5()
for line in sagef:
if line[0:12] != ' _st_.goboom':
m.update(line)
s = '%' + m.hexdigest() + '% md5sum of corresponding .sage file\
(minus "goboom" lines)\n'
self.souttmp.write(s)
% \end{macrocode}
% Now, we do issue warnings to run Sage on the |.sage| file and an
% external program might look for those to detect the need to rerun
% Sage, but those warnings do not quite capture all situations. (If
% you've already produced the |.sout| file and change a |\sage| call, no
% warning will be issued since all the |\ref|s find a |\newlabel|.)
% Anyway, I think it's easier to grab an MD5 sum out of the end of the
% file than parse the output from running |latex| on your file. (The
% regular expression |^%[0-9a-f]{32}%| will find the MD5 sum. Note that
% there are percent signs on each side of the hex string.)
%
% Now we are done with the |.sout.tmp| file. Close it, rename it, and
% tell the user we're done.
% \begin{macrocode}
self.souttmp.close()
os.rename(self.filename + '.sout.tmp', self.filename + '.sout')
self.progress('Sage processing complete. Run LaTeX on %s.tex again.' %\
self.filename)
% \end{macrocode}
% \end{macro}
%
% \iffalse
%</python>%<*staticscript>
% \fi
%
% \section{Included Python scripts}
%
% Here we describe the Python code for |makestatic.py|, which removes
% \ST commands to produce a ``static'' file, and |extractsagecode.py|,
% which extracts all the Sage code from a |.tex| file.
%
% \subsection{makestatic.py}
%
% First, |makestatic.py| script. It's about the most basic, generic
% Python script taking command-line arguments that you'll find. The
% |#!/usr/bin/env python| line is provided for us by the |.ins| file's
% preamble, so we don't put it here.
% \begin{macrocode}
import sys
import time
import getopt
import os.path
from sagetexparse import DeSageTex
def usage():
print("""Usage: %s [-h|--help] [-o|--overwrite] inputfile [outputfile]
Removes SageTeX macros from `inputfile' and replaces them with the
Sage-computed results to make a "static" file. You'll need to have run
Sage on `inputfile' already.
`inputfile' can include the .tex extension or not. If you provide
`outputfile', the results will be written to a file of that name.
Specify `-o' or `--overwrite' to overwrite the file if it exists.
See the SageTeX documentation for more details.""" % sys.argv[0])
try:
opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite'])
except getopt.GetoptError, err:
print str(err)
usage()
sys.exit(2)
overwrite = False
for o, a in opts:
if o in ('-h', '--help'):
usage()
sys.exit()
elif o in ('-o', '--overwrite'):
overwrite = True
if len(args) == 0 or len(args) > 2:
print('Error: wrong number of arguments. Make sure to specify options first.\n')
usage()
sys.exit(2)
if len(args) == 2 and (os.path.exists(args[1]) and not overwrite):
print('Error: %s exists and overwrite option not specified.' % args[1])
sys.exit(1)
src, ext = os.path.splitext(args[0])
% \end{macrocode}
% All the real work gets done in the line below. Sorry it's not more
% exciting-looking.
% \begin{macrocode}
desagetexed = DeSageTex(src)
% \end{macrocode}
% This part is cool: we need double percent signs at the beginning of
% the line because Python needs them (so they get turned into single
% percent signs) \emph{and} because \textsf{Docstrip} needs them (so the
% line gets passed into the generated file). It's perfect!
% \begin{macrocode}
header = """\
%% SageTeX commands have been automatically removed from this file and
%% replaced with plain LaTeX. Processed %s.
""" % time.strftime('%a %d %b %Y %H:%M:%S', time.localtime())
if len(args) == 2:
dest = open(args[1], 'w')
else:
dest = sys.stdout
dest.write(header)
dest.write(desagetexed.result)
% \end{macrocode}
%
% \iffalse
%</staticscript>%<*extractscript>
% \fi
%
% \subsection{extractsagecode.py}
%
% Same idea as |makestatic.py|, except this does basically the opposite
% thing.
% \begin{macrocode}
import sys
import time
import getopt
import os.path
from sagetexparse import SageCodeExtractor
def usage():
print("""Usage: %s [-h|--help] [-o|--overwrite] inputfile [outputfile]
Extracts Sage code from `inputfile'.
`inputfile' can include the .tex extension or not. If you provide
`outputfile', the results will be written to a file of that name,
otherwise the result will be printed to stdout.
Specify `-o' or `--overwrite' to overwrite the file if it exists.
See the SageTeX documentation for more details.""" % sys.argv[0])
try:
opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite'])
except getopt.GetoptError, err:
print str(err)
usage()
sys.exit(2)
overwrite = False
for o, a in opts:
if o in ('-h', '--help'):
usage()
sys.exit()
elif o in ('-o', '--overwrite'):
overwrite = True
if len(args) == 0 or len(args) > 2:
print('Error: wrong number of arguments. Make sure to specify options first.\n')
usage()
sys.exit(2)
if len(args) == 2 and (os.path.exists(args[1]) and not overwrite):
print('Error: %s exists and overwrite option not specified.' % args[1])
sys.exit(1)
src, ext = os.path.splitext(args[0])
sagecode = SageCodeExtractor(src)
header = """\
# This file contains Sage code extracted from %s%s.
# Processed %s.
""" % (src, ext, time.strftime('%a %d %b %Y %H:%M:%S', time.localtime()))
if len(args) == 2:
dest = open(args[1], 'w')
else:
dest = sys.stdout
dest.write(header)
dest.write(sagecode.result)
% \end{macrocode}
%
% \iffalse
%</extractscript>%<*parsermod>
% \fi
%
% \subsection{The parser module}
%
% Here's the module that does the actual parsing and replacing. It's
% really quite simple, thanks to the awesome
% \href{http://pyparsing.wikispaces.com}{Pyparsing module}. The parsing
% code below is nearly self-documenting! Compare that to fancy regular
% expressions, which sometimes look like someone sneezed punctuation all
% over the screen.
% \begin{macrocode}
import sys
from pyparsing import *
% \end{macrocode}
% First, we define this very helpful parser: it finds the matching
% bracket, and doesn't parse any of the intervening text. It's basically
% like hitting the percent sign in Vim. This is useful for parsing \LTX
% stuff, when you want to just grab everything enclosed by matching
% brackets.
% \begin{macrocode}
def skipToMatching(opener, closer):
nest = nestedExpr(opener, closer)
nest.setParseAction(lambda l, s, t: l[s:getTokensEndLoc()])
return nest
curlybrackets = skipToMatching('{', '}')
squarebrackets = skipToMatching('[', ']')
% \end{macrocode}
% Next, parser for |\sage| and |\sageplot| calls:
% \begin{macrocode}
sagemacroparser = '\\sage' + curlybrackets('code')
sageplotparser = ('\\sageplot'
+ Optional(squarebrackets)('opts')
+ Optional(squarebrackets)('format')
+ curlybrackets('code'))
% \end{macrocode}
%
% With those defined, let's move on to our classes.
%
% \begin{macro}{SoutParser}
% Here's the parser for the generated |.sout| file. The code below does
% all the parsing of the |.sout| file and puts the results into a
% dictionary. Notice that it's on the order of 10 lines of code---hooray
% for Pyparsing!
% \begin{macrocode}
class SoutParser():
def __init__(self, fn):
self.label = {}
% \end{macrocode}
% A label line looks like
% \begin{quote}
% |\newlabel{@sageinline|\meta{integer}|}{|\marg{bunch of \LTX code}|{}{}{}{}}|
% \end{quote}
% which makes the parser definition below pretty obvious. We assign some
% names to the interesting bits so the |newlabel| method can make the
% \meta{integer} and \meta{bunch of \LTX code} into the keys and values
% of a dictionary. The |DeSageTeX| class then uses that dictionary to
% replace bits in the |.tex| file with their Sage-computed results.
% \begin{macrocode}
parselabel = ('\\newlabel{@sageinline'
+ Word(nums)('num')
+ '}{'
+ curlybrackets('result')
+ '{}{}{}{}}')
% \end{macrocode}
% We tell it to ignore comments, and hook up the dictionary-making
% method.
% \begin{macrocode}
parselabel.ignore('%' + restOfLine)
parselabel.setParseAction(self.newlabel)
% \end{macrocode}
% A |.sout| file consists of one or more such lines. Now go parse the
% file we were given.
% \begin{macrocode}
try:
OneOrMore(parselabel).parseFile(fn)
except IOError:
print 'Error accessing %s; exiting. Does your .sout file exist?' % fn
sys.exit(1)
% \end{macrocode}
% Pyparser's parse actions get called with three arguments: the string
% that matched, the location of the beginning, and the resulting parse
% object. Here we just add a new key-value pair to the dictionary,
% remembering to strip off the enclosing brackets from the ``result''
% bit.
% \begin{macrocode}
def newlabel(self, s, l, t):
self.label[int(t.num)] = t.result[1:-1]
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{DeSageTeX}
% Now we define a parser for \LTX files that use \ST commands. We assume
% that the provided |fn| is just a basename.
% \begin{macrocode}
class DeSageTex():
def __init__(self, fn):
self.sagen = 0
self.plotn = 0
self.fn = fn
self.sout = SoutParser(fn + '.sout')
% \end{macrocode}
% Parse |\sage| macros. We just need to pull in the result from the
% |.sout| file and increment the counter---that's what |self.sage| does.
% \begin{macrocode}
smacro = sagemacroparser
smacro.setParseAction(self.sage)
% \end{macrocode}
% Parse the |\usepackage{sagetex}| line. Right now we don't support
% comma-separated lists of packages.
% \begin{macrocode}
usepackage = ('\\usepackage'
+ Optional(squarebrackets)
+ '{sagetex}')
usepackage.setParseAction(replaceWith("""\\RequirePackage{verbatim}
\\RequirePackage{graphicx}"""))
% \end{macrocode}
% Parse |\sageplot| macros.
% \begin{macrocode}
splot = sageplotparser
splot.setParseAction(self.plot)
% \end{macrocode}
% The printed environments (|sageblock| and |sageverbatim|) get turned
% into |verbatim| environments.
% \begin{macrocode}
beginorend = oneOf('begin end')
blockorverb = 'sage' + oneOf('block verbatim')
blockorverb.setParseAction(replaceWith('verbatim'))
senv = '\\' + beginorend + '{' + blockorverb + '}'
% \end{macrocode}
% The non-printed |sagesilent| environment gets commented out. We could
% remove all the text, but this works and makes going back to \ST
% commands (de-de-\ST{}ing?) easier.
% \begin{macrocode}
silent = Literal('sagesilent')
silent.setParseAction(replaceWith('comment'))
ssilent = '\\' + beginorend + '{' + silent + '}'
% \end{macrocode}
% The |\sagetexindent| macro is no longer relevant, so remove it from
% the output (``suppress'', in Pyparsing terms).
% \begin{macrocode}
stexindent = Suppress('\\setlength{\\sagetexindent}' + curlybrackets)
% \end{macrocode}
% Now we define the parser that actually goes through the file. It just
% looks for any one of the above bits, while ignoring anything that
% should be ignored.
% \begin{macrocode}
doit = smacro | senv | ssilent | usepackage | splot | stexindent
doit.ignore('%' + restOfLine)
doit.ignore('\\begin{verbatim}' + SkipTo('\\end{verbatim}'))
doit.ignore('\\begin{comment}' + SkipTo('\\end{comment}'))
% \end{macrocode}
% We can't use the |parseFile| method, because that expects a ``complete
% grammar'' in which everything falls into some piece of the parser.
% Instead we suck in the whole file as a single string, and run
% |transformString| on it, since that will just pick out the interesting
% bits and munge them according to the above definitions.
% \begin{macrocode}
str = ''.join(open(fn + '.tex', 'r').readlines())
self.result = doit.transformString(str)
% \end{macrocode}
% That's the end of the class constructor, and it's all we need to do
% here. You access the results of parsing via the |result| string.
%
% We do have two methods to define. The first does the same thing that
% |\ref| does in your \LTX file: returns the content of the label and
% increments a counter.
% \begin{macrocode}
def sage(self, s, l, t):
self.sagen += 1
return self.sout.label[self.sagen - 1]
% \end{macrocode}
% The second method returns the appropriate |\includegraphics| command.
% It does need to account for the default argument.
% \begin{macrocode}
def plot(self, s, l, t):
self.plotn += 1
if len(t.opts) == 0:
opts = '[width=.75\\textwidth]'
else:
opts = t.opts[0]
return ('\\includegraphics%s{sage-plots-for-%s.tex/plot-%s}' %
(opts, self.fn, self.plotn - 1))
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{SageCodeExtractor}
% This class does the opposite of the first: instead of removing Sage
% stuff and leaving only \LTX, this removes all the \LTX and leaves only
% Sage.
% \begin{macrocode}
class SageCodeExtractor():
def __init__(self, fn):
smacro = sagemacroparser
smacro.setParseAction(self.macroout)
splot = sageplotparser
splot.setParseAction(self.plotout)
% \end{macrocode}
% Above, we used the general parsers for |\sage| and |\sageplot|. We
% have to redo the environment parsers because it seems too hard to
% define one parser object that will do both things we want: above, we
% just wanted to change the environment name, and here we want to suck
% out the code. Here, it's important that we find matching begin/end
% pairs; above it wasn't. At any rate, it's not a big deal to redo this
% parser.
% \begin{macrocode}
env_names = oneOf('sageblock sageverbatim sagesilent')
senv = '\\begin{' + env_names('env') + '}' + SkipTo(
'\\end{' + matchPreviousExpr(env_names) + '}')('code')
senv.leaveWhitespace()
senv.setParseAction(self.envout)
doit = smacro | splot | senv
str = ''.join(open(fn + '.tex', 'r').readlines())
self.result = ''
doit.transformString(str)
def macroout(self, s, l, t):
self.result += '# \\sage{} from line %s\n' % lineno(l, s)
self.result += t.code[1:-1] + '\n\n'
def plotout(self, s, l, t):
self.result += '# \\sageplot{} from line %s:\n' % lineno(l, s)
if t.format is not '':
self.result += '# format: %s' % t.format[0][1:-1] + '\n'
self.result += t.code[1:-1] + '\n\n'
def envout(self, s, l, t):
self.result += '# %s environment from line %s:' % (t.env,
lineno(l, s))
self.result += t.code[0] + '\n'
% \end{macrocode}
% \end{macro}
%
% \iffalse
%</parsermod>% \fi
%
% \section{Credits and acknowledgements}
%
% According to the original README file, this system was originally done
% by Gonzalo Tornaria and Joe Wetherell. Later Harald Schilly made some
% improvements and modifications. Almost all the examples in the
% |example.tex| file are from Harald.
%
% Dan Drake rewrote and extended the style file (there is effectively
% zero original code there), made significant changes to the Python
% module, put both files into \textsf{Docstrip} format, and wrote all
% the documentation and extra Python scripts.
%
% Many thanks to Jason Grout for his numerous comments, suggestions, and
% feedback.
%
% \section{Copying and licenses}
%
% If you are unnaturally curious about the current state of the \ST
% package, you can visit \url{http://www.bitbucket.org/ddrake/sagetex/}.
% There is a Mercurial repository and other stuff there.
%
% As for the terms and conditions under which you can copy and modify
% \ST:
%
% The \emph{source code} of the \ST package may be redistributed and/or
% modified under the terms of the GNU General Public License as
% published by the Free Software Foundation, either version 2 of the
% License, or (at your option) any later version. To view a copy of this
% license, see \url{http://www.gnu.org/licenses/} or send a letter to
% the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
% Boston, MA 02110-1301, USA.
%
% The \emph{documentation} of the \ST package is licensed under the
% Creative Commons Attribution-Noncommercial-Share Alike 3.0 License. To
% view a copy of this license, visit
% \url{http://creativecommons.org/licenses/by-nc-sa/3.0/} or send a
% letter to Creative Commons, 171 Second Street, Suite 300, San
% Francisco, California, 94105, USA.
%
% \iffalse
% I've run into a situation where the index wants to start on the very
% last line of the page, and I actually get errors: ``Package multicol
% Error: Error saving partial page.'' The problem goes away if I fiddle
% with some lines so that the index starts elsewhere. Putting in a
% clearpage below makes the index start nicely in the middle of a page
% (until my change history gets too long!) and solves all those
% problems. It can be removed/pulled into this comment if you're
% confident the pagebreak problems won't occur.
% \clearpage
% \fi