Moved the files to new Django app named scipycon and modified settings.
# encoding: utf-8
import os
import re
import sys
import shutil
import codecs
from glob import glob
from docutils import core as docCore
conf_name = 'SciPy2009'
current_dir = '/media/python/workspace/kiwipycon/project/kiwipycon/proceedings/booklet'
outdir = current_dir + os.sep + 'output'
sourcedir = current_dir + os.sep + 'sources'
try:
os.mkdir(outdir)
except:
pass
outfilename = outdir + os.sep + 'booklet.tex'
##############################################################################
# Routines for supervised execution
##############################################################################
from threading import Thread
import os
import signal
from subprocess import Popen
from time import sleep
def delayed_kill(pid, delay=10):
sleep(delay)
try:
os.kill(pid, signal.SIGTERM)
except OSError:
pass
def supervise_popen(command, timeout=10):
process = Popen(command)
Thread(target=delayed_kill, args=(process.pid,timeout),).start()
process.wait()
##############################################################################
# LaTeX generation functions.
##############################################################################
def protect(string):
r''' Protects all the "\" in a string by adding a second one before
>>> protect(r'\foo \*')
'\\\\foo \\\\*'
'''
return re.sub(r"\\", r"\\\\", string)
def safe_unlink(filename):
""" Remove a file from the disk only if it exists, if not r=fails silently
"""
if os.path.exists(filename):
os.unlink(filename)
rxcountpages = re.compile(r"$\s*/Type\s*/Page[/\s]", re.MULTILINE|re.DOTALL)
def count_pages(filename):
data = file(filename,"rb").read()
return len(rxcountpages.findall(data))
def tex2pdf(filename, remove_tex=True, timeout=10, runs=2):
""" Compiles a TeX file with pdfLaTeX (or LaTeX, if or dvi ps requested)
and cleans up the mess afterwards
"""
current_dir = os.getcwd()
os.chdir(os.path.dirname(filename))
print >> sys.stderr, "Compiling document to pdf"
basename = os.path.splitext(os.path.basename(filename))[0]
if os.path.exists(basename + '.pdf'):
os.unlink(basename + '.pdf')
for _ in range(runs):
supervise_popen(("pdflatex", "--interaction", "scrollmode",
os.path.basename(filename)), timeout=timeout)
error_file = None
errors = file(os.path.abspath(basename + '.log')).readlines()[-1]
if not os.path.exists(basename + '.pdf') or \
"Fatal error" in errors:
error_file = os.path.abspath(basename + '.log')
if remove_tex:
safe_unlink(filename+".tex")
safe_unlink(filename+".log")
safe_unlink(filename+".aux")
safe_unlink(filename+".out")
os.chdir(current_dir)
return error_file
def rst2latex(rst_string, no_preamble=True, allow_latex=True):
""" Calls docutils' engine to convert a rst string to a LaTeX file.
"""
overrides = {'output_encoding': 'utf-8', 'initial_header_level': 3,
'no_doc_title': True, 'use_latex_citations': True,
'use_latex_footnotes':True}
if allow_latex:
rst_string = u'''.. role:: math(raw)
:format: latex
\n\n''' + rst_string
tex_string = docCore.publish_string(
source=rst_string,
writer_name='latex2e',
settings_overrides=overrides)
if no_preamble:
extract_document = \
re.compile(r'.*\\begin\{document\}(.*)\\end\{document\}',
re.DOTALL)
matches = extract_document.match(tex_string)
tex_string = matches.groups()[0]
return tex_string
def get_latex_preamble():
""" Retrieve the required preamble from docutils.
"""
full_document = rst2latex('\n', no_preamble=False)
preamble = re.split(r'\\begin\{document\}', full_document)[0]
## Remove the documentclass.
preamble = r"""
%s
\makeatletter
\newcommand{\class@name}{gael}
\makeatother
\usepackage{ltxgrid}
%s
""" % (
preamble.split('\n')[0],
'\n'.join(preamble.split('\n')[1:]),
)
return preamble
##############################################################################
# Functions to generate part of the booklet
##############################################################################
def addfile(outfile, texfilename):
""" Includes the content of a tex file in our outfile.
"""
include = codecs.open(texfilename, 'r')
data = include.readlines()
outfile.write(ur'\thispagestyle{empty}' + u'\n')
outfile.writelines(data)
def preamble(outfile):
outfile.write(r'''
%s
\usepackage{abstracts}
\usepackage{ltxgrid}
\usepackage{amssymb,latexsym,amsmath,amsthm}
\usepackage{longtable}
\geometry{left=.8cm, textwidth=17cm, bindingoffset=0.6cm,
textheight=25.3cm, twoside}
\usepackage{hyperref}
\hypersetup{pdftitle={Proceedings of the 8th Annual Python in Science Conference}}
\begin{document}
'''.encode('utf-8') % get_latex_preamble())
# XXX SciPy08 should not be hard coded, but to run out of the webapp
def hack_include_graphics(latex_text):
""" Replaces all the \includegraphics call with call that impose the
width to be 0.9\linewidth.
"""
latex_text = re.sub(r'\\setlength\{\\rightmargin\}\{\\leftmargin\}',
r'\\setlength{\\leftmargin}{4ex}\\setlength{\\rightmargin}{0ex}',
latex_text)
latex_text = re.sub(r'\\begin\{quote\}\n\\begin\{itemize\}',
r'\\begin{itemize}',
latex_text)
latex_text = re.sub(r'\\end\{itemize\}\n\\end\{quote\}',
r'\\end{itemize}',
latex_text)
latex_text = re.sub(r'\\includegraphics(\[.*\])?\{',
r'\includegraphics[width=\linewidth]{',
latex_text)
latex_text = re.sub(r'\\href\{([^}]+)\}\{http://(([^{}]|(\{[^}]*\}))+)\}',
r'''%
% Break penalties to have URL break easily:
\mathchardef\UrlBreakPenalty=0
\mathchardef\UrlBigBreakPenalty=0
%\hskip 0pt plus 2em
\href{\1}{\url{\1}}''',
latex_text)
latex_text = re.sub(r'\\href\{([^}]+)\}\{https://(([^{}]|(\{[^}]*\}))+)\}',
r'''%
% Break penalties to have URL break easily:
\mathchardef\UrlBreakPenalty=0
\mathchardef\UrlBigBreakPenalty=0
\linebreak
\href{\1}{\url{\1}}''',
latex_text)
return latex_text
def render_abstract(outfile, abstract, start_page=None):
""" Writes the LaTeX string corresponding to one abstract.
"""
if start_page is not None:
outfile.write(r"""
\setcounter{page}{%i}
""" % start_page)
else:
if hasattr(abstract, 'start_page'):
start_page = abstract.start_page
else:
start_page = 1
if not abstract.authors:
author_list = abstract.owners
else:
author_list = abstract.authors
authors = []
print dir(author_list[0])
for author in author_list:
# If the author has no surname, he is not an author
if author.surname:
if author.email_address:
email = r'(\email{%s})' % author.email_address
else:
email = ''
authors.append(ur'''\otherauthors{
%s %s
%s --
\address{%s, %s}
}''' % (author.first_names, author.surname,
email,
author.institution,
author.city))
if authors:
authors = u'\n'.join(authors)
authors += r'\addauthorstoc{%s}' % ', '.join(
'%s. %s' % (author.first_names[0], author.surname)
for author in author_list
)
author_cite_list = ['%s. %s' % (a.first_names[0], a.surname)
for a in author_list]
if len(author_cite_list) > 4:
author_cite_list = author_cite_list[:3]
author_cite_list.append('et al.')
citation = ', '.join(author_cite_list) + \
'in Proc. SciPy 2009, G. Varoquaux, S. van der Walt, J. Millman (Eds), '
copyright = '\\copyright 2009, %s' % ( ', '.join(author_cite_list))
else:
authors = ''
citation = 'Citation'
copyright = 'Copyright'
if hasattr(abstract, 'num_pages'):
citation += 'pp. %i--%i' % (start_page, start_page +
abstract.num_pages)
else:
citation += 'p. %i'% start_page
if hasattr(abstract, 'number'):
abstract.url = 'http://conference.scipy.org/proceedings/%s/paper_%i' \
% (conf_name, abstract.number)
url = r'\url{%s}' % abstract.url
else:
url = ''
paper_text = abstract.paper_text
if paper_text == '':
paper_text = abstract.summary
# XXX: It doesn't seem to be right to be doing this, but I get a
# nasty UnicodeDecodeError on some rare abstracts, elsewhere.
paper_text = codecs.utf_8_decode(hack_include_graphics(
rst2latex(paper_text)))[0]
paper_abstract = abstract.paper_abstract
if paper_abstract is None:
paper_abstract = ''
if not paper_abstract=='':
paper_abstract = ur'\begin{abstract}%s\end{abstract}' % \
paper_abstract#.encode('utf-8')
abstract_dict = {
'text': paper_text.encode('utf-8'),
'abstract': paper_abstract.encode('utf-8'),
'authors': authors.encode('utf-8'),
'title': abstract.title.encode('utf-8'),
'citation': citation.encode('utf-8'),
'copyright': copyright.encode('utf-8'),
'url': url.encode('utf-8'),
}
outfile.write(codecs.utf_8_decode(ur'''
\phantomsection
\hypertarget{chapter}{}
\vspace*{-2em}
\resetheadings{%(title)s}{%(citation)s}{%(url)s}{%(copyright)s}
\title{%(title)s}
\begin{minipage}{\linewidth}
%(authors)s
\end{minipage}
\noindent\rule{\linewidth}{0.2ex}
\vspace*{-0.5ex}
\twocolumngrid
%(abstract)s
\sloppy
%(text)s
\fussy
\onecolumngrid
\smallskip
\vfill
\filbreak
\clearpage
'''.encode('utf-8') % abstract_dict )[0])
def copy_files(dest=outfilename):
""" Copy the required file from the source dir to the output dir.
"""
dirname = os.path.dirname(dest)
if dirname == '':
dirname = '.'
for filename in glob(sourcedir+os.sep+'*'):
destfile = os.path.abspath(dirname + os.sep +
os.path.basename(filename))
shutil.copy2(filename, destfile)
def mk_abstract_preview(abstract, outfilename, attach_dir, start_page=None):
""" Generate a preview for an given paper.
"""
copy_files()
outdir = os.path.dirname(os.path.abspath(outfilename))
for f in glob(os.path.join(attach_dir, '*')):
if os.path.isdir(f) and not os.path.exists(f):
os.makedirs(f)
else:
if not outdir == os.path.dirname(os.path.abspath(f)):
shutil.copy2(f, outdir)
for f in glob(os.path.join(sourcedir, '*')):
if os.path.isdir(f):
os.makedirs(f)
else:
destfile = os.path.abspath(os.path.join(outdir, f))
shutil.copy2(f, outdir)
outbasename = os.path.splitext(outfilename)[0]
outfilename = outbasename + '.tex'
outfile = codecs.open(outfilename, 'w', 'utf-8')
preamble(outfile)
render_abstract(outfile, abstract, start_page=start_page)
outfile.write(ur'\end{document}' + u'\n')
outfile.close()
tex2pdf(outbasename, remove_tex=False)
abstract.num_pages = count_pages(outbasename + '.pdf')
# Generate the tex file again, now that we know the length.
outfile = codecs.open(outfilename, 'w', 'utf-8')
preamble(outfile)
render_abstract(outfile, abstract, start_page=start_page)
outfile.write(ur'\end{document}' + u'\n')
outfile.close()
return tex2pdf(os.path.splitext(outfilename)[0], remove_tex=False)
##############################################################################
# Code for using outside of the webapp.
##############################################################################
def mk_zipfile():
""" Generates a zipfile with the required files to build an
abstract.
"""
from zipfile import ZipFile
zipfilename = os.path.join(os.path.dirname(__file__),
'mk_scipy_paper.zip')
z = ZipFile(zipfilename, 'w')
for filename in glob(os.path.join(sourcedir, '*')):
if not os.path.isdir(filename):
z.write(filename, arcname='source/' + os.path.basename(filename))
z.write(__file__, arcname='mk_scipy_paper.py')
return zipfilename
class Bunch(dict):
def __init__(self, **kwargs):
dict.__init__(self, **kwargs)
self.__dict__ = self
def __reprt(self):
return repr(self.__dict__)
author_like = Bunch(
first_names='XX',
surname='XXX',
email_address='xxx@XXX',
institution='XXX',
address='XXX',
country='XXX'
)
abstract_like = Bunch(
paper_abstract='An abstract',
authors=[author_like, ],
title='',
)
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-o", "--output", dest="outfilename",
default="./paper.pdf",
help="output to FILE", metavar="FILE")
parser.usage = """%prog [options] rst_file [data_file]
Compiles a given rest file and information file to pdf for the SciPy
proceedings.
"""
(options, args) = parser.parse_args()
if not len(args) in (1, 2):
print "One or two arguments required: the input rest file and " \
"the input data file"
print ''
parser.print_help()
sys.exit(1)
infile = args[0]
if len(args)==1:
data_file = 'data.py'
if os.path.exists('data.py'):
print "Using data file 'data.py'"
else:
print "Generating the data file and storing it in data.py"
print "You will need to edit this file to add title, author " \
"information, and abstract."
abstract = abstract_like
file('data.py', 'w').write(repr(abstract))
elif len(args)==2:
data_file = args[1]
abstract = Bunch( **eval(file(data_file).read()))
abstract.authors = [Bunch(**a) for a in abstract.authors]
abstract['summary'] = u''
abstract['paper_text'] = file(infile).read().decode('utf-8')
outfilename = options.outfilename
mk_abstract_preview(abstract, options.outfilename,
os.path.dirname(options.outfilename))
# Ugly, but I don't want to wait on the thread.
sys.exit()