# This script takes a lyx file and runs the python code in it.
# Then rewrites the lyx file again.
#
# Each section of code portion is assumed to be in the same namespace
# where a from numpy import * has been applied
#
# If a PYNEW inside a Note is encountered, the name space is restarted
#
# The output (if any) is replaced in the file
# by the output produced during the code run.
#
# Options:
# -n name of code section (default MyCode)
#
import sys
import optparse
import cStringIO
import re
import os
newre = re.compile(r"\\begin_inset Note.*PYNEW\s+\\end_inset", re.DOTALL)
def getoutput(tstr, dic):
print "\n\nRunning..."
print tstr,
tempstr = cStringIO.StringIO()
sys.stdout = tempstr
code = compile(tstr, '<input>', 'exec')
try:
res = eval(tstr, dic)
sys.stdout = sys.__stdout__
except SyntaxError:
try:
res = None
exec code in dic
finally:
sys.stdout = sys.__stdout__
if res is None:
res = tempstr.getvalue()
else:
res = tempstr.getvalue() + '\n' + repr(res)
if res != '':
print "\nOutput is"
print res,
return res
# now find the code in the code segment
def getnewcodestr(substr, dic):
end = substr.find('\\layout ')
lines = substr[:end].split('\\newline')
outlines = []
first = 1
cmd = ''
lines.append('dummy')
for line in lines:
line = line.strip()
if (line[:3]=='>>>') or (line == 'dummy'):
# we have a new output
pyoutstr = getoutput(cmd, dic).strip()
if pyoutstr != '':
pyout = pyoutstr.split('\n')
outlines.extend(pyout)
cmd = line[4:]
elif (line[:3]=='...'):
# continuation output
cmd += "\n%s" % line[4:]
else:
# first line or output
if first:
first = 0
cmd = line
else:
continue
if line != 'dummy':
outlines.append(line)
return "\n\\newline \n".join(outlines), end
def runpycode(lyxstr, name='MyCode'):
schobj = re.compile(r"\\layout %s\s+>>> " % name)
outstr = cStringIO.StringIO()
num = 0
indx = []
for it in schobj.finditer(lyxstr):
indx.extend([it.start(), it.end()])
num += 1
if num == 0:
print "Nothing found for %s" % name
return lyxstr
start = 0
del indx[0]
indx.append(len(lyxstr))
edic = {}
exec 'from numpy import *' in edic
exec 'set_printoptions(linewidth=65)' in edic
# indx now contains [st0,en0, ..., stN,enN]
# where stX is the start of code segment X
# and enX is the start of \layout MyCode for
# the X+1 code section (or string length if X=N)
for k in range(num):
# first write everything up to the start of the code segment
substr = lyxstr[start:indx[2*k]]
outstr.write(substr)
if start > 0:
mat = newre.search(substr)
# if PYNEW found, then start a new namespace
if mat:
edic = {}
exec 'from numpy import *' in edic
exec 'set_printoptions(linewidth=65)' in edic
# now find the code in the code segment
# endoutput will contain the index just past any output
# already present in the lyx string.
substr = lyxstr[indx[2*k]:indx[2*k+1]]
lyxcodestr, endcode = getnewcodestr(substr, edic)
# write the lyx for the input + new output
outstr.write(lyxcodestr)
outstr.write('\n')
start = endcode + indx[2*k]
outstr.write(lyxstr[start:])
return outstr.getvalue()
def main(args):
usage = "%prog {options} filename"
parser = optparse.OptionParser(usage)
parser.add_option('-n','--name', default='MyCode')
options, args = parser.parse_args(args)
if len(args) < 1:
parser.error("incorrect number of arguments")
os.system('cp -f %s %s.bak' % (args[0], args[0]))
fid = file(args[0])
str = fid.read()
fid.close()
print "Processing %s" % options.name
newstr = runpycode(str, options.name)
fid = file(args[0],'w')
fid.write(newstr)
fid.close()
if __name__ == "__main__":
main(sys.argv[1:])
|