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

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.


11.01.2022 08:03

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.


29.06.2020 14:58

How this Blog Works internally

Just a few notes how my blog works internally.

Flask Server

The blog backend is written in Flask, a rather minimalist web framework in Python. As there are no users here, I don't need any authorization. I do not have a database backend. Anything I need is available via Web APIs.

Markdown

I write my posts in Markdown. To parse them and display them as HTML, I use the markdown2 Python package, which supports a few extras compared to Vanilla markdown, but is also still rather basic. Still, the parser is very fast and reliable.

Some Custom Stuff

I have added a few functionalities, e.g.

GitLab CI

Publishing new posts works like a charm thanks to GitLab's awesome CI functionalities. Every time I push to my blog repository, it automatically deploys everything to my webspace and restarts the web service. This way, I do not need any edit functionalities in my blog, can quickly experiment with new features on my development machine (without breaking production) and always have a backup and history. If that isn't awesome, nothing is.


26.06.2020 21:18

Marrying BibSonomy and BibLaTeX

(This is a rewrite of an older blog post of mine that disappeared together with that awful WordPress page)

I manage my scientific references in BibSonomy. With a standard LaTeX+BibTeX setup, I would have to download my bibliography and save it into a file. When doing this again for every paper, I sooner or later end up with many versions of my BibTeX entries, since I introduce some abbreviations in order to squeeze the whole thing into some random page limit, or maybe I correct some things, etc. etc.

Managing my references in BibSonomy should however help me to centralize them and be consistent throughout all of my works. This is where BibLaTeX (and biber) comes into play. Using BibLaTeX, I am able to not only provide a file as input for BibTeX, but also a web URL. Luckily, BibSonomy allows us to export a reference list as bibtex using a simple webcall. For example, if I want to export the list of publications that I tagged with myown (which can be found at https://www.bibsonomy.org/user/thoni/myown) as a BibTeX file, I simply add a /bib directly after the base URL: https://www.bibsonomy.org/bib/user/thoni/myown.

Finally, I enter the following command into my LaTeX main file:

\addbibresource[location=remote]{https://www.bibsonomy.org/bib/user/thoni/myown}

and poof, I have access to all my standardized references that I worked so hard to assemble.

Have fun writing your paper, thesis, commentary... :)


26.06.2020 21:18

My notes

Here I add some notes about anything I like to.

My Coursera notes