<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:dc="http://purl.org/dc/elements/1.1/"
      xml:base="https://reinout.vanrees.org/" xml:lang="en">
  <link rel="self"
        href="https://reinout.vanrees.org/weblog/atom.xml" />
  <link href="https://reinout.vanrees.org/weblog/"
        rel="alternate" type="text/html" />

  <title type="html">Reinout van Rees' weblog</title>
  <subtitle>Python, grok, books, history, faith, etc.</subtitle>
  <updated>2026-05-08T14:37:00+01:00</updated>
  <id>urn:syndication:a55644db8591c020bd38852775819a9a</id>

  
    <entry>
      <title>PyGrunn: Python at Spotify: twenty years - Gijs Molenaar</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/05/08/7-python-at-spotify.html" />
      <id>http://reinout.vanrees.org/weblog/2026/05/08/7-python-at-spotify.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-05-08T00:00:00+01:00</published>
      <updated>2026-05-08T14:37:00+01:00</updated>

      
        <category term="python" />
      
        <category term="pygrunn" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2026/05/08/index.html">my summaries</a> of
the 2026 one-day <a class="reference external" href="https://pygrunn.org/">PyGrunn conference</a> in Groningen, NL).</p>
<p>His parents owned a record store in some Dutch town. First records, then CDs. A social
shop where you would gather to listen to CDs to determine whether to buy them. His
father's brother actually started the oldest record store in Amsterdam, Concerto. It
still exists.</p>
<p>Then the world changed. Napster, CD-burners. Illegal downloading. (He himself was one of
them). His parents stopped selling music in 2008. He himself got into engineering. He
ended up in South Africa, doing workflow orchesration for radio telescopes. There he
introduced Docker and containers. He gave a <a class="reference external" href="https://reinout.vanrees.org/weblog/2016/05/13/2_kliko.html">talk at Pygrunn about it in 2016</a>.</p>
<p>While he was in the South African desert, in Sweden someone started the <a class="reference external" href="https://open.spotify.com/">Spotify</a> company. He actually had used a library (&quot;luigi&quot;) made by
Spotify in his telescope work.</p>
<p>He tried to get a job at Spotify and succeeded. So the kid who grew up in a record store
now works at the company that reinvented how people listen to music.</p>
<p>It all started for Spotify with Java (jboss 5). They hated it. It was replaced with Python:
the reason was that nobody hated it. 80% of the code became python. A lot was async:
they used &quot;twisted&quot; in the beginning, later gevent and greenlets.</p>
<p>But the Python GIL (global interpreter lock) made multi-core impossible. So you needed
to use multiple processes, each with their own overhead. They also didn't like the lack
of type safety: they have 100+ services. Some of those problems are partially solved
now, but at the time the switched back to Java. Partially it was cultural: they could
hire quite some Oracle employees that knew Java.</p>
<p>Python was still used a lot, just not for the core services. Nowadays, Python is used a
lot for machine learning. They have 950 Python services, 470 libraries. 180000 Python
files in 7500 repositories. 322x FastApi, 272x Streamlit repositories. And still lots of
luigi. Luigi is the framework that inspired airflow: it has lots of starts on github,
the most of all their open source repositories.</p>
<p>They now also started <a class="reference external" href="https://spotify.github.io/pedalboard/">pedalboard</a>, a nice
Pythonic way of modifying audio (it is a wrapper around a c++ library). Also nice:
<a class="reference external" href="https://backstage.spotify.com/">https://backstage.spotify.com/</a> , a backend/portal for collecting all the
developer-related data. Workflow statuses and so. (The backend is open source, the
dashboard not).</p>
<p>At Spotify, the programmers are really encouraged to use <strong>agentic programming</strong>. He
hasn't touched his editor in the last six months! It really changed his life. Initially
he was a bit depressed: can someone who's less talented but with the same amount of
tokens really do the same as me? But it is really a next level and he gets amazing
productivity out of it. Having unlimited tokens helps.</p>
<p>It changes open source. Forking used to be a declaration of war. Nowadays it is a sign
of popularity. You can fork something and have AI keep it up to date with minimal
engineer effort. When the cost of maintaining your own fork approaches zero, what does
that do with the economics of open source? Is cooperation still a thing? What is the
goal/effect of open sourcing? Or is it only a way for AIs to find security bugs in your
software?</p>
<p>His parents ran a record store for 42 years. Then technology disrupted the music
industry. They had to reinvent themselves. It was scary and sad, but they adapted. Now
the same force is disrupting <strong>our</strong> industry. Where will it go?</p>
<img alt="https://reinout.vanrees.org/images/2026/lac-de-kruth7.jpg" src="https://reinout.vanrees.org/images/2026/lac-de-kruth7.jpg" />
<p><em>Unrelated photo: the &quot;lac de Kruth-Wildenstein&quot; reservoir during a family holiday in
France in 2006.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>PyGrunn: list-man, pragmatic system integration - Doeke Zanstra</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/05/08/6-list-man.html" />
      <id>http://reinout.vanrees.org/weblog/2026/05/08/6-list-man.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-05-08T00:00:00+01:00</published>
      <updated>2026-05-08T13:28:00+01:00</updated>

      
        <category term="python" />
      
        <category term="pygrunn" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2026/05/08/index.html">my summaries</a> of
the 2026 one-day <a class="reference external" href="https://pygrunn.org/">PyGrunn conference</a> in Groningen, NL).</p>
<p>When automating in a big company with many systems, you often end up with spaghetti:
many systems connecting to a lot of the others... A common solution is to have a &quot;bus
architecture&quot;. Generic existing &quot;<em>enterprise</em> service bus&quot; solutions were clearly
overkill, so he proposed an alternative solution.</p>
<p>He made a couple of assumptions/choices. All data is tabular data. He wanted to store a
copy of data in a database. SQL views to access the data. So: multiple sources that he
wanted to import in a central database (which would function as a sort of &quot;read-only
enterprise service bus&quot;). And a generic sql/view-based way of accessing the data.</p>
<p>He <strong>initially</strong> focused on read-only data. And he started real simple. Just a bash script
that ran regularly that scraped data from other systems and injected it in the database.</p>
<p>In the <strong>second version</strong> of the system, for every system he wrote a target/command in a
<tt class="docutils literal">Makefile</tt>. Every thing that needed to be scraped got its own table (called a &quot;list&quot;
in his system&quot;). Lists could be compared. The first killer app was a comparison between
a telephone list and the list of employees so that differences could be consolidated.</p>
<p>For the <strong>third version</strong>, he started using more and more python. CSV file imports.
Downloaders from REST APIs. All configurable so that he could use the same python script
for many different sources.</p>
<p>He now had a simple sytem for which he could write views and exports.</p>
<ul class="simple">
<li>Publishing data on the intranet via the &quot;jekyll&quot; static site generator. For instance
a &quot;mug book&quot; of all employees.</li>
<li>And regularly exporting a list of names+emailaddresses in a format suitable for the
multifunctional printer: to make it easy to select your email address when scanning on
the printer.</li>
<li>An export to a google spreadsheet that combined the holiday spreadsheet with the data
on part-time days.</li>
</ul>
<p>Security was handled with a role-based system.</p>
<img alt="https://reinout.vanrees.org/images/2026/lac-de-kruth6.jpg" src="https://reinout.vanrees.org/images/2026/lac-de-kruth6.jpg" />
<p><em>Unrelated photo: the &quot;lac de Kruth-Wildenstein&quot; reservoir during a family holiday in
France in 2006.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>PyGrunn: JSON freedom or chaos, how to trust your data - Bart Dorlandt</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/05/08/5-json-freedom.html" />
      <id>http://reinout.vanrees.org/weblog/2026/05/08/5-json-freedom.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-05-08T00:00:00+01:00</published>
      <updated>2026-05-08T12:44:00+01:00</updated>

      
        <category term="python" />
      
        <category term="pygrunn" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2026/05/08/index.html">my summaries</a> of
the 2026 one-day <a class="reference external" href="https://pygrunn.org/">PyGrunn conference</a> in Groningen, NL).</p>
<p>Subtitle: a real-world journey from chaos to confidence using <a class="reference external" href="https://github.com/pydantic/pydantic">Pydantic</a> and <a class="reference external" href="https://docs.pytest.org/">Pytest</a>.</p>
<p>Idealy, you'd have perfect json files with a fixed format and rigorous validation and
ideally generated. But in a customer project, the other programmers weren't too happy
about it. They had massive JSON files, partially manually crafted. Some where just one
single line and others were vertically aligned. And perhaps someone depended on the
specific format for some &quot;sed&quot; or &quot;awk&quot; hacking... So whatever happens: <em>it works,
don't touch it</em>.</p>
<p>The <strong>freedom trap</strong>. No schema means no contract. No contract means no trust. Fields
accumulate, nobody removes them: &quot;someone might be using it&quot;. Multi-team challenges: not
everyone has the same skillset.</p>
<p>He wanted a different future: a <em>trusted</em> future. Validated and tested and formatted.</p>
<p>Pydantic is a python library for data validation using Python type annotations. You can
define a data model with type hints. it will automatically validate and parse data
according to those models:</p>
<pre class="literal-block">
from ipaddress import IPv4Address
from pydantic import BaseModel

class Server(BaseModel):
    hostname: str
    ip: IPv4Address
    ...
</pre>
<p>Make sure to look at <tt class="docutils literal"><span class="pre">pydantic-extra-types</span></tt>, they have lots of handy types like
&quot;two-character country code&quot;.</p>
<p>There's <tt class="docutils literal">AfterValidator</tt>, you can use it to add a second validator to a field. So
first the <tt class="docutils literal">str</tt> type to validate it is a string, then afterwards some ip address
validator or so.</p>
<p><strong>Understanding the data</strong> is important. Split it up in smaller pieces and try to
understand/model/validate those. Especially in a corporate setting, splitting up the
problem is handy: you have some small success you can mention at the standup :-)</p>
<p>Do it iteratively. One piece at a time. If you find a problem, create a ticket for it.
It might not get fixed, but at least you end up with a list you can slowly tackle with
the rest of the organisation.</p>
<p>A good tip: if you discover an error in the data, provide a good, clear error message
that your colleague can understand.</p>
<p>When you export the data, use <tt class="docutils literal">model_dump(exclude_optional=True)</tt> to exclude all the
optional fields instead of having it as <tt class="docutils literal">my_field: None</tt>.</p>
<p><strong>Bonus</strong>: you can call <tt class="docutils literal">YourModel.model_json_schema()</tt> to generate a JSON schema for
the Pydantic model. You can then use the JSON schema in vscode when you manually edit
your JSON.</p>
<p>Pydantic is great at validating individual fields and structures. But not at validating
things that span the entire document, like making sure that all hostnames are unique. He
used Pytest for it: he wrote such <strong>validation checks as pytest functions</strong>!. You can
even use Pytest test parametrization to run the same test on multiple directories.</p>
<img alt="https://reinout.vanrees.org/images/2026/lac-de-kruth5.jpg" src="https://reinout.vanrees.org/images/2026/lac-de-kruth5.jpg" />
<p><em>Unrelated photo: the &quot;lac de Kruth-Wildenstein&quot; reservoir during a family holiday in
France in 2006.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>PyGrunn: introducing httpxyz: forking a top-100 Python package - Michiel Beijen</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/05/08/4-httpxyz.html" />
      <id>http://reinout.vanrees.org/weblog/2026/05/08/4-httpxyz.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-05-08T00:00:00+01:00</published>
      <updated>2026-05-08T12:04:00+01:00</updated>

      
        <category term="python" />
      
        <category term="django" />
      
        <category term="pygrunn" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2026/05/08/index.html">my summaries</a> of
the 2026 one-day <a class="reference external" href="https://pygrunn.org/">PyGrunn conference</a> in Groningen, NL).</p>
<p>Years ago he listened to the &quot;corecursive&quot; podcast (recommended by Michiel), <a class="reference external" href="https://corecursive.com/data-compression-yann-collet/">the one
where Yann Collet got interviewed</a>. He's the author of the LZ4
and zstandard (<tt class="docutils literal">zstd</tt>) compression algorithm. In 2016 zstandard was released. In 2017 it was used
in the linux kernel. Since 2020 it is one of the official formats in zipfiles. And in
2025 it got added to the Python standard library in version 3.14.</p>
<p><tt class="docutils literal">requests</tt> is one of the most popular Python libraries. <tt class="docutils literal">httpx</tt> has a similar API,
but it is better. A top 100 pypy packages. Main advantages: HTTP/2 support and async
support.</p>
<p>He liked httpx a lot. And zstandard, too. But zstandard wasn't supported by httpx. All
browsers support it, but not httpx. So he made a pull request in early 2024. It got
merged! But there was no new release yet. The maintainer asked if he wanted to create a
PR for the release. He did it and there was a new release. Hurray!</p>
<p>Months later, a bug surfaced. He created a bugfix, but that wasn't merged and wasn't
merged and wasn't merged. And there was no new release. And then the httpx maintainer
recently turned off all discussion on github. Earlier the maintainer had done the same
to django restframework. And to mkdocs. All heavily-used packages! And in the &quot;encode&quot;
github organisation/company that uses donations to fund open source development.
Weird...</p>
<p>There are also performance issues in httpx, which especially is a problem for several AI
libraries.</p>
<p>So... he started <a class="reference external" href="https://httpxyz.org/">httpxyz</a>, it bills itself as the maintained
fork of <a class="reference external" href="https://www.python-httpx.org/">httpx</a>. More info about the reasons for the
fork at <a class="reference external" href="https://tildeweb.nl/~michiel/httpxyz.html">https://tildeweb.nl/~michiel/httpxyz.html</a> .</p>
<p>It contains most of  the bugfixes that have been pending for a while. More maintainers.
Performance is much better (they needed to fork httpcore into httpcorexyz, it is 4x faster).
API compatible. You just have to change the import. They used a PIL/pillow trick to make
sure that if you import <tt class="docutils literal">httpxz</tt>, later <tt class="docutils literal">httpx</tt> imports use httpxyz instead.</p>
<p>There turned out to be quite a lot of small performance errors in the old code.</p>
<p><strong>An important performance tip</strong>: use client (or if you use <tt class="docutils literal">requests</tt>, use <tt class="docutils literal">request.Session()</tt>):</p>
<pre class="literal-block">
import httpxyz

c = httpxyz.Client()
c.get(...)
c.get(...)
</pre>
<p>instead of just:</p>
<pre class="literal-block">
import httpxyz

httpxyz.get(...)
httpxyz.get(...)
</pre>
<p>Using a client means httpxyz (or requests) can use http features to spead up your
requests a lot. Automatic connection keepilive. No more TCP handschake for every
individual request. And no TLS/https handshake. And if your server supports http/2, the
improvement is even bigger. You do need to install <tt class="docutils literal">httpxyz[http2]</tt> and specifiy
<tt class="docutils literal">httpxyz.Client(http2=True)</tt>.</p>
<p>Nice: httpxyz also has a command line interface.</p>
<p>Something he only mentioned briefly: there oauth2 client_credentials support. You have
to define a way to grab an oauth2 token, but the rest of the client work just uses the
regular methods. Handy.</p>
<p>They're on <a class="reference external" href="https://codeberg.org/httpxyz/httpxyz">https://codeberg.org/httpxyz/httpxyz</a> instead of on github.</p>
<img alt="https://reinout.vanrees.org/images/2026/lac-de-kruth4.jpg" src="https://reinout.vanrees.org/images/2026/lac-de-kruth4.jpg" />
<p><em>Unrelated photo: the &quot;lac de Kruth-Wildenstein&quot; reservoir during a family holiday in
France in 2006.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>PyGrunn: how to sort and route your (physical) mail - Bart Dorlandt</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/05/08/3-physical-mail.html" />
      <id>http://reinout.vanrees.org/weblog/2026/05/08/3-physical-mail.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-05-08T00:00:00+01:00</published>
      <updated>2026-05-08T12:16:00+01:00</updated>

      
        <category term="python" />
      
        <category term="pygrunn" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2026/05/08/index.html">my summaries</a> of
the 2026 one-day <a class="reference external" href="https://pygrunn.org/">PyGrunn conference</a> in Groningen, NL).</p>
<p>Full title: how to store and route your (physical) mail like a pro - personal edition.</p>
<p>How do you deal with your mail? Your physical mail? How do you store it? If the tax
people want to have some information, can you find it, for instance?</p>
<p>Bart's motto is <em>there must be a better way</em>. So what is the pragmatic approach to
better physical mail handling? A mail handling system that is flexible, automated,
searchable and easy to use.</p>
<p>He discovered <a class="reference external" href="https://docs.paperless-ngx.com/">paperless-ngx</a>, an open source
document management system that allow you to store, organize and search your documents.
Web interface, api, it can also read emails (via the &quot;gotenburg&quot; plugin). It can watch
folders for new docs to process. It has features for structuring, self-improving
(without AI). Tags. And you can have workflows.</p>
<p>Nice. Documents can go to Paperless. But he still has his bookkeeping system (he has his
own company). And the bookkeeper wants emails with documents that are in Paperless. Can
he improve this? For instance for receipts. He didn't want to scan all of them to PDF.
And regular phone cameras don't produce PDFs.</p>
<p>He started using &quot;dropbox camera&quot;. It works great for scanning receipts and documents.
It recognizes corners and pages and enhances the contrast. It produces PDFs and uploads
them to dropbox. (You must accept the fact that it ends up in the cloud: he build all
this pre-Trump...)</p>
<p>He has a <em>Synology NAS</em> at home. That has a CloudSync app that you can use to sync the
dropbox folder to the NAS.</p>
<p>He wanted to make some python glue gode. Ability to send to multiple destinations.
Process folders for new files. Moving files to a &quot;done&quot; folder. Python looks at the
various folders: he configured a specific custom &quot;processor&quot; per folder. So a
move-to-paperless processor, for instance. And a processor that emails the scanned
receipts directly to the bookkeeper.</p>
<p>Lots of it is automated. Just drop a PDF in a folder and the system takes care of it.
Once in a while he checks Paperless and categorizes/stores what's left in the inbox.</p>
<p>It was a personal project, so he used it to experiment with <em>Dataclass</em> and <em>Protocol</em>.
<strong>Don't forget to learn when you create/automate something for yourself.</strong></p>
<p>He finds it awesome that something <em>this</em> easy saves him hours! <strong>What can</strong> <em>you</em>
<strong>automate in your life?</strong></p>
<img alt="https://reinout.vanrees.org/images/2026/lac-de-kruth3.jpg" src="https://reinout.vanrees.org/images/2026/lac-de-kruth3.jpg" />
<p><em>Unrelated photo: the &quot;lac de Kruth-Wildenstein&quot; reservoir during a family holiday in
France in 2006.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>PyGrunn: layered architecture - Mike Huls</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/05/08/1-layered-architecture.html" />
      <id>http://reinout.vanrees.org/weblog/2026/05/08/1-layered-architecture.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-05-08T00:00:00+01:00</published>
      <updated>2026-05-08T08:39:00+01:00</updated>

      
        <category term="python" />
      
        <category term="pygrunn" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2026/05/08/index.html">my summaries</a> of
the 2026 one-day <a class="reference external" href="https://pygrunn.org/">PyGrunn conference</a> in Groningen, NL).</p>
<p>Full title: layered architecture for readable, robust, and extensible apps.</p>
<p>Note: there's a related article <a class="reference external" href="https://mikehuls.com/layered-architecture-for-building-readable-robust-and-extensible-apps/">on his own website</a>
:-)</p>
<p>Layered architecture resonates with people that make okay applications: their
application do what they need to do. But once people start asking for changes, they get
nervous. There might be huge functions. Or there might be no tests, &quot;as it takes too
much time to spin up the database&quot;. <strong>Brittle applications</strong>. Small changes are
disproportionally expensive.</p>
<p>The goal of this talk: create apps that are readable, robust and extensible. By using
the principle of separating everything in layers with a specific responsibility. It is
not a one-size-fits-all solution: you have to adapt it to your situation.</p>
<p>The layers that he proposes:</p>
<ul class="simple">
<li>Interface: how the ouside world calls your application. An API or UI.</li>
<li>Infrastructure and Repository: your contact with the outside world (like a database).<ul>
<li>Infrastructure is tools. A http client. A mail sender.</li>
<li>Repository: persistence. SQL queries, caches. The aim is to decouple the rest of the
system from db/cache/etc.</li>
</ul>
</li>
<li>Application: heart of your system, orchestrating the business logic. The Interface
talks to the Application layer, the Application layer talks the infra/repo. And uses
the Domain layer.</li>
<li>Domain: constraints and definitions. He often uses Pydantic models here. It reflects
the business meaning. It should be strict. Fail early. The &quot;language&quot; used should be a
shared language between the engineers and the business people.</li>
</ul>
<p>There are some rules, like the Interface only talks to the Application, not directly to
the Infrastructure. And your code should be structured the same way. So a <tt class="docutils literal">repo/</tt> dir,
an <tt class="docutils literal">infra/</tt> dir etc.</p>
<p>What are the benefits?</p>
<ul class="simple">
<li>It is more readable, you know where stuff is. This also helps with onboarding.</li>
<li>It is more understandable, also to business people.</li>
<li>Your app will be much more maintainable.</li>
<li>Structure is clearer.</li>
<li>Because you have more separation between concerns, validation is easier, so you tend
to do more of it.</li>
<li>Evolvable. You can build upon your existing code instead of modifying it.</li>
</ul>
<p>How to get started?</p>
<ul class="simple">
<li>Start with separate directories. If you wonder where a function should go, it probably
has too many responsibilities :-)</li>
<li>Add tests.</li>
<li>Start small.</li>
<li>Focus on validation. Fail early.</li>
<li>Isolate the business logic.</li>
<li>Concentrate on the borders and separations.</li>
</ul>
<p>Something to watch out for is making your models too big. You might have to split it
into separate systems with their own responibility. A payment system, separate from the
inventory system, for instance. You might want to create a small, focused shared domain
system.</p>
<img alt="https://reinout.vanrees.org/images/2026/lac-de-kruth1.jpg" src="https://reinout.vanrees.org/images/2026/lac-de-kruth1.jpg" />
<p><em>Unrelated photo: the &quot;lac de Kruth-Wildenstein&quot; reservoir during a family holiday in
France in 2006.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>Djangocon EU: lightning talks day 3</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/04/17/9-lightning-talks-day3.html" />
      <id>http://reinout.vanrees.org/weblog/2026/04/17/9-lightning-talks-day3.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-04-17T00:00:00+01:00</published>
      <updated>2026-04-17T14:19:00+01:00</updated>

      
        <category term="django" />
      
        <category term="djangocon" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/tags/djangocon.html">my summaries</a> of
the <a class="reference external" href="https://2026.djangocon.eu/">2026 Djangocon EU in Athens</a>).</p>
<div class="section" id="announcement-carlton-gibson">
<h1>Announcement - Carlton Gibson</h1>
<p>They've been working on improving the technical governance of Django. They'd like to get
feedback. There's a <a class="reference external" href="https://www.djangoproject.com/weblog/2026/apr/16/new-technical-governance-request-for-community-fee/">blog post about it</a>.</p>
<p>Oh, and look at the &quot;30% off PyCharm&quot; button on the django website, that raises quite a
lot of funds for Django. PyCharm's sponsoring is a very sizeable financial part of
Django, thanks!</p>
</div>
<div class="section" id="even-more-table-partitioning-with-django-postgres-and-uuids-tim-bell">
<h1>Even more table partitioning with Django, Postgres and UUIDs - Tim Bell</h1>
<p>(See his earlier talk on partitioning).</p>
<p>UUID is 128-bits, usually displayed as hex strings. It starts with the unix
timestamp, followed by several random fields (in version 7). In version 8, you have more
flexibility. You can customize it to put a specific value (an id of a related field in
their case) in the first field.</p>
<p>Partitioning per UUID (they used it as their ID) then effectively <em>also</em> partitions on
the related field.</p>
</div>
<div class="section" id="speeding-up-django-startup-times-with-lazy-imports-anze-pecar">
<h1>Speeding up Django startup times with lazy imports - Anze Pecar</h1>
<p>Imports in Python can be slow. Luckily, python has something build-in to check it, the
&quot;importtime&quot; flag:</p>
<pre class="literal-block">
python -X importtime manage.py check
</pre>
<p>He worked around the packages he found by importing the package inside the functions
where he used them. It worked, but it was ugly.</p>
<p>Look at things like <tt class="docutils literal">post_worker_init</tt> in gunicorn, you can use that to pre-load the
offending modules.</p>
<p>You can also wait for python 3.15. PEP810: explicit lazy imports!</p>
</div>
<div class="section" id="pyladies-seoul-rebooting-a-community-for-women-in-tech-scenes-hwayoung-cha">
<h1>PyLadies Seoul: rebooting a community for women in tech scenes - Hwayoung Cha</h1>
<p>At Pycon Korea 2023 there were only three woman in attendance. So: time to re-start
Pyladies Seoul! And with success. One of the new attendees is now a CTO of a company
(and also a PyLadies volunteer herself).</p>
<p>They'll also start a Django workshop soon.</p>
<p>Join your local PyLadies chapter!</p>
</div>
<div class="section" id="what-i-learned-during-learning-to-solve-rubic-cube-venelin-stoykov">
<h1>What I learned during learning to solve rubic cube - Venelin Stoykov</h1>
<p>He learned solving a Rubic cube in about two weeks.</p>
<p>We can learn new things more easily by association with things we already know. We need
to practice a lot. Repeat, repeat: that way we tell our brain that we need to remember
it.</p>
<p>&quot;Thinking slow and fast&quot; is a book he recommends.</p>
<p>AI is like the fast thinking. Fast is also a bit sloppy and often a bit wrong.</p>
<p>If we really want to understand something, it takes time and work.</p>
</div>
<div class="section" id="why-volunteering-and-contributing-to-communities-is-important-alex-gomez">
<h1>Why volunteering and contributing to communities is important - Alex Gómez</h1>
<p>Get involved! Volunteer! Do some work! Volunteers are necessary.</p>
<p>Volunteering is a lot of work, but it is worth it.</p>
</div>
<div class="section" id="djangofmt-a-django-template-formatter-written-in-rust-thibaut-decombe">
<h1>Djangofmt, a Django template formatter written in rust - Thibaut Decombe</h1>
<p>Djangofmt, a fast, html aware, django template formatter, written in Rust.</p>
<p><a class="reference external" href="https://github.com/UnknownPlatypus/djangofmt">https://github.com/UnknownPlatypus/djangofmt</a></p>
<p>You can run it as a pre-commit hook.</p>
<img alt="https://reinout.vanrees.org/images/2026/kat9.jpeg" src="https://reinout.vanrees.org/images/2026/kat9.jpeg" />
<p><em>Unrelated photo explanation: a cat I encountered in Athens in the morning near the
hotel.</em></p>
</div>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>Djangocon EU: supply chain attacks on Python projects - Mateusz Bełczowski</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/04/17/8-dependencies-supply-chain-attacks.html" />
      <id>http://reinout.vanrees.org/weblog/2026/04/17/8-dependencies-supply-chain-attacks.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-04-17T00:00:00+01:00</published>
      <updated>2026-04-17T13:48:00+01:00</updated>

      
        <category term="django" />
      
        <category term="djangocon" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/tags/djangocon.html">my summaries</a> of
the <a class="reference external" href="https://2026.djangocon.eu/">2026 Djangocon EU in Athens</a>).</p>
<p>Full title: what's in your dependencies? Supply chain attacks on Python projects.</p>
<p>How supply chain attacks work: attackers don't attack your code directly, they target
something you trust. A typical Django project has lots of dependencies. Direct
dependencies and &quot;transitive dependencies&quot;, dependencies of our dependencies. If you
depend on <tt class="docutils literal">requests</tt>, <tt class="docutils literal">requests</tt> itself will grab <tt class="docutils literal">certify</tt> and <tt class="docutils literal">urllib3</tt>.</p>
<p>Possible package attacks:</p>
<ul class="simple">
<li>Inject malicious code directly into the repo.</li>
<li>Create malicious package. Typosquatting (abusing typos), slopsquatting (abusing typos
made by LLMs). &quot;Brandjacking&quot;: quickly after <tt class="docutils literal">deepseek</tt> became popular, a
<tt class="docutils literal">deepseekai</tt> package was published that stole credentials.</li>
<li>Compromise existing package. Credential stealing, CI/CD exploits.</li>
</ul>
<p>What attackers typically do with access is to steal credentials. Environment variables,
cloud keys (<tt class="docutils literal">AWS_xyz</tt>), pypi tokens, ssh private keys, database URLs, saved passwords.</p>
<p>Example: num2words was hacked in July 2025. Phishing leading to maintainer credentials
theft. Fake login page at pypj.org instead of pypi.org. Then they uploaded faulty
releases with the captured credentials. Credentials weren't rotated, so a second attack
happened a few days later. This malware targeted <tt class="docutils literal">.pypirc</tt> files, leading to more
compromises.</p>
<p>How can we defend from this kind of attacks? Depends on the kind of attack. When
publishing via GitHub actions, use &quot;trusted publishing&quot;, in that case there are no
credentials to steal.</p>
<p>Another example: LiteLLM was compromised via trivy, a security scanner that itself was
compromised... It in turn collected environment variables, secrets and ssh keys, bundled
it all in a tarball and posted it to some legitimate-looking domain.</p>
<p>Some myths:</p>
<ul class="simple">
<li>&quot;Lockfiles protect us&quot;. No, they only prevent accidental upgrades, not when adding a
package for the first time.</li>
<li>&quot;Just don't install suspicious packages&quot;. Lots is installed via transitive
dependencies.</li>
<li>&quot;We run everything in Docker so we're safe&quot;. It limits the blast radius, but credentials
and environment variables are still at risk.</li>
<li>&quot;We can fully prevent attacks&quot;.</li>
</ul>
<p>Some tips:</p>
<ul class="simple">
<li>Use dependency cooldowns. <tt class="docutils literal">uv</tt> has &quot;exclude-newer&quot;, <tt class="docutils literal">pip</tt> has &quot;uploaded-prior-to&quot;.
Don't be the first to install a fresh release, as most malicious packages are
discovered within hours or days.</li>
<li>Pin versions and verify hashes.</li>
</ul>
<p>Pypi is getting better:</p>
<ul class="simple">
<li>Trusted publishing.</li>
<li>Project quarantine.</li>
<li>Attestations: cryptographic tools to verify the source.</li>
<li>Typosquatting protection.</li>
</ul>
<p>AI has risks:</p>
<ul class="simple">
<li>Slopsquatting. Hallucinated package names that get exploited.</li>
<li>Prompt injection via github issues.</li>
<li>Agents often &quot;just&quot; pip-install things directly.</li>
</ul>
<p>Note: AI can also be used to detect malware! A small project started after the LiteLLM
compromise managed to detect a dangerous different compromise almost the moment it was
published.  Nice!</p>
<img alt="https://reinout.vanrees.org/images/2026/kat8.jpeg" src="https://reinout.vanrees.org/images/2026/kat8.jpeg" />
<p><em>Unrelated photo explanation: a cat I encountered in Athens on an evening stroll in the
neighbourhood behind the hotel. It was a cat on the hunt: relevant to the topic of this
talk :-)</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>Djangocon EU: Django templates on the frontend? - Christophe Henry</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/04/17/7-django-templates-frontend.html" />
      <id>http://reinout.vanrees.org/weblog/2026/04/17/7-django-templates-frontend.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-04-17T00:00:00+01:00</published>
      <updated>2026-04-17T12:25:00+01:00</updated>

      
        <category term="django" />
      
        <category term="djangocon" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/tags/djangocon.html">my summaries</a> of
the <a class="reference external" href="https://2026.djangocon.eu/">2026 Djangocon EU in Athens</a>).</p>
<p>It all started with formsets: you generate a new form based on other forms. You can use
it to create pretty fancy forms. But your designer can get quite creative. And you might
have variable forms that have to react to user input.</p>
<p>A common solution is to use htmx, but that means server requests all the time. And some
users have really bad connections. Regular requests aren't handy in that scenario.</p>
<p>He looked at django-rusty-templates: Django's template engine implemented in Rust. It
had a template parser that he could re-use. With OXC (javascript oxidation compiler) he
converted that to javascript.</p>
<p>That way, he could offload much of the django form creation handling to the frontend,
including reacting to user input and showing alerts.</p>
<p>The work-in-progress project is called django-template-transpiler:
<a class="reference external" href="https://github.com/christophehenry/django-template-transpiler">https://github.com/christophehenry/django-template-transpiler</a> . Don't use it for
production.</p>
<img alt="https://reinout.vanrees.org/images/2026/kat7.jpeg" src="https://reinout.vanrees.org/images/2026/kat7.jpeg" />
<p><em>Unrelated photo explanation: a cat I encountered in Athens on an evening stroll in the
neighbourhood behind the hotel.</em></p>
</div>

      ]]>
      </content>

    </entry>
  
    <entry>
      <title>Djangocon EU: How Django is helping to build the biggest X-ray observatory to date - Loes Crama</title>
      <link rel="alternate" type="text/html"
            href="https://reinout.vanrees.org/weblog/2026/04/17/6-x-ray.html" />
      <id>http://reinout.vanrees.org/weblog/2026/04/17/6-x-ray.html</id>
      <!-- id is not https: prevents old entries from showing up again -->
      <author>
        <name>Reinout van Rees</name>
      </author>
      <published>2026-04-17T00:00:00+01:00</published>
      <updated>2026-04-17T12:09:00+01:00</updated>

      
        <category term="django" />
      
        <category term="djangocon" />
      

      <content type="html"><![CDATA[
      <div class="document">
<p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/tags/djangocon.html">my summaries</a> of
the <a class="reference external" href="https://2026.djangocon.eu/">2026 Djangocon EU in Athens</a>).</p>
<p>She works at <a class="reference external" href="https://www.cosine.eu/">Cosine</a>, they develop measurement systems and space instrumentation. They
work for the space industry (ESA, NASA, etc).</p>
<p>They're now working on &quot;high-energy optics&quot;, the NewAthena x-ray observatory, the biggest
one to date. NewAthena: NEW Advanced Telescope for High-ENergy Astrophysics. Planned
launch is in 2037 on Ariane 6.4.</p>
<p>Talking about rocket science is cool, but where's the software? Within the company,
software is an internal service, supporting scientists. Handling data in many ways:
visualization, analysis, processing, management. Django plays a big role in all of this.</p>
<p>When you build something with Django in a scientific context, you really need to
understand the data. Workflows must be flexible. R&amp;D and production often don't need to
be strictly separated. Multiple datastores for various purposes (like an extra MongoDB,
for instance) is often handy.</p>
<p>Their application consists of:</p>
<ul class="simple">
<li>SXRO (silicon x-ray optics) database.</li>
<li>A Mysql database.</li>
<li>Django.</li>
</ul>
<p>The goal is to track all the components that go into the observatory. Status and
quality. Configuration and geometry. Component relationships. Inspections. History of
all the components.</p>
<p>The default <strong>Django admin</strong> is their primary method of using the application. Often, it
is said that the admin is not <em>not</em> <strong>not</strong> intended for end users. But they're using it
anyway. It is an internal tool for technical people. Most of them have a PhD: they can
handle such an interface. They've been using it for years.</p>
<p>There are some third party packages:</p>
<ul class="simple">
<li><a class="reference external" href="https://django-simple-history.readthedocs.io/en/stable/">django-simple-history</a>:
easy history.</li>
<li><a class="reference external" href="https://pypi.org/project/djangoql/">djangoql</a>: advanced queries for the search bar.</li>
<li>django-admin-rangefilter, django-admin-list-filter-dropdown,
django-admin-numeric-filter: little tools to tweak the filters on the right hand side.</li>
</ul>
<p>There are some separate forms, mostly for actions performed in the lab or cleanroom. For
instance a form where you can use an ipad to indicate defects in one of the components
by just drawing on the picture of the component.</p>
<p>There's also a REST API. Other software and data tools can use it to integrate with
Django:</p>
<ul class="simple">
<li>Observability tools (prometheus/grafana).</li>
<li>JupyterHub.</li>
<li>Stacking robots.</li>
</ul>
<p>They use: djangorestframework, drf-spectacular (API docs), django-filter (filtering via GET parameters).</p>
<p>Django is their software backbone. A general-purpose framework that's well suited for a
scientific context.</p>
<img alt="https://reinout.vanrees.org/images/2026/kat6.jpeg" src="https://reinout.vanrees.org/images/2026/kat6.jpeg" />
<p><em>Unrelated photo explanation: a cat I encountered in Athens on an evening stroll in the
neighbourhood behind the hotel.</em></p>
</div>

      ]]>
      </content>

    </entry>
  

</feed>