<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Derk Weijers on Qstars IT Blog - Cloud, Kubernetes &amp; Software Engineering</title>
        <link>https://blog.qstars.nl/authors/derk-weijers/</link>
        <description>Recent content in Derk Weijers on Qstars IT Blog - Cloud, Kubernetes &amp; Software Engineering</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Mon, 02 Mar 2026 10:00:00 +0200</lastBuildDate><atom:link href="https://blog.qstars.nl/authors/derk-weijers/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Pre-commit vs Prek - The Differences</title>
        <link>https://blog.qstars.nl/posts/pre-commit-vs-prek/</link>
        <pubDate>Mon, 02 Mar 2026 10:00:00 +0200</pubDate>
        
        <guid>https://blog.qstars.nl/posts/pre-commit-vs-prek/</guid>
        <description>&lt;img src="https://blog.qstars.nl/posts/pre-commit-vs-prek/prek.jpg" alt="Featured image of post Pre-commit vs Prek - The Differences" /&gt;&lt;p&gt;If you&amp;rsquo;ve been working with Python (or really any language) for a while, chances are you&amp;rsquo;ve used &lt;a class=&#34;link&#34; href=&#34;https://pre-commit.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pre-commit&lt;/a&gt;. It&amp;rsquo;s been the de facto standard for managing git hooks for years. You define your hooks in a &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;, run &lt;code&gt;pre-commit install&lt;/code&gt;, and you&amp;rsquo;re good to go. It handles the installation and execution of hooks written in any language, without requiring root access.&lt;/p&gt;
&lt;p&gt;But recently, as I found out at &lt;a class=&#34;link&#34; href=&#34;https://fosdem.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;FOSDEM&lt;/a&gt;, a new tool has been making the rounds: &lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;prek&lt;/a&gt;. It&amp;rsquo;s like a version of pre-commit, built in Rust. And if you&amp;rsquo;ve been following the Python ecosystem, you&amp;rsquo;ll notice a trend here. First we got &lt;a class=&#34;link&#34; href=&#34;https://github.com/astral-sh/ruff&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Ruff&lt;/a&gt; as a replacement for Flake8, Black, and isort. Then &lt;a class=&#34;link&#34; href=&#34;https://github.com/astral-sh/uv&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;uv&lt;/a&gt; came along to replace pip venv (and maybe even Poetry). Now prek is here to speed things up as well.&lt;/p&gt;
&lt;p&gt;The Rust rewrite of pre-commit is gaining traction fast. For a couple of my projects I decided to give prek a shot and see how it compares to good old pre-commit. Let me walk you through the differences.&lt;/p&gt;
&lt;h2 id=&#34;a-quick-recap&#34;&gt;A quick recap
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://blog.qstars.nl/posts/pre-commit-vs-prek/rust.jpg&#34;
	width=&#34;735&#34;
	height=&#34;500&#34;
	srcset=&#34;https://blog.qstars.nl/posts/pre-commit-vs-prek/rust_hu_62f996648fabec0f.jpg 480w, https://blog.qstars.nl/posts/pre-commit-vs-prek/rust_hu_3bb200502c8cf22.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Rust, Rust everywhere&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;352px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;pre-commit&#34;&gt;pre-commit
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://pre-commit.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pre-commit&lt;/a&gt; has been around since 2014 and has a massive ecosystem. It&amp;rsquo;s a multi-language package manager for git hooks. You specify the hooks you want, and pre-commit manages everything: downloading the tools, setting up isolated virtual environments, and running the hooks on every commit.&lt;/p&gt;
&lt;p&gt;A typical configuration looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;repos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;https://github.com/pre-commit/pre-commit-hooks&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v4.6.0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hooks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;check-yaml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;end-of-file-fixer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;trailing-whitespace&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;https://github.com/astral-sh/ruff-pre-commit&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v0.8.0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hooks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ruff&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ruff-format&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Getting started is straightforward:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install pre-commit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pre-commit install --install-hooks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. Now every time you commit, your hooks will run.&lt;/p&gt;
&lt;h3 id=&#34;prek&#34;&gt;prek
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;prek&lt;/a&gt; is a drop-in replacement for pre-commit, built in Rust by &lt;a class=&#34;link&#34; href=&#34;https://github.com/j178&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;j178&lt;/a&gt;. It&amp;rsquo;s designed to be faster, dependency-free, and fully compatible with your existing &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;. That last part is key: you don&amp;rsquo;t have to change your configuration at all.&lt;/p&gt;
&lt;p&gt;Installation is just as simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Using uv (recommended)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv tool install prek
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv add --dev prek
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Or via pip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install prek
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The migration? Two commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pre-commit uninstall
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;prek install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. No configuration changes, no compatibility issues. Your existing &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; works as-is.&lt;/p&gt;
&lt;h2 id=&#34;so-why-would-you-switch&#34;&gt;So why would you switch?
&lt;/h2&gt;&lt;h3 id=&#34;speed&#34;&gt;Speed
&lt;/h3&gt;&lt;p&gt;Let&amp;rsquo;s be real, this is the main reason. pre-commit is written in Python and creates isolated virtual environments for each hook. This architecture is robust, but it introduces overhead. Especially the initial setup can take a while.&lt;/p&gt;
&lt;p&gt;prek is significantly faster. According to the &lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/benchmark/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;official benchmarks&lt;/a&gt;, installing hooks for Apache Airflow (which has a large and complex pre-commit configuration) took about 18 seconds with prek versus 187 seconds with pre-commit. That&amp;rsquo;s roughly &lt;strong&gt;10x faster&lt;/strong&gt;. For runtime, the numbers vary but prek is consistently 2-5x faster, depending on the hooks and whether the fast path is enabled.&lt;/p&gt;
&lt;p&gt;On the CPython codebase, running &lt;code&gt;check-toml&lt;/code&gt; across all files:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Tool&lt;/th&gt;
          &lt;th&gt;Time (warm cache)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;prek&lt;/td&gt;
          &lt;td&gt;~77ms&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;pre-commit&lt;/td&gt;
          &lt;td&gt;~352ms&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That&amp;rsquo;s about &lt;strong&gt;4.5x faster&lt;/strong&gt;. And these numbers get more dramatic with cold caches and larger hook configurations.&lt;/p&gt;
&lt;h3 id=&#34;disk-space&#34;&gt;Disk space
&lt;/h3&gt;&lt;p&gt;prek redesigned how hook environments and toolchains are managed. Instead of creating a separate virtual environment for each hook, it shares toolchains between hooks. The result? After installing hooks for Apache Airflow, prek used about 810MB of disk space compared to 1.6GB for pre-commit. That&amp;rsquo;s roughly &lt;strong&gt;half the disk usage&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&#34;no-python-dependency&#34;&gt;No Python dependency
&lt;/h3&gt;&lt;p&gt;One of the things that has always bugged me about pre-commit is that it&amp;rsquo;s a Python tool. That means you need a Python installation to use it, even if you&amp;rsquo;re working on a Node.js or Go project. prek ships as a single binary with no dependencies. It doesn&amp;rsquo;t require Python or any other runtime.&lt;/p&gt;
&lt;p&gt;Even better: if your hooks need Python, prek will automatically install the required version for you. No more hassle with your system Python version not matching what the hooks expect.&lt;/p&gt;
&lt;h3 id=&#34;parallel-execution&#34;&gt;Parallel execution
&lt;/h3&gt;&lt;p&gt;pre-commit runs hooks sequentially. prek can run hooks in parallel based on &lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/configuration/#priority&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;priority&lt;/a&gt;. Hooks with the same priority may run concurrently, reducing the end-to-end runtime. This is especially useful when you have multiple independent hooks that don&amp;rsquo;t need to run in a specific order.&lt;/p&gt;
&lt;h3 id=&#34;better-cli-experience&#34;&gt;Better CLI experience
&lt;/h3&gt;&lt;p&gt;prek comes with some nice quality-of-life improvements over pre-commit&amp;rsquo;s CLI (&lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/diff/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;full list&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prek run --directory &amp;lt;dir&amp;gt;&lt;/code&gt; runs hooks for files in a specific directory. No more piping &lt;code&gt;git ls-files&lt;/code&gt; into &lt;code&gt;xargs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prek run --last-commit&lt;/code&gt; runs hooks on files changed in the last commit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prek run [HOOK] [HOOK]&lt;/code&gt; lets you select and run multiple hooks at once.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prek list&lt;/code&gt; gives you a nice overview of all configured hooks and their descriptions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prek auto-update&lt;/code&gt; supports &lt;code&gt;--cooldown-days&lt;/code&gt; to avoid picking up brand-new releases immediately — a neat defense against supply chain attacks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;monorepo-support&#34;&gt;Monorepo support
&lt;/h3&gt;&lt;p&gt;If you work with monorepos, prek has built-in &lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/workspace/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;workspace mode&lt;/a&gt;. Each subproject can have its own &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; file, and prek handles running hooks across all of them. This is something pre-commit doesn&amp;rsquo;t support natively, and it doesn&amp;rsquo;t seem this will be implemented soon.&lt;/p&gt;
&lt;h3 id=&#34;built-in-hooks&#34;&gt;Built-in hooks
&lt;/h3&gt;&lt;p&gt;prek implements some common hooks from &lt;code&gt;pre-commit-hooks&lt;/code&gt; natively in Rust (&lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/builtin/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;see the list&lt;/a&gt;). These are faster than their Python counterparts and can run offline with &lt;code&gt;repo: builtin&lt;/code&gt;, which is not available in pre-commit.&lt;/p&gt;
&lt;h2 id=&#34;where-pre-commit-still-wins&#34;&gt;Where pre-commit still wins
&lt;/h2&gt;&lt;p&gt;It wouldn&amp;rsquo;t be fair to not mention the areas where pre-commit still has the upper hand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maturity and ecosystem&lt;/strong&gt;: pre-commit has been around for over a decade. It has extensive documentation, a massive community, and a proven track record. When something goes wrong, you&amp;rsquo;re more likely to find an answer on Stack Overflow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Language support&lt;/strong&gt;: While prek supports most commonly used languages, some are not yet fully supported for drop-in parity with pre-commit. Check the &lt;a class=&#34;link&#34; href=&#34;https://prek.j178.dev/languages/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Language Support&lt;/a&gt; page for the current status.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pre-commit.ci&lt;/strong&gt;: If you use &lt;a class=&#34;link&#34; href=&#34;https://pre-commit.ci/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pre-commit.ci&lt;/a&gt; for running hooks in CI and auto-fixing pull requests, there&amp;rsquo;s no equivalent for prek yet. That said, there is a &lt;a class=&#34;link&#34; href=&#34;https://github.com/j178/prek-action&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;prek GitHub Action&lt;/a&gt; available for CI integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Battle-tested edge cases&lt;/strong&gt;: pre-commit has handled just about every obscure configuration and edge case out there. prek is newer and, while it&amp;rsquo;s already used by projects like CPython, FastAPI, Apache Airflow, and Django, it might not handle every niche scenario yet.&lt;/p&gt;
&lt;h2 id=&#34;whos-already-using-prek&#34;&gt;Who&amp;rsquo;s already using prek?
&lt;/h2&gt;&lt;p&gt;The adoption list is actually quite impressive for such a young tool. Projects like &lt;a class=&#34;link&#34; href=&#34;https://github.com/python/cpython/issues/143148&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CPython&lt;/a&gt;, &lt;a class=&#34;link&#34; href=&#34;https://github.com/fastapi/fastapi/pull/14572&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;FastAPI&lt;/a&gt;, &lt;a class=&#34;link&#34; href=&#34;https://github.com/apache/airflow/issues/44995&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Apache Airflow&lt;/a&gt;, &lt;a class=&#34;link&#34; href=&#34;https://github.com/astral-sh/ruff/pull/22505&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Ruff&lt;/a&gt;, and &lt;a class=&#34;link&#34; href=&#34;https://github.com/home-assistant/core/pull/160427&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Home Assistant&lt;/a&gt; have either adopted prek or are in the process of switching. That&amp;rsquo;s a pretty strong signal.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;If you&amp;rsquo;re already using pre-commit and everything works fine, there&amp;rsquo;s no rush to switch. pre-commit is a solid, battle-tested tool that will continue to serve you well.&lt;/p&gt;
&lt;p&gt;However, if you find yourself annoyed by slow hook installations, if you&amp;rsquo;re working in a monorepo, or if you just like your tools to be fast, prek is absolutely worth trying. The migration path is painless and fully reversible. Give it a spin, see if it works for your setup, and enjoy the speed boost.&lt;/p&gt;
&lt;p&gt;The trend of rewriting Python tooling in Rust isn&amp;rsquo;t slowing down, and prek fits right into this movement alongside Ruff and uv. It&amp;rsquo;s exciting to see the Python ecosystem getting faster without sacrificing the developer experience we&amp;rsquo;ve come to expect.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>uv has pushed a BIG update</title>
        <link>https://blog.qstars.nl/posts/python-uv-030/</link>
        <pubDate>Thu, 22 Aug 2024 10:00:06 +0200</pubDate>
        
        <guid>https://blog.qstars.nl/posts/python-uv-030/</guid>
        <description>&lt;img src="https://blog.qstars.nl/posts/python-uv-030/uv-030.png" alt="Featured image of post uv has pushed a BIG update" /&gt;&lt;p&gt;Python&amp;rsquo;s ecosystem is constantly evolving, with tools and libraries emerging to address the growing needs of developers. Among these tools is the uv package manager, an innovative approach to handling Python dependencies. The recent release of uv 0.3.0 introduces a range of exciting features and improvements, solidifying its position as a cutting-edge tool for Python developers. In this post, we’ll take a closer look at what’s new in uv 0.3.0 and how it can streamline your development workflow.&lt;/p&gt;
&lt;h2 id=&#34;what-is-uv&#34;&gt;What is uv?
&lt;/h2&gt;&lt;p&gt;If you&amp;rsquo;re unfimiliar with uv that&amp;rsquo;s okay. It hasn&amp;rsquo;t been around for a long time and only recently started to gain traction. The uv package manager is designed to provide a modern and efficient way to manage Python packages and dependencies. It aims to simplify the process of creating and maintaining Python environments, offering a more intuitive and less error-prone alternative to traditional tools like pip and venv. By combining dependency resolution, environment management, and packaging into a single tool, uv empowers developers to manage their Python projects with ease. It&amp;rsquo;s inspired by Cargo (the package manager for Rust) and its ultimate goal is to be a tool that can do anything related to manage your Python projects. Since it&amp;rsquo;s written in Rust, it&amp;rsquo;s extremely fast.&lt;/p&gt;
&lt;h2 id=&#34;key-features-and-updates-in-uv-030&#34;&gt;Key Features and Updates in uv 0.3.0
&lt;/h2&gt;&lt;p&gt;The 0.3.0 release of uv introduces several new features and improvements, reflecting the feedback from early adopters and the project’s ongoing commitment to innovation. Here are the key updates:&lt;/p&gt;
&lt;h3 id=&#34;enhanced-dependency-resolution&#34;&gt;Enhanced Dependency Resolution
&lt;/h3&gt;&lt;p&gt;One of the most notable enhancements in uv 0.3.0 is the improved dependency resolution algorithm. This update addresses some of the common pain points associated with dependency conflicts by offering more sophisticated resolution strategies. The new algorithm is faster and more accurate, reducing the likelihood of dependency clashes and ensuring that your environment is both stable and reproducible.&lt;/p&gt;
&lt;h3 id=&#34;lockfile-support&#34;&gt;Lockfile Support
&lt;/h3&gt;&lt;p&gt;uv 0.3.0 introduces support for lockfiles, a much-requested feature. Lockfiles allow you to freeze the exact versions of all dependencies in your project, ensuring that anyone who installs your project’s dependencies gets the same versions that you used during development. This is particularly valuable for collaborative projects or deployment scenarios where consistency across environments is critical.&lt;/p&gt;
&lt;h3 id=&#34;customizable-environments&#34;&gt;Customizable Environments
&lt;/h3&gt;&lt;p&gt;With version 0.3.0, uv now allows for more customization of your Python environments. You can specify different environments for development, testing, and production, each with its own set of dependencies and configurations. This feature streamlines the process of switching between different stages of your project, making it easier to maintain separate environments without conflicts.&lt;/p&gt;
&lt;h3 id=&#34;improved-cli-experience&#34;&gt;Improved CLI Experience
&lt;/h3&gt;&lt;p&gt;The command-line interface (CLI) in uv 0.3.0 has been refined for better usability. The new release introduces more intuitive commands, clearer error messages, and enhanced help documentation. These improvements make it easier for both new and experienced users to navigate the tool and perform common tasks quickly.&lt;/p&gt;
&lt;h3 id=&#34;expanded-plugin-ecosystem&#34;&gt;Expanded Plugin Ecosystem
&lt;/h3&gt;&lt;p&gt;Another significant update is the expansion of the uv plugin ecosystem. The 0.3.0 release includes several new plugins that extend the functionality of uv, offering features like integration with popular CI/CD pipelines, automatic virtual environment creation, and support for advanced packaging formats. These plugins make uv even more versatile, allowing developers to tailor it to their specific needs.&lt;/p&gt;
&lt;h2 id=&#34;why-should-you-checkout-uv&#34;&gt;Why Should You Checkout uv?
&lt;/h2&gt;&lt;p&gt;The release of uv 0.3.0 underscores the tool’s potential to become a staple in the Python development community. Its focus on simplicity, performance, and flexibility makes it an attractive option for developers who want to streamline their workflow and reduce the overhead associated with managing Python dependencies. Whether you’re working on a small personal project or a large-scale enterprise application, uv provides the tools you need to maintain clean, reliable, and reproducible environments.&lt;/p&gt;
&lt;p&gt;As stated before, uv is extremely fast. This table (credits: from the uv repo) compares installing &lt;a class=&#34;link&#34; href=&#34;https://trio.readthedocs.io/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Trio&lt;/a&gt;&amp;rsquo;s dependencies with a warm cache.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Name&lt;/th&gt;
          &lt;th&gt;Time (less is better)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;uv&lt;/td&gt;
          &lt;td&gt;0.06s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Poetry&lt;/td&gt;
          &lt;td&gt;0.99s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;pdm&lt;/td&gt;
          &lt;td&gt;1.90s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;pip-sync&lt;/td&gt;
          &lt;td&gt;4.63s&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;getting-started-with-uv-030&#34;&gt;Getting Started with uv 0.3.0
&lt;/h2&gt;&lt;p&gt;If you’re new to uv or looking to upgrade to the latest version, getting started is straightforward. You can install uv using pip:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;22
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;23
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# On macOS and Linux.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ curl -LsSf https://astral.sh/uv/install.sh &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# On Windows.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ powershell -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;irm https://astral.sh/uv/install.ps1 | iex&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# With pip.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip install uv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a project - uv will automatically fetch Python versions as needed, you don&amp;#39;t need to install Python to get started&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv init helloworld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Install dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv add flask
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create the virtualenvironment and install the dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv sync
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run Ruff without adding it as dependency&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uvx ruff check
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Or install ruff as tool in the virtualenvironment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv tool install ruff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ruff check
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Once installed, you can initialize a new project or manage existing dependencies with simple, intuitive commands. The official (and majorly updated) &lt;a class=&#34;link&#34; href=&#34;https://docs.astral.sh/uv/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;documentation&lt;/a&gt; provides comprehensive guidance on how to leverage the new features introduced in 0.3.0.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;The uv package manager continues to evolve with the release of version 0.3.0, bringing with it a host of features that make Python dependency management more efficient and user-friendly. Especially the new project, tool, script and python sub-commands will make the developer experience of using uv a whole lot smoother. Uv is now one step closer to being a full-fledged Python project manager.&lt;/p&gt;
&lt;p&gt;For more info about uv, make sure to checkout the official &lt;a class=&#34;link&#34; href=&#34;https://github.com/astral-sh/uv&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;repository&lt;/a&gt;!&lt;/p&gt;
&lt;aside class=&#34;qstars-cta qstars-cta--python-jobs&#34; lang=&#34;en&#34;&gt;
    &lt;p class=&#34;qstars-cta__kicker&#34;&gt;We&amp;#39;re hiring&lt;/p&gt;
    &lt;h3 class=&#34;qstars-cta__title&#34;&gt;Opinions about Python tooling?&lt;/h3&gt;
    &lt;div class=&#34;qstars-cta__body&#34;&gt;Good. We&amp;rsquo;re looking for software and platform engineers who care about this
sort of thing. You&amp;rsquo;d be building cloud and software platforms for
organisations across the Netherlands.&lt;/div&gt;
    &lt;a class=&#34;qstars-cta__button&#34; href=&#34;https://www.qstars.nl/werken-bij-qstars?utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_campaign=python-jobs&#34; rel=&#34;noopener&#34;&gt;
        &lt;span&gt;See our openings&lt;/span&gt;
        &lt;svg class=&#34;qstars-cta__arrow&#34; viewBox=&#34;0 0 24 24&#34; width=&#34;18&#34; height=&#34;18&#34;
             fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34;
             stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; aria-hidden=&#34;true&#34;&gt;
            &lt;line x1=&#34;5&#34; y1=&#34;12&#34; x2=&#34;19&#34; y2=&#34;12&#34;&gt;&lt;/line&gt;
            &lt;polyline points=&#34;12 5 19 12 12 19&#34;&gt;&lt;/polyline&gt;
        &lt;/svg&gt;
    &lt;/a&gt;
&lt;/aside&gt;

</description>
        </item>
        <item>
        <title>Recap EuroPython 2024</title>
        <link>https://blog.qstars.nl/posts/europython-2024/</link>
        <pubDate>Wed, 24 Jul 2024 10:00:06 +0200</pubDate>
        
        <guid>https://blog.qstars.nl/posts/europython-2024/</guid>
        <description>&lt;img src="https://blog.qstars.nl/posts/europython-2024/europython-2024.png" alt="Featured image of post Recap EuroPython 2024" /&gt;&lt;p&gt;July came around again, which meant it was time for another edition of EuroPython! Like last year, it was held in the beautiful city of Prague.&lt;/p&gt;
&lt;h2 id=&#34;ai-and-machine-learning&#34;&gt;AI and Machine Learning
&lt;/h2&gt;&lt;p&gt;Like with all (technical) conferences in the past year, AI is dominating the landscape. While there was a lot of focus on AI and LLM during EuroPython 2023, it felt like there was more room for other topics this year. Of course, AI wasn&amp;rsquo;t completely gone, especially &lt;a class=&#34;link&#34; href=&#34;https://blogs.nvidia.com/blog/what-is-retrieval-augmented-generation/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;RAG&lt;/a&gt; was pretty popular this year.&lt;/p&gt;
&lt;h2 id=&#34;typings&#34;&gt;Typings
&lt;/h2&gt;&lt;p&gt;While this is a bit of controversial topic within the Python landscape, adding type annotations to your codebase is becoming more popular. Especially with bigger codebases, adding type annotations can improved the readability, integrity and maintainability of a codebase. During one of the talks, given by &lt;a class=&#34;link&#34; href=&#34;https://note35.github.io/about&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Kir Chou&lt;/a&gt;, we dived into &lt;a class=&#34;link&#34; href=&#34;https://peps.python.org/pep-0729/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PEP 729&lt;/a&gt; which is a proposal to govern the typing process. While it&amp;rsquo;s still in-progress, it has support from all the major type checkers to create a consistent typing experience.&lt;/p&gt;
&lt;p&gt;If/when this PEP gets accepted, type checkers should become more robust and consistent, resulting in more resilient code.&lt;/p&gt;
&lt;h2 id=&#34;talks&#34;&gt;Talks
&lt;/h2&gt;&lt;p&gt;In general, the talks were really good. The amount of proposals was huge (a new record, even!) so there was more than enough to choose from. A lot of talks were from a personal perspective from people who just wanted to share experience on certain topics. It was nice to see they included real-life use-cases. For example, the talk &lt;a class=&#34;link&#34; href=&#34;https://ep2024.europython.eu/session/how-to-sell-a-big-refactor-or-rewrite-to-the-business&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;How to sell a big refactor or rewrite to the business?&lt;/a&gt; included about 5 use-cases when a company decided to do a rewrite/refactor including the reasoning and strategy. This is incredibly helpful if you&amp;rsquo;re dealing with this situation as well.&lt;/p&gt;
&lt;h2 id=&#34;social-event&#34;&gt;Social Event
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://blog.qstars.nl/gabriel.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Gabriel Loci ex-monastery - credits: EuroPython website&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;The social event is one of the highlights of the conference. It&amp;rsquo;s a paid event to relax, network and hangout with friends from earlier EuroPythons. This year it was being held in an awesome location, the historic Gabriel Loci ex-monastery (which also was the location for PyCon CZ!).&lt;/p&gt;
&lt;p&gt;This year&amp;rsquo;s social event was different than others we&amp;rsquo;ve attended. Everyone was free to bring their instruments and boardgames. You could either sit outside (which is pretty nice in terms of temperature this time of year) and have a chat with each other, or sit inside and play boardgames. There as also a jam session for those who brought their instruments.&lt;/p&gt;
&lt;p&gt;This event is were friendships are made!&lt;/p&gt;
&lt;h2 id=&#34;sprints&#34;&gt;Sprints
&lt;/h2&gt;&lt;p&gt;The sprints were a bit new to us. Normally we&amp;rsquo;d spend the weekend in the city the conference is held in, however since this was my 5th time in Prague &lt;em&gt;and&lt;/em&gt; we heard really good things about the sprint weekend, we decided to join this year.&lt;/p&gt;
&lt;p&gt;The sprint weekend is a weekend where open-source projects invite EuroPython attendees to join in their coding efforts. All skill levels are welcome to join as most issues range from beginner to expert. This year, the sprint weekend was held in the University of Economics of Prague. There was food, drinks, good wifi and cool projects to work on. In terms of networking, this was the perfect place to do so! We met awesome people and got talked with some of the people who gave talks or are EuroPython/PyCon organizer.&lt;/p&gt;
&lt;p&gt;This is definitely something we´d like to participate on again next year!&lt;/p&gt;
&lt;p&gt;The projects we&amp;rsquo;ve worked on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bas&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;https://github.com/python/cpython&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CPython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Benny&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;https://micropython.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MicroPython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Derk&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;https://falcon.readthedocs.io/en/stable/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Falcon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;dei&#34;&gt;DEI
&lt;/h2&gt;&lt;p&gt;EuroPython has been actively promoting Diversity, Equity, and Inclusion (DEI) in its community. This is one of the areas where it differs from other conferences (that we attend) and it&amp;rsquo;s highly integrated into the program and events.&lt;/p&gt;
&lt;p&gt;Here are some key aspects of DEI at EuroPython:&lt;/p&gt;
&lt;h3 id=&#34;code-of-conduct&#34;&gt;Code of Conduct
&lt;/h3&gt;&lt;p&gt;EuroPython enforces a comprehensive Code of Conduct to ensure a welcoming and harassment-free environment for all participants. This includes clear guidelines on expected behavior and steps for reporting incidents.&lt;/p&gt;
&lt;h3 id=&#34;diversity-grants&#34;&gt;Diversity Grants
&lt;/h3&gt;&lt;p&gt;The conference offers diversity grants to support individuals from underrepresented groups, helping them to attend the conference by covering expenses such as travel and accommodation.&lt;/p&gt;
&lt;h3 id=&#34;diverse-speaker-line-up&#34;&gt;Diverse Speaker Line-up
&lt;/h3&gt;&lt;p&gt;EuroPython strives to include a diverse range of speakers, ensuring representation from different backgrounds, genders, and communities. They actively encourage and support new and diverse voices in their call for proposals.&lt;/p&gt;
&lt;h3 id=&#34;workshops-and-panels-on-dei&#34;&gt;Workshops and Panels on DEI
&lt;/h3&gt;&lt;p&gt;The conference often includes workshops, panels, and discussions focused on DEI topics. These sessions are designed to raise awareness, share best practices, and promote actionable steps towards inclusivity within the Python community.&lt;/p&gt;
&lt;h3 id=&#34;community-building-activities&#34;&gt;Community Building Activities
&lt;/h3&gt;&lt;p&gt;EuroPython fosters a sense of community through various networking events and activities that are inclusive and accessible to all participants, aiming to build a supportive and diverse community around Python.&lt;/p&gt;
&lt;h3 id=&#34;accessibility&#34;&gt;Accessibility
&lt;/h3&gt;&lt;p&gt;The conference venues and materials are chosen and designed with accessibility in mind, ensuring that participants with disabilities can fully engage with the event.&lt;/p&gt;
&lt;h3 id=&#34;childcare-facilities&#34;&gt;Childcare Facilities
&lt;/h3&gt;&lt;p&gt;Recognizing the importance of supporting attendees with families, EuroPython often provides childcare facilities, making it easier for parents to participate in the conference.&lt;/p&gt;
&lt;h2 id=&#34;playlist--videos&#34;&gt;Playlist / Videos
&lt;/h2&gt;&lt;p&gt;If you&amp;rsquo;d like to see the sessions, the initial version of the &lt;a class=&#34;link&#34; href=&#34;https://youtube.com/playlist?list=PL8uoeex94UhG1Awatk-G-_VR5RHrNq2AX&amp;amp;si=ffPRVtgHXlMsEYWa&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;YouTube&lt;/a&gt; playlist is now available!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Going Distroless</title>
        <link>https://blog.qstars.nl/posts/going-distroless/</link>
        <pubDate>Thu, 09 May 2024 10:00:06 +0200</pubDate>
        
        <guid>https://blog.qstars.nl/posts/going-distroless/</guid>
        <description>&lt;img src="https://blog.qstars.nl/posts/going-distroless/going-distroless.png" alt="Featured image of post Going Distroless" /&gt;&lt;p&gt;You probably know this saying:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is no such thing as &amp;ldquo;cloud&amp;rdquo; - The cloud is just somebody else&amp;rsquo;s computer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And I must admit that&amp;rsquo;s exactly what I thought when I first heard about &lt;em&gt;distroless images&lt;/em&gt;. But what is distroless and what are the pros and cons? Let&amp;rsquo;s dive in!&lt;/p&gt;
&lt;h2 id=&#34;what-is-distroless&#34;&gt;What is distroless
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Distroless&amp;rdquo; images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Distroless images are &lt;em&gt;very&lt;/em&gt; small images. They just contain your application and their runtime dependencies. They don&amp;rsquo;t contain extras like shells and package managers - basically everything you would typically find in Linux distributions.&lt;/p&gt;
&lt;p&gt;That being said, distroless images still contain a distribution - In the end there&amp;rsquo;s no such thing as no distro.&lt;/p&gt;
&lt;h2 id=&#34;why-distroless&#34;&gt;Why distroless
&lt;/h2&gt;&lt;p&gt;When I first heard of distroless, it was because I was investigating the high vulnerabilities count in one of my projects. The client uses multiple tools to check for issues like code smell, missing tests and vulnerabilities in container images.&lt;/p&gt;
&lt;p&gt;I reached out to the team that&amp;rsquo;s deploying these tools to check what can be done, since we&amp;rsquo;re using official (Python) images most vulnerabilities didn&amp;rsquo;t impact our code/application but still blocked our CI/CD pipelines. They introduced distroless images, something that was kind of new to me. They would probably solve most of our issues, but there&amp;rsquo;s got to be a catch, right?&lt;/p&gt;
&lt;p&gt;Google, one of the contributors to distroless, says the following about distroless:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Restricting what&amp;rsquo;s in your runtime container to precisely what&amp;rsquo;s necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years. It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.&lt;/p&gt;
&lt;p&gt;Distroless images are very small. The smallest distroless image, gcr.io/distroless/static-debian11, is around 2 MiB. That&amp;rsquo;s about 50% of the size of alpine (~5 MiB), and less than 2% of the size of debian (124 MiB).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;examples&#34;&gt;Examples
&lt;/h2&gt;&lt;p&gt;Time to checkout some distroless examples. The tests below are ran locally. After building an image, &lt;a class=&#34;link&#34; href=&#34;https://trivy.dev&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Trivy&lt;/a&gt; is used to run a security scan.&lt;/p&gt;
&lt;h3 id=&#34;rust-rocket&#34;&gt;Rust (&lt;a class=&#34;link&#34; href=&#34;https://rocket.rs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Rocket&lt;/a&gt;)
&lt;/h3&gt;&lt;p&gt;Let&amp;rsquo;s start with benchmarking a normal Rust 1.77 &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/derkweijers/30f67f6d0dfd180d99942dc5a00dea7e#file-dockerfile-rust-fat&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;image&lt;/a&gt;. It&amp;rsquo;s a basic Rocket application with just a single endpoint. The base image used is &lt;code&gt;rust:1.77&lt;/code&gt;, and the OS is fully updated. This gives the following results:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rust-fat
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;==================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total: &lt;span class=&#34;m&#34;&gt;1056&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;UNKNOWN: 5, LOW: 501, MEDIUM: 438, HIGH: 107, CRITICAL: 5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s build the same application, but now with a distroless &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/derkweijers/30f67f6d0dfd180d99942dc5a00dea7e#file-dockerfile-rust-distroless&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;image&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rust-distroless
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;=============================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total: &lt;span class=&#34;m&#34;&gt;21&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;UNKNOWN: 0, LOW: 13, MEDIUM: 7, HIGH: 1, CRITICAL: 0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Not zero, but definitely better. Let&amp;rsquo;s compare the image sizes:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Name&lt;/th&gt;
          &lt;th&gt;Size&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;rust-fat&lt;/td&gt;
          &lt;td&gt;2.45GB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;rust-distroless&lt;/td&gt;
          &lt;td&gt;39.1MB&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That&amp;rsquo;s quite a difference! Let&amp;rsquo;s see some more examples.&lt;/p&gt;
&lt;h3 id=&#34;java-micronaut&#34;&gt;Java (&lt;a class=&#34;link&#34; href=&#34;https://micronaut.io&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Micronaut&lt;/a&gt;)
&lt;/h3&gt;&lt;p&gt;A simple Maven &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/derkweijers/30f67f6d0dfd180d99942dc5a00dea7e#file-dockerfile-mvn-fat&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;image&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mvn-fat
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;======================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total: &lt;span class=&#34;m&#34;&gt;75&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;UNKNOWN: 0, LOW: 55, MEDIUM: 20, HIGH: 0, CRITICAL: 0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;v.s. a distroless &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/derkweijers/30f67f6d0dfd180d99942dc5a00dea7e#file-dockerfile-mvn-distroless&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;image&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mvn-distroless
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;============================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total: &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;UNKNOWN: 0, LOW: 18, MEDIUM: 2, HIGH: 3, CRITICAL: 1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Name&lt;/th&gt;
          &lt;th&gt;Size&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;mvn-fat&lt;/td&gt;
          &lt;td&gt;414MB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;mvn-distroless&lt;/td&gt;
          &lt;td&gt;236MB&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;python-flask&#34;&gt;Python (Flask)
&lt;/h3&gt;&lt;p&gt;And then a bit of a tricky one. So far we&amp;rsquo;ve used languages who compile/package their dependencies with the executable they ship. Python works differently so needs a few more steps.&lt;/p&gt;
&lt;p&gt;Lets start with a simple &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/derkweijers/30f67f6d0dfd180d99942dc5a00dea7e#file-dockerfile-python-fat&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Python API&lt;/a&gt; (Flask with Gunicorn):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python-fat &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;debian 12.5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;==================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total: &lt;span class=&#34;m&#34;&gt;124&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;UNKNOWN: 0, LOW: 71, MEDIUM: 39, HIGH: 13, CRITICAL: 1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And now the &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/derkweijers/30f67f6d0dfd180d99942dc5a00dea7e#file-dockerfile-python-distroless&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;distroless image&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python-distroless &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;debian 12.5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;==================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total: &lt;span class=&#34;m&#34;&gt;70&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;UNKNOWN: 0, LOW: 23, MEDIUM: 30, HIGH: 16, CRITICAL: 1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s definitely less, but still quite a lot (and the critical one is still present).
As can be seen in the image we disable creating a virtual environment and we need to copy the entire &lt;code&gt;/usr/local/lib/python3.11/site-packages&lt;/code&gt; over to the distroless image (to get the dependencies &amp;ldquo;installed&amp;rdquo;). We also need to explicitly update the &lt;code&gt;PYTHONPATH&lt;/code&gt; variable, to tell Python where to look for packages and modules.&lt;/p&gt;
&lt;p&gt;Lastly, sizes. The resulting image is just a bit smaller.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Name&lt;/th&gt;
          &lt;th&gt;Size&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;python-fat&lt;/td&gt;
          &lt;td&gt;259MB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;python-distroless&lt;/td&gt;
          &lt;td&gt;134MB&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Distroless images can greatly reduce the size of images. Since it removes a lot of OS level tooling that&amp;rsquo;s (often) not needed, it can also remove quite some vulnerabilities.&lt;/p&gt;
&lt;p&gt;However, since it removes so much from the image it also makes it harder to debug. Since there is no shell, you can&amp;rsquo;t &lt;code&gt;exec&lt;/code&gt; into the container to see it&amp;rsquo;s content or troubleshoot a process. Furthermore, if you need some OS-level dependency installed it gets quite harder. You can&amp;rsquo;t run &lt;code&gt;sudo apt install somepackage&lt;/code&gt; since there&amp;rsquo;s no package-manager installed either.&lt;/p&gt;
&lt;p&gt;Distroless images are not suitable for every piece of software and workload. They might require a bit more configuration and maintenance. But, as with many things in IT, it&amp;rsquo;s a great tool for the right jobs.&lt;/p&gt;
&lt;p&gt;Google&amp;rsquo;s distroless images are built with &lt;a class=&#34;link&#34; href=&#34;https://bazel.build&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Bazel&lt;/a&gt;. If you&amp;rsquo;d like to apply more customizations or automate the process of creating images, I highly encourage to checkout the docs.&lt;/p&gt;
&lt;p&gt;In a future blog we&amp;rsquo;ll discuss other images that can be used to create safe and clean Docker images.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Combining Poetry and Conda</title>
        <link>https://blog.qstars.nl/posts/combining-poetry-and-conda/</link>
        <pubDate>Sun, 11 Feb 2024 13:22:22 +0100</pubDate>
        
        <guid>https://blog.qstars.nl/posts/combining-poetry-and-conda/</guid>
        <description>&lt;img src="https://blog.qstars.nl/posts/combining-poetry-and-conda/retrosupply.png" alt="Featured image of post Combining Poetry and Conda" /&gt;&lt;p&gt;For one of my clients I had to convert a couple of pip-managed repositories to Poetry-managed ones. When I got to the last repo, there was one catch: it required Conda as well. This is quite straightforward, with the help of some packages and a couple of config changes.&lt;/p&gt;
&lt;h2 id=&#34;pip-vs-poetry-vs-conda&#34;&gt;Pip v.s. Poetry v.s. Conda
&lt;/h2&gt;&lt;p&gt;Lets quickly recap the three tools we will discuss today.&lt;/p&gt;
&lt;h3 id=&#34;pip&#34;&gt;pip
&lt;/h3&gt;&lt;p&gt;Pip is probably one of the most known package managers for Python. It enables developers to fetch and install Python packages from either the internet or a private repository. Pip has been the standard for a lot of years and will probably being used for many years to come.&lt;/p&gt;
&lt;h3 id=&#34;poetry&#34;&gt;Poetry
&lt;/h3&gt;&lt;p&gt;In the past few years Poetry quickly gained traction. Build upon pip, it&amp;rsquo;s a package manager on steroids. With the help of &lt;code&gt;pyproject.toml&lt;/code&gt; files you can define your packages (either individually or in groups), set the configuration for groups of packages, define settings for your favourite linters and tools and define the environment to build your packages. It can (and will so by default) also create your virtual environments.&lt;/p&gt;
&lt;h3 id=&#34;conda&#34;&gt;Conda
&lt;/h3&gt;&lt;p&gt;Then there&amp;rsquo;s also Conda. Conda has a lot of similarities with Poetry. One of the benefits of Conda (and this is also the reason my client uses it) is that repositories like conda-forge contain pre-compiled packages; something that&amp;rsquo;s not always the case with PyPi (the public package repository that both pip and Poetry use by default).&lt;/p&gt;
&lt;h2 id=&#34;combining-poetry--conda&#34;&gt;Combining Poetry &amp;amp; Conda
&lt;/h2&gt;&lt;p&gt;When picking up this story, it sounded pretty straightforward. However, one of the issues is that both Poetry and Conda are package managers, as well as environment managers that can conflict with each other quite easily. So how do we set this up?&lt;/p&gt;
&lt;p&gt;Since Poetry is quite straightforward to configure to the needs of Conda, we&amp;rsquo;ll use Conda as the base environment. Then we modify Poetry to use this environment as well.&lt;/p&gt;
&lt;p&gt;Lets start with setting up a base &lt;code&gt;environment.yml&lt;/code&gt; to define our Conda setup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;poetry-and-conda&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;channels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;conda-forge&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;dependencies&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;python==3.11.*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;gmsh&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;conda-lock&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;poetry&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;platforms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;linux-64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;osx-64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;win-64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;These packages are just some examples, however there are a few important things to note here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We define a Python version, this should be kept the same as what we will define in our &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;poetry&lt;/code&gt; will be installed as a dependency as well. This ensures that the poetry command (which we will use later) is used in the context of the Conda environment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We define platforms which will be used for our conda lock file, which will be generated with the &lt;code&gt;conda-lock&lt;/code&gt; tool. You can remove the platforms you don&amp;rsquo;t need.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this out of the way we can configure a lock file. The lock file will be used to create reproducible environments across installations. We create the lock files with a temporary environment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conda create -p /tmp/condaenv -c conda-forge &lt;span class=&#34;nv&#34;&gt;python&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3.11.*&amp;#34;&lt;/span&gt; conda-lock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conda activate /tmp/condaenv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conda-lock -k explicit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conda deactivate
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -rf /tmp/condaenv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;So what&amp;rsquo;s happening here? We create an environment, using the conda-forge &lt;a class=&#34;link&#34; href=&#34;https://docs.anaconda.com/business/cloud/channels/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;channel&lt;/a&gt;, and setup Python 3.11 (the same that we&amp;rsquo;ve defined in the &lt;code&gt;environment.yml&lt;/code&gt;) and conda-lock. We will then activate the environment, run the &lt;code&gt;conda-lock&lt;/code&gt; command which will pick-up the dependencies from the &lt;code&gt;environment.yml&lt;/code&gt;, resolve them and put their exact versions and hashes into a file called &lt;code&gt;conda-linux-64.lock&lt;/code&gt;. Using this file, we can create reprodusable environments, which is great when working in teams (everyone will get the exact same version of packages when setting up the environment).
After that&amp;rsquo;s done we deactivate the environment and remove it from the system.&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s time to get the &lt;em&gt;real&lt;/em&gt; environment up and running!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conda create --name poetry-and-conda -c conda-forge --file conda-osx-64.lock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;First, we&amp;rsquo;ll generate the environment from the lock file. We&amp;rsquo;ll give it a name, specify the conda-forge channel and make use of the lock file we generated earlier to install the required packages. Please note that I&amp;rsquo;m using the &lt;code&gt;conda-osx-64.lock&lt;/code&gt; file. If you&amp;rsquo;re on Windows or Linux, you should use one those flavours instead. If you&amp;rsquo;re just using a single platform, you can remove the others from the &lt;code&gt;environment.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s time to activate the environment and configure Poetry:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conda activate poetry-and-conda
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Verify which Poetry we&amp;#39;re using&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which poetry
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Note that this will point to Poetry installed in the environment,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# not my globally installed Poetry.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /opt/homebrew/Caskroom/miniconda/base/envs/poetry-and-conda/bin/poetry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Make sure Poetry doesn&amp;#39;t create another environment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry config --local virtualenvs.create &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Start a Poetry project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry init -n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;By running &lt;code&gt;poetry config --local virtualenvs.create false&lt;/code&gt; we will get a &lt;code&gt;poetry.toml&lt;/code&gt; that contains some local config that will prevent the creation of virtual environments for just this project. If you&amp;rsquo;re working in a team it&amp;rsquo;s important to commit this to your repository as well. When running the init command, make sure the Python version matches with what you&amp;rsquo;ve used to setup the Conda environment.&lt;/p&gt;
&lt;p&gt;We can now use Poetry to install PyPi (or private repository, when configured) packages.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry add flask flask-login
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry add --group dev pytest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Since we&amp;rsquo;ve configured Poetry to &lt;em&gt;not&lt;/em&gt; create an environment for this project, it will install the packages in the current environment - the Conda environment in this case.&lt;/p&gt;
&lt;p&gt;With the setup above, we&amp;rsquo;ve added both conda(-forge) packages and PyPi packages. They&amp;rsquo;re all installed in the same environment, so the interpeter is able to find the packages, regardless of which tool installed them. Now we can create a webapp (an API for example) with Flask (as installed with Poetry) that uses gmsh (that&amp;rsquo;s installed with Conda).&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s it! Now you&amp;rsquo;ve got a Conda and Poetry hybrid environment. I would recommend to stick with a single solution as much as possible, but sometimes you&amp;rsquo;re required to combine the two.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
