latex

Documentation can be found at https://pythonhosted.org/latex .

Allows calling LaTeX from Python without leaving a mess. Similar to the (officially obsolete) tex package, whose successor is not PyPi-installable:

min_latex = (r"\documentclass{article}"
             r"\begin{document}"
             r"Hello, world!"
             r"\end{document}")

from latex import build_pdf

# this builds a pdf-file inside a temporary directory
pdf = build_pdf(min_latex)

# look at the first few bytes of the header
print bytes(pdf)[:10]

Also comes with support for using Jinja2 templates to generate LaTeX files.

make_env can be used to create an Environment that plays well with LaTex:

Variables can be used in a LaTeX friendly way: Hello, \VAR{name|e}.

Note that autoescaping is off. Blocks are creating using the block macro:

\BLOCK{if weather is 'good'}
Hooray.
\BLOCK{endif}

\#{comments are supported as well}
%# and so are line comments

To keep things short, line statements can be used:

%- if weather is good
Yay.
%- endif

Example use

from jinja2.loaders import FileSystemLoader
from latex.jinja2 import make_env

env = make_env(loader=FileSystemLoader('.'))
tpl = env.get_template('doc.latex')

print(tpl.render(name="Alice"))

The base.latex demonstrates how \BLOCK{...} is substituted for {% ... %}:

\documentclass{article}
\begin{document}
\BLOCK{block body}\BLOCK{endblock}
\end{document}

Finally, doc.latex shows why the %- syntax is usually preferable:

%- extends "base.latex"

%- block body
Hello, \VAR{name|e}.
%- endblock

More examples

Reading latex-source from a file:

ex1.latex
\documentclass{article}
\begin{document}

\section{Lorem ipsum dolor}
Vestibulum et rhoncus nisi. Sed a nunc ante.

\end{document}
ex1.py
from latex import build_pdf

# build_pdf's source parameter can be a file-like object or a string
pdf = build_pdf(open('ex1.latex'))

# pdf is an instance of a data object (see http://pythonhosted.org/data/)
# most often, we will want to save it to a file, as with this example
pdf.save_to('ex1.pdf')

Using the Jinja2-template support:

ex2.latex
\documentclass{article}
\begin{document}

\section{Greetings, {\VAR{name}}!}
It is great to see you.
%- if name == "Alice"
Especially you, Alice!
%- endif

\end{document}
ex2.py
from jinja2 import FileSystemLoader
from latex.jinja2 import make_env
from latex import build_pdf

# create a jinja2 environment with latex-compatible markup and instantiate a
# template
env = make_env(loader=FileSystemLoader('.'))
tpl = env.get_template('ex2.latex')

# create a greeting for all of our friends
for name in ['Alice', 'Bob', 'Carol']:
    filename = 'hello-{}.pdf'.format(name.lower())

    pdf = build_pdf(tpl.render(name=name))
    pdf.save_to(filename)

Since the LaTeX source file is copied to a temporary directory, no additional files of the same folder are found by TeX by default. This is alleviated by using the TEXINPUTS [1] environment variable:

ex3.latex
\documentclass{article}
\usepackage{ex3}

\begin{document}
This is \important{very} important.
\end{document}
ex3.sty
\newcommand{\important}[1]{{\textbf{\underline{#1}}}}
ex3.py
import os

from latex import build_pdf

# we need to supply absolute paths
current_dir = os.path.abspath(os.path.dirname(__file__))

# we are adding an empty string to include the default locations (this is
# described on the tex manpage)
pdf = build_pdf(open('ex3.latex'), texinputs=[current_dir, ''])

pdf.save_to('ex3.pdf')
[1]See man 1 tex, the TEXINPUTS section.

Error formatting

LaTeX errors can be quite cryptic and hard to find in a sea of log messages, to alleviate this, latex offers some basic log parsing functions:

ex4.py
from latex import build_pdf, LatexBuildError


# the following inline latex-document is not valid:
src = r"""
\documentclass{article}\begin{document}
\THISCONTROLSEQUENCEDOESNOTEXIT
\end{document}
"""

# when building, catch the exception and print a clean error message
try:
    build_pdf(src)
except LatexBuildError as e:
    for err in e.get_errors():
        print u'Error in {0[filename]}, line {0[line]}: {0[error]}'.format(err)
        # also print one line of context
        print u'    {}'.format(err['context'][1])
        print

The resulting output:

Error in /tmp/tmpm9bfc0/tmpr50TJG.latex, line 3: Undefined control sequence.
    l.3 \THISCONTROLSEQUENCEDOESNOTEXIT

Error in /tmp/tmpm9bfc0/tmpr50TJG.latex, line 3: ==> Fatal error occurred, no output PDF file
     produced!

API

latex.escape(s, fold_newlines=True)

Escapes a string to make it usable in LaTeX text mode. Will replace special characters as well as newlines.

Parameters:
  • s – The string to escape.
  • fold_newlines – If true, multiple newlines will be reduced to just a single \. Otherwise, whitespace is kept intact by adding multiple [naselineskip].
class latex.build.LatexBuilder

Base class for Latex builders.

build_pdf(source, texinputs=[])

Generates a PDF from LaTeX a source.

If there are errors generating a LatexError is raised.

Parameters:
  • source – The LaTeX source.
  • texinputs – Include paths for TeX. An empty string causes the default path to be added (see the tex manpage).
Returns:

A Data instance containing the generated PDF.

is_available()

Checks if builder is available.

Builders that depend on external programs like latexmk can check if these are found on the path or make sure other prerequisites are met.

Returns:A boolean indicating availability.
class latex.build.LatexMkBuilder(latexmk='latexmk', pdflatex='pdflatex')

A latexmk based builder for LaTeX files.

Uses the latexmk script to build latex files, which is part of some popular LaTeX distributions like texlive.

The build process consists of copying the source file to a temporary directory and running latexmk on it, which will take care of reruns.

Parameters:
  • latexmk – The path to the latexmk binary (will looked up on $PATH).
  • pdflatex – The path to the pdflatex binary (will looked up on $PATH).
class latex.build.PdfLatexBuilder(pdflatex='pdflatex', max_runs=15)

A simple pdflatex based buidler for LaTeX files.

Builds LaTeX files by copying them to a temporary directly and running pdflatex until the associated .aux file stops changing.

Note

This may miss changes if biblatex or other additional tools are used. Usually, the LatexMkBuilder will give more reliable results.

Parameters:
  • pdflatex – The path to the pdflatex binary (will looked up on $PATH).
  • max_runs – An integer providing an upper limit on the amount of times pdflatex can be rerun before an exception is thrown.
latex.build.build_pdf(source, texinputs=[])

Builds a LaTeX source to PDF.

Will automatically instantiate an available builder (or raise a exceptions.RuntimeError if none are available) and build the supplied source with it.

Parameters are passed on to the builder’s build_pdf() function.

latex.jinja2.make_env(*args, **kwargs)

Creates an Environment with different defaults.

Per default, autoescape will be disabled and trim_blocks enabled. All start/end/prefix strings will be changed for a more LaTeX-friendly version (see the docs for details).

Any arguments will be passed on to the Environment constructor and override new values.

Finally, the |e, |escape and |forceescape filters will be replaced with a call to latex.escape().

exception latex.exc.LatexBuildError(logfn=None)

LaTeX call exception.

get_errors(*args, **kwargs)

Parse the log for errors.

Any arguments are passed on to parse_log().

Returns:The return of parse_log(), applied to the log associated with this build error.
latex.errors.parse_log(log, context_size=3)

Parses latex log output and tries to extract error messages.

Requires -file-line-error to be active.

Parameters:
  • log – The contents of the logfile as a string.
  • context_size – Number of lines to keep as context, including the original error line.
Returns:

A dictionary containig line (line number, an int), error, (the error message), filename (name of the temporary file used for building) and context (list of lines, starting with with the error line).