Skip to content

2022

Jinja in LaTeX

When updating your CV, you usually want to get your information straight across several systems. For example, I want to convey the same information on

  • my webpage
  • my LinkedIn/Xing profile
  • my CV as a PDF

However, when updating this info in a single one of these systems, I also need to update all the other systems manually. But I am not a computer guy because I want to do things manually. I have a LaTeX CV (as should everyone) and I know a bit about Python. So one obvious option for me was to implement the macro bits in LaTeX and then fill them out using Python. The necessary information that I need can then be gathered from any kind of data source that Python has access to (read: database, API, text files, you name it).

So, let's start with some juicy bits.

I recently wrote my own CV document class so that my main document basically looks like this (Note to myself: I should publish that somewhere):

\documentclass[a4paper,10pt]{cv-superior}
\usepackage[utf8]{inputenc}

\begin{document}
\defcustomlength{\headerheight}{3.6cm}
\defcustomlength{\contentheight}{\dimexpr\paperheight - \headerheight\relax}
\defcustomlength{\leftblockwidth}{.3\paperwidth}
\defcustomlength{\rightblockwidth}{\dimexpr\paperwidth - \leftblockwidth\relax}
\defcustomlength{\entrysep}{.5cm}

\begin{tikzpicture}[remember picture,overlay]

\header{THOMAS}{NIEBLER}{Software Architect}
\section{PROFILE}
\begin{entrylist}
    \plaintextentry{...}
\end{entrylist}

\section{EXPERIENCE}
\begin{entrylist}
    \listentryemployer{Bosch Rexroth AG}{Apr' 19 -- now}

    \listentry{Software Architect}
    {Bosch Rexroth AG}
    {Lohr am Main, Germany}
    {Feb '21 -- now}
    {
        \begin{itemize}
            \item ...
        \end{itemize}
    }

    % some more list entries, eventually with different employers
\end{entrylist}

\section{COMPETENCIES}
\begin{entrylist}
    \simplelistentry{Technical}{
        \begin{itemize}
            \item
        \end{itemize}
    }

    % some more entries like this
\end{entrylist}

% Everything that is a smallsection needs a smallentrylist and appears on the left hand side.
\smallsection{EDUCATION}
\begin{smallentrylist}
    \smalllistentry{PhD, Computer Science}
    {University of Würzburg}
    {Mar '19}

    % ...
\end{smallentrylist}

\smallsection{TECHNOLOGIES}
\begin{smallentrylist}
    \skills{
    LaTeX tinkering/over 9000,
    other stuff/5
    }
\end{smallentrylist}
\end{tikzpicture}
\end{document}

This is for now pure LaTeX. However, with those macros, the whole document generation can easily be done through Jinja templating.

First off, what is Jinja templating?

Using Jinja templating, we can insert some kind of placeholders ("templates") into a document. This is e.g. done in web documents (Jinja is for example used within the Flask framework), but according to the Jinja webpage, it can be used with any kind of text file (yes, it also says LaTeX).

Rendering Jinja templates is a breeze using the Jinja API when using simple HTML pages (example shamelessly copied from the API page):

from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
    loader=PackageLoader("yourapp")
)
my_variable_dict = {
    "my": "variables",
    "are": "defined",
    "right": "here",
    "this_should": "be filled",
    "with some": "python magic"
}

template = env.get_template("mytemplate.html")

output = template.render(**my_variable_dict)

An exemplary yourapp/templates/mytemplate.html could look like this:

<html>
<body>
My {{my}} are {{are}} {% if right is "here" %}
right here
{% else %}
somewhere else
{% endif %} ...
</body>
</html>

And the final result residing in output would look like this:

<html>
<body>
My variables are defined right here ...
</body>
</html>

Now, rendering a Jinja template in LaTeX is a little bit more tricky, as we cannot easily use curled braces and percentage signs for our template indicators, as those signs are also part of LaTeX's syntax. Just imagine a block opening with a comment directly following it, e.g.:

\textbf{%
some bold text
}

This looks like a block opening to Jinja, causing quite some confusion (and obviously: no rendered documents).

Luckily, we just have to adjust the Environment instantiation a bit, for example:

env = Environment(
    loader=PackageLoader("yourapp"),
    block_start_string='<BLOCK>',
    block_end_string='</BLOCK>',
    variable_start_string='<VAR>',
    variable_end_string='</VAR>',
)


With this, we are now ready to render the following LaTeX template:

\documentclass{a4paper, 10pt}

\begin{document}

<BLOCK>for x in range(5)</BLOCK>
  \textbf{<VAR>x</VAR>}\\
<BLOCK>endfor</BLOCK>

\end{document}

resulting in the syntactically perfectly valid LaTeX document:

\documentclass{a4paper, 10pt}

\begin{document}
  \textbf{0}\\
  \textbf{1}\\
  \textbf{2}\\
  \textbf{3}\\
  \textbf{4}\\

\end{document}

The used example code can be found in this GitHub repository.

Going back to my CV, my final document would now look like this:

\documentclass[a4paper,10pt]{cv-superior}
\usepackage[utf8]{inputenc}

\begin{document}
\defcustomlength{\headerheight}{3.6cm}
\defcustomlength{\contentheight}{\dimexpr\paperheight - \headerheight\relax}
\defcustomlength{\leftblockwidth}{.3\paperwidth}
\defcustomlength{\rightblockwidth}{\dimexpr\paperwidth - \leftblockwidth\relax}
\defcustomlength{\entrysep}{.5cm}

\begin{tikzpicture}[remember picture,overlay]

\header{THOMAS}{NIEBLER}{Software Architect}
\section{PROFILE}
\begin{entrylist}
    \plaintextentry{<VAR>profiletext</VAR>}
\end{entrylist}

\section{EXPERIENCE}
\begin{entrylist}
<BLOCK>for entry in experience_list</BLOCK>
    <BLOCK>if entry.employer_with_several_roles_first_role</BLOCK>
    \listentryemployer{<VAR>entry.employer</VAR>}{<VAR>entry.employer_start</VAR> -- <VAR>entry.employer_end</VAR>}
    <BLOCK>endif</BLOCK>
    \listentry{<VAR>entry.role</VAR>}
    {<VAR>entry.employer</VAR>}
    {<VAR>entry.location</VAR>}
    {<VAR>entry.role_start</VAR> -- <VAR>entry.end</VAR>}
    {
        <VAR>entry.content</VAR>
    }
<BLOCK>endfor</BLOCK>
\end{entrylist}

% and so on...

\end{tikzpicture}
\end{document}

So I'd simply loop over all my entries that I had received from some kind of data origin and that's it. To be honest, the final solution is not as practical as I thought it to be as I had other problems afterwards, especially with compiling the code automatically. In the end, Overleaf was a way more convenient alternative.

Some lessons learned as a Software Architect

I started out in the role of a Software Architect roughly one year ago. Here I found that my previous image of architecture work does differ quite a bit from what was actually expected of me.

Correction #1: Shifting around blocks is a task that comes only very late

I originally thought that the task of an architect is to devise the architecture of a software system, i.e. shifting around different blocks of functionality. While this is not entirely wrong, it comprises only a small part of what should actually be done. The task of a software architect is to make sure that an intended software product does fulfill its task and can be developed.

Correction #2: Titles are (actually) meaningless

Yes, I hold a PhD. Does not matter a bit here. People love to assign themselves fancy titles. Do not pay attention to these self-assigned titles. However, pay close attention to what they say and do. If it overlaps, great. If there's an obvious discrepancy, try to stay away.

Correction #3: Talk non-nerdy to me

Software Architects must be great communicators, yes. Be aware who you talk to! While you were chosen (amongst the other great qualities you surely possess) because are technically very proficient, most times, you will communicate with people on the far end of the proficiency spectrum. Talk to them with very easy words and maybe slightly inaccurate descriptions, as long as it helps to make them understand. Technical details are for developers.

Correction #4: Software is only a large part of your architecture

As a software architect, you design the architecture of a piece of software. The decisions you take while designing are however heavily influenced by the ecosystem where the software will be used in. This ecosystem can be entirely non-soft, for example the hardware parts of a car's sensor and actor infrastructure, or even something entirely unpredictable, like the human that is attempting to drive the car.