Source

Toric varieties paper / sagetex.py

Full commit
##
## 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) 2008--2010 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__ = """
  [2010/10/20 v2.3 embedding Sage into LaTeX documents]
""".strip()
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()
version = ' '.join(__version__.strip('[').split()[0:2])
from sage.misc.latex import latex
from sage.misc.preparser import preparse
import os
import os.path
import hashlib
import traceback
import subprocess
import shutil
class SageTeXProcessor():
  def __init__(self, jobname):
    self.progress('Processing Sage code for {0}.tex...'.format(jobname))
    self.didinitplot = False
    self.useimagemagick = False
    self.useepstopdf = False
    self.plotdir = 'sage-plots-for-' + jobname + '.tex'
    self.filename = jobname
    self.name = os.path.splitext(jobname)[0]
    autogenstr = """% This file was *autogenerated* from {0}.sagetex.sage with
 % sagetex.py version {1}\n""".format(self.name, version)
    self.souttmp = open(self.filename + '.sagetex.sout.tmp', 'w')
    self.souttmp.write(autogenstr)
    self.scmdtmp = open(self.filename + '.sagetex.scmd.tmp', 'w')
    self.scmdtmp.write(autogenstr)
    self.scmdpos = 3
  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 {0}'.format(counter))
    self.souttmp.write('\\newlabel{@sageinline' + str(counter) + '}{{%\n' +
                 s.rstrip() + '}{}{}{}{}}\n')

  def savecmd(self, counter, s):
    self.progress('Sage commandline {0}'.format(counter))
    self.scmdtmp.write(s.rstrip() + "\n")
    begin = self.scmdpos
    end = begin + len(s.splitlines()) - 1
    self.scmdpos = end+1
    return begin, end
  def blockbegin(self):
    self.progress('Code block begin...', False)
  def blockend(self):
    self.progress('end')
  def doctest(self, counter, str, globals, locals, include_text_output):
      print 'in doctest'
      current_statement = None
      current_lines = None
      latex_string = ""
      line_iterator = (line.lstrip() for line in str.splitlines())

      # Gobbles everything until the first "sage: ..." block
      for line in line_iterator:
          if line.startswith("sage: "):
              break
      else:
          return
      sage_block = 0
      while True:
          # At each
          assert line.startswith("sage: ")
          current_statement  = line[6:]
          current_lines = "  "+line
          for line in line_iterator:
              if line.startswith("sage: "):
                  break
              elif line.startswith("..."):
                  current_statement +="\n"+line[6:]
                  current_lines +="\n  "+line
              elif include_text_output:
                  current_lines +="\n  "+line
          else:
              line = None # we reached the last line
          # Now we have digested everything from the current sage: ... to the next one or to the last line
          # Let us handle it
          verbatimboxname = "@sageinline%s-code%s"%(counter,sage_block)
          self.souttmp.write("\\begin{SaveVerbatim}{%s}\n"%verbatimboxname)
          self.souttmp.write(current_lines)
          self.souttmp.write("\n\\end{SaveVerbatim}\n")
          latex_string += "\UseVerbatim{%s}\n"%verbatimboxname
          current_statement = preparse(current_statement)
          try: # How to test whether the code is an Python expression or a statement?
              # In the first case, we compute the result and include it in the latex
              result = eval(current_statement, globals, locals)
              latex_string += r"""\abovedisplayskip=0pt plus 3pt
\abovedisplayshortskip=0pt plus 3pt
\begin{displaymath}""" + "\n {0}\n".format(latex(result)) + r"\end{displaymath}" + "\n"
          except SyntaxError:
              # If this fails, we assume that the code was a statement, and just execute it
              exec current_statement in globals, locals
          current_lines = current_statement = None
          if line is None: break
          sage_block += 1
      self.inline(counter, latex_string)
  def commandline(self, counter, str, globals, locals, text_output):
      current_statement = None
      current_lines = None
      line_iterator = (line.lstrip() for line in str.splitlines())
      latex_string = r"\ifhmode\unskip\unskip\fi\vspace{\sagecommandlineskip}" + "\n"
      bottom_skip =  r"\vspace{\sagecommandlineskip}" + "\n"

      # Gobbles everything until the first "sage: ..." block
      for line in line_iterator:
          if line.startswith("sage: "):
              break
      else:
          return
      sage_block = 0
      while True:
          # At each
          assert line.startswith("sage: ")
          current_statement  = line[6:]
          current_lines = line
          for line in line_iterator:
              if line.startswith("sage: "):
                  break
              elif line.startswith("...   "):
                  current_statement += "\n"+line[6:]
                  current_lines += "\n"+line
          else:
              line = None # we reached the last line
          # Now have everything from "sage:" to the next "sage:"

          if current_lines.find('#@')>=0:
              escapeoption = ',escapeinside={\\#@}{\\^^M}'
          else:
              escapeoption = ''

          begin, end = self.savecmd(counter,current_lines)
          latex_string += r"\lstinputlisting[firstline={0},lastline={1},firstnumber={2},style=SageInput{3}]{{{4}.sagetex.scmd}}".format(begin, end, begin-2, escapeoption, self.name)+"\n"

          current_statement = preparse(current_statement)
          try:  # is it an expression?
              result = eval(current_statement, globals, locals)
              resultstr = "{0}".format(result)
              begin, end = self.savecmd(counter,resultstr)
              if text_output:
                latex_string += r"\lstinputlisting[firstline={0},lastline={1},firstnumber={2},style=SageOutput]{{{3}.sagetex.scmd}}".format(begin, end, begin-2, self.name)+"\n"
                bottom_skip = r"\vspace{\sagecommandlineskip}" + "\n"
              else:
                latex_string += (
                  r"\begin{displaymath}" + "\n" +
                  latex(result)          + "\n" +
                  r"\end{displaymath}"   + "\n" )
                bottom_skip = ''
          except SyntaxError:  # must be a statement!
              exec current_statement in globals, locals
          current_lines = current_statement = None
          if line is None: break
          sage_block += 1
      latex_string += bottom_skip + r"\noindent" + "\n"
      self.inline(counter, latex_string)
  def plot(self, counter, _p_, format='notprovided', **kwargs):
      if not self.didinitplot:
          self.initplot()
      self.progress('Plot {0}'.format(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-{0}.eps'.format(counter))
              self.progress('Calling epstopdf to convert plot-{0}.eps to PDF'.format(
                            counter))
              subprocess.check_call(['epstopdf', epsfile])
              continue
          plotfilename = os.path.join(self.plotdir, 'plot-{0}.{1}'.format(counter, fmt))
          try:
              _p_.save(filename=plotfilename, **kwargs)
          except ValueError as inst:
              if 'filetype not supported by save' in str(inst):
                  newfilename = plotfilename[:-3] + 'png'
                  print '  saving {0} failed; saving to {1} instead.'.format(
                                                    plotfilename, newfilename)
                  _p_.save(filename=newfilename, **kwargs)
                  break
              else:
                  raise
          if format != 'notprovided' and self.useimagemagick:
              self.progress('Calling Imagemagick to convert plot-{0}.{1} to EPS'.format(
                counter, format))
              self.toeps(counter, format)
  def toeps(self, counter, ext):
    subprocess.check_call(['convert',\
      '{0}/plot-{1}.{2}'.format(self.plotdir, counter, ext), \
      '{0}/plot-{1}.eps'.format(self.plotdir, counter)])
  def goboom(self, line):
    print('\n**** Error in Sage code on line {0} of {1}.tex! Traceback\
 follows.'.format(line, self.filename))
    traceback.print_exc()
    print('\n**** Running Sage on {0}.sage failed! Fix {0}.tex and try\
 again.'.format(self.filename))
    self.souttmp.close()
    os.remove(self.filename + '.sagetex.sout.tmp')
    self.scmdtmp.close()
    os.remove(self.filename + '.sagetex.scmd.tmp')
    sys.exit(int(1))
  def endofdoc(self):
    sagef = open(self.filename + '.sagetex.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.scmdtmp.write(s)
    self.souttmp.close()
    os.rename(self.filename + '.sagetex.sout.tmp', self.filename + '.sagetex.sout')
    self.scmdtmp.close()
    os.rename(self.filename + '.sagetex.scmd.tmp', self.filename + '.sagetex.scmd')
    self.progress('Sage processing complete. Run LaTeX on {0}.tex again.'.format(
             self.filename))