summaryrefslogtreecommitdiff
path: root/project/scipycon/proceedings/booklet
diff options
context:
space:
mode:
Diffstat (limited to 'project/scipycon/proceedings/booklet')
-rw-r--r--project/scipycon/proceedings/booklet/__init__.py0
-rw-r--r--project/scipycon/proceedings/booklet/mk_booklet.py94
-rw-r--r--project/scipycon/proceedings/booklet/mk_scipy_paper.py463
3 files changed, 557 insertions, 0 deletions
diff --git a/project/scipycon/proceedings/booklet/__init__.py b/project/scipycon/proceedings/booklet/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/scipycon/proceedings/booklet/__init__.py
diff --git a/project/scipycon/proceedings/booklet/mk_booklet.py b/project/scipycon/proceedings/booklet/mk_booklet.py
new file mode 100644
index 0000000..c27ddf7
--- /dev/null
+++ b/project/scipycon/proceedings/booklet/mk_booklet.py
@@ -0,0 +1,94 @@
+# encoding: utf-8
+
+import os
+import sys
+import codecs
+import re
+
+try:
+ from sanum import model
+except:
+ root_dir = os.path.abspath(os.getcwd() + '/../../')
+ os.chdir(root_dir)
+ sys.path.append(root_dir)
+ from sanum import model
+
+import sanum
+
+import turbogears
+turbogears.update_config(configfile="dev.cfg",
+ modulename="sanum.config")
+
+
+from mk_scipy_paper import tex2pdf, current_dir , copy_files, preamble, \
+ render_abstract, addfile, sourcedir, outdir, outfilename
+
+
+def hack_include_graphics(latex_text, attach_dir):
+ """ Replaces all the \includegraphics call with call that impose the
+ width to be 0.9\linewidth.
+ """
+ latex_text = re.sub(r'\\includegraphics(\[.*\])?\{',
+ r'\includegraphics\1{' + attach_dir,
+ latex_text)
+ return latex_text
+
+
+class MyStringIO(object):
+ """ An unicode-friendly stringIO-like object.
+ """
+
+ def __init__(self):
+ self.lines = []
+
+ def write(self, line):
+ self.lines.append(line)
+
+ def getvalue(self):
+ return u''.join(self.lines)
+
+def mk_booklet_tex(outfilename):
+ """ Generate the entire booklet latex file.
+ """
+ outfile = codecs.open(outfilename, 'w', 'utf-8')
+ preamble(outfile)
+ copy_files()
+ #addfile(outfile, sourcedir + os.sep + 'title.tex')
+ addfile(outfile, sourcedir + os.sep + 'introduction.tex')
+
+ #outfile.write(ur'\setcounter{page}{0}' + '\n')
+
+ #from sanum.controllers import Root as Controller
+ abstracts = model.Abstract.select()
+ for abstract in abstracts:
+ if not abstract.approved:
+ continue
+ print abstract.title
+ # Hack: I don't use a stringIO, because it is not unicode-safe.
+ tmpout = MyStringIO()
+ # Hack: I don't wont to be bound to the controller, to be
+ # abstractle to run without cherrypy.
+ #attach_dir = Controller._paper_attach_dir(abstract.id)
+ attach_dir = os.path.abspath(os.sep.join(
+ (os.path.dirname(sanum.__file__), 'static',
+ 'papers', '%i' % abstract.id))) + os.sep
+ render_abstract(tmpout, abstract)
+ outstring = hack_include_graphics(tmpout.getvalue(),
+ attach_dir)
+ outfile.write(outstring)
+ #outfile.write(ur'\fillbreak' + '\n')
+
+ outfile.write(ur'\end{document}' + '\n')
+
+
+
+
+def mk_booklet(outfilename=outfilename):
+ """ Generate the entire booklet pdf file.
+ """
+ name, ext = os.path.splitext(outfilename)
+ mk_booklet_tex(name + '.tex')
+ return tex2pdf(name, remove_tex=False, timeout=60)
+
+if __name__ == '__main__':
+ mk_booklet(outfilename)
diff --git a/project/scipycon/proceedings/booklet/mk_scipy_paper.py b/project/scipycon/proceedings/booklet/mk_scipy_paper.py
new file mode 100644
index 0000000..7b4eca0
--- /dev/null
+++ b/project/scipycon/proceedings/booklet/mk_scipy_paper.py
@@ -0,0 +1,463 @@
+# 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/scipycon/project/scipycon/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()