diff options
Diffstat (limited to 'macros/latex/contrib/sagetex')
-rw-r--r-- | macros/latex/contrib/sagetex/PKG-INFO | 19 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/README.md | 10 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/example.pdf | bin | 276082 -> 277744 bytes | |||
-rw-r--r-- | macros/latex/contrib/sagetex/py-and-sty.dtx | 14 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/sagetex.dtx | 28 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/sagetex.ins | 9 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/sagetex.pdf | bin | 497692 -> 501661 bytes | |||
-rw-r--r-- | macros/latex/contrib/sagetex/scripts.dtx | 410 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/setup.py | 11 |
9 files changed, 259 insertions, 242 deletions
diff --git a/macros/latex/contrib/sagetex/PKG-INFO b/macros/latex/contrib/sagetex/PKG-INFO index 628c7e2da9..6cc7afeaa0 100644 --- a/macros/latex/contrib/sagetex/PKG-INFO +++ b/macros/latex/contrib/sagetex/PKG-INFO @@ -1,12 +1,15 @@ -Metadata-Version: 1.0 +Metadata-Version: 2.1 Name: sagetex -Version: 3.5 +Version: 3.6.1 Summary: Embed Sage code and plots into LaTeX Home-page: https://github.com/sagemath/sagetex -Author: SageMath developers -Author-email: sage-devel@googlegroups.com +Author: Dan Drake +Author-email: dr.dan.drake@gmail.com +Maintainer: SageMath developers +Maintainer-email: sage-devel@googlegroups.com License: GPLv2+ -Description: The SageTeX package allows you to embed code, - results of computations, and plots from the Sage mathematics - software suite (http://sagemath.org) into LaTeX documents. -Platform: UNKNOWN +License-File: LICENSE + +The SageTeX package allows you to embed code, + results of computations, and plots from the Sage mathematics + software suite (http://sagemath.org) into LaTeX documents. diff --git a/macros/latex/contrib/sagetex/README.md b/macros/latex/contrib/sagetex/README.md index f6e75ac061..2864569f39 100644 --- a/macros/latex/contrib/sagetex/README.md +++ b/macros/latex/contrib/sagetex/README.md @@ -8,7 +8,7 @@ computations, and plots from the Sage mathematics software suite SageTeX is included with Sage, so to use it, you only need to make the file sagetex.sty known to TeX; that file will be in -SAGE_ROOT/local/share/texmf/tex/latex/sagetex, along with +SAGE_ROOT/venv/share/texmf/tex/latex/sagetex, along with documentation and examples. See the Sage tutorial at https://doc.sagemath.org/html/en/tutorial/sagetex.html for a quick usage introduction, and for complete installation @@ -23,14 +23,14 @@ the SAGE_ROOT/... directory mentioned above. If you want to extract any of SageTeX's files from the .dtx sources, you can do - 0. Run `latex sagetex.ins' + 0. Run `latex sagetex.ins` To regenerate the documentation, do - 1. Run `latex sagetex.dtx' - 2. Run `sage sagetex.sage' + 1. Run `latex sagetex.dtx` + 2. Run `sage sagetex.sage` 3. Run the indexing commands that the .ins file told you about. - 4. Run `latex sagetex.dtx' again. + 4. Run `latex sagetex.dtx` again. You can skip step 3 if you don't care about the index. You will need the pgf and tikz packages installed to typeset the figures. diff --git a/macros/latex/contrib/sagetex/example.pdf b/macros/latex/contrib/sagetex/example.pdf Binary files differindex af815f0b56..2f8c9347d5 100644 --- a/macros/latex/contrib/sagetex/example.pdf +++ b/macros/latex/contrib/sagetex/example.pdf diff --git a/macros/latex/contrib/sagetex/py-and-sty.dtx b/macros/latex/contrib/sagetex/py-and-sty.dtx index 49bf5cd05e..acd92c08e2 100644 --- a/macros/latex/contrib/sagetex/py-and-sty.dtx +++ b/macros/latex/contrib/sagetex/py-and-sty.dtx @@ -29,7 +29,7 @@ % and |listings| for the |sagecommandline| environment. % \begin{macrocode} \RequirePackage{listings} -\RequirePackage{color} +\RequirePackage{xcolor} \lstdefinelanguage{Sage}[]{Python} {morekeywords={False,sage,True},sensitive=true} \lstdefinelanguage{SageOutput}[]{} @@ -68,9 +68,9 @@ \lstdefinestyle{SageOutput}{ style=DefaultSageOutput, } -\definecolor{dbluecolor}{rgb}{0.01,0.02,0.7} -\definecolor{dgreencolor}{rgb}{0.2,0.4,0.0} -\definecolor{dgraycolor}{rgb}{0.30,0.3,0.30} +\providecolor{dbluecolor}{rgb}{0.01,0.02,0.7} +\providecolor{dgreencolor}{rgb}{0.2,0.4,0.0} +\providecolor{dgraycolor}{rgb}{0.30,0.3,0.30} % \end{macrocode} % Unsurprisingly, the |\sageplot| command works poorly without graphics % support. @@ -1243,7 +1243,7 @@ http://doc.sagemath.org/html/en/tutorial/sagetex.html.""".format(jobname, raise SyntaxError(""" SageTeX no longer supports "..." for line continuation in sagexample and sagecommandline environments. Use "....:", which matches what the Sage interpreter uses. See the documentation and example file in -SAGE_ROOT/local/share/doc/sagetex.""") +SAGE_ROOT/venv/share/doc/sagetex.""") if has_cont: cmd.append(line[has_cont.end():]) ret.append((start, end, '\n'.join(cmd))) @@ -1521,9 +1521,9 @@ SAGE_ROOT/local/share/doc/sagetex.""") % \begin{center} % \verb+egrep -v '^( _st_.goboom| ?_st_.current_tex_line|print(.SageT)' filename.sage | md5sum+ % \end{center} -% in a shell. The included |run-sagetex-if-necessary| uses this +% in a shell. The included |sagetex-run| uses this % mechanism to, well, only run Sage when necessary; see -% \autoref{sec:run-sagetex-if-necessary}. +% \autoref{sec:sagetex-run}. % \begin{macrocode} def endofdoc(self): sagef = open(self.filename + '.sagetex.sage', 'r') diff --git a/macros/latex/contrib/sagetex/sagetex.dtx b/macros/latex/contrib/sagetex/sagetex.dtx index b5598d990e..e028698816 100644 --- a/macros/latex/contrib/sagetex/sagetex.dtx +++ b/macros/latex/contrib/sagetex/sagetex.dtx @@ -30,10 +30,10 @@ %<latex>\ProvidesPackage{sagetex} %<python>__version__ = """ %<*latex|python> - [2020/08/12 v3.5 embedding Sage into LaTeX documents] + [2022/08/21 v3.6.1 embedding Sage into LaTeX documents] %</latex|python> %<python>""".strip() -%<latex>\newcommand{\ST@ver}{2020/08/12 v3.5} +%<latex>\newcommand{\ST@ver}{2022/08/21 v3.6.1} %<*driver> \documentclass{ltxdoc} \usepackage{sagetex} @@ -261,9 +261,9 @@ suggestions. % |sage.plot.plot?| and look for |ticks| and |tick_formatter|.) % % Till Tantau has some good commentary on the use of graphics in the -% \href{http://www.ctan.org/tex-archive/help/Catalogue/entries/pgf.html}{``Guidelines +% \href{https://pgf-tikz.github.io/pgf/pgfmanual.pdf}{``Guidelines % on Graphics'' section of the \textsc{pgf} manual} (chapter 7 of the -% manual for version 2.10). You should always give careful thought and +% manual for version 3.1.9). 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: % @@ -539,7 +539,7 @@ suggestions. % ``\percent'' inside such an environment will get written, uh, verbatim % to the |.sage| file. % -% \paragraph{Arguments with side effects} +% \subsubsection{Arguments with side effects} % % Be careful when feeding |\sage| and |\sagestr| arguments that have % side effects, since in some situations they can get evaluated more @@ -763,7 +763,7 @@ suggestions. % indented when typeset. You can change this length however you like % with |\setlength|: do |\setlength{\sagetexindent}{6ex}| or whatever. % -% \DescribeEnv{sageexample} This environment allow you to include +% \DescribeEnv{sageexample} This environment allows you to include % doctest-like snippets in your document that will be nicely typeset. % For example, % \begin{quote} @@ -811,7 +811,7 @@ suggestions. % Thi\'ery.\\ % % \DescribeEnv{sagecommandline} This environment is similar to the -% sageexample environment in that it allow you to use \ST as a +% sageexample environment in that it allows you to use \ST as a % pretty-printing command line, or to include doctest-like snippets in % your document. The difference is that the output is typeset as text, % much like running Sage on the command line, using the @@ -839,7 +839,7 @@ suggestions. % You have a choice of either explicitly providing the Sage output or % leaving it up to the computer to fill in the blanks. Above, the output % for $t$ was provided, but the output for the |factor()| command -% wasn't. Moreover, any Sage comment that starts with a ``at'' sign is +% wasn't. Moreover, any Sage comment that starts with an ``at'' sign is % escaped to \LTX. In particular, you can use |\label| to mark line % numbers in order to |\ref|erence and |\pageref|erence them as usual. % See the example file to see this mechanism in action. @@ -960,8 +960,8 @@ suggestions. % the typesetting engine dropdown menu and then typeset. % % (You can also replace "|sage|" above with the -% |run-sagetex-if-necessary| script---see -% \autoref{sec:run-sagetex-if-necessary}.) +% |sagetex-run| script---see +% \autoref{sec:sagetex-run}.) % % \subsection{Using Beamer} % @@ -1054,11 +1054,11 @@ suggestions. % % \subsubsection{The 21st century way} % -% The SageMathCloud -% (\href{http://cloud.sagemath.com}{\texttt{cloud.sagemath.com}}) service has +% CoCalc +% (\href{https://cocalc.com/}{\texttt{cocalc.com/}}) has % full support for \ST, is free to use, and has many fantastic % collaboration features. If you somehow want to collaborate on a -% \ST-enabled \TeX document with a colleague, using SageMathCloud is one +% \ST-enabled \TeX document with a colleague, using CoCalc is one % of the best and easiest ways to do it. You and your collaborators % simply create an account, then make a project for your collaboration, % and add all the collaborators to the project. Then you can all enjoy @@ -1066,7 +1066,7 @@ suggestions. % % \subsubsection{The $N$th century way, for $N < 21$} % -% Using anything other than SageMathCloud, |git|, or similar tools these +% Using anything other than CoCalc, |git|, or similar tools these % days seems pretty primitive. If emailing |.tex| files back and forth % seems perfectly reasonable to you, or if you have to send a file to a % journal, the easiest way is to simply include with your document the diff --git a/macros/latex/contrib/sagetex/sagetex.ins b/macros/latex/contrib/sagetex/sagetex.ins index dd8dabb80a..bbbbe1388a 100644 --- a/macros/latex/contrib/sagetex/sagetex.ins +++ b/macros/latex/contrib/sagetex/sagetex.ins @@ -84,7 +84,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>. \from{py-and-sty.dtx}{python}}} \generate{\file{sagetexparse.py}{\from{scripts.dtx}{parsermod}}} - \usedir{scripts/sagetex} % Now define a new preamble with the shebang line at the top. @@ -92,10 +91,10 @@ with this program. If not, see <http://www.gnu.org/licenses/>. \def\envpypreamble{\hash!/usr/bin/env python^^J\pypreamble} \usepreamble\envpypreamble -\generate{\file{run-sagetex-if-necessary.py}{\from{scripts.dtx}{ifnecessaryscript}}} -\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}}} +\generate{\file{sagetex-run.py}{\from{scripts.dtx}{ifnecessaryscript}}} +\generate{\file{sagetex-makestatic.py}{\from{scripts.dtx}{staticscript}}} +\generate{\file{sagetex-extract.py}{\from{scripts.dtx}{extractscript}}} +\generate{\file{sagetex-remote.py}{\from{remote-sagetex.dtx}{remotesagetex}}} \obeyspaces \Msg{******************************************************************} diff --git a/macros/latex/contrib/sagetex/sagetex.pdf b/macros/latex/contrib/sagetex/sagetex.pdf Binary files differindex 4ad0f319e8..66f93e8add 100644 --- a/macros/latex/contrib/sagetex/sagetex.pdf +++ b/macros/latex/contrib/sagetex/sagetex.pdf diff --git a/macros/latex/contrib/sagetex/scripts.dtx b/macros/latex/contrib/sagetex/scripts.dtx index 8f7048dcef..988f9732dc 100644 --- a/macros/latex/contrib/sagetex/scripts.dtx +++ b/macros/latex/contrib/sagetex/scripts.dtx @@ -1,27 +1,26 @@ % \section{Included Python scripts} % \label{sec:included-scripts} % -% Here we describe the Python code for |run-sagetex-if-necessary|, and -% also |makestatic.py|, which removes \ST commands to produce a -% ``static'' file, and |extractsagecode.py|, which extracts all the Sage -% code from a |.tex| file. +% Here we describe the Python code for \ST scripts, for running +% Sage only if necessary, substituting in Sage outputs to produce +% a ``static'' file, and extracting all Sage code from a |.tex| file. % -% \subsection{run-sagetex-if-necessary} -% \label{sec:run-sagetex-if-necessary} +% \subsection{\texttt{sagetex-run}} +% \label{sec:sagetex-run} % \iffalse %<*ifnecessaryscript> % \fi % % When working on a document that uses \ST, running Sage every time you % typeset your document may take too long, especially since it often -% won't be necessary. This script is a drop-in replacement for Sage: +% is not necessary. This script is a drop-in replacement for Sage: % instead of % \begin{center} % |sage document.sagetex.sage| % \end{center} % you can do % \begin{center} -% |run-sagetex-if-necessary.py document.sagetex.sage| +% |sagetex-run document.sagetex.sage| % \end{center} % and it will use the MD5 mechanism described in the |endofdoc| macro % (page~{\pageref{macro:endofdoc}). With this, you can set up your editor @@ -29,105 +28,114 @@ % that does % \begin{quote} % |pdflatex $1|\\ -% |run-sagetex-if-necessary.py $1| +% |sagetex-run $1| % \end{quote} % which will only, of course, run Sage when necessary. % \begin{macrocode} - -# given a filename f, examines f.sagetex.sage and f.sagetex.sout and -# runs Sage if necessary. +""" +Given a filename f, examines f.sagetex.sage and f.sagetex.sout and +runs Sage if necessary. +""" import hashlib import sys import os import re import subprocess -from six import PY3 - -# CHANGE THIS AS APPROPRIATE -path_to_sage = os.path.expanduser('~/bin/sage') -# or try to auto-find it: -# path_to_sage = subprocess.check_output(['which', 'sage']).strip() -# or just tell me: -# path_to_sage = '/usr/local/bin/sage' - -if sys.argv[1].endswith('.sagetex.sage'): - src = sys.argv[1][:-13] -else: - src = os.path.splitext(sys.argv[1])[0] - -usepackage = r'usepackage(\[.*\])?{sagetex}' -uses_sagetex = False - -# if it does not use sagetex, obviously running sage is unnecessary -with open(src + '.tex') as texf: - for line in texf: - if line.strip().startswith(r'\usepackage') and re.search(usepackage, line): - uses_sagetex = True - break - -if not uses_sagetex: - print(src + ".tex doesn't seem to use SageTeX, exiting.") - sys.exit(0) - -# if something goes wrong, assume we need to run Sage -run_sage = True -ignore = r"^( _st_.goboom|print\('SageT| ?_st_.current_tex_line)" - -try: - with open(src + '.sagetex.sage', 'r') as sagef: - h = hashlib.md5() - for line in sagef: - if not re.search(ignore, line): - if PY3: - h.update(bytearray(line,'utf8')) - else: - h.update(bytearray(line)) -except IOError: - print('{0}.sagetex.sage not found, I think you need to typeset {0}.tex first.'.format(src)) - sys.exit(1) - -try: - with open(src + '.sagetex.sout', 'r') as outf: - for line in outf: - m = re.match('%([0-9a-f]+)% md5sum', line) - if m: - print('computed md5:', h.hexdigest()) - print('sagetex.sout md5:', m.group(1)) - if h.hexdigest() == m.group(1): - run_sage = False +import shutil +import argparse + +def argparser(): + p = argparse.ArgumentParser(description=__doc__.strip()) + p.add_argument('--sage', action='store', default=find_sage(), + help="Location of the Sage executable") + p.add_argument('src', help="Input file name (basename or .sagetex.sage)") + return p + +def find_sage(): + return shutil.which('sage') or 'sage' + +def run(args): + src = args.src + path_to_sage = args.sage + + if src.endswith('.sagetex.sage'): + src = src[:-13] + else: + src = os.path.splitext(src)[0] + + # Ensure results are output in the same directory as the source files + os.chdir(os.path.dirname(src)) + src = os.path.basename(src) + + usepackage = r'usepackage(\[.*\])?{sagetex}' + uses_sagetex = False + + # If it does not use sagetex, obviously running sage is unnecessary. + if os.path.isfile(src + '.tex'): + with open(src + '.tex') as texf: + for line in texf: + if line.strip().startswith(r'\usepackage') and re.search(usepackage, line): + uses_sagetex = True break -except IOError: - pass - -if run_sage: - print('Need to run Sage on {0}.'.format(src)) - sys.exit(subprocess.call([path_to_sage, src + '.sagetex.sage'])) -else: - print('Not necessary to run Sage on {0}.'.format(src)) + else: + # The .tex file might not exist if LaTeX output was put to a different + # directory, so in that case just assume we need to build. + uses_sagetex = True + + if not uses_sagetex: + print(src + ".tex doesn't seem to use SageTeX, exiting.", file=sys.stderr) + sys.exit(1) + + # if something goes wrong, assume we need to run Sage + run_sage = True + ignore = r"^( _st_.goboom|print\('SageT| ?_st_.current_tex_line)" + + try: + with open(src + '.sagetex.sage', 'r') as sagef: + h = hashlib.md5() + for line in sagef: + if not re.search(ignore, line): + h.update(bytearray(line,'utf8')) + except IOError: + print('{0}.sagetex.sage not found, I think you need to typeset {0}.tex first.' + ''.format(src), file=sys.stderr) + sys.exit(1) + + try: + with open(src + '.sagetex.sout', 'r') as outf: + for line in outf: + m = re.match('%([0-9a-f]+)% md5sum', line) + if m: + print('computed md5:', h.hexdigest()) + print('sagetex.sout md5:', m.group(1)) + if h.hexdigest() == m.group(1): + run_sage = False + break + except IOError: + pass + + if run_sage: + print('Need to run Sage on {0}.'.format(src)) + sys.exit(subprocess.call([path_to_sage, src + '.sagetex.sage'])) + else: + print('Not necessary to run Sage on {0}.'.format(src)) + +if __name__ == "__main__": + run(argparser().parse_args()) % \end{macrocode} % -% \subsection{makestatic.py} -% \label{sec:makestatic} +% \subsection{\texttt{sagetex-makestatic}} +% \label{sec:sagetex-makestatic} % \iffalse %</ifnecessaryscript> %<*staticscript> % \fi % -% Now the |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. +% Now the |sagetex-makestatic|: +% % \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. @@ -136,53 +144,61 @@ Sage on `inputfile' already. `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 as 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]) +See the SageTeX documentation for more details. +""" +import sys +import time +import os.path +import argparse + +from sagetexparse import DeSageTex + +def argparser(): + p = argparse.ArgumentParser(description=__doc__.strip()) + p.add_argument('inputfile', help="Input file name (basename or .tex)") + p.add_argument('outputfile', nargs='?', default=None, help="Output file name") + p.add_argument('-o', '--overwrite', action="store_true", default=False, + help="Overwrite output file if it exists") + p.add_argument('-s', '--sout', action="store", default=None, + help="Location of the .sagetex.sout file") + return p + +def run(args): + src, dst, overwrite = args.inputfile, args.outputfile, args.overwrite + + if dst is not None and (os.path.exists(dst) and not overwrite): + print('Error: %s exists and overwrite option not specified.' % dst, + file=sys.stderr) + sys.exit(1) + + src, ext = os.path.splitext(src) + texfn = src + '.tex' + soutfn = args.sout if args.sout is not None else src + '.sagetex.sout' % \end{macrocode} % All the real work gets done in the line below. Sorry it's not more % exciting-looking. % \begin{macrocode} -desagetexed = DeSageTex(src) + desagetexed = DeSageTex(texfn, soutfn) % \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\n%% replaced with plain LaTeX. Processed %s.\n" % time.strftime('%a %d %b %Y %H:%M:%S', time.localtime()) + header = ("%% SageTeX commands have been automatically removed from this file and\n" + "%% replaced with plain LaTeX. Processed %s.\n" + "" % time.strftime('%a %d %b %Y %H:%M:%S', time.localtime())) -if len(args) == 2: - dest = open(args[1], 'w') -else: - dest = sys.stdout + if dst is not None: + dest = open(dst, 'w') + else: + dest = sys.stdout -dest.write(header) -dest.write(desagetexed.result) + dest.write(header) + dest.write(desagetexed.result) + +if __name__ == "__main__": + run(argparser().parse_args()) % \end{macrocode} % % \iffalse @@ -190,20 +206,12 @@ dest.write(desagetexed.result) %<*extractscript> % \fi % -% \subsection{extractsagecode.py} +% \subsection{\texttt{sagetex-extract}} % -% Same idea as |makestatic.py|, except this does basically the opposite +% Same idea as |sagetex-makestatic|, 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 @@ -212,47 +220,49 @@ 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 as 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) +See the SageTeX documentation for more details. +""" +import sys +import time +import os.path +import argparse + +from sagetexparse import SageCodeExtractor + +def argparser(): + p = argparse.ArgumentParser(description=__doc__.strip()) + p.add_argument('inputfile', help="Input file name (basename or .tex)") + p.add_argument('outputfile', nargs='?', default=None, help="Output file name") + p.add_argument('-o', '--overwrite', action="store_true", default=False, + help="Overwrite output file if it exists") + p.add_argument('--no-inline', action="store_true", default=False, + help="Extract code only from Sage environments") + return p + +def run(args): + src, dst, overwrite = args.inputfile, args.outputfile, args.overwrite + + if dst is not None and (os.path.exists(dst) and not overwrite): + print('Error: %s exists and overwrite option not specified.' % dst, + file=sys.stderr) + sys.exit(1) + + src, ext = os.path.splitext(src) + sagecode = SageCodeExtractor(src + '.tex', inline=not args.no_inline) + header = ("#> This file contains Sage code extracted from %s%s.\n" + "#> Processed %s.\n" + "" % (src, ext, time.strftime('%a %d %b %Y %H:%M:%S', time.localtime()))) + + if dst is not None: + dest = open(dst, 'w') + else: + dest = sys.stdout + + dest.write(header) + dest.write(sagecode.result) + +if __name__ == "__main__": + run(argparser().parse_args()) % \end{macrocode} % % \iffalse @@ -271,6 +281,8 @@ dest.write(sagecode.result) % over the screen. % \begin{macrocode} import sys +import os +import textwrap from pyparsing import * % \end{macrocode} % First, we define this very helpful parser: it finds the matching @@ -281,8 +293,7 @@ from pyparsing import * % \begin{macrocode} def skipToMatching(opener, closer): nest = nestedExpr(opener, closer) - nest.setParseAction(lambda l, s, t: l[s:getTokensEndLoc()]) - return nest + return originalTextFor(nest) curlybrackets = skipToMatching('{', '}') squarebrackets = skipToMatching('[', ']') @@ -290,6 +301,7 @@ squarebrackets = skipToMatching('[', ']') % Next, parser for |\sage|, |\sageplot|, and pause/unpause calls: % \begin{macrocode} sagemacroparser = r'\sage' + curlybrackets('code') +sagestrmacroparser = r'\sagestr' + curlybrackets('code') sageplotparser = (r'\sageplot' + Optional(squarebrackets)('opts') + Optional(squarebrackets)('format') @@ -356,17 +368,19 @@ class SoutParser(): % that the provided |fn| is just a basename. % \begin{macrocode} class DeSageTex(): - def __init__(self, fn): + def __init__(self, texfn, soutfn): self.sagen = 0 self.plotn = 0 - self.fn = fn - self.sout = SoutParser(fn + '.sagetex.sout') + self.fn = os.path.basename(texfn) + self.sout = SoutParser(soutfn) % \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} + strmacro = sagestrmacroparser smacro = sagemacroparser smacro.setParseAction(self.sage) + strmacro.setParseAction(self.sage) % \end{macrocode} % Parse the |\usepackage{sagetex}| line. Right now we don't support % comma-separated lists of packages. @@ -410,7 +424,7 @@ class DeSageTex(): % 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 = smacro | senv | ssilent | usepackage | splot | stexindent |strmacro doit.ignore('%' + restOfLine) doit.ignore(r'\begin{verbatim}' + SkipTo(r'\end{verbatim}')) doit.ignore(r'\begin{comment}' + SkipTo(r'\end{comment}')) @@ -422,7 +436,7 @@ class DeSageTex(): % |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()) + str = ''.join(open(texfn, '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 @@ -456,7 +470,7 @@ class DeSageTex(): % Sage. % \begin{macrocode} class SageCodeExtractor(): - def __init__(self, fn): + def __init__(self, texfn, inline=True): smacro = sagemacroparser smacro.setParseAction(self.macroout) @@ -483,34 +497,38 @@ class SageCodeExtractor(): sunpause = sagetexunpause sunpause.setParseAction(self.unpause) - doit = smacro | splot | senv | spause | sunpause + if inline: + doit = smacro | splot | senv | spause | sunpause + else: + doit = senv | spause | sunpause + doit.ignore('%' + restOfLine) - str = ''.join(open(fn + '.tex', 'r').readlines()) + str = ''.join(open(texfn, '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' + self.result += '#> \\sage{} from line %s\n' % lineno(l, s) + self.result += textwrap.dedent(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' + self.result += '#> \\sageplot{} from line %s:\n' % lineno(l, s) + if t.format != '': + self.result += '#> format: %s' % t.format[0][1:-1] + '\n' + self.result += textwrap.dedent(t.code[1:-1]) + '\n\n' def envout(self, s, l, t): - self.result += '# %s environment from line %s:' % (t.env, + self.result += '#> %s environment from line %s:' % (t.env, lineno(l, s)) - self.result += t.code[0] + '\n' + self.result += textwrap.dedent(''.join(t.code)) + '\n' def pause(self, s, l, t): - self.result += ('# SageTeX (probably) paused on input line %s.\n\n' % + 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' % + self.result += ('#> SageTeX (probably) unpaused on input line %s.\n\n' % (lineno(l, s))) % \end{macrocode} % \end{macro} diff --git a/macros/latex/contrib/sagetex/setup.py b/macros/latex/contrib/sagetex/setup.py index 28e2712065..b83a6bbac8 100644 --- a/macros/latex/contrib/sagetex/setup.py +++ b/macros/latex/contrib/sagetex/setup.py @@ -4,27 +4,24 @@ setup(name='sagetex', long_description="""The SageTeX package allows you to embed code, results of computations, and plots from the Sage mathematics software suite (http://sagemath.org) into LaTeX documents.""", - version='3.5', + version='3.6.1', author='Dan Drake', author_email='dr.dan.drake@gmail.com', maintainer='SageMath developers', maintainer_email='sage-devel@googlegroups.com', url='https://github.com/sagemath/sagetex', license='GPLv2+', - py_modules=['sagetex'], + py_modules=['sagetex', 'sagetexparse'], + scripts=['sagetex-run', 'sagetex-extract', 'sagetex-makestatic', 'sagetex-remote'], + install_requires=['pyparsing'], data_files = [('share/texmf/tex/latex/sagetex', ['example.tex', 'CONTRIBUTORS', - 'extractsagecode.py', - 'run-sagetex-if-necessary.py', - 'makestatic.py', 'scripts.dtx', 'remote-sagetex.dtx', - 'remote-sagetex.py', 'py-and-sty.dtx', 'sagetex.dtx', 'sagetex.ins', - 'sagetexparse.py', 'sagetex.sty']), ('share/doc/sagetex', [ 'example.tex', |