diff options
author | Karl Berry <karl@freefriends.org> | 2009-06-21 00:23:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-06-21 00:23:51 +0000 |
commit | d5c69362ef92a985a1cecefe6bbbca5eb51e822a (patch) | |
tree | b6af1179a24bd3d2401d9540741fc4c161d7664b /Master | |
parent | f7498423bd232008266cf75bb0c1faa1465fbb1e (diff) |
sage 2.2.1 (20jun09), omitting python scripts in bin
git-svn-id: svn://tug.org/texlive/trunk@13843 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
15 files changed, 3374 insertions, 1163 deletions
diff --git a/Master/texmf-dist/doc/latex/sagetex/README b/Master/texmf-dist/doc/latex/sagetex/README index 2e9d512d0eb..d677252b478 100644 --- a/Master/texmf-dist/doc/latex/sagetex/README +++ b/Master/texmf-dist/doc/latex/sagetex/README @@ -3,13 +3,21 @@ computations, and plots from the Sage mathematics software suite (http://sagemath.org) into LaTeX documents. ==================================================================== -To use SageTeX, you need the files sagetex.sty and sagetex.py. If those -haven't been extracted from the .dtx file, you'll need to do: +The recommended way to acquire and install SageTeX is by installing the +Sage spkg; visit http://sagemath.org/packages/optional/, find the +current version number, and run "sage -i sagetex-[version]" in a +terminal. Then you'll need to make the file sagetex.sty known to TeX; +that file will be in SAGE_ROOT/local/share/texmf/tex/generic/sagetex, +along with documentation and examples. + +If you can't or don't want to install SageTeX by using Sage, you can use +this CTAN package. If sagetex.py and sagetex.sty haven't been extracted +from the .dtx file, you'll need to do: 0. Run `latex sagetexpackage.ins' If a PDF file of the documentation wasn't included with this -distribution of SageTex, you will need to build the documentation +distribution of SageTeX, you will need to build the documentation yourself. To do that: 1. Run `latex sagetexpackage.dtx' @@ -30,7 +38,12 @@ the documentation.) To use the SageTeX package with your own documents, see the "Installation" section of the documentation. -This works builds on a lot of work by others; see the "Credits" section +SageTeX now includes `remote-sagetex.py', a plain Python script that +allows you to use a remote Sage server instead of a local Sage +installation, so now you can use SageTeX on any computer with TeX and +Python 2.6 installed. + +This work builds on a lot of work by others; see the "Credits" section of the documentation for credits. The source code may be modified and distributed under the terms of the GPL, v2 or later; the documentation may be modified and distributed under a Creative Commons Attribution - @@ -40,4 +53,4 @@ section of the documentation. Please let me know if you find any bugs or have any ideas for improvement! -- Dan Drake <ddrake@member.ams.org> +- Dan Drake <http://mathsci.kaist.ac.kr/~drake/> diff --git a/Master/texmf-dist/doc/latex/sagetex/example.pdf b/Master/texmf-dist/doc/latex/sagetex/example.pdf Binary files differindex 52b3ba0e34a..270018177db 100644 --- a/Master/texmf-dist/doc/latex/sagetex/example.pdf +++ b/Master/texmf-dist/doc/latex/sagetex/example.pdf diff --git a/Master/texmf-dist/doc/latex/sagetex/example.tex b/Master/texmf-dist/doc/latex/sagetex/example.tex index 0f84e3152e6..d9c67589fbc 100644 --- a/Master/texmf-dist/doc/latex/sagetex/example.tex +++ b/Master/texmf-dist/doc/latex/sagetex/example.tex @@ -1,32 +1,39 @@ % General example LaTeX file for including Sage calculations and plots -% Build with: (pdf)latex example.tex; sage example.sage; pdflatex -% example.tex Please read README and the documentation of the SageTeX -% package for more information! +% Build with: +% +% (pdf)latex example.tex; sage example.sage; pdflatex example.tex +% +% Please read README and the documentation of the SageTeX package for +% more information! \documentclass{article} -\title{Examples of embedding Sage in \LaTeX} -\author{} - +\title{Examples of embedding Sage in \LaTeX{} with \textsf{Sage\TeX}} +\author{Dan Drake and others} +\usepackage{amsmath} \usepackage{sagetex} -% -% If you want sagetex to use Imagemagick's convert utility to make eps -% files from png files when generating a dvi file, add the -% "imagemagick" option above: +% +% If you want SageTeX to use Imagemagick's `convert' utility to make eps +% files from png files when generating a dvi file, add the "imagemagick" +% option above: % % \usepackage[imagemagick]{sagetex} +\setlength{\sagetexindent}{10ex} + \begin{document} \maketitle \section{Inline Sage, code blocks} This is an example $2+2=\sage{2+2}$. If you raise the current year mod -$100$ ($\sage{mod(\the\year, 100)}$) to the power of the current day -($\the\day$), you get $\sage{Integer(mod(\the\year, 100))^\the\day}$. -Also, $\the\year$ modulo $42$ is $\sage{\the\year \percent 42}$. +$100$ (which equals $\sage{mod(\the\year, 100)}$) to the power of the +current day ($\the\day$), you get $\sage{Integer(mod(\the\year, +100))^\the\day}$. Also, $\the\year$ modulo $42$ is $\sage{\the\year +\percent 42}$. Code block which uses a variable \texttt{s} to store the solutions: \begin{sageblock} + 1+1 var('a,b,c') eqn = [a+b*c==1, b-a*c==0, a+b==5] s = solve(eqn, a,b,c) @@ -46,8 +53,8 @@ E = EllipticCurve("37a") \end{sageblock} You can't do assignment inside \verb|\sage| macros, since Sage doesn't know how to typeset the output of such a thing. So you have to use a -code block. The elliptic curve $E$ given by $\sage{E}$ -has discriminant $\sage{E.discriminant()}$. +code block. The elliptic curve $E$ given by $\sage{E}$ has discriminant +$\sage{E.discriminant()}$. You can do anything in a code block that you can do in Sage and/or Python. Here we save an elliptic curve into a file. @@ -60,8 +67,8 @@ except IOError: E.save('E2') \end{sageblock} -The 9999th Fourier coefficient of $\sage{E}$ is -$\sage{E.anlist(100000)[9999]}$. +The 9999th Fourier coefficient of $\sage{E}$ is +$\sage{E.anlist(100000)[9999]}$. The following code block doesn't appear in the typeset file\dots \begin{sagesilent} @@ -72,9 +79,9 @@ but we can refer to whatever we did in that code block: $e=\sage{e}$. \begin{sageblock} var('x') - f = log(sin(x)/x) + f(x) = log(sin(x)/x) \end{sageblock} -The Taylor Series of $f$ is: $\sage{ f.taylor(x, 0, 10) }$. +The Taylor Series of $f$ begins: $\sage{ f.taylor(x, 0, 10) }$. \section{Plotting} @@ -83,8 +90,10 @@ Here's a plot of the elliptic curve $E$. \sageplot{E.plot(-3,3)} \begin{sagesilent} + # the var line is unecessary unless you've defined x to be something + # other than a symbolic variable var('x') - f=-x^3+3*x^2+7*x-4 + f(x) = -x^3+3*x^2+7*x-4 \end{sagesilent} You can use variables to hold plot objects and do stuff with them. @@ -94,7 +103,7 @@ You can use variables to hold plot objects and do stuff with them. Here's a small plot of $f$ from $-5$ to $5$, which I've centered: -\centerline{\sageplot[scale=.2]{p}} +\begin{center} \sageplot[scale=.2]{p} \end{center} On second thought, use the default size of $3/4$ the \verb|\textwidth| and don't use axes: @@ -120,7 +129,7 @@ almost all situations. (Although see the section on 3D plotting.) \sageplot[angle=45, width=.5\textwidth][png]{plot1} If you use regular \verb|latex| to make a DVI file, you'll see a box, -beause DVI files can't include PNG files. If you use \verb|pdflatex| +because DVI files can't include PNG files. If you use \verb|pdflatex| that will work. See the documentation for details. When using \verb|\sageplot|, you can pass in just about anything that @@ -160,12 +169,15 @@ And here's the picture: \sageplot{matrixprogram} +Reset \texttt{x} in Sage so that it's not a generator for the polynomial +ring: \sage{var('x')} + \subsection{3D plotting} 3D plotting right now is problematic because there's no convenient way to produce vector graphics. We can make PNGs, though, and since the \verb|sageplot| command defaults to EPS and PDF, \emph{you must specify -a valid format for 3D plotting}. Sage right now (version 2.10.3) can't +a valid format for 3D plotting}. Sage right now (version 3.4.2) can't produce EPS or PDF files from plot3d objects, so if you don't specify a valid format, things will go badly. You can specify the ``\texttt{imagemagick}'' option, which will use the Imagemagick @@ -182,4 +194,71 @@ Here's the famous Sage cube graph: % passing an option to includegraphics \sageplot[][png]{G.plot3d(engine='tachyon')} +\section{Pausing Sage\TeX} +\label{sec:pausing-sagetex} + +Sometimes you want to ``pause'' for a bit while writing your document if +you have embedded a long calculation or just want to concentrate on the +\LaTeX{} and ignore any Sage stuff. You can use the \verb|\sagetexpause| +and \verb|\sagetexunpause| macros to do that. + +\sagetexpause + +A calculation: $\sage{factor(2^325 + 1)}$ and a code environment that +simulates a time-consuming calculation. While paused, this will get +skipped over. +\begin{sageblock} + import time + time.sleep(15) +\end{sageblock} + +Graphics are also skipped: \sageplot{plot(2*sin(x^2) + x^2, (x, 0, 5))} + +\sagetexunpause + +\section{Make Sage write your \LaTeX{} for you} + +With \textsf{Sage\TeX}, you can not only have Sage do your math for you, +it can write parts of your \LaTeX{} document for you! For example, I +hate writing \texttt{tabular} environments; there's too many fiddly +little bits of punctuation and whatnot\ldots and what if you want to add +a column? It's a pain---or rather, it \emph{was} a pain. Here's how to +make Pascal's triangle. It requires the \texttt{amsmath} package because +of what Sage does when producing a \LaTeX{} representation of a string. +(It puts it inside a \verb|\text| macro.) + +\begin{sageblock} +def pascals_triangle(n): + # start of the table + s = r"\begin{tabular}{cc|" + "r" * (n+1) + "}" + s += r" & & $k$: & \\" + # second row, with k values: + s += r" & " + for k in [0..n]: + s += "& %d " % k + s += r"\\" + # the n = 0 row: + s += r"\hline" + "\n" + r"$n$: & 0 & 1 & \\" + # now the rest of the rows + for r in [1..n]: + s += " & %d " % r + for k in [0..r]: + s += "& %d " % binomial(r, k) + s += r"\\" + # add the last line and return + s += r"\end{tabular}" + return s + +# how big should the table be? +n = 8 +\end{sageblock} + +Okay, now here's the table. To change the size, edit \texttt{n} above. +If you have several tables, you can use this to get them all the same +size, while changing only one thing. + +\begin{center} + \sage{pascals_triangle(n)} +\end{center} + \end{document} diff --git a/Master/texmf-dist/doc/latex/sagetex/extractsagecode.py b/Master/texmf-dist/doc/latex/sagetex/extractsagecode.py new file mode 100644 index 00000000000..62200d42d68 --- /dev/null +++ b/Master/texmf-dist/doc/latex/sagetex/extractsagecode.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +## +## This is file `extractsagecode.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## scripts.dtx (with options: `extractscript') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> +## +## This program is free software: you can redistribute it and/or modify it +## 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. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see <http://www.gnu.org/licenses/>. +## +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) diff --git a/Master/texmf-dist/doc/latex/sagetex/makestatic.py b/Master/texmf-dist/doc/latex/sagetex/makestatic.py new file mode 100644 index 00000000000..2121d9b78c5 --- /dev/null +++ b/Master/texmf-dist/doc/latex/sagetex/makestatic.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +## +## This is file `makestatic.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## scripts.dtx (with options: `staticscript') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> +## +## This program is free software: you can redistribute it and/or modify it +## 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. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see <http://www.gnu.org/licenses/>. +## +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]) +desagetexed = DeSageTex(src) +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) diff --git a/Master/texmf-dist/doc/latex/sagetex/remote-sagetex.py b/Master/texmf-dist/doc/latex/sagetex/remote-sagetex.py new file mode 100644 index 00000000000..e8946bd1814 --- /dev/null +++ b/Master/texmf-dist/doc/latex/sagetex/remote-sagetex.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python +## +## This is file `remote-sagetex.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## remote-sagetex.dtx (with options: `remotesagetex') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> +## +## This program is free software: you can redistribute it and/or modify it +## 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. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see <http://www.gnu.org/licenses/>. +## +from __future__ import print_function +import json +import sys +import time +import re +import urllib +import hashlib +import os +import os.path +import shutil +import getopt +from contextlib import closing + +######################################################################### +# You can provide a filename here and the script will read your login # +# information from that file. The format must be: # +# # +# server = 'http://foo.com:8000' # +# username = 'my_name' # +# password = 's33krit' # +# # +# You can omit one or more of those lines, use " quotes, and put hash # +# marks at the beginning of a line for comments. Command-line args # +# take precedence over information from the file. # +######################################################################### +login_info_file = None # e.g. '/home/foo/Private/sagetex-login.txt' + +usage = """Process a SageTeX-generated .sage file using a remote Sage server. + +Usage: {0} [options] inputfile.sage + +Options: + + -h, --help: print this message + -s, --server: the Sage server to contact + -u, --username: username on the server + -p, --password: your password + -f, --file: get login information from a file + +If the server does not begin with the four characters `http', then +`https://' will be prepended to the server name. + +You can hard-code the filename from which to read login information into +the remote-sagetex script. Command-line arguments take precedence over +the contents of that file. See the SageTeX documentation for formatting +details. + +If any of the server, username, and password are omitted, you will be +asked to provide them. + +See the SageTeX documentation for more details on usage and limitations +of remote-sagetex.""".format(sys.argv[0]) + +server, username, password = (None,) * 3 + +try: + opts, args = getopt.getopt(sys.argv[1:], 'hs:u:p:f:', + ['help', 'server=', 'user=', 'password=', 'file=']) +except getopt.GetoptError as err: + print(str(err), usage, sep='\n\n') + sys.exit(2) + +for o, a in opts: + if o in ('-h', '--help'): + print(usage) + sys.exit() + elif o in ('-s', '--server'): + server = a + elif o in ('-u', '--user'): + username = a + elif o in ('-p', '--password'): + password = a + elif o in ('-f', '--file'): + login_info_file = a + +if len(args) != 1: + print('Error: must specify exactly one file. Please specify options first.', + usage, sep='\n\n') + sys.exit(2) + +jobname = os.path.splitext(args[0])[0] +traceback_str = 'Exception in SageTeX session {0}:'.format(time.time()) +def parsedotsage(fn): + with open(fn, 'r') as f: + inline = re.compile(r" _st_.inline\((?P<num>\d+), (?P<code>.*)\)") + plot = re.compile(r" _st_.plot\((?P<num>\d+), (?P<code>.*)\)") + goboom = re.compile(r" _st_.goboom\((?P<num>\d+)\)") + pausemsg = re.compile(r"print.'(?P<msg>SageTeX (un)?paused.*)'") + blockbegin = re.compile(r"_st_.blockbegin\(\)") + ignore = re.compile(r"(try:)|(except):") + in_comment = False + in_block = False + cmds = [] + for line in f.readlines(): + if line.startswith('"""'): + in_comment = not in_comment + elif not in_comment: + m = pausemsg.match(line) + if m: + cmds.append({'type': 'pause', + 'msg': m.group('msg')}) + m = inline.match(line) + if m: + cmds.append({'type': 'inline', + 'num': m.group('num'), + 'code': m.group('code')}) + m = plot.match(line) + if m: + cmds.append({'type': 'plot', + 'num': m.group('num'), + 'code': m.group('code')}) + m = goboom.match(line) + if m: + cmds[-1]['goboom'] = m.group('num') + if in_block: + in_block = False + if in_block and not ignore.match(line): + cmds[-1]['code'] += line + if blockbegin.match(line): + cmds.append({'type': 'block', + 'code': ''}) + in_block = True + return cmds +debug = False +class RemoteSage: + def __init__(self, server, user, password): + self._srv = server.rstrip('/') + sep = '___S_A_G_E___' + self._response = re.compile('(?P<header>.*)' + sep + + '\n*(?P<output>.*)', re.DOTALL) + self._404 = re.compile('404 Not Found') + self._session = self._get_url('login', + urllib.urlencode({'username': user, + 'password': + password}))['session'] + self._codewrap = """try: +{{0}} +except: + print('{0}') + traceback.print_exc()""".format(traceback_str) + self.do_block(""" + import traceback + def __st_plot__(counter, _p_, format='notprovided', **kwargs): + if format == 'notprovided': + formats = ['eps', 'pdf'] + else: + formats = [format] + for fmt in formats: + plotfilename = 'plot-%s.%s' % (counter, fmt) + _p_.save(filename=plotfilename, **kwargs)""") + + def _encode(self, d): + return 'session={0}&'.format(self._session) + urllib.urlencode(d) + + def _get_url(self, action, u): + with closing(urllib.urlopen(self._srv + '/simple/' + action + + '?' + u)) as h: + data = self._response.match(h.read()) + result = json.loads(data.group('header')) + result['output'] = data.group('output').rstrip() + return result + + def _get_file(self, fn, cell, ofn=None): + with closing(urllib.urlopen(self._srv + '/simple/' + 'file' + '?' + + self._encode({'cell': cell, 'file': fn}))) as h: + myfn = ofn if ofn else fn + data = h.read() + if not self._404.search(data): + with open(myfn, 'w') as f: + f.write(data) + else: + print('Remote server reported {0} could not be found:'.format( + fn)) + print(data) + def _do_cell(self, code): + realcode = self._codewrap.format(code) + result = self._get_url('compute', self._encode({'code': realcode})) + if result['status'] == 'computing': + cell = result['cell_id'] + while result['status'] == 'computing': + sys.stdout.write('working...') + sys.stdout.flush() + time.sleep(10) + result = self._get_url('status', self._encode({'cell': cell})) + if debug: + print('cell: <<<', realcode, '>>>', 'result: <<<', + result['output'], '>>>', sep='\n') + return result + + def do_inline(self, code): + return self._do_cell(' print(latex({0}))'.format(code)) + + def do_block(self, code): + result = self._do_cell(code) + for fn in result['files']: + self._get_file(fn, result['cell_id']) + return result + + def do_plot(self, num, code, plotdir): + result = self._do_cell(' __st_plot__({0}, {1})'.format(num, code)) + for fn in result['files']: + self._get_file(fn, result['cell_id'], os.path.join(plotdir, fn)) + return result + def close(self): + sys.stdout.write('Logging out of {0}...'.format(server)) + sys.stdout.flush() + self._get_url('logout', self._encode({})) + print('done') +def do_plot_setup(plotdir): + printc('initializing plots directory...') + if os.path.isdir(plotdir): + shutil.rmtree(plotdir) + os.mkdir(plotdir) + return True + +did_plot_setup = False +plotdir = 'sage-plots-for-' + jobname + '.tex' + +def labelline(n, s): + return r'\newlabel{@sageinline' + str(n) + '}{{' + s + '}{}{}{}{}}\n' + +def printc(s): + print(s, end='') + sys.stdout.flush() + +error = re.compile("(^" + traceback_str + ")|(^Syntax Error:)", re.MULTILINE) + +def check_for_error(string, line): + if error.search(string): + print(""" +**** Error in Sage code on line {0} of {1}.tex! +{2} +**** Running Sage on {1}.sage failed! Fix {1}.tex and try again.""".format( + line, jobname, string)) + sys.exit(1) +print('Processing Sage code for {0}.tex using remote Sage server.'.format( + jobname)) + +if login_info_file: + with open(login_info_file, 'r') as f: + print('Reading login information from {0}.'.format(login_info_file)) + get_val = lambda x: x.split('=')[1].strip().strip('\'"') + for line in f: + print(line) + if not line.startswith('#'): + if line.startswith('server') and not server: + server = get_val(line) + if line.startswith('username') and not username: + username = get_val(line) + if line.startswith('password') and not password: + password = get_val(line) + +if not server: + server = raw_input('Enter server: ') + +if not server.startswith('http'): + server = 'https://' + server + +if not username: + username = raw_input('Enter username: ') + +if not password: + from getpass import getpass + password = getpass('Please enter password for user {0} on {1}: '.format( + username, server)) + +printc('Parsing {0}.sage...'.format(jobname)) +cmds = parsedotsage(jobname + '.sage') +print('done.') + +sout = '% This file was *autogenerated* from the file {0}.sage.\n'.format( + os.path.splitext(jobname)[0]) + +printc('Logging into {0} and starting session...'.format(server)) +with closing(RemoteSage(server, username, password)) as sage: + print('done.') + for cmd in cmds: + if cmd['type'] == 'inline': + printc('Inline formula {0}...'.format(cmd['num'])) + result = sage.do_inline(cmd['code']) + check_for_error(result['output'], cmd['goboom']) + sout += labelline(cmd['num'], result['output']) + print('done.') + if cmd['type'] == 'block': + printc('Code block begin...') + result = sage.do_block(cmd['code']) + check_for_error(result['output'], cmd['goboom']) + print('end.') + if cmd['type'] == 'plot': + printc('Plot {0}...'.format(cmd['num'])) + if not did_plot_setup: + did_plot_setup = do_plot_setup(plotdir) + result = sage.do_plot(cmd['num'], cmd['code'], plotdir) + check_for_error(result['output'], cmd['goboom']) + print('done.') + if cmd['type'] == 'pause': + print(cmd['msg']) + if int(time.time()) % 2280 == 0: + printc('Unscheduled offworld activation; closing iris...') + time.sleep(1) + print('end.') + +with open(jobname + '.sage', 'r') as sagef: + h = hashlib.md5() + for line in sagef: + if (not line.startswith(' _st_.goboom') and + not line.startswith("print 'SageT")): + h.update(line) + sout += """%{0}% md5sum of corresponding .sage file +{1} (minus "goboom" and pause/unpause lines) +""".format(h.hexdigest(), '%') + +printc('Writing .sout file...') +with open(jobname + '.sout', 'w') as soutf: + soutf.write(sout) + print('done.') +print('Sage processing complete. Run LaTeX on {0}.tex again.'.format(jobname)) + diff --git a/Master/texmf-dist/doc/latex/sagetex/sagetex.py b/Master/texmf-dist/doc/latex/sagetex/sagetex.py index 2686b4348f5..576847894f7 100644 --- a/Master/texmf-dist/doc/latex/sagetex/sagetex.py +++ b/Master/texmf-dist/doc/latex/sagetex/sagetex.py @@ -1,38 +1,39 @@ -""" -%% -%% This is file `sagetex.py', -%% generated with the docstrip utility. -%% -%% The original source files were: -%% -%% sagetexpackage.dtx (with options: `python') -%% -%% This is a generated file. -%% -%% Copyright (C) 2008 by Dan Drake <ddrake@member.ams.org> -%% -%% This program is free software: you can redistribute it and/or modify it -%% 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. -%% -%% This program is distributed in the hope that it will be useful, but -%% WITHOUT ANY WARRANTY; without even the implied warranty of -%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%% General Public License for more details. -%% -%% You should have received a copy of the GNU General Public License along -%% with this program. If not, see <http://www.gnu.org/licenses/> -%% +## +## This is file `sagetex.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## sagetexpackage.dtx (with options: `python') +## py-and-sty.dtx (with options: `python') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> +## +## This program is free software: you can redistribute it and/or modify it +## 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. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see <http://www.gnu.org/licenses/>. +## +__version__ = """ + [2009/06/17 v2.2.1 embedding Sage into LaTeX documents] """ 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 used by Sage scripts generated from a LaTeX document -using the sagetex package. Keep it somewhere where Sage and Python can -find it and it will automatically be imported.""") +This file will be automatically used by Sage scripts generated from a +LaTeX document using the SageTeX package.""") sys.exit() from sage.misc.latex import latex import os @@ -41,86 +42,83 @@ import hashlib import traceback import subprocess import shutil -initplot_done = False -dirname = None -filename = "" -def progress(t,linebreak=True): - if linebreak: - print(t) - else: - sys.stdout.write(t) -def openout(f): - global filename - filename = f - global _file_ - _file_ = open(f + '.sout.tmp', 'w') - s = '% This file was *autogenerated* from the file ' + \ - os.path.splitext(filename)[0] + '.sage.\n' - _file_.write(s) - progress('Processing Sage code for %s.tex...' % filename) -def initplot(f): - global initplot_done - if not initplot_done: - progress('Initializing plots directory') - global dirname - dirname = 'sage-plots-for-' + f + '.tex' - if os.path.isdir(dirname): - shutil.rmtree(dirname) - os.mkdir(dirname) - initplot_done = True -def inline(counter, s): - progress('Inline formula %s' % counter) - _file_.write('\\newlabel{@sagelabel' + str(counter) + '}{{' + \ - latex(s) + '}{}{}{}{}}\n') -def blockbegin(): - progress('Code block begin...', False) -def blockend(): - progress('end') -def plot(counter, p, format='notprovided', epsmagick=False, **kwargs): - global dirname - progress('Plot %s' % counter) - if format == 'notprovided': - formats = ['eps', 'pdf'] - else: - formats = [format] - for fmt in formats: - plotfilename = os.path.join(dirname, 'plot-%s.%s' % (counter, fmt)) - #print(' plotting %s with args %s' % (plotfilename, kwargs)) - p.save(filename=plotfilename, **kwargs) - if format != 'notprovided' and epsmagick is True: - print('Calling Imagemagick to convert plot-%s.%s to EPS' % \ - (counter, format)) - toeps(counter, format) -def toeps(counter, ext): - global dirname - subprocess.check_call(['convert',\ - '%s/plot-%s.%s' % (dirname, counter, ext), \ - '%s/plot-%s.eps' % (dirname, counter)]) -def goboom(line): - global filename - print('\n**** Error in Sage code on line %s of %s.tex! Traceback\ - follows.' % (line, filename)) - traceback.print_exc() - print('\n**** Running Sage on %s.sage failed! Fix %s.tex and try\ - again.' % (filename, filename)) - os.remove(filename + '.sout.tmp') - sys.exit(1) -def endofdoc(): - global filename - sagef = open(filename + '.sage', 'r') - m = hashlib.md5() - for line in sagef: - if line[0:15] != ' sagetex.goboom': - m.update(line) - s = '%' + m.hexdigest() + '% md5sum of .sage file (minus "goboom" \ -lines) that produced this\n' - _file_.write(s) - _file_.close() - os.rename(filename + '.sout.tmp', filename + '.sout') - progress('Sage processing complete. Run LaTeX on %s.tex again.' %\ - filename) -""" -\endinput -%% -%% End of file `sagetex.py'. -""" +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 + 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) + def progress(self, t,linebreak=True): + if linebreak: + print(t) + else: + sys.stdout.write(t) + sys.stdout.flush() + def initplot(self): + self.progress('Initializing plots directory') + if os.path.isdir(self.plotdir): + shutil.rmtree(self.plotdir) + os.mkdir(self.plotdir) + self.didinitplot = True + def inline(self, counter, s): + self.progress('Inline formula %s' % counter) + self.souttmp.write('\\newlabel{@sageinline' + str(counter) + '}{{' + \ + latex(s).rstrip() + '}{}{}{}{}}\n') + def blockbegin(self): + self.progress('Code block begin...', False) + def blockend(self): + self.progress('end') + def plot(self, counter, _p_, format='notprovided', **kwargs): + if not self.didinitplot: + self.initplot() + self.progress('Plot %s' % counter) + if format == 'notprovided': + formats = ['eps', 'pdf'] + else: + formats = [format] + for fmt in formats: + 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)) + _p_.save(filename=plotfilename, **kwargs) + if format != 'notprovided' and self.useimagemagick: + self.progress('Calling Imagemagick to convert plot-%s.%s to EPS' % \ + (counter, format)) + self.toeps(counter, format) + def toeps(self, counter, ext): + subprocess.check_call(['convert',\ + '%s/plot-%s.%s' % (self.plotdir, counter, ext), \ + '%s/plot-%s.eps' % (self.plotdir, counter)]) + 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(int(1)) + def endofdoc(self): + sagef = open(self.filename + '.sage', 'r') + m = hashlib.md5() + for line in sagef: + if line[0:12] != " _st_.goboom" and line[0:12] != "print 'SageT": + m.update(line) + s = '%' + m.hexdigest() + '% md5sum of corresponding .sage file\ + (minus "goboom" and pause/unpause lines)\n' + self.souttmp.write(s) + 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) + diff --git a/Master/texmf-dist/doc/latex/sagetex/sagetexpackage.pdf b/Master/texmf-dist/doc/latex/sagetex/sagetexpackage.pdf Binary files differindex 43a32df1580..2f9fc546ecd 100644 --- a/Master/texmf-dist/doc/latex/sagetex/sagetexpackage.pdf +++ b/Master/texmf-dist/doc/latex/sagetex/sagetexpackage.pdf diff --git a/Master/texmf-dist/doc/latex/sagetex/sagetexparse.py b/Master/texmf-dist/doc/latex/sagetex/sagetexparse.py new file mode 100644 index 00000000000..c1927348032 --- /dev/null +++ b/Master/texmf-dist/doc/latex/sagetex/sagetexparse.py @@ -0,0 +1,151 @@ +## +## This is file `sagetexparse.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## scripts.dtx (with options: `parsermod') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> +## +## This program is free software: you can redistribute it and/or modify it +## 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. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see <http://www.gnu.org/licenses/>. +## +import sys +from pyparsing import * +def skipToMatching(opener, closer): + nest = nestedExpr(opener, closer) + nest.setParseAction(lambda l, s, t: l[s:getTokensEndLoc()]) + return nest + +curlybrackets = skipToMatching('{', '}') +squarebrackets = skipToMatching('[', ']') +sagemacroparser = r'\sage' + curlybrackets('code') +sageplotparser = (r'\sageplot' + + Optional(squarebrackets)('opts') + + Optional(squarebrackets)('format') + + curlybrackets('code')) +sagetexpause = Literal(r'\sagetexpause') +sagetexunpause = Literal(r'\sagetexunpause') +class SoutParser(): + def __init__(self, fn): + self.label = [] + parselabel = (r'\newlabel{@sageinline' + + Word(nums)('num') + + '}{' + + curlybrackets('result') + + '{}{}{}{}}') + parselabel.ignore('%' + restOfLine) + parselabel.setParseAction(self.newlabel) + try: + OneOrMore(parselabel).parseFile(fn) + except IOError: + print 'Error accessing %s; exiting. Does your .sout file exist?' % fn + sys.exit(1) + def newlabel(self, s, l, t): + self.label.append(t.result[1:-1]) +class DeSageTex(): + def __init__(self, fn): + self.sagen = 0 + self.plotn = 0 + self.fn = fn + self.sout = SoutParser(fn + '.sout') + smacro = sagemacroparser + smacro.setParseAction(self.sage) + usepackage = (r'\usepackage' + + Optional(squarebrackets) + + '{sagetex}') + usepackage.setParseAction(replaceWith(r"""% "\usepackage{sagetex}" line was here: +\RequirePackage{verbatim} +\RequirePackage{graphicx} +\newcommand{\sagetexpause}{\relax} +\newcommand{\sagetexunpause}{\relax}""")) + splot = sageplotparser + splot.setParseAction(self.plot) + beginorend = oneOf('begin end') + blockorverb = 'sage' + oneOf('block verbatim') + blockorverb.setParseAction(replaceWith('verbatim')) + senv = '\\' + beginorend + '{' + blockorverb + '}' + silent = Literal('sagesilent') + silent.setParseAction(replaceWith('comment')) + ssilent = '\\' + beginorend + '{' + silent + '}' + stexindent = Suppress(r'\setlength{\sagetexindent}' + curlybrackets) + doit = smacro | senv | ssilent | usepackage | splot | stexindent + doit.ignore('%' + restOfLine) + doit.ignore(r'\begin{verbatim}' + SkipTo(r'\end{verbatim}')) + doit.ignore(r'\begin{comment}' + SkipTo(r'\end{comment}')) + doit.ignore(r'\sagetexpause' + SkipTo(r'\sagetexunpause')) + str = ''.join(open(fn + '.tex', 'r').readlines()) + self.result = doit.transformString(str) + def sage(self, s, l, t): + self.sagen += 1 + return self.sout.label[self.sagen - 1] + def plot(self, s, l, t): + self.plotn += 1 + if len(t.opts) == 0: + opts = r'[width=.75\textwidth]' + else: + opts = t.opts[0] + return (r'\includegraphics%s{sage-plots-for-%s.tex/plot-%s}' % + (opts, self.fn, self.plotn - 1)) +class SageCodeExtractor(): + def __init__(self, fn): + smacro = sagemacroparser + smacro.setParseAction(self.macroout) + + splot = sageplotparser + splot.setParseAction(self.plotout) + env_names = oneOf('sageblock sageverbatim sagesilent') + senv = r'\begin{' + env_names('env') + '}' + SkipTo( + r'\end{' + matchPreviousExpr(env_names) + '}')('code') + senv.leaveWhitespace() + senv.setParseAction(self.envout) + + spause = sagetexpause + spause.setParseAction(self.pause) + + sunpause = sagetexunpause + sunpause.setParseAction(self.unpause) + + doit = smacro | splot | senv | spause | sunpause + + 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' + + def pause(self, s, l, t): + self.result += ('# SageTeX (probably) paused on input line %s.\n\n' % + (lineno(l, s))) + + def unpause(self, s, l, t): + self.result += ('# SageTeX (probably) unpaused on input line %s.\n\n' % + (lineno(l, s))) + diff --git a/Master/texmf-dist/source/latex/sagetex/py-and-sty.dtx b/Master/texmf-dist/source/latex/sagetex/py-and-sty.dtx new file mode 100644 index 00000000000..3798ec58547 --- /dev/null +++ b/Master/texmf-dist/source/latex/sagetex/py-and-sty.dtx @@ -0,0 +1,907 @@ +% \section{Implementation} +% \label{sec: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} +% \label{sec:sty-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, default indent, and flags. +% \begin{macrocode} +\newcounter{ST@inline} +\newcounter{ST@plot} +\setcounter{ST@inline}{0} +\setcounter{ST@plot}{0} +\newlength{\sagetexindent} +\setlength{\sagetexindent}{5ex} +\newif\ifST@paused +\ST@pausedfalse +% \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. If +% the |.sout| file isn't found, print the usual \TeX-style message. This +% allows programs +% (\href{http://www.phys.psu.edu/~collins/software/latexmk-jcc/}{\texttt{Latexmk}}, for example) +% that read the |.log| file or terminal output to detect +% the need for another typesetting run to do so. If the ``\texttt{No +% file foo.sout}'' line doesn't work for some software package, please +% let me know and I can change it to use |PackageInfo| or whatever. +% \begin{macrocode} +\InputIfFileExists{\jobname.sout}{}{\typeout{No file \jobname.sout.}} +% \end{macrocode} +% \changes{v2.1.1}{2009/05/14}{Add typeout if .sout file not found} +% +% 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. We need this for the |\sage| macro below. +% \begin{macrocode} +\AtBeginDocument{\provideenvironment{NoHyper}{}{}} +% \end{macrocode} +% +% \subsubsection{The \texttt{\protect\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}. Back in \LTX-land: if paused, say so. +% \begin{macrocode} +\ifST@paused + \mbox{(Sage\TeX{} is paused)}% +% \end{macrocode} +% Otherwise\ldots 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} +\else + \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. +% \begin{macrocode} + \@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{} +\fi +% \end{macrocode} +% In any case, the last thing to do is step the counter. +% \begin{macrocode} +\stepcounter{ST@inline}} +% \end{macrocode} +% \end{macro} +% +% \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{\protect\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} +% Step the counter and we're done with the usual work. +% \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. If we are paused, it just puts in a little box saying +% so. +% \begin{macrocode} +\newcommand{\ST@inclgrfx}[2]{\ifST@paused + \fbox{\rule[-1cm]{0cm}{2cm}Sage\TeX{} is paused; no graphic} +\else + \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}} +\fi} +% \end{macrocode} +% \autoref{f:stig} makes this a bit clearer. +% \begin{figure} +% \centering +% \begin{tikzpicture} +% \tikzstyle{level 1}=[sibling distance=4cm] +% \node [box] {Paused?} +% child {node [box] {Insert ``we're paused'' box} +% edge from parent node[left] {yes}} +% child {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}} +% edge from parent node[right] {no}}; +% \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 the 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.\\ +% +% \subsubsection{Pausing \ST} +% \label{sec:pausing-sagetex} +% +% How can one have Sage to stop processing \ST output for a little +% while, and then start again? At first I thought I would need some sort +% of ``goto'' statement in Python, but later realized that there's a +% dead simple solution: write triple quotes to the |.sage| file to +% comment out the code. Okay, so this isn't \emph{really} commenting out +% the code; PEP 8 says block comments should use ``|#|'' and Sage will +% read in the ``commented-out'' code as a string literal. For the +% purposes of \ST, I think this is a good decision, though, since (1) +% the pausing mechanism is orthogonal to everything else, which makes it +% easier to not screw up other code, and (2) it will always work. +% +% This illustrates what I really like about \ST: it mixes \LTX and +% Sage/Python, and often what is difficult or impossible in one system +% is trivial in the other. +% +% \begin{macro}{sagetexpause} +% This macro pauses \ST by effectively commenting out code in the +% |.sage| file. When running the corresponding |.sage| file, Sage will +% skip over any commands issued while \ST is paused. +% \begin{macrocode} +\newcommand{\sagetexpause}{\ifST@paused\relax\else +\ST@wsf{print 'SageTeX paused on \jobname.tex line \the\inputlineno'^^J"""} +\ST@pausedtrue +\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{sagetexunpause} +% This is the obvious companion to |\sagetexpause|. +% \begin{macrocode} +\newcommand{\sagetexunpause}{\ifST@paused +\ST@wsf{"""^^Jprint 'SageTeX unpaused on \jobname.tex line \the\inputlineno'} +\ST@pausedfalse +\fi} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{End-of-document cleanup} +% \label{sec:end-of-doc-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. We check to see if +% we're paused first, so that we can finish the triple-quoted string in +% the |.sage| file. +% \begin{macrocode} +\AtEndDocument{\ifST@paused +\ST@wsf{"""^^Jprint 'SageTeX unpaused at end of \jobname.tex'} +\fi +\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} +% \label{sec:py-file} +% +% \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) + sys.stdout.flush() +% \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).rstrip() + '}{}{}{}{}}\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)) + _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} +% \phantomsection\label{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(int(1)) +% \end{macrocode} +% We use |int(1)| above to make sure |sys.exit| sees a Python integer; +% see +% \href{http://trac.sagemath.org/sage_trac/ticket/2861#comment:5}{ticket +% \#2861}. +% \changes{v2.0.2}{2008/04/21}{Make sure sys.exit sees a Python integer} +% \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| and pause/unpause lines, so we will strip those lines out. +% What we do below is exactly equivalent to running +% \begin{center} +% \verb+egrep '^( _st_.goboom|print .SageT)' filename.sage | md5sum+ +% \end{center} +% in a shell. +% \begin{macrocode} + def endofdoc(self): + sagef = open(self.filename + '.sage', 'r') + m = hashlib.md5() + for line in sagef: + if line[0:12] != " _st_.goboom" and line[0:12] != "print 'SageT": + m.update(line) + s = '%' + m.hexdigest() + '% md5sum of corresponding .sage file\ + (minus "goboom" and pause/unpause 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} +% % \changes{v2.1.1}{2009/05/14}{Fix bug in finding md5 sum introduced by +% pause facility} +% \end{macro} + +% \endinput +%</python> +% Local Variables: +% mode: doctex +% TeX-master: "sagetexpackage" +% End: diff --git a/Master/texmf-dist/source/latex/sagetex/remote-sagetex.dtx b/Master/texmf-dist/source/latex/sagetex/remote-sagetex.dtx new file mode 100644 index 00000000000..2360e220277 --- /dev/null +++ b/Master/texmf-dist/source/latex/sagetex/remote-sagetex.dtx @@ -0,0 +1,438 @@ +% \section{The \texttt{remote-sagetex} script} +% \label{sec:remote-sagetex-code} +% +% +% Here we describe the Python code for |remote-sagetex.py|. Since its +% job is to replicate the functionality of using Sage and |sagetex.py|, +% there is some overlap with the Python module. +% +% \iffalse +%<*remotesagetex> +% \fi +% +% 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} +from __future__ import print_function +import json +import sys +import time +import re +import urllib +import hashlib +import os +import os.path +import shutil +import getopt +from contextlib import closing + +######################################################################### +# You can provide a filename here and the script will read your login # +# information from that file. The format must be: # +# # +# server = 'http://foo.com:8000' # +# username = 'my_name' # +# password = 's33krit' # +# # +# You can omit one or more of those lines, use " quotes, and put hash # +# marks at the beginning of a line for comments. Command-line args # +# take precedence over information from the file. # +######################################################################### +login_info_file = None # e.g. '/home/foo/Private/sagetex-login.txt' + + +usage = """Process a SageTeX-generated .sage file using a remote Sage server. + +Usage: {0} [options] inputfile.sage + +Options: + + -h, --help: print this message + -s, --server: the Sage server to contact + -u, --username: username on the server + -p, --password: your password + -f, --file: get login information from a file + +If the server does not begin with the four characters `http', then +`https://' will be prepended to the server name. + +You can hard-code the filename from which to read login information into +the remote-sagetex script. Command-line arguments take precedence over +the contents of that file. See the SageTeX documentation for formatting +details. + +If any of the server, username, and password are omitted, you will be +asked to provide them. + +See the SageTeX documentation for more details on usage and limitations +of remote-sagetex.""".format(sys.argv[0]) + +server, username, password = (None,) * 3 + +try: + opts, args = getopt.getopt(sys.argv[1:], 'hs:u:p:f:', + ['help', 'server=', 'user=', 'password=', 'file=']) +except getopt.GetoptError as err: + print(str(err), usage, sep='\n\n') + sys.exit(2) + +for o, a in opts: + if o in ('-h', '--help'): + print(usage) + sys.exit() + elif o in ('-s', '--server'): + server = a + elif o in ('-u', '--user'): + username = a + elif o in ('-p', '--password'): + password = a + elif o in ('-f', '--file'): + login_info_file = a + +if len(args) != 1: + print('Error: must specify exactly one file. Please specify options first.', + usage, sep='\n\n') + sys.exit(2) + +jobname = os.path.splitext(args[0])[0] +% \end{macrocode} +% When we send things to the server, we get everything back as a string, +% including tracebacks. We can search through output using regexps to +% look for typical traceback strings, but there's a more robust way: put +% in a special string that changes every time and is printed when +% there's an error, and look for that. Then it is massively unlikely +% that a user's code could produce output that we'll mistake for an +% actual traceback. System time will work well enough for these +% purposes. We produce this string now, and we it when parsing the +% |.sage| file (we insert it into code blocks) and when parsing the +% output that the remote server gives us. +% \begin{macrocode} +traceback_str = 'Exception in SageTeX session {0}:'.format(time.time()) +% \end{macrocode} +% \begin{macro}{parsedotsage} +% To figure out what commands to send the remote server, we actually +% read in the |.sage| file as strings and parse it. This seems a bit +% strange, but since we know exactly what the format of that file is, we +% can parse it with a couple flags and a handful of regexps. +% \begin{macrocode} +def parsedotsage(fn): + with open(fn, 'r') as f: +% \end{macrocode} +% Here are the regexps we use to snarf the interesting bits out of the +% |.sage| file. Below we'll use the |re| module's |match| function so we +% needn't anchor any of these at the beginning of the line. +% \begin{macrocode} + inline = re.compile(r" _st_.inline\((?P<num>\d+), (?P<code>.*)\)") + plot = re.compile(r" _st_.plot\((?P<num>\d+), (?P<code>.*)\)") + goboom = re.compile(r" _st_.goboom\((?P<num>\d+)\)") + pausemsg = re.compile(r"print.'(?P<msg>SageTeX (un)?paused.*)'") + blockbegin = re.compile(r"_st_.blockbegin\(\)") + ignore = re.compile(r"(try:)|(except):") + in_comment = False + in_block = False + cmds = [] +% \end{macrocode} +% Okay, let's go through the file. We're going to make a list of +% dictionaries. Each dictionary corresponds to something we have to do +% with the remote server, except for the pause/unpause ones, which we +% only use to print out information for the user. All the dictionaries +% have a |type| key, which obviously tells you type they are. The +% pause/unpause dictionaries then just have a |msg| which we toss out to +% the user. The ``real'' dictionaries all have the following keys: +% \begin{itemize} +% \item |type|: one of |inline|, |plot|, and |block|. +% \item |goboom|: used to help the user pinpoint errors, just like the +% |goboom| function (page \pageref{macro:goboom}) does. +% \item |code|: the code to be executed. +% \end{itemize} +% Additionally, the |inline| and |plot| dicts have a |num| key for the +% label we write to the |.sout| file. +% +% Here's the whole parser loop. The interesting bits are for parsing +% blocks because there we need to accumulate several lines of code. +% \begin{macrocode} + for line in f.readlines(): + if line.startswith('"""'): + in_comment = not in_comment + elif not in_comment: + m = pausemsg.match(line) + if m: + cmds.append({'type': 'pause', + 'msg': m.group('msg')}) + m = inline.match(line) + if m: + cmds.append({'type': 'inline', + 'num': m.group('num'), + 'code': m.group('code')}) + m = plot.match(line) + if m: + cmds.append({'type': 'plot', + 'num': m.group('num'), + 'code': m.group('code')}) +% \end{macrocode} +% The order of the next three ``if''s is important, since we need the +% ``goboom'' line and the ``blockbegin'' line to \emph{not} get included +% into the block's code. Note that the lines in the |.sage| file already +% have some indentation, which we'll use when sending the block to the +% server---we wrap the text in a try/except. +% \begin{macrocode} + m = goboom.match(line) + if m: + cmds[-1]['goboom'] = m.group('num') + if in_block: + in_block = False + if in_block and not ignore.match(line): + cmds[-1]['code'] += line + if blockbegin.match(line): + cmds.append({'type': 'block', + 'code': ''}) + in_block = True + return cmds +% \end{macrocode} +% \end{macro} +% Parsing the |.sage| file is simple enough so that we can write one +% function and just do it. Interacting with the remote server is a bit +% more complicated, and requires us to carry some state, so let's make a +% class. +% +% \begin{macro}{RemoteSage} +% \changes{v2.2.1}{2009/06/20}{Fix stupid bug in \texttt{do\_inline()} +% so that we actually write output to .sout file} +% +% This is pretty simple; it's more or less a translation of the examples +% in \texttt{sage/server/simple/twist.py}. +% \begin{macrocode} +debug = False +class RemoteSage: + def __init__(self, server, user, password): + self._srv = server.rstrip('/') + sep = '___S_A_G_E___' + self._response = re.compile('(?P<header>.*)' + sep + + '\n*(?P<output>.*)', re.DOTALL) + self._404 = re.compile('404 Not Found') + self._session = self._get_url('login', + urllib.urlencode({'username': user, + 'password': + password}))['session'] +% \end{macrocode} +% In the string below, we want to do ``partial formatting'': we format +% in the traceback string now, and want to be able to format in the code +% later. The double braces get ignored by |format()| now, and are picked +% up by |format()| when we use this later. +% \begin{macrocode} + self._codewrap = """try: +{{0}} +except: + print('{0}') + traceback.print_exc()""".format(traceback_str) + self.do_block(""" + import traceback + def __st_plot__(counter, _p_, format='notprovided', **kwargs): + if format == 'notprovided': + formats = ['eps', 'pdf'] + else: + formats = [format] + for fmt in formats: + plotfilename = 'plot-%s.%s' % (counter, fmt) + _p_.save(filename=plotfilename, **kwargs)""") + + def _encode(self, d): + return 'session={0}&'.format(self._session) + urllib.urlencode(d) + + def _get_url(self, action, u): + with closing(urllib.urlopen(self._srv + '/simple/' + action + + '?' + u)) as h: + data = self._response.match(h.read()) + result = json.loads(data.group('header')) + result['output'] = data.group('output').rstrip() + return result + + def _get_file(self, fn, cell, ofn=None): + with closing(urllib.urlopen(self._srv + '/simple/' + 'file' + '?' + + self._encode({'cell': cell, 'file': fn}))) as h: + myfn = ofn if ofn else fn + data = h.read() + if not self._404.search(data): + with open(myfn, 'w') as f: + f.write(data) + else: + print('Remote server reported {0} could not be found:'.format( + fn)) + print(data) +% \end{macrocode} +% The |code| below gets stuffed between a try/except, so make sure it's +% indented! +% \begin{macrocode} + def _do_cell(self, code): + realcode = self._codewrap.format(code) + result = self._get_url('compute', self._encode({'code': realcode})) + if result['status'] == 'computing': + cell = result['cell_id'] + while result['status'] == 'computing': + sys.stdout.write('working...') + sys.stdout.flush() + time.sleep(10) + result = self._get_url('status', self._encode({'cell': cell})) + if debug: + print('cell: <<<', realcode, '>>>', 'result: <<<', + result['output'], '>>>', sep='\n') + return result + + def do_inline(self, code): + return self._do_cell(' print(latex({0}))'.format(code)) + + def do_block(self, code): + result = self._do_cell(code) + for fn in result['files']: + self._get_file(fn, result['cell_id']) + return result + + def do_plot(self, num, code, plotdir): + result = self._do_cell(' __st_plot__({0}, {1})'.format(num, code)) + for fn in result['files']: + self._get_file(fn, result['cell_id'], os.path.join(plotdir, fn)) + return result +% \end{macrocode} +% When using the simple server API, it's important to log out so the +% server doesn't accumulate idle sessions that take up lots of memory. +% We define a |close()| method and use this class with the |closing| +% context manager that always calls |close()| on the way out. +% \begin{macrocode} + def close(self): + sys.stdout.write('Logging out of {0}...'.format(server)) + sys.stdout.flush() + self._get_url('logout', self._encode({})) + print('done') +% \end{macrocode} +% \end{macro} +% Next we have a little pile of miscellaneous functions and variables +% that we want to have at hand while doing our work. Note that we again +% use the traceback string in the error-finding regular expression. +% \begin{macrocode} +def do_plot_setup(plotdir): + printc('initializing plots directory...') + if os.path.isdir(plotdir): + shutil.rmtree(plotdir) + os.mkdir(plotdir) + return True + +did_plot_setup = False +plotdir = 'sage-plots-for-' + jobname + '.tex' + +def labelline(n, s): + return r'\newlabel{@sageinline' + str(n) + '}{{' + s + '}{}{}{}{}}\n' + +def printc(s): + print(s, end='') + sys.stdout.flush() + +error = re.compile("(^" + traceback_str + ")|(^Syntax Error:)", re.MULTILINE) + +def check_for_error(string, line): + if error.search(string): + print(""" +**** Error in Sage code on line {0} of {1}.tex! +{2} +**** Running Sage on {1}.sage failed! Fix {1}.tex and try again.""".format( + line, jobname, string)) + sys.exit(1) +% \end{macrocode} +% Now let's actually start doing stuff. +% \begin{macrocode} +print('Processing Sage code for {0}.tex using remote Sage server.'.format( + jobname)) + +if login_info_file: + with open(login_info_file, 'r') as f: + print('Reading login information from {0}.'.format(login_info_file)) + get_val = lambda x: x.split('=')[1].strip().strip('\'"') + for line in f: + print(line) + if not line.startswith('#'): + if line.startswith('server') and not server: + server = get_val(line) + if line.startswith('username') and not username: + username = get_val(line) + if line.startswith('password') and not password: + password = get_val(line) + +if not server: + server = raw_input('Enter server: ') + +if not server.startswith('http'): + server = 'https://' + server + +if not username: + username = raw_input('Enter username: ') + +if not password: + from getpass import getpass + password = getpass('Please enter password for user {0} on {1}: '.format( + username, server)) + +printc('Parsing {0}.sage...'.format(jobname)) +cmds = parsedotsage(jobname + '.sage') +print('done.') + +sout = '% This file was *autogenerated* from the file {0}.sage.\n'.format( + os.path.splitext(jobname)[0]) + +printc('Logging into {0} and starting session...'.format(server)) +with closing(RemoteSage(server, username, password)) as sage: + print('done.') + for cmd in cmds: + if cmd['type'] == 'inline': + printc('Inline formula {0}...'.format(cmd['num'])) + result = sage.do_inline(cmd['code']) + check_for_error(result['output'], cmd['goboom']) + sout += labelline(cmd['num'], result['output']) + print('done.') + if cmd['type'] == 'block': + printc('Code block begin...') + result = sage.do_block(cmd['code']) + check_for_error(result['output'], cmd['goboom']) + print('end.') + if cmd['type'] == 'plot': + printc('Plot {0}...'.format(cmd['num'])) + if not did_plot_setup: + did_plot_setup = do_plot_setup(plotdir) + result = sage.do_plot(cmd['num'], cmd['code'], plotdir) + check_for_error(result['output'], cmd['goboom']) + print('done.') + if cmd['type'] == 'pause': + print(cmd['msg']) + if int(time.time()) % 2280 == 0: + printc('Unscheduled offworld activation; closing iris...') + time.sleep(1) + print('end.') + +with open(jobname + '.sage', 'r') as sagef: + h = hashlib.md5() + for line in sagef: + if (not line.startswith(' _st_.goboom') and + not line.startswith("print 'SageT")): + h.update(line) +% \end{macrocode} +% Putting the |{1}| in the string, just to replace it with |%|, seems a +% bit weird, but if I put a single percent sign there, Docstrip won't +% put that line into the resulting |.py| file---and if I put two percent +% signs, it replaces them with |\MetaPrefix| which is |##| when this +% file is generated. This is a quick and easy workaround. +% \begin{macrocode} + sout += """%{0}% md5sum of corresponding .sage file +{1} (minus "goboom" and pause/unpause lines) +""".format(h.hexdigest(), '%') + +printc('Writing .sout file...') +with open(jobname + '.sout', 'w') as soutf: + soutf.write(sout) + print('done.') +print('Sage processing complete. Run LaTeX on {0}.tex again.'.format(jobname)) +% \end{macrocode} + +% \endinput +%</remotesagetex> +% Local Variables: +% mode: doctex +% TeX-master: "sagetexpackage" +% End: diff --git a/Master/texmf-dist/source/latex/sagetex/sagetexpackage.dtx b/Master/texmf-dist/source/latex/sagetex/sagetexpackage.dtx index 95be02d58d0..6b6acfd8f4e 100644 --- a/Master/texmf-dist/source/latex/sagetex/sagetexpackage.dtx +++ b/Master/texmf-dist/source/latex/sagetex/sagetexpackage.dtx @@ -1,22 +1,24 @@ % \iffalse meta-comment % -% Copyright (C) 2008 by Dan Drake <ddrake@member.ams.org> +% Copyright (C) 2009 by Dan Drake <ddrake (at) member (dot) ams (dot) org> % ------------------------------------------------------- % -% See the "Copying and licenses" section for the terms under which this -% source code and documentation may be modified and distributed. +% See the "Copying and licenses" section in 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 -% and sagetex.py. -% +% This work consists of the files sagetexpackage.dtx, py-and-sty.dtx, +% scripts.dtx, remote-sagetex.dtx, sagetexpackage.ins, example.tex, +% and the derived files sagetex.sty, sagetex.py, sagetexparse.py, +% makestatic.py, extractsagecode.py, and remote-sagetex.py. +% % \fi % % \iffalse @@ -25,27 +27,112 @@ %</driver> %<latex>\NeedsTeXFormat{LaTeX2e} %<latex>\ProvidesPackage{sagetex} -%<*latex> - [2008/03/12 v1.4 embedding Sage into LaTeX documents] -%</latex> +%<python>__version__ = """ +%<*latex|python> + [2009/06/17 v2.2.1 embedding Sage into LaTeX documents] +%</latex|python> +%<python>""" %<*driver> \documentclass{ltxdoc} \usepackage{sagetex} \usepackage{xspace} \usepackage{tikz} \usepackage{hyperref} -\EnableCrossrefs +% \iffalse +% Work around a problem with using Docstrip and hyperref; for macros and +% such described with DescribeMacro and friends, plain Docstrip puts +% something like this into the .idx file: +% +% \indexentry{sage=\verb!*+\sage+|usage}{5} +% +% and defines \usage{}. hyperref comes along and sneakily alters those +% lines and adds: +% +% \indexentry{sage=\verb!*+\sage+|usage|hyperpage}{5} +% +% and makeindex gets confused because you can't have two | things in one +% indexentry. I could probably figure out how to fix this in LaTeX, but +% it's easier to run sed on the .idx file to remove the extra | and +% define a new macro that makes the text italic and puts in the +% hyperlink. +% +% Another option is to forget about all this and just pass the +% hyperindex=false option to hyperref, but then you don't get +% hyperlinked page numbers. +% \fi +\newcommand{\usagehyperpage}[1]{\textit{\hyperpage{#1}}} + +\renewcommand{\subsubsectionautorefname}{section} +\renewcommand{\subsectionautorefname}{section} +\EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} - \DocInput{sagetexpackage.dtx} - \PrintChanges - \PrintIndex +\DocInput{sagetexpackage.dtx} +\StopEventually{ +\section{Credits and acknowledgments} + +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} +\label{sec:copying-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 meta-comment + 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 page break problems won't occur. +\clearpage +\fi +} + +\DocInput{py-and-sty.dtx} +\DocInput{scripts.dtx} +\DocInput{remote-sagetex.dtx} +\Finale +\PrintChanges +\PrintIndex \end{document} %</driver> % \fi % -% \CheckSum{0} +% \CheckSum{335} % % \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 @@ -65,47 +152,62 @@ % % \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.} +% 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} +% \changes{v2.1}{2009/05/12}{Add pausing support} +% \changes{v2.1}{2009/05/12}{Get version written to .py file} +% \changes{v2.2}{2009/06/17}{Add remote-sagetex.py script} % -% \GetFileInfo{sagetexpackage.dtx} +% \GetFileInfo{sagetex.sty} % % \DoNotIndex{\newcommand,\newenvironment,\the} -% -% \newcommand{\ST}{\textsf{sagetex}\xspace} +% +% \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} +% +% \newcommand{\warningbox}[1]{\colorbox[rgb]{1, 0.6, 0.6}% +% {\parbox{.97\textwidth}{#1}}} +% +% \tikzstyle{box}=[draw, shape=rectangle, thick] +% +% \title{The \ST{} package\thanks{This document corresponds to +% \ST \fileversion, dated \filedate.}} +% +% \author{Dan Drake and others\thanks{Author's website: +% \href{http://mathsci.kaist.ac.kr/~drake/} +% {\texttt{mathsci.kaist.ac.kr/$\sim$drake/}}.}} +% % \iffalse -% For some reason, getting a blackslash in a typewriter font to print -% inside an fbox is really hard. Verbatim stuff doesn't work because -% it's fragile. This code works; it's copied out of Scott Pakin's -% dtxtut.tex. -% -% There is \textbackslash but I don't like how that looks. +% Don't put any other code from this file into the .sty or .py +% file: +%<*!latex&!python> +% This lets us use verbatim environments in the documentation. % \fi -% {\catcode`\|=0 \catcode`\\=12 -% |gdef|bslash{\}} -% -% \title{The \ST{} package\thanks{This document -% corresponds to \textsf{sagetex}~\fileversion, dated \filedate.}} -% \author{Dan Drake (\texttt{ddrake@member.ams.org}) and others} % % \maketitle % % \section{Introduction} % -% Why should the Haskell folks have all the fun? -% +% 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. (Well, 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. +% 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 @@ -116,27 +218,28 @@ % 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*10^3 = \sage{26^3*10^3}$|\\ -% |license plates.| +% |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 $\sage{26^3 * 10^3}$ license plates. +% 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. +% 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: +% 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:| % @@ -157,8 +260,8 @@ % 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, +% 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$, @@ -166,7 +269,7 @@ % % 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 +% \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: % @@ -183,44 +286,132 @@ % 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} +% \autoref{sec:usage}, we will see what what we can do with \ST. % -% The simplest way to ``install'' \ST is to copy the files -% |sagetex.sty| and |sagetex.py| into the same directory -% as your document. This will always work, as \LTX and Python search the -% current directory for files. It is also convenient for zipping up a -% directory to send to a colleague who is not yet enlightened enough to -% be using \ST. % -% Rather than make lots of copies of those files, you can keep them in -% one place and update the TEXINPUTS and PYTHONPATH environment -% variables appropriately. -% -% Perhaps the best solution is to put the files into a directory -% searched by \TeX{} and friends, and then edit the |sagetex.sty| file -% so that the |.sage| files we generate update Python's path -% appropriately---look for ``Python path'' in |sagetex.sty|. This is -% suitable for a system-wide installation, or if you are the kind of -% person who keeps a |texmf| tree in your home directory. +% \section{Installation} +% \label{sec: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 file name. 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. The |remote-sagetex.py| script allows you to +% use \ST on a computer that doesn't have Sage installed; see +% \autoref{sec:remote-sagetex} for more information. +% +% Also included are |makestatic.py| and |extractsagecode.py|, which are +% convenience scripts that you can use after you've written your +% document. See \autoref{sec:makestatic-usage} 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{sec:usage} % -% \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. 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 which, when you run \LTX -% on your source file again, will pull in all the results of Sage's -% computation. +% 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. +% to run \LTX, then run Sage, then run \LTX again. You can even ``run +% Sage'' on a computer that doesn't have Sage installed by using the +% |remote-sagetex.py| script; see \autoref{sec:remote-sagetex}. Whenever +% this manual says ``run Sage'', you can either directly run Sage, or +% use the |remote-sagetex.py| script. % % 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 @@ -235,15 +426,31 @@ % 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} +% \texttt{example.tex}\dots}\\ +% +% \noindent\warningbox{\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} +% \label{sec:sagemacro-usage} % -% \DescribeMacro{\sage} +% \DescribeMacro{sage} % \fbox{\texttt{\bslash sage}\marg{Sage code}} -% -% \noindent takes whatever Sage code you give it, runs Sage's |latex| -% function on it, and puts the result into your document. +% 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 @@ -265,14 +472,28 @@ % 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 plus foo is|\\ -% |$\sage{factor(foo + \thepage)}$|. +% |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 plus $12$ is $\sage{factor(\thepage + 12)}$. % -% The |\sage| command doesn't automatically use math mode for its -% output, so be sure to use dollar signs or a displayed math environment +% 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, another Sage/\LTX cycle on this source file +% should fix it. 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 should get the correct value +% above. However, in some cases, even \emph{that} doesn't work because +% of some kind of \TeX{} weirdness in ending the one page a bit short +% and starting another.}) 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 @@ -284,17 +505,17 @@ % 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 +% described in \autoref{sec:codeblockenv} isn't necessary; a literal % ``\percent'' inside such an environment will get written, uh, verbatim % to the |.sage| file. % % \subsection{Graphics and plotting} +% \label{sec:graphics-plotting} % % \noindent \DescribeMacro{\sageplot} % \fbox{\texttt{\bslash sageplot}\oarg{ltx opts}\oarg{fmt}\{\meta{graphics % obj}, \meta{keyword args}\}} -% -% \noindent plots the given Sage graphics object and runs an +% 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}. @@ -351,9 +572,12 @@ % to colleagues. % % If you ask for, say, a PNG file, keep in mind that ordinary |latex| -% and DVI files have no support for DVI files; \ST detects this and will -% warn you that it cannot find a suitable file if using |latex|. If you -% use |pdflatex|, there will be no problems because PDF files can +% 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 @@ -362,7 +586,7 @@ % \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. @@ -373,42 +597,47 @@ % anytime; if \ST can't find the files, it will warn you to run Sage to % regenerate them.\\ % -% \noindent\fbox{\parbox{\textwidth}{\textbf{WARNING!} When you run Sage -% on your |.sage| file, all files in the -% \texttt{sage-plots-for-filename.tex} directory \emph{will be deleted!} -% Do not put any files into that directory that you do not want to get -% automatically deleted.}} +% \noindent\warningbox{\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.\footnote{We -% use a typewriter font here to indicate the binaries which produce DVI -% and PDF files, respectively, as opposed to ``\LTX'' which refers to -% the entire typesetting system.} \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. -% +% 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 \emph{always} issue a -% warning about incompatible graphics if you use |latex|, provided -% you've processed the |.sage| file and the PNG file exists. (Running -% |pdflatex| on the same file will work, since PDF files can include PNG -% files.) +% 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 one option: |imagemagick|. If you specify this +% 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 @@ -423,7 +652,9 @@ % to see your graphics when you use |latex| and DVI files while writing % your document. % -% \paragraph{But that's not good enough!} \label{s:notgoodenough} +% \subsubsection{But that's not good enough!} +% \label{sec: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 @@ -437,10 +668,10 @@ % turn off anything in \LTX, so you can always do things manually. % % \subsection{Verbatim-like environments} -% \label{s:codeblockenv} +% \label{sec:codeblockenv} % % The \ST package provides several environments for typesetting and -% executing Sage code.\\ +% 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 @@ -449,9 +680,9 @@ % \begin{quote} % |\begin{sageblock}|\\ % | var('x')|\\ -% | f = sin(x) - 1|\\ -% | g = log(x)|\\ -% | h = diff(f(x) * g(x), x)|\\ +% | f(x) = sin(x) - 1|\\ +% | g(x) = log(x)|\\ +% | h(x) = diff(f(x) * g(x), x)|\\ % |\end{sageblock}| % \end{quote} % and then anytime later write in your source file @@ -460,7 +691,7 @@ % |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 +% diff((sin(x) - 1)*log(x), x)(x=1)}$. You can use any Sage or Python % commands inside a |sageblock|; all the commands get sent directly to % Sage.\\ % @@ -471,9 +702,9 @@ % *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. +% 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 @@ -495,15 +726,46 @@ % 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. -% +% +% \subsection{Pausing \ST} +% \label{sec:pausing-st-usage} +% +% Sometimes when you are writing a document, you may wish to temporarily +% turn off or pause \ST to concentrate more on your document than on the +% Sage computations, or to simply have your document typeset faster. You +% can do this with the following commands. +% +% \DescribeMacro{\sagetexpause} \DescribeMacro{\sagetexunpause} Use +% these macros to ``pause'' and ``unpause'' \ST. After issuing this +% macro, \ST will simply skip over the corresponding calculations. +% Anywhere a |\sage| macro is used while paused, you will simply see +% \sagetexpause ``\sage{dummy call to sage to illustrate +% pausing}'', and anywhere a |\sageplot| macro is used, you will see:\\ +% +% \noindent +% \sageplot{dummy call to sageplot to illustrate pausing} +% \sagetexunpause\\ +% +% \noindent Anything in the verbatim-like environments of +% \autoref{sec:codeblockenv} will be typeset or not as usual, but none +% of the Sage code will be executed. +% +% Obviously, you use |\sagetexunpause| to unpause \ST and return to the +% usual state of affairs. Both commands are idempotent; issuing them +% twice or more in a row is the same as issuing them once. This means +% you don't need to precisely match pause and unpause commands: once +% paused, \ST stays paused until it sees |\sagetexunpause| and +% vice versa. % % \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. To use code block environments -% in a \textsc{beamer} presentation, do: +% \subsection{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}|\\ @@ -513,24 +775,26 @@ % \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. +% 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. +% \subsection{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!'' +% (\autoref{sec: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('plot = commands to make your plot')|\\ -% |mathematica('Export["%s/graphicsfile.eps", plot]' % os.getcwd())| +% |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. % @@ -545,795 +809,166 @@ % 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-usage} +% +% 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.) % -% \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@|''. -% -% 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} -% -% \begin{macro}{\ST@epsim} -% By default, we don't use ImageMagick to create EPS files when a -% non-default format is specified. -% \begin{macrocode} -\newcommand{\ST@epsim}{False} -% \end{macrocode} -% The expansion of that macro gets put into a Python function call, so -% it works to have it be one of the strings ``|True|'' or ``|False|''. -% \end{macro} -% -% Declare the |imagemagick| option and process it: -% \begin{macrocode} -\DeclareOption{imagemagick}{\renewcommand{\ST@epsim}{True}} -\ProcessOptions\relax -% \end{macrocode} -% The |\relax| is a little incantation suggested by the ``\LaTeXe{} for -% class and package writers'' manual, section 4.7. -% -% It's time to deal with files. Open the |.sage| file: -% \begin{macrocode} -\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. If you know what directory |sagetex.py| will be kept in, delete -% the |\iffalse| and |\fi| lines in the generated style file -% (\emph{don't} do it in the |.dtx| file) and change the directory -% appropriately. This is useful if you have a |texmf| tree in your home -% directory or are installing \ST system-wide; then you don't need to -% copy |sagetex.py| into the same directory as your document. -% \begin{macrocode} -\newcommand{\ST@wsf}[1]{\immediate\write\ST@sf{#1}} -\iffalse -%% To get .sage files to automatically change the Python path to find -%% sagetex.py, delete the \iffalse and \fi lines surrounding this and -%% change the directory below to where sagetex.py can be found. -\ST@wsf{import sys} -\ST@wsf{sys.path.insert(0, 'directory with sagetex.py')} -\fi -\ST@wsf{import sagetex} -\ST@wsf{sagetex.openout('\jobname')} -% \end{macrocode} -% \end{macro} -% 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} -% -% Now let's define the cool stuff. -% -% \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.) -% \begin{macrocode} -\newcommand{\sage}[1]{% -\ST@wsf{try:}% -\ST@wsf{ sagetex.inline(\theST@inline, #1)}% -\ST@wsf{except:}% -\ST@wsf{ sagetex.goboom(\the\inputlineno)}% -% \end{macrocode} -% 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{@sagelabel\theST@inline}\end{NoHyper}% -% \end{macrocode} -% Now check to see if the label has already been defined. (The internal -% implementation of labels in \LTX involves defining a function -% ``|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@@sagelabel\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} -% -% \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} -% -% \tikzstyle{box}=[draw, shape=rectangle, thick] -% -% \begin{macro}{\sageplot} -% \changes{v1.3}{2008/03/08}{Iron out warnings, cool Ti\emph{k}Z 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} -% That percent sign followed by a square bracket seems necessary; I have -% no idea why. -% -% 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} 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. Note that the |\write| gobbles up line endings, so -% the |sageplot| bits below get written to the |.sage| file as one line. -% \begin{macrocode} -\def\ST@sageplot[#1][#2]#3{% -\ST@wsf{try:}% -\ST@wsf{ sagetex.initplot('\jobname')}% -\ST@wsf{ sagetex.plot(\theST@plot, #3, format='#2', epsmagick=\ST@epsim)}% -\ST@wsf{except:}% -\ST@wsf{ sagetex.goboom(\the\inputlineno)}% -% \end{macrocode} -% 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, 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. -% -% \tikzstyle{box}=[draw, shape=rectangle, thick] +% There is another option, and that is to use the |makestatic.py| script +% included with \ST. % -% \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 so, try to include an EPS file anyway. -% \begin{macrocode} - {\ifthenelse{\equal{\ST@epsim}{True}} - {\ST@inclgrfx{#1}{eps}}% -% \end{macrocode} -% If we're not using the imagemagick option, we're going to issue some -% sort of warning, depending on whether the file exists yet or not. -% \begin{macrocode} - {\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}% - {\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}% - \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}}% - {\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}% - \PackageWarning{sagetex}{Graphics file - \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space - does not exist}% - \gdef\ST@rerun{x}}}}% -\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} - {\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}% - \PackageWarning{sagetex}{Graphics file - \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space does not - exist}% - \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} -% -% \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 last bit is some magic from the |verbatim| package -% manual that makes \LTX respect line breaks. -% \begin{macrocode} -\newcommand{\ST@beginsfbl}{% - \@bsphack% - \ST@wsf{sagetex.blockbegin()}% - \ST@wsf{try:}% - \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:}% -\ST@wsf{ sagetex.goboom(\the\inputlineno)}% -\ST@wsf{sagetex.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{sagetex.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}% -\PackageWarningNoLine{sagetex}{Run Sage on \jobname.sage, and then run -LaTeX on \jobname.tex again}}} -% \end{macrocode} -% -% -% \subsection{The Python module} +% 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. +% +% One large limitation of this script is that it can't change anything +% while \ST is paused, since Sage doesn't compute anything for such +% parts of your document. It also doesn't check to see if pause and +% unpause commands are inside comments or verbatim environments. If +% you're going to use |makestatic.py|, just remove all pause/unpause +% statements. +% +% 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. +% +% \section{Using \ST without Sage installed} +% \label{sec:remote-sagetex} +% +% You may want to edit and typeset a \ST-ified file on a computer that +% doesn't have Sage installed. How can you do that? We need to somehow +% run Sage on the |.sage| file. The included script +% \texttt{remote-sagetex.py} takes advantage of Sage's network +% transparency and will use a remote server to do all the computations. +% Anywhere in this manual where you are told to ``run Sage'', instead of +% actually running Sage, you can run +% \begin{center} +% \texttt{python remote-sagetex.py filename.sage} +% \end{center} +% The script will ask you for a server, username, and password, then +% process all your code and write a |.sout| file and graphics files +% exactly as if you had used a local copy of Sage to process the |.sage| +% script. (With some minor limitations and differences; see below.) +% +% One important point: \emph{the script requires Python 2.6}. It will +% not work with earlier versions. (It will work with Python 3.0 or later +% with some trivial changes.) +% +% You can provide the server, username and password with the +% command-line switches |--server|, |--username|, and |--password|, or +% you can put that information into a file and use the |--file| switch +% to specify that file. The format of the file must be like the +% following: +% \begin{verbatim} + # hash mark at beginning of line marks a comment + server = "http://example.com:1234" + username = 'my_user_name' + password = 's33krit'\end{verbatim} +% As you can see, it's really just like assigning a string to a variable +% in Python. You can use single or double quotes and use hash marks to +% start comments. You can't have comments on the same line as an +% assignment, though. You can omit any of those pieces of information +% information; the script will ask for anything it needs to know. +% Information provided as a command line switch takes precedence over +% anything found in the file. +% +% You can keep this file separate from your \LTX documents in a secure +% location; for example, on a USB thumb drive or in an automatically +% encrypted directory (like |~/Private| in Ubuntu). This makes it much +% harder to accidentally upload your private login information to the +% arXiv, put it on a website, send it to a colleague, or otherwise make +% your private information public. +% +% \subsection{Limitations of \texttt{remote-sagetex.py}} +% \label{sec:remote-sagetex-limitations} +% +% The |remote-sagetex.py| script has several limitations. It completely +% ignores the |epstopdf| and |imagemagick| flags. The |epstopdf| flag is +% not a big deal, since it was originally introduced to work around a +% matplotlib bug which has since been fixed. Not having |imagemagick| +% support means that you cannot automatically convert 3D graphics to eps +% format; using |pdflatex| to make PDFs works around this issue. +% +% +% \subsection{Other caveats} +% \label{sec:remote-sagetex-caveats} +% +% Right now, the ``simple server API'' that |remote-sagetex.py| uses is +% not terribly robust, and if you interrupt the script, it's possible to +% leave an idle session running on the server. If many idle sessions +% accumulate on the server, it can use up a lot of memory and cause the +% server to be slow, unresponsive, or maybe even crash. For now, I +% recommend that you only run the script manually. It's probably best to +% not configure your \TeX{} editing environment to automatically run +% |remote-sagetex.py| whenever you typeset your document, at least not +% without showing you the output or alerting you about errors. % + + % \iffalse -% Hey, docstrip! Stop putting code into the .sty file, and start -% putting it into the .py file. -%</latex> -%<*python> -% Thanks. +% Local Variables: +% mode: doctex +% TeX-master: t +% End: % \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 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 used by Sage scripts generated from a LaTeX document -using the sagetex package. Keep it somewhere where Sage and Python can -find it and it will automatically be imported.""") - sys.exit() -% \end{macrocode} -% We start with some imports and definitions of our global variables. -% This is a relatively specialized use of Sage, so using global -% variables isn't a bad idea. Plus I think when we import this module, -% they will all stay inside the |sagetex| namespace anyway. -% \begin{macrocode} -from sage.misc.latex import latex -import os -import os.path -import hashlib -import traceback -import subprocess -import shutil -initplot_done = False -dirname = None -filename = "" -% \end{macrocode} -% -% \begin{macro}{progress} -% This function justs 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(t,linebreak=True): - if linebreak: - print(t) - else: - sys.stdout.write(t) -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{openout} -% This function opens a |.sout.tmp| file and writes 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} -def openout(f): - global filename - filename = f - global _file_ - _file_ = open(f + '.sout.tmp', 'w') - s = '% This file was *autogenerated* from the file ' + \ - os.path.splitext(filename)[0] + '.sage.\n' - _file_.write(s) - progress('Processing Sage code for %s.tex...' % filename) -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{initplot} -% We only want to create the plots directory if the user actually plots -% something. This function creates the directory and sets the -% |initplot_done| 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(f): - global initplot_done - if not initplot_done: - progress('Initializing plots directory') - global dirname -% \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, I think we could find out the correct -% extension, but it would involve a lot of irritating mucking around. -% \begin{macrocode} - dirname = 'sage-plots-for-' + f + '.tex' - if os.path.isdir(dirname): - shutil.rmtree(dirname) - os.mkdir(dirname) - initplot_done = True -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{inline} -% This function works with |\sage| from the style file 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, 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(counter, s): - progress('Inline formula %s' % counter) - _file_.write('\\newlabel{@sagelabel' + 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} -% 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. -% \begin{macrocode} -def blockbegin(): - progress('Code block begin...', False) -def blockend(): - progress('end') -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{plot} -% I hope it's obvious that this function does plotting. 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(counter, p, format='notprovided', epsmagick=False, **kwargs): - global dirname - 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. -% \begin{macrocode} - if format == 'notprovided': - formats = ['eps', 'pdf'] - else: - formats = [format] - for fmt in formats: - plotfilename = os.path.join(dirname, '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 epsmagick is True: - print('Calling Imagemagick to convert plot-%s.%s to EPS' % \ - (counter, format)) - 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(counter, ext): - global dirname - subprocess.check_call(['convert',\ - '%s/plot-%s.%s' % (dirname, counter, ext), \ - '%s/plot-%s.eps' % (dirname, 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 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(line): - global filename - print('\n**** Error in Sage code on line %s of %s.tex! Traceback\ - follows.' % (line, filename)) - traceback.print_exc() - print('\n**** Running Sage on %s.sage failed! Fix %s.tex and try\ - again.' % (filename, filename)) - os.remove(filename + '.sout.tmp') - sys.exit(1) -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{endofdoc} -% When we're done processing, we have a couple little cleanup tasks. We -% want to put the MD5 sm 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 tell 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, say, a line break 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 calls to Sage have -% 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 '^ sagetex.goboom' filename.sage | md5sum+ -% \end{center} -% (In fact, what we do below produces exactly the same sum.) -% \begin{macrocode} -def endofdoc(): - global filename - sagef = open(filename + '.sage', 'r') - m = hashlib.md5() - for line in sagef: - if line[0:15] != ' sagetex.goboom': - m.update(line) - s = '%' + m.hexdigest() + '% md5sum of .sage file (minus "goboom" \ -lines) that produced this\n' - _file_.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.) -% -% Now we are done with the |.sout| file. Close it, rename it, and tell -% the user we're done. -% \begin{macrocode} - _file_.close() - os.rename(filename + '.sout.tmp', filename + '.sout') - progress('Sage processing complete. Run LaTeX on %s.tex again.' %\ - filename) -% \end{macrocode} -% \end{macro} -% -% \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 almost zero -% original code there), made significant changes to the Python module, -% put both files into \textsf{Docstrip} format, and wrote all the -% documentation. -% -% Many thanks to Jason Grout for his numerous comments, suggestions, and -% feedback. -% -% \section{Copying and licenses} -% -% 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. diff --git a/Master/texmf-dist/source/latex/sagetex/sagetexpackage.ins b/Master/texmf-dist/source/latex/sagetex/sagetexpackage.ins index b91433f7b34..f759ec4ad71 100644 --- a/Master/texmf-dist/source/latex/sagetex/sagetexpackage.ins +++ b/Master/texmf-dist/source/latex/sagetex/sagetexpackage.ins @@ -1,19 +1,19 @@ %% This is `sagetexpackage.ins', part of the sagetex package. -% -%% Copyright (C) 2008 by Dan Drake <ddrake@member.ams.org> +%% +%% Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> %% %% This program is free software: you can redistribute it and/or modify %% it 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. -%% +%% %% This program is distributed in the hope that it will be useful, but %% WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU %% General Public License for more details. -%% +%% %% You should have received a copy of the GNU General Public License -%% along with this program. If not, see <http://www.gnu.org/licenses/> +%% along with this program. If not, see <http://www.gnu.org/licenses/>. \input docstrip.tex \keepsilent @@ -22,9 +22,9 @@ \declarepreamble\defaultpreamble -This is a generated file. +This is a generated file. It is part of the SageTeX package. -Copyright (C) 2008 by Dan Drake <ddrake@member.ams.org> +Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -33,44 +33,75 @@ option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/> +with this program. If not, see <http://www.gnu.org/licenses/>. \endpreamble % We use a name other than `sagetex' because when using the sagetex -% package in a file called `foo.dtx', a file `foo.py' will be produced -% -- and below, we generate a file called sagetex.py. Thus we use a name -% other than `sagetex.dtx' so that building the documentation doesn't -% clobber the very Python file we need to build the documentation! +% package in a file called `foo.dtx', a file `foo.py' will be +% produced---and below, we generate a file called sagetex.py. Thus we +% use a name other than `sagetex.dtx' so that building the documentation +% doesn't clobber the very Python file we need to build the +% documentation! + +\generate{\file{sagetex.sty}{\from{sagetexpackage.dtx}{latex} + \from{py-and-sty.dtx}{latex}}} + +% Define a new preamble with #'s as comment characters for the Python +% files. I hate copying the same text, but defining a "\boilerplate" +% macro requires me to manually do \MetaPrefix\space and ^^J everywhere +% and it's more annoying than this. -\generate{\file{sagetex.sty}{\from{sagetexpackage.dtx}{latex}}} +\catcode`\#=12 +\def\hash{#} +\catcode`\#=6 + +\def\MetaPrefix{\hash\hash} +\declarepreamble\pypreamble + +This is a generated file. It is part of the SageTeX package. + +Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> + +This program is free software: you can redistribute it and/or modify it +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. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. + +\endpreamble +\usepreamble\pypreamble +\nopostamble +\generate{\file{sagetex.py}{\from{sagetexpackage.dtx}{python} + \from{py-and-sty.dtx}{python}}} +\generate{\file{sagetexparse.py}{\from{scripts.dtx}{parsermod}}} -% Some trickery to get triple quotes around the {pre,post}amble. This is -% a modification of what the Docstrip manual suggests; their method -% resulted in some bits being printed twice because, I think, of a -% problem in \declare{pre,post}amble. At any rate, this gives us a -% properly commented Python file with the same preamble as the .sty -% file. +% Now define a new preamble with the shebang line at the top. -\edef\defaultpreamble{"""^^J% - \defaultpreamble^^J% - """} -\edef\defaultpostamble{"""^^J% - \defaultpostamble^^J% - """} +\def\envpypreamble{\hash!/usr/bin/env python^^J\pypreamble} +\usepreamble\envpypreamble -\generate{\file{sagetex.py}{\from{sagetexpackage.dtx}{python}}} +\generate{\file{makestatic.py}{\from{scripts.dtx}{staticscript}}} +\generate{\file{extractsagecode.py}{\from{scripts.dtx}{extractscript}}} +\generate{\file{remote-sagetex.py}{\from{remote-sagetex.dtx}{remotesagetex}}} \obeyspaces \Msg{******************************************************************} \Msg{* *} \Msg{* To finish the installation, move the following files *} -\Msg{* into directories searched by TeX and Sage, respectively. *} +\Msg{* into directories searched by TeX and Sage, respectively: *} \Msg{* *} \Msg{* sagetex.sty *} \Msg{* sagetex.py *} diff --git a/Master/texmf-dist/source/latex/sagetex/scripts.dtx b/Master/texmf-dist/source/latex/sagetex/scripts.dtx new file mode 100644 index 00000000000..40914a4165b --- /dev/null +++ b/Master/texmf-dist/source/latex/sagetex/scripts.dtx @@ -0,0 +1,424 @@ +% \section{Included Python scripts} +% \label{sec:included-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} +% \label{sec:makestatic} +% \iffalse +%<*staticscript> +% \fi +% +% 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} +% \changes{v2.2}{2009/06/17}{Update parser module to handle pause/unpause} +% +% 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|, |\sageplot|, and pause/unpause calls: +% \begin{macrocode} +sagemacroparser = r'\sage' + curlybrackets('code') +sageplotparser = (r'\sageplot' + + Optional(squarebrackets)('opts') + + Optional(squarebrackets)('format') + + curlybrackets('code')) +sagetexpause = Literal(r'\sagetexpause') +sagetexunpause = Literal(r'\sagetexunpause') +% \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 +% list. 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 = (r'\newlabel{@sageinline' + + Word(nums)('num') + + '}{' + + curlybrackets('result') + + '{}{}{}{}}') +% \end{macrocode} +% We tell it to ignore comments, and hook up the list-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.append(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 = (r'\usepackage' + + Optional(squarebrackets) + + '{sagetex}') + usepackage.setParseAction(replaceWith(r"""% "\usepackage{sagetex}" line was here: +\RequirePackage{verbatim} +\RequirePackage{graphicx} +\newcommand{\sagetexpause}{\relax} +\newcommand{\sagetexunpause}{\relax}""")) +% \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(r'\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(r'\begin{verbatim}' + SkipTo(r'\end{verbatim}')) + doit.ignore(r'\begin{comment}' + SkipTo(r'\end{comment}')) + doit.ignore(r'\sagetexpause' + SkipTo(r'\sagetexunpause')) +% \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 = r'[width=.75\textwidth]' + else: + opts = t.opts[0] + return (r'\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 = r'\begin{' + env_names('env') + '}' + SkipTo( + r'\end{' + matchPreviousExpr(env_names) + '}')('code') + senv.leaveWhitespace() + senv.setParseAction(self.envout) + + spause = sagetexpause + spause.setParseAction(self.pause) + + sunpause = sagetexunpause + sunpause.setParseAction(self.unpause) + + doit = smacro | splot | senv | spause | sunpause + + 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' + + def pause(self, s, l, t): + self.result += ('# SageTeX (probably) paused on input line %s.\n\n' % + (lineno(l, s))) + + def unpause(self, s, l, t): + self.result += ('# SageTeX (probably) unpaused on input line %s.\n\n' % + (lineno(l, s))) +% \end{macrocode} +% \end{macro} + +% \endinput +%</parsermod> +% Local Variables: +% mode: doctex +% TeX-master: "sagetexpackage" +% End: diff --git a/Master/texmf-dist/tex/latex/sagetex/sagetex.sty b/Master/texmf-dist/tex/latex/sagetex/sagetex.sty index 16e9a2aefb1..79fccf61d07 100644 --- a/Master/texmf-dist/tex/latex/sagetex/sagetex.sty +++ b/Master/texmf-dist/tex/latex/sagetex/sagetex.sty @@ -5,10 +5,11 @@ %% The original source files were: %% %% sagetexpackage.dtx (with options: `latex') +%% py-and-sty.dtx (with options: `latex') %% -%% This is a generated file. +%% This is a generated file. It is part of the SageTeX package. %% -%% Copyright (C) 2008 by Dan Drake <ddrake@member.ams.org> +%% Copyright (C) 2009 by Dan Drake <ddrake@member.ams.org> %% %% This program is free software: you can redistribute it and/or modify it %% under the terms of the GNU General Public License as published by the @@ -17,15 +18,15 @@ %% %% This program is distributed in the hope that it will be useful, but %% WITHOUT ANY WARRANTY; without even the implied warranty of -%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%% General Public License for more details. +%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +%% Public License for more details. %% %% You should have received a copy of the GNU General Public License along -%% with this program. If not, see <http://www.gnu.org/licenses/> +%% with this program. If not, see <http://www.gnu.org/licenses/>. %% \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{sagetex} - [2008/03/12 v1.4 embedding Sage into LaTeX documents] + [2009/06/17 v2.2.1 embedding Sage into LaTeX documents] \RequirePackage{verbatim} \RequirePackage{graphicx} \RequirePackage{makecmds} @@ -37,44 +38,55 @@ \setcounter{ST@plot}{0} \newlength{\sagetexindent} \setlength{\sagetexindent}{5ex} -\newcommand{\ST@epsim}{False} -\DeclareOption{imagemagick}{\renewcommand{\ST@epsim}{True}} +\newif\ifST@paused +\ST@pausedfalse +\AtBeginDocument{\@ifundefined{ST@final}{% +\newwrite\ST@sf% +\immediate\openout\ST@sf=\jobname.sage% +\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')}}% +{\newcommand{\ST@wsf}[1]{\relax}}} +\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}}}} +\DeclareOption{imagemagick}{% + \newcommand{\ST@useimagemagick}{x}% + \AtBeginDocument{% + \@ifundefined{ST@final}{% + \ST@wsf{_st_.useimagemagick = True}}{}}} +\DeclareOption{epstopdf}{% +\AtBeginDocument{% +\@ifundefined{ST@final}{% + \ST@wsf{_st_.useepstopdf = True}}{}}} \ProcessOptions\relax -\newwrite\ST@sf -\immediate\openout\ST@sf=\jobname.sage -\newcommand{\ST@wsf}[1]{\immediate\write\ST@sf{#1}} -\iffalse -%% To get .sage files to automatically change the Python path to find -%% sagetex.py, delete the \iffalse and \fi lines surrounding this and -%% change the directory below to where sagetex.py can be found. -\ST@wsf{import sys} -\ST@wsf{sys.path.insert(0, 'directory with sagetex.py')} +\InputIfFileExists{\jobname.sout}{}{\typeout{No file \jobname.sout.}} +\AtBeginDocument{\provideenvironment{NoHyper}{}{}} +\newcommand{\sage}[1]{\ST@wsf{% +try:^^J + _st_.inline(\theST@inline, #1)^^Jexcept:^^J + _st_.goboom(\the\inputlineno)}% +\ifST@paused + \mbox{(Sage\TeX{} is paused)}% +\else + \begin{NoHyper}\ref{@sageinline\theST@inline}\end{NoHyper} + \@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{} \fi -\ST@wsf{import sagetex} -\ST@wsf{sagetex.openout('\jobname')} -\InputIfFileExists{\jobname.sout}{}{} -\newcommand{\sage}[1]{% -\ST@wsf{try:}% -\ST@wsf{ sagetex.inline(\theST@inline, #1)}% -\ST@wsf{except:}% -\ST@wsf{ sagetex.goboom(\the\inputlineno)}% -\begin{NoHyper}\ref{@sagelabel\theST@inline}\end{NoHyper}% -\@ifundefined{r@@sagelabel\theST@inline}{\gdef\ST@rerun{x}}{}% \stepcounter{ST@inline}} -\AtBeginDocument{\provideenvironment{NoHyper}{}{}} \catcode`\%=12 \newcommand{\percent}{%} \catcode`\%=14 \newcommand{\ST@plotdir}{sage-plots-for-\jobname.tex} +\newcommand{\ST@missingfilebox}{\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}} \newcommand{\sageplot}[1][width=.75\textwidth]{% - \@ifnextchar[{\ST@sageplot[#1]}{\ST@sageplot[#1][notprovided]}%] -} -\def\ST@sageplot[#1][#2]#3{% -\ST@wsf{try:}% -\ST@wsf{ sagetex.initplot('\jobname')}% -\ST@wsf{ sagetex.plot(\theST@plot, #3, format='#2', epsmagick=\ST@epsim)}% -\ST@wsf{except:}% -\ST@wsf{ sagetex.goboom(\the\inputlineno)}% + \@ifnextchar[{\ST@sageplot[#1]}{\ST@sageplot[#1][notprovided]}} +\def\ST@sageplot[#1][#2]#3{\ST@wsf{try:^^J + _st_.plot(\theST@plot, format='#2', _p_=#3)^^Jexcept:^^J + _st_.goboom(\the\inputlineno)}% \ifpdf \ifthenelse{\equal{#2}{notprovided}}% {\ST@inclgrfx{#1}{pdf}}% @@ -82,38 +94,39 @@ \else \ifthenelse{\equal{#2}{notprovided}}% {\ST@inclgrfx{#1}{eps}}% - {\ifthenelse{\equal{\ST@epsim}{True}} - {\ST@inclgrfx{#1}{eps}}% + {\@ifundefined{ST@useimagemagick}% {\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}% - {\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}% + {\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}}% - {\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}% + {\ST@missingfilebox% \PackageWarning{sagetex}{Graphics file \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space - does not exist}% - \gdef\ST@rerun{x}}}}% + does not exist. Plot command is}% + \gdef\ST@rerun{x}}}% + {\ST@inclgrfx{#1}{eps}}}% \fi \stepcounter{ST@plot}} -\newcommand{\ST@inclgrfx}[2]{% +\newcommand{\ST@inclgrfx}[2]{\ifST@paused + \fbox{\rule[-1cm]{0cm}{2cm}Sage\TeX{} is paused; no graphic} +\else \IfFileExists{\ST@plotdir/plot-\theST@plot.#2}% {\includegraphics[#1]{\ST@plotdir/plot-\theST@plot.#2}}% - {\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}% + {\ST@missingfilebox% \PackageWarning{sagetex}{Graphics file \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space does not - exist}% - \gdef\ST@rerun{x}}} + exist. Plot command is}% + \gdef\ST@rerun{x}} +\fi} \newcommand{\ST@beginsfbl}{% - \@bsphack% - \ST@wsf{sagetex.blockbegin()}% - \ST@wsf{try:}% + \@bsphack\ST@wsf{% +_st_.blockbegin()^^Jtry:}% \let\do\@makeother\dospecials\catcode`\^^M\active} \newcommand{\ST@endsfbl}{% -\ST@wsf{except:}% -\ST@wsf{ sagetex.goboom(\the\inputlineno)}% -\ST@wsf{sagetex.blockend()}} +\ST@wsf{except:^^J + _st_.goboom(\the\inputlineno)^^J_st_.blockend()}} \newenvironment{sageblock}{\ST@beginsfbl% \def\verbatim@processline{\ST@wsf{ \the\verbatim@line}% \hspace{\sagetexindent}\the\verbatim@line\par}% @@ -127,11 +140,21 @@ \def\verbatim@processline{\hspace{\sagetexindent}\the\verbatim@line\par}% \verbatim}% {\endverbatim} -\AtEndDocument{\ST@wsf{sagetex.endofdoc()}% +\newcommand{\sagetexpause}{\ifST@paused\relax\else +\ST@wsf{print 'SageTeX paused on \jobname.tex line \the\inputlineno'^^J"""} +\ST@pausedtrue +\fi} +\newcommand{\sagetexunpause}{\ifST@paused +\ST@wsf{"""^^Jprint 'SageTeX unpaused on \jobname.tex line \the\inputlineno'} +\ST@pausedfalse +\fi} +\AtEndDocument{\ifST@paused +\ST@wsf{"""^^Jprint 'SageTeX unpaused at end of \jobname.tex'} +\fi +\ST@wsf{_st_.endofdoc()}% \@ifundefined{ST@rerun}{}% {\PackageWarningNoLine{sagetex}{There were undefined Sage formulas -and/or plots}% -\PackageWarningNoLine{sagetex}{Run Sage on \jobname.sage, and then run +and/or plots.^^JRun Sage on \jobname.sage, and then run LaTeX on \jobname.tex again}}} \endinput %% |