├── docs ├── examples │ ├── ex3.sty │ ├── ex3.latex │ ├── ex1.latex │ ├── ex2.latex │ ├── ex4.txt │ ├── ex1.py │ ├── ex3.py │ ├── ex2.py │ └── ex4.py ├── index.rst ├── Makefile └── conf.py ├── sample.latex ├── tox.ini ├── sample_test.py ├── tests ├── test_example.py ├── test_escape.py ├── test_xelatex.py ├── test_pdfbuild.py └── test_errors.py ├── setup.py ├── latex ├── exc.py ├── errors.py ├── __init__.py ├── jinja2.py └── build.py ├── LICENSE └── README.rst /docs/examples/ex3.sty: -------------------------------------------------------------------------------- 1 | \newcommand{\important}[1]{{\textbf{\underline{#1}}}} 2 | -------------------------------------------------------------------------------- /sample.latex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \begin{document} 3 | Hello, world! 4 | \end{document} 5 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27,py33,py34 3 | 4 | [testenv] 5 | deps=pytest 6 | commands=py.test -rs 7 | -------------------------------------------------------------------------------- /sample_test.py: -------------------------------------------------------------------------------- 1 | from latex.build import build_pdf 2 | 3 | r = build_pdf(open('sample.latex')) 4 | r.save_to('sample.pdf') 5 | -------------------------------------------------------------------------------- /docs/examples/ex3.latex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{ex3} 3 | 4 | \begin{document} 5 | This is \important{very} important. 6 | \end{document} 7 | -------------------------------------------------------------------------------- /docs/examples/ex1.latex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \begin{document} 3 | 4 | \section{Lorem ipsum dolor} 5 | Vestibulum et rhoncus nisi. Sed a nunc ante. 6 | 7 | \end{document} 8 | -------------------------------------------------------------------------------- /docs/examples/ex2.latex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \begin{document} 3 | 4 | \section{Greetings, {\VAR{name}}!} 5 | It is great to see you. 6 | %- if name == "Alice" 7 | Especially you, Alice! 8 | %- endif 9 | 10 | \end{document} 11 | -------------------------------------------------------------------------------- /docs/examples/ex4.txt: -------------------------------------------------------------------------------- 1 | Error in /tmp/tmpm9bfc0/tmpr50TJG.latex, line 3: Undefined control sequence. 2 | l.3 \THISCONTROLSEQUENCEDOESNOTEXIT 3 | 4 | Error in /tmp/tmpm9bfc0/tmpr50TJG.latex, line 3: ==> Fatal error occurred, no output PDF file 5 | produced! 6 | 7 | -------------------------------------------------------------------------------- /docs/examples/ex1.py: -------------------------------------------------------------------------------- 1 | from latex import build_pdf 2 | 3 | # build_pdf's source parameter can be a file-like object or a string 4 | pdf = build_pdf(open('ex1.latex')) 5 | 6 | # pdf is an instance of a data object (see http://pythonhosted.org/data/) 7 | # most often, we will want to save it to a file, as with this example 8 | pdf.save_to('ex1.pdf') 9 | -------------------------------------------------------------------------------- /docs/examples/ex3.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from latex import build_pdf 4 | 5 | # we need to supply absolute paths 6 | current_dir = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | # we are adding an empty string to include the default locations (this is 9 | # described on the tex manpage) 10 | pdf = build_pdf(open('ex3.latex'), texinputs=[current_dir, '']) 11 | 12 | pdf.save_to('ex3.pdf') 13 | -------------------------------------------------------------------------------- /tests/test_example.py: -------------------------------------------------------------------------------- 1 | def test_run_example(): 2 | min_latex = (r"\documentclass{article}" 3 | r"\begin{document}" 4 | r"Hello, world!" 5 | r"\end{document}") 6 | 7 | from latex import build_pdf 8 | 9 | # this builds a pdf-file inside a temporary directory 10 | pdf = build_pdf(min_latex) 11 | 12 | # look at the first few bytes of the header 13 | print(bytes(pdf)[:10]) 14 | -------------------------------------------------------------------------------- /tests/test_escape.py: -------------------------------------------------------------------------------- 1 | from latex import escape 2 | 3 | 4 | def test_escape(): 5 | inp = u'He%%llo~ World$!' 6 | out = u'He\\%\\%llo\\textasciitilde{} World\\$!' 7 | 8 | assert out == escape(inp) 9 | 10 | 11 | def test_newline_escape(): 12 | inp = 'Hello\n\n\nWorld' 13 | out = r'Hello\\World' 14 | 15 | assert out == escape(inp) 16 | 17 | 18 | def test_newline_escape_no_folding(): 19 | inp = 'Hello\n\n\nWorld' 20 | out = r'Hello\\[3\baselineskip]World' 21 | 22 | assert out == escape(inp, False) 23 | -------------------------------------------------------------------------------- /docs/examples/ex2.py: -------------------------------------------------------------------------------- 1 | from jinja2 import FileSystemLoader 2 | from latex.jinja2 import make_env 3 | from latex import build_pdf 4 | 5 | # create a jinja2 environment with latex-compatible markup and instantiate a 6 | # template 7 | env = make_env(loader=FileSystemLoader('.')) 8 | tpl = env.get_template('ex2.latex') 9 | 10 | # create a greeting for all of our friends 11 | for name in ['Alice', 'Bob', 'Carol']: 12 | filename = 'hello-{}.pdf'.format(name.lower()) 13 | 14 | pdf = build_pdf(tpl.render(name=name)) 15 | pdf.save_to(filename) 16 | -------------------------------------------------------------------------------- /docs/examples/ex4.py: -------------------------------------------------------------------------------- 1 | from latex import build_pdf, LatexBuildError 2 | 3 | 4 | # the following inline latex-document is not valid: 5 | src = r""" 6 | \documentclass{article}\begin{document} 7 | \THISCONTROLSEQUENCEDOESNOTEXIT 8 | \end{document} 9 | """ 10 | 11 | # when building, catch the exception and print a clean error message 12 | try: 13 | build_pdf(src) 14 | except LatexBuildError as e: 15 | for err in e.get_errors(): 16 | print u'Error in {0[filename]}, line {0[line]}: {0[error]}'.format(err) 17 | # also print one line of context 18 | print u' {}'.format(err['context'][1]) 19 | print 20 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from setuptools import setup, find_packages 7 | 8 | 9 | def read(fname): 10 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 11 | 12 | 13 | setup( 14 | name='latex', 15 | version='0.7.0.dev1', 16 | description='Wrappers for calling LaTeX/building LaTeX documents.', 17 | long_description=read('README.rst'), 18 | author='Marc Brinkmann', 19 | author_email='git@marcbrinkmann.de', 20 | url='http://github.com/mbr/latex', 21 | license='MIT', 22 | packages=find_packages(exclude=['tests']), 23 | install_requires=['tempdir', 'data', 'future', 'shutilwhich'], 24 | classifiers=[ 25 | 'Programming Language :: Python :: 2', 26 | 'Programming Language :: Python :: 3', 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /tests/test_xelatex.py: -------------------------------------------------------------------------------- 1 | from latex import build_pdf 2 | from latex.build import LatexMkBuilder 3 | 4 | # the example below should not compile on pdflatex, but on xelatex 5 | min_latex = r""" 6 | \documentclass[12pt]{article} 7 | \usepackage{fontspec} 8 | 9 | \setmainfont{Times New Roman} 10 | 11 | \title{Sample font document} 12 | \author{Hubert Farnsworth} 13 | \date{this month, 2014} 14 | 15 | \begin{document} 16 | 17 | \maketitle 18 | 19 | This an \textit{example} of document compiled 20 | with \textbf{xelatex} compiler. LuaLaTeX should 21 | work fine also. 22 | 23 | \end{document} 24 | """ 25 | 26 | def test_xelatex(): 27 | builder = LatexMkBuilder(variant='xelatex') 28 | pdf = builder.build_pdf(min_latex) 29 | 30 | assert pdf 31 | 32 | 33 | def test_xelatexmk(): 34 | pdf = build_pdf(min_latex, builder='xelatexmk') 35 | 36 | assert pdf 37 | -------------------------------------------------------------------------------- /tests/test_pdfbuild.py: -------------------------------------------------------------------------------- 1 | from latex import build_pdf, LatexBuildError 2 | from latex.errors import parse_log 3 | 4 | import pytest 5 | 6 | 7 | def test_generates_something(): 8 | min_latex = r""" 9 | \documentclass{article} 10 | \begin{document} 11 | Hello, world! 12 | \end{document} 13 | """ 14 | 15 | pdf = build_pdf(min_latex) 16 | 17 | assert pdf 18 | 19 | 20 | def test_raises_correct_exception_on_fail(): 21 | broken_latex = r"""foo""" 22 | 23 | with pytest.raises(LatexBuildError): 24 | build_pdf(broken_latex) 25 | 26 | 27 | def test_finds_errors_correctly(): 28 | broken_latex = r""" 29 | \documentclass{article} 30 | \begin{document} 31 | All good 32 | \undefinedcontrolsequencehere 33 | \end{document} 34 | """ 35 | 36 | try: 37 | build_pdf(broken_latex) 38 | except LatexBuildError as e: 39 | assert parse_log(e.log) == e.get_errors() 40 | else: 41 | assert False, 'no exception raised' 42 | -------------------------------------------------------------------------------- /latex/exc.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from .errors import parse_log 4 | 5 | 6 | class LatexError(Exception): 7 | pass 8 | 9 | 10 | class LatexBuildError(LatexError): 11 | """LaTeX call exception.""" 12 | 13 | # the binary log is probably latin1 or utf8? 14 | # utf8 throws errors occasionally, so we try with latin1 15 | # and ignore invalid chars 16 | LATEX_MESSAGE_ENCODING = 'latin1' 17 | 18 | def __init__(self, logfn=None): 19 | if os.path.exists(logfn): 20 | binlog = open(logfn, 'rb').read() 21 | self.log = binlog.decode(self.LATEX_MESSAGE_ENCODING, 'ignore') 22 | else: 23 | self.log = None 24 | 25 | def __str__(self): 26 | return str(self.log) 27 | 28 | def get_errors(self, *args, **kwargs): 29 | """Parse the log for errors. 30 | 31 | Any arguments are passed on to :func:`.parse_log`. 32 | 33 | :return: The return of :func:`.parse_log`, applied to the log 34 | associated with this build error. 35 | """ 36 | return parse_log(self.log) 37 | -------------------------------------------------------------------------------- /latex/errors.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | LATEX_ERR_RE = re.compile(r'(?P([a-zA-Z]:)?[^:]+):(?P[0-9]+):' 4 | r'\s*(?P.*)') 5 | 6 | 7 | def parse_log(log, context_size=3): 8 | """Parses latex log output and tries to extract error messages. 9 | 10 | Requires ``-file-line-error`` to be active. 11 | 12 | :param log: The contents of the logfile as a string. 13 | :param context_size: Number of lines to keep as context, including the 14 | original error line. 15 | :return: A dictionary containig ``line`` (line number, an int), ``error``, 16 | (the error message), ``filename`` (name of the temporary file 17 | used for building) and ``context`` (list of lines, starting with 18 | with the error line). 19 | """ 20 | lines = log.splitlines() 21 | errors = [] 22 | 23 | for n, line in enumerate(lines): 24 | m = LATEX_ERR_RE.match(line) 25 | if m: 26 | err = m.groupdict().copy() 27 | err['context'] = lines[n:n + context_size] 28 | try: 29 | err['line'] = int(err['line']) 30 | except TypeError: 31 | pass # ignore invalid int conversion 32 | errors.append(err) 33 | 34 | return errors 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Marc Brinkmann 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of latex nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | 4 | More examples 5 | ------------- 6 | 7 | Reading ``latex``-source from a file: 8 | 9 | .. literalinclude:: examples/ex1.latex 10 | :caption: ex1.latex 11 | :language: tex 12 | 13 | .. literalinclude:: examples/ex1.py 14 | :caption: ex1.py 15 | 16 | 17 | Using the `Jinja2 `_-template support: 18 | 19 | 20 | .. literalinclude:: examples/ex2.latex 21 | :caption: ex2.latex 22 | :language: tex 23 | 24 | .. literalinclude:: examples/ex2.py 25 | :caption: ex2.py 26 | 27 | 28 | Since the LaTeX source file is copied to a temporary directory, no additional 29 | files of the same folder are found by TeX by default. This is alleviated by 30 | using the ``TEXINPUTS`` [1]_ environment variable: 31 | 32 | .. literalinclude:: examples/ex3.latex 33 | :caption: ex3.latex 34 | :language: tex 35 | 36 | .. literalinclude:: examples/ex3.sty 37 | :caption: ex3.sty 38 | :language: tex 39 | 40 | .. literalinclude:: examples/ex3.py 41 | :caption: ex3.py 42 | 43 | .. [1] See ``man 1 tex``, the ``TEXINPUTS`` section. 44 | 45 | 46 | Error formatting 47 | ---------------- 48 | 49 | LaTeX errors can be quite cryptic and hard to find in a sea of log messages, to 50 | alleviate this, ``latex`` offers some basic log parsing functions: 51 | 52 | .. literalinclude:: examples/ex4.py 53 | :caption: ex4.py 54 | 55 | The resulting output: 56 | 57 | .. literalinclude:: examples/ex4.txt 58 | 59 | 60 | API 61 | === 62 | 63 | .. autofunction:: latex.escape 64 | 65 | .. automodule:: latex.build 66 | :members: 67 | 68 | .. autofunction:: latex.jinja2.make_env 69 | 70 | .. automodule:: latex.exc 71 | :members: 72 | 73 | .. automodule:: latex.errors 74 | :members: 75 | -------------------------------------------------------------------------------- /latex/__init__.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from .exc import LatexBuildError 4 | from .build import build_pdf 5 | 6 | CHAR_ESCAPE = { 7 | u'&': u'\\&', 8 | u'%': u'\\%', 9 | u'$': u'\\$', 10 | u'#': u'\\#', 11 | u'_': u'\\_', 12 | u'{': u'\\{', 13 | u'}': u'\\}', 14 | u'~': u'\\textasciitilde{}', 15 | u'^': u'\\textasciicircum{}', 16 | u'\\': u'\\textbackslash{}', 17 | 18 | # these may be optional: 19 | u'<': u'\\textless{}', 20 | u'>': u'\\textgreater{}', 21 | u'|': u'\\textbar{}', 22 | u'"': u'\\textquotedbl{}', 23 | 24 | # to prevent issues with '\\' linebreaks 25 | u'[': u'{[}', 26 | u']': u'{]}', 27 | } 28 | 29 | 30 | def _sub_tbl(tbl): 31 | return r'|'.join(re.escape(k) for k in sorted(tbl.keys())) 32 | 33 | 34 | ESCAPE_RE = re.compile(r'\n+|' + _sub_tbl(CHAR_ESCAPE)) 35 | 36 | 37 | def escape(s, fold_newlines=True): 38 | """Escapes a string to make it usable in LaTeX text mode. Will replace 39 | special characters as well as newlines. 40 | 41 | Some problematic characters like ``[`` and ``]`` are escaped into groups 42 | (e.g. ``{[}``), because they tend to cause problems when mixed with ``\\`` 43 | newlines otherwise. 44 | 45 | :param s: The string to escape. 46 | :param fold_newlines: If true, multiple newlines will be reduced to just a 47 | single ``\\``. Otherwise, whitespace is kept intact 48 | by adding multiple ``[n\baselineskip]``. 49 | """ 50 | 51 | def sub(m): 52 | c = m.group() 53 | if c in CHAR_ESCAPE: 54 | return CHAR_ESCAPE[c] 55 | 56 | if c.isspace(): 57 | if fold_newlines: 58 | return r'\\' 59 | return r'\\[{}\baselineskip]'.format(len(c)) 60 | 61 | return ESCAPE_RE.sub(sub, s) 62 | -------------------------------------------------------------------------------- /latex/jinja2.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from markupsafe import Markup 4 | from jinja2 import Environment 5 | 6 | from . import escape 7 | 8 | 9 | class LatexMarkup(Markup): 10 | def unescape(self): 11 | raise NotImplementedError 12 | 13 | def stripstags(self): 14 | raise NotImplementedError 15 | 16 | @classmethod 17 | def escape(cls, s): 18 | if hasattr(s, '__html__'): 19 | return s.__html__() 20 | 21 | rv = escape(s) 22 | if rv.__class__ is not cls: 23 | return cls(rv) 24 | return rv 25 | 26 | 27 | ENV_ARGS = { 28 | 'block_start_string': '\BLOCK{', 29 | 'block_end_string': '}', 30 | 'variable_start_string': '\VAR{', 31 | 'variable_end_string': '}', 32 | 'comment_start_string': '\#{', 33 | 'comment_end_string': '}', 34 | 'line_statement_prefix': '%-', 35 | 'line_comment_prefix': '%#', 36 | 'trim_blocks': True, 37 | 'autoescape': False, 38 | } 39 | 40 | 41 | def make_env(*args, **kwargs): 42 | """Creates an :py:class:`~jinja2.Environment` with different defaults. 43 | 44 | Per default, ``autoescape`` will be disabled and ``trim_blocks`` enabled. 45 | All start/end/prefix strings will be changed for a more LaTeX-friendly 46 | version (see the docs for details). 47 | 48 | Any arguments will be passed on to the :py:class:`~jinja2.Environment` 49 | constructor and override new values. 50 | 51 | Finally, the ``|e``, ``|escape`` and ``|forceescape`` filters will be 52 | replaced with a call to :func:`latex.escape`.""" 53 | ka = ENV_ARGS.copy() 54 | ka.update(kwargs) 55 | 56 | env = Environment(*args, **ka) 57 | env.filters['e'] = LatexMarkup.escape 58 | env.filters['escape'] = LatexMarkup.escape 59 | env.filters['forceescape'] = LatexMarkup.escape # FIXME: this is a bug 60 | return env 61 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | latex 2 | ===== 3 | 4 | Documentation can be found at https://pythonhosted.org/latex . 5 | 6 | Allows calling LaTeX from Python without leaving a mess. Similar to the 7 | (officially obsolete) `tex `_ package, whose 8 | `successor `_ is not PyPi-installable: 9 | 10 | .. code-block:: python 11 | 12 | min_latex = (r"\documentclass{article}" 13 | r"\begin{document}" 14 | r"Hello, world!" 15 | r"\end{document}") 16 | 17 | from latex import build_pdf 18 | 19 | # this builds a pdf-file inside a temporary directory 20 | pdf = build_pdf(min_latex) 21 | 22 | # look at the first few bytes of the header 23 | print bytes(pdf)[:10] 24 | 25 | Also comes with support for using `Jinja2 `_ templates 26 | to generate LaTeX files. 27 | 28 | ``make_env`` can be used to create an ``Environment`` that plays well with 29 | LaTex:: 30 | 31 | Variables can be used in a LaTeX friendly way: Hello, \VAR{name|e}. 32 | 33 | Note that autoescaping is off. Blocks are creating using the block macro: 34 | 35 | \BLOCK{if weather is 'good'} 36 | Hooray. 37 | \BLOCK{endif} 38 | 39 | \#{comments are supported as well} 40 | %# and so are line comments 41 | 42 | To keep things short, line statements can be used: 43 | 44 | %- if weather is good 45 | Yay. 46 | %- endif 47 | 48 | 49 | Example use 50 | ----------- 51 | 52 | .. code-block:: python 53 | 54 | from jinja2.loaders import FileSystemLoader 55 | from latex.jinja2 import make_env 56 | 57 | env = make_env(loader=FileSystemLoader('.')) 58 | tpl = env.get_template('doc.latex') 59 | 60 | print(tpl.render(name="Alice")) 61 | 62 | The ``base.latex`` demonstrates how ``\BLOCK{...}`` is substituted for 63 | ``{% ... %}``: 64 | 65 | .. code-block:: latex 66 | 67 | \documentclass{article} 68 | \begin{document} 69 | \BLOCK{block body}\BLOCK{endblock} 70 | \end{document} 71 | 72 | Finally, ``doc.latex`` shows why the ``%-`` syntax is usually preferable: 73 | 74 | .. code-block:: latex 75 | 76 | %- extends "base.latex" 77 | 78 | %- block body 79 | Hello, \VAR{name|e}. 80 | %- endblock 81 | 82 | 83 | Translations using Babel 84 | ------------------------ 85 | 86 | Strings from ``.latex``-templates can be extracted, provided your `babel.cfg` is setup correctly: 87 | 88 | .. code-block:: ini 89 | 90 | [jinja2: *.latex] 91 | block_start_string = \BLOCK{ 92 | block_end_string = } 93 | variable_start_string = \VAR{ 94 | variable_end_string = } 95 | comment_start_string = \#{ 96 | comment_end_string = } 97 | line_statement_prefix = %- 98 | line_comment_prefix = %# 99 | trim_blocks = True 100 | autoescape = False 101 | -------------------------------------------------------------------------------- /tests/test_errors.py: -------------------------------------------------------------------------------- 1 | from latex.errors import parse_log 2 | 3 | 4 | sample_error = r""" 5 | "This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2015/dev/Debian) (preloaded format=pdflatex 2015.7.13) 22 JUL 2015 13:01\nentering extended mode\n file:line:error style messages enabled.\n %&-line parsing enabled.\n**/tmp/tmpy8VAYd/tmpBfplPL.latex\n(/tmp/tmpy8VAYd/tmpBfplPL.latex\nLaTeX2e <2014/05/01>\nBabel <3.9l> and hyphenation patterns for 79 languages loaded.\n(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls\nDocument Class: article 2014/09/29 v1.4h Standard LaTeX document class\n(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo\nFile: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)\n)\n\\c@part=\\count79\n\\c@section=\\count80\n\\c@subsection=\\count81\n\\c@subsubsection=\\count82\n\\c@paragraph=\\count83\n\\c@subparagraph=\\count84\n\\c@figure=\\count85\n\\c@table=\\count86\n\\abovecaptionskip=\\skip41\n\\belowcaptionskip=\\skip42\n\\bibindent=\\dimen102\n) (./tmpBfplPL.aux)\n\\openout1 = `tmpBfplPL.aux'.\n\nLaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 3.\nLaTeX Font Info: ... okay on input line 3.\nLaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 3.\nLaTeX Font Info: ... okay on input line 3.\nLaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 3.\nLaTeX Font Info: ... okay on input line 3.\nLaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 3.\nLaTeX Font Info: ... okay on input line 3.\nLaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 3.\nLaTeX Font Info: ... okay on input line 3.\nLaTeX Font Info: Checking defaults for U/cmr/m/n on input line 3.\nLaTeX Font Info: ... okay on input line 3.\n/tmp/tmpy8VAYd/tmpBfplPL.latex:5: Undefined control sequence.\nl.5 \\undefinedcontrolsequencehere\n \nHere is how much of TeX's memory you used:\n 199 strings out of 493105\n 2182 string characters out of 6137072\n 52476 words of memory out of 5000000\n 3752 multiletter control sequences out of 15000+600000\n 3640 words of font info for 14 fonts, out of 8000000 for 9000\n 1141 hyphenation exceptions out of 8191\n 23i,0n,17p,150b,36s stack positions out of 5000i,500n,10000p,200000b,80000s\n\n/tmp/tmpy8VAYd/tmpBfplPL.latex:5: ==> Fatal error occurred, no output PDF file\n produced!\n" 6 | (Pdb) print e.log 7 | This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2015/dev/Debian) (preloaded format=pdflatex 2015.7.13) 22 JUL 2015 13:01 8 | entering extended mode 9 | file:line:error style messages enabled. 10 | %&-line parsing enabled. 11 | **/tmp/tmpy8VAYd/tmpBfplPL.latex 12 | (/tmp/tmpy8VAYd/tmpBfplPL.latex 13 | LaTeX2e <2014/05/01> 14 | Babel <3.9l> and hyphenation patterns for 79 languages loaded. 15 | (/usr/share/texlive/texmf-dist/tex/latex/base/article.cls 16 | Document Class: article 2014/09/29 v1.4h Standard LaTeX document class 17 | (/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo 18 | File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option) 19 | ) 20 | \c@part=\count79 21 | \c@section=\count80 22 | \c@subsection=\count81 23 | \c@subsubsection=\count82 24 | \c@paragraph=\count83 25 | \c@subparagraph=\count84 26 | \c@figure=\count85 27 | \c@table=\count86 28 | \abovecaptionskip=\skip41 29 | \belowcaptionskip=\skip42 30 | \bibindent=\dimen102 31 | ) (./tmpBfplPL.aux) 32 | \openout1 = `tmpBfplPL.aux'. 33 | 34 | LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 3. 35 | LaTeX Font Info: ... okay on input line 3. 36 | LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 3. 37 | LaTeX Font Info: ... okay on input line 3. 38 | LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 3. 39 | LaTeX Font Info: ... okay on input line 3. 40 | LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 3. 41 | LaTeX Font Info: ... okay on input line 3. 42 | LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 3. 43 | LaTeX Font Info: ... okay on input line 3. 44 | LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 3. 45 | LaTeX Font Info: ... okay on input line 3. 46 | /tmp/tmpy8VAYd/tmpBfplPL.latex:5: Undefined control sequence. 47 | l.5 \undefinedcontrolsequencehere 48 | 49 | Here is how much of TeX's memory you used: 50 | 199 strings out of 493105 51 | 2182 string characters out of 6137072 52 | 52476 words of memory out of 5000000 53 | 3752 multiletter control sequences out of 15000+600000 54 | 3640 words of font info for 14 fonts, out of 8000000 for 9000 55 | 1141 hyphenation exceptions out of 8191 56 | 23i,0n,17p,150b,36s stack positions out of 5000i,500n,10000p,200000b,80000s 57 | 58 | /tmp/tmpy8VAYd/tmpBfplPL.latex:5: ==> Fatal error occurred, no output PDF file 59 | produced! 60 | 61 | """ 62 | 63 | 64 | def test_sample_error(): 65 | errs = parse_log(sample_error) 66 | assert len(errs) == 2 67 | err = errs[0] 68 | 69 | assert err['error'] == 'Undefined control sequence.' 70 | assert err['line'] == 5 71 | assert err['filename'] == '/tmp/tmpy8VAYd/tmpBfplPL.latex' 72 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = -n 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/latex.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/latex.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/latex" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/latex" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /latex/build.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | from subprocess import CalledProcessError 4 | 5 | from future.utils import raise_from 6 | from data import Data as I 7 | from data.decorators import data 8 | from shutilwhich import which 9 | from six.moves import shlex_quote 10 | from tempdir import TempDir 11 | 12 | from .exc import LatexBuildError 13 | 14 | 15 | class LatexBuilder(object): 16 | """Base class for Latex builders.""" 17 | 18 | def build_pdf(self, source, texinputs=[]): 19 | """Generates a PDF from LaTeX a source. 20 | 21 | If there are errors generating a ``LatexError`` is raised. 22 | 23 | :param source: The LaTeX source. 24 | :param texinputs: Include paths for TeX. An empty string causes the 25 | default path to be added (see the tex manpage). 26 | :returns: A :class:`~data.Data` instance containing the generated PDF. 27 | """ 28 | raise NotImplementedError 29 | 30 | def is_available(self): 31 | """Checks if builder is available. 32 | 33 | Builders that depend on external programs like ``latexmk`` can check 34 | if these are found on the path or make sure other prerequisites are 35 | met. 36 | 37 | :return: A boolean indicating availability.""" 38 | raise NotImplementedError 39 | 40 | 41 | class LatexMkBuilder(LatexBuilder): 42 | """A latexmk based builder for LaTeX files. 43 | 44 | Uses the `latexmk 45 | `_ script to 46 | build latex files, which is part of some popular LaTeX distributions like 47 | `texlive `_. 48 | 49 | The build process consists of copying the source file to a temporary 50 | directory and running latexmk on it, which will take care of reruns. 51 | 52 | :param latexmk: The path to the ``latexmk`` binary (will be looked up on 53 | ``$PATH``). 54 | :param pdflatex: The path to the ``pdflatex`` binary (will be looked up on 55 | ``$PATH``). 56 | :param xelatex: The path to the ``xelatex`` binary (will be looked up on 57 | ``$PATH``). 58 | :param variant: The LaTeX variant to use. Valid choices are 59 | `pdflatex` and `xelatex`. Defaults to `pdflatex`. 60 | """ 61 | 62 | def __init__(self, latexmk='latexmk', pdflatex='pdflatex', 63 | xelatex='xelatex', variant='pdflatex'): 64 | self.latexmk = latexmk 65 | self.pdflatex = pdflatex 66 | self.xelatex = xelatex 67 | self.variant = variant 68 | 69 | @data('source') 70 | def build_pdf(self, source, texinputs=[]): 71 | with TempDir() as tmpdir,\ 72 | source.temp_saved(suffix='.latex', dir=tmpdir) as tmp: 73 | 74 | # close temp file, so other processes can access it also on Windows 75 | tmp.close() 76 | 77 | base_fn = os.path.splitext(tmp.name)[0] 78 | output_fn = base_fn + '.pdf' 79 | 80 | latex_cmd = [shlex_quote(self.pdflatex), 81 | '-interaction=batchmode', 82 | '-halt-on-error', 83 | '-no-shell-escape', 84 | '-file-line-error', 85 | '%O', 86 | '%S', ] 87 | 88 | if self.variant == 'pdflatex': 89 | args = [self.latexmk, 90 | '-pdf', 91 | '-pdflatex={}'.format(' '.join(latex_cmd)), 92 | tmp.name, ] 93 | elif self.variant == 'xelatex': 94 | args = [self.latexmk, 95 | '-xelatex', 96 | tmp.name, ] 97 | else: 98 | raise ValueError('Invalid LaTeX variant: {}'.format( 99 | self.variant)) 100 | 101 | # create environment 102 | newenv = os.environ.copy() 103 | newenv['TEXINPUTS'] = os.pathsep.join(texinputs) + os.pathsep 104 | 105 | try: 106 | subprocess.check_call(args, 107 | cwd=tmpdir, 108 | env=newenv, 109 | stdin=open(os.devnull, 'r'), 110 | stdout=open(os.devnull, 'w'), 111 | stderr=open(os.devnull, 'w'), ) 112 | except CalledProcessError as e: 113 | raise_from(LatexBuildError(base_fn + '.log'), e) 114 | 115 | return I(open(output_fn, 'rb').read(), encoding=None) 116 | 117 | def is_available(self): 118 | if not which(self.latexmk): 119 | return False 120 | 121 | if self.variant == 'pdflatex': 122 | return bool(which(self.pdflatex)) 123 | if self.variant == 'xelatex': 124 | return bool(which(self.xelatex)) 125 | 126 | 127 | class PdfLatexBuilder(LatexBuilder): 128 | """A simple pdflatex based buidler for LaTeX files. 129 | 130 | Builds LaTeX files by copying them to a temporary directly and running 131 | ``pdflatex`` until the associated ``.aux`` file stops changing. 132 | 133 | .. note:: This may miss changes if ``biblatex`` or other additional tools 134 | are used. Usually, the :class:`~latex.build.LatexMkBuilder` will 135 | give more reliable results. 136 | 137 | :param pdflatex: The path to the ``pdflatex`` binary (will looked up on 138 | ``$PATH``). 139 | :param max_runs: An integer providing an upper limit on the amount of times 140 | ``pdflatex`` can be rerun before an exception is thrown. 141 | """ 142 | 143 | def __init__(self, pdflatex='pdflatex', max_runs=15): 144 | self.pdflatex = pdflatex 145 | self.max_runs = 15 146 | 147 | @data('source') 148 | def build_pdf(self, source, texinputs=[]): 149 | with TempDir() as tmpdir,\ 150 | source.temp_saved(suffix='.latex', dir=tmpdir) as tmp: 151 | 152 | # close temp file, so other processes can access it also on Windows 153 | tmp.close() 154 | 155 | # calculate output filename 156 | base_fn = os.path.splitext(tmp.name)[0] 157 | output_fn = base_fn + '.pdf' 158 | aux_fn = base_fn + '.aux' 159 | args = [self.pdflatex, '-interaction=batchmode', '-halt-on-error', 160 | '-no-shell-escape', '-file-line-error', tmp.name] 161 | 162 | # create environment 163 | newenv = os.environ.copy() 164 | newenv['TEXINPUTS'] = os.pathsep.join(texinputs) + os.pathsep 165 | 166 | # run until aux file settles 167 | prev_aux = None 168 | runs_left = self.max_runs 169 | while runs_left: 170 | try: 171 | subprocess.check_call(args, 172 | cwd=tmpdir, 173 | env=newenv, 174 | stdin=open(os.devnull, 'r'), 175 | stdout=open(os.devnull, 'w'), ) 176 | except CalledProcessError as e: 177 | raise_from(LatexBuildError(base_fn + '.log'), e) 178 | 179 | # check aux-file 180 | aux = open(aux_fn, 'rb').read() 181 | 182 | if aux == prev_aux: 183 | break 184 | 185 | prev_aux = aux 186 | runs_left -= 1 187 | else: 188 | raise RuntimeError( 189 | 'Maximum number of runs ({}) without a stable .aux file ' 190 | 'reached.'.format(self.max_runs)) 191 | 192 | return I(open(output_fn, 'rb').read(), encoding=None) 193 | 194 | def is_available(self): 195 | return bool(which(self.pdflatex)) 196 | 197 | 198 | BUILDERS = { 199 | 'latexmk': LatexMkBuilder, 200 | 'pdflatex': PdfLatexBuilder, 201 | 'xelatexmk': lambda: LatexMkBuilder(variant='xelatex'), 202 | } 203 | 204 | PREFERRED_BUILDERS = ('latexmk', 'pdflatex', 'xelatexmk') 205 | 206 | 207 | def build_pdf(source, texinputs=[], builder=None): 208 | """Builds a LaTeX source to PDF. 209 | 210 | Will automatically instantiate an available builder (or raise a 211 | :class:`exceptions.RuntimeError` if none are available) and build the 212 | supplied source with it. 213 | 214 | Parameters are passed on to the builder's 215 | :meth:`~latex.build.LatexBuilder.build_pdf` function. 216 | 217 | :param builder: Specify which builder should be used - ``latexmk``, 218 | ``pdflatex`` or ``xelatexmk``. 219 | """ 220 | if builder is None: 221 | builders = PREFERRED_BUILDERS 222 | elif builder not in BUILDERS: 223 | raise RuntimeError('Invalid Builder specified') 224 | else: 225 | builders = (builder, ) 226 | 227 | for bld in builders: 228 | bld_cls = BUILDERS[bld] 229 | builder = bld_cls() 230 | if not builder.is_available(): 231 | continue 232 | return builder.build_pdf(source, texinputs) 233 | else: 234 | raise RuntimeError('No available builder could be instantiated. ' 235 | 'Please make sure LaTeX is installed.') 236 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # latex documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Mar 26 13:15:19 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | from collections import OrderedDict 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | #sys.path.insert(0, os.path.abspath('.')) 21 | 22 | # -- General configuration ----------------------------------------------------- 23 | 24 | # If your documentation needs a minimal Sphinx version, state it here. 25 | #needs_sphinx = '1.0' 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be extensions 28 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 29 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] 30 | 31 | # Add any paths that contain templates here, relative to this directory. 32 | templates_path = ['_templates'] 33 | 34 | # The suffix of source filenames. 35 | source_suffix = '.rst' 36 | 37 | # The encoding of source files. 38 | #source_encoding = 'utf-8-sig' 39 | 40 | # The master toctree document. 41 | master_doc = 'index' 42 | 43 | # General information about the project. 44 | project = u'latex' 45 | copyright = u'2015, Marc Brinkmann' 46 | 47 | # The version info for the project you're documenting, acts as replacement for 48 | # |version| and |release|, also used in various other places throughout the 49 | # built documents. 50 | # 51 | # The short X.Y version. 52 | version = '0.6.5' 53 | # The full version, including alpha/beta/rc tags. 54 | release = '0.6.5.dev1' 55 | 56 | # The language for content autogenerated by Sphinx. Refer to documentation 57 | # for a list of supported languages. 58 | #language = None 59 | 60 | # There are two options for replacing |today|: either, you set today to some 61 | # non-false value, then it is used: 62 | #today = '' 63 | # Else, today_fmt is used as the format for a strftime call. 64 | #today_fmt = '%B %d, %Y' 65 | 66 | # List of patterns, relative to source directory, that match files and 67 | # directories to ignore when looking for source files. 68 | exclude_patterns = ['_build'] 69 | 70 | # The reST default role (used for this markup: `text`) to use for all documents. 71 | #default_role = None 72 | 73 | # If true, '()' will be appended to :func: etc. cross-reference text. 74 | #add_function_parentheses = True 75 | 76 | # If true, the current module name will be prepended to all description 77 | # unit titles (such as .. function::). 78 | #add_module_names = True 79 | 80 | # If true, sectionauthor and moduleauthor directives will be shown in the 81 | # output. They are ignored by default. 82 | #show_authors = False 83 | 84 | # The name of the Pygments (syntax highlighting) style to use. 85 | pygments_style = 'sphinx' 86 | 87 | # A list of ignored prefixes for module index sorting. 88 | #modindex_common_prefix = [] 89 | 90 | 91 | # -- Options for HTML output --------------------------------------------------- 92 | 93 | # The theme to use for HTML and HTML Help pages. See the documentation for 94 | # a list of builtin themes. 95 | html_theme = 'alabaster' 96 | 97 | # Theme options are theme-specific and customize the look and feel of a theme 98 | # further. For a list of options available for each theme, see the 99 | # documentation. 100 | html_theme_options = { 101 | 'github_user': 'mbr', 102 | 'github_repo': 'latex', 103 | 'github_button': 'false', 104 | 'extra_nav_links': OrderedDict([ 105 | ('latex @ PyPI', 'https://pypi.python.org/pypi/latex'), 106 | ('latex @ github', 'https://github.com/mbr/latex'), 107 | ('Issue Tracker', 'https://github.com/mbr/latex/issues'), 108 | ]) 109 | } 110 | 111 | # Add any paths that contain custom themes here, relative to this directory. 112 | 113 | # The name for this set of Sphinx documents. If None, it defaults to 114 | # " v documentation". 115 | #html_title = None 116 | 117 | # A shorter title for the navigation bar. Default is the same as html_title. 118 | #html_short_title = None 119 | 120 | # The name of an image file (relative to this directory) to place at the top 121 | # of the sidebar. 122 | #html_logo = None 123 | 124 | # The name of an image file (within the static path) to use as favicon of the 125 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 126 | # pixels large. 127 | #html_favicon = None 128 | 129 | # Add any paths that contain custom static files (such as style sheets) here, 130 | # relative to this directory. They are copied after the builtin static files, 131 | # so a file named "default.css" will overwrite the builtin "default.css". 132 | # html_static_path = ['_static'] 133 | 134 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 135 | # using the given strftime format. 136 | #html_last_updated_fmt = '%b %d, %Y' 137 | 138 | # If true, SmartyPants will be used to convert quotes and dashes to 139 | # typographically correct entities. 140 | #html_use_smartypants = True 141 | 142 | # Custom sidebar templates, maps document names to template names. 143 | html_sidebars = { 144 | '**': [ 145 | 'about.html', 146 | 'navigation.html', 147 | # 'relations.html', 148 | # 'searchbox.html', 149 | 'donate.html', 150 | ] 151 | } 152 | 153 | # Additional templates that should be rendered to pages, maps page names to 154 | # template names. 155 | #html_additional_pages = {} 156 | 157 | # If false, no module index is generated. 158 | #html_domain_indices = True 159 | 160 | # If false, no index is generated. 161 | #html_use_index = True 162 | 163 | # If true, the index is split into individual pages for each letter. 164 | #html_split_index = False 165 | 166 | # If true, links to the reST sources are added to the pages. 167 | #html_show_sourcelink = True 168 | 169 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 170 | #html_show_sphinx = True 171 | 172 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 173 | #html_show_copyright = True 174 | 175 | # If true, an OpenSearch description file will be output, and all pages will 176 | # contain a tag referring to it. The value of this option must be the 177 | # base URL from which the finished HTML is served. 178 | #html_use_opensearch = '' 179 | 180 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 181 | #html_file_suffix = None 182 | 183 | # Output file base name for HTML help builder. 184 | htmlhelp_basename = 'latexdoc' 185 | 186 | 187 | # -- Options for LaTeX output -------------------------------------------------- 188 | 189 | latex_elements = { 190 | # The paper size ('letterpaper' or 'a4paper'). 191 | #'papersize': 'letterpaper', 192 | 193 | # The font size ('10pt', '11pt' or '12pt'). 194 | #'pointsize': '10pt', 195 | 196 | # Additional stuff for the LaTeX preamble. 197 | #'preamble': '', 198 | } 199 | 200 | # Grouping the document tree into LaTeX files. List of tuples 201 | # (source start file, target name, title, author, documentclass [howto/manual]). 202 | latex_documents = [ 203 | ('index', 'latex.tex', u'latex Documentation', 204 | u'Marc Brinkmann', 'manual'), 205 | ] 206 | 207 | # The name of an image file (relative to this directory) to place at the top of 208 | # the title page. 209 | #latex_logo = None 210 | 211 | # For "manual" documents, if this is true, then toplevel headings are parts, 212 | # not chapters. 213 | #latex_use_parts = False 214 | 215 | # If true, show page references after internal links. 216 | #latex_show_pagerefs = False 217 | 218 | # If true, show URL addresses after external links. 219 | #latex_show_urls = False 220 | 221 | # Documents to append as an appendix to all manuals. 222 | #latex_appendices = [] 223 | 224 | # If false, no module index is generated. 225 | #latex_domain_indices = True 226 | 227 | 228 | # -- Options for manual page output -------------------------------------------- 229 | 230 | # One entry per manual page. List of tuples 231 | # (source start file, name, description, authors, manual section). 232 | man_pages = [ 233 | ('index', 'latex', u'latex Documentation', 234 | [u'Marc Brinkmann'], 1) 235 | ] 236 | 237 | # If true, show URL addresses after external links. 238 | #man_show_urls = False 239 | 240 | 241 | # -- Options for Texinfo output ------------------------------------------------ 242 | 243 | # Grouping the document tree into Texinfo files. List of tuples 244 | # (source start file, target name, title, author, 245 | # dir menu entry, description, category) 246 | texinfo_documents = [ 247 | ('index', 'latex', u'latex Documentation', 248 | u'Marc Brinkmann', 'latex', 'One line description of project.', 249 | 'Miscellaneous'), 250 | ] 251 | 252 | # Documents to append as an appendix to all manuals. 253 | #texinfo_appendices = [] 254 | 255 | # If false, no module index is generated. 256 | #texinfo_domain_indices = True 257 | 258 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 259 | #texinfo_show_urls = 'footnote' 260 | 261 | 262 | # Example configuration for intersphinx: refer to the Python standard library. 263 | intersphinx_mapping = {'http://docs.python.org/': None, 264 | 'http://jinja.pocoo.org/docs/': None, 265 | 'http://pythonhosted.org/data': None} 266 | --------------------------------------------------------------------------------