<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Anže's Blog</title><link>http://blog.pecar.me/</link><description>Recent content on Anže's Blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 08 Jun 2026 01:15:00 +0100</lastBuildDate><atom:link href="http://blog.pecar.me/feed.xml" rel="self" type="application/rss+xml"/><item><title>The 15-Year-Old iptables Rule That Broke My DNS</title><link>http://blog.pecar.me/the-15-year-old-iptables-rule-that-broke-my-dns/</link><pubDate>Mon, 08 Jun 2026 01:15:00 +0100</pubDate><guid>http://blog.pecar.me/the-15-year-old-iptables-rule-that-broke-my-dns/</guid><description>&lt;p>One of my servers has a weird problem after every reboot: it can ping IP addresses just fine, but it can&amp;rsquo;t resolve any DNS names.&lt;/p>
&lt;pre tabindex="0">&lt;code>$ ping 8.8.8.8 # works
$ ping google.com # ping: google.com: Temporary failure in name resolution
&lt;/code>&lt;/pre>&lt;p>I&amp;rsquo;ve been working around this for a while now: after every reboot I&amp;rsquo;d SSH in and overwrite &lt;code>/etc/resolv.conf&lt;/code> to point straight at &lt;code>8.8.8.8&lt;/code> instead of the local &lt;code>127.0.0.53&lt;/code> stub. That got DNS working again, but it was never a real fix. &lt;code>/etc/resolv.conf&lt;/code> is regenerated on boot, so my edit vanished the next time the machine came up and I was back to fixing it by hand. This time I decided to attempt to properly debug it with Claude.&lt;/p></description></item><item><title>Fedidevs 9h Outage Postmortem</title><link>http://blog.pecar.me/fedidevs-9h-outage-postmortem/</link><pubDate>Wed, 13 May 2026 09:54:55 +0100</pubDate><guid>http://blog.pecar.me/fedidevs-9h-outage-postmortem/</guid><description>&lt;p>Today I had almost 9 hours of downtime on fedidevs.com and some of my other sites that I run on a Raspberry Pi at home. The alert came in just as I was heading to bed and I didn&amp;rsquo;t see it until I woke up this morning 🫣&lt;/p>
&lt;p>Since &lt;a href="https://fosstodon.org/@jake@theorangeone.net/116566388806900818">Jake on Mastodon&lt;/a> asked for a Cloudflare-style postmortem, here it is:&lt;/p>
&lt;h2 id="incident-report-9h-loss-of-upstream-connectivity-on-the-raspberrypi-host">Incident report: ~9h loss of upstream connectivity on the &lt;code>raspberrypi&lt;/code> host&lt;/h2>
&lt;p>&lt;strong>Date:&lt;/strong> 2026-05-12 / 2026-05-13&lt;/p></description></item><item><title>Letting Claude Upgrade My Raspberry Pi</title><link>http://blog.pecar.me/letting-claude-upgrade-my-raspberry-pi/</link><pubDate>Sun, 10 May 2026 19:00:00 +0100</pubDate><guid>http://blog.pecar.me/letting-claude-upgrade-my-raspberry-pi/</guid><description>&lt;p>I have two Raspberry Pis at home. One hosts my various sites including &lt;a href="https://fedidevs.com/">fedidevs.com&lt;/a> and the other supports it by storing backups of all the configs and data. This includes a streaming hot standby of the Postgres database that powers some of my sites. I am not (yet) brave enough to run Claude on my primary Pi, but I decided to let it loose on my secondary.&lt;/p>
&lt;p>Doing an in-place dist upgrade on a Raspberry Pi is &lt;a href="https://www.raspberrypi.com/documentation/computers/os.html#upgrade">generally not recommended&lt;/a>. The official guidance is to do a clean install instead. Since it felt very likely that I&amp;rsquo;d be doing a clean install in any case to get from Bookworm (Debian 12) to Trixie (Debian 13), I figured this was the perfect opportunity to see if Claude could pull a miracle.&lt;/p></description></item><item><title>Agents Day Lisbon</title><link>http://blog.pecar.me/agents-day-lisbon/</link><pubDate>Mon, 04 May 2026 19:38:17 +0100</pubDate><guid>http://blog.pecar.me/agents-day-lisbon/</guid><description>&lt;p>Last week I attended the &lt;a href="https://www.agentsday.org/">Agents Day&lt;/a> Hackathon in Lisbon. It was a full day of talks, socializing, and building agents.&lt;/p>
&lt;div class="gallery">&lt;a href="http://blog.pecar.me/pics/agents-day1_hu_ad706fc4b199a1d2.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/agents-day1_hu_242ed28d78f90ad8.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/agents-day2_hu_917fd08145e925bb.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/agents-day2_hu_c1ec9b257e78b3d7.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/agents-day5_hu_10c98954c275e9d2.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/agents-day5_hu_2d871d18a78c6a2a.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/agents-day7_hu_b504e7c2d15b3db1.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/agents-day7_hu_1739d5a1104a8d99.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;/div>

&lt;h2 id="talks">Talks&lt;/h2>
&lt;p>There were a few talks and a round table discussion during the hackathon. The most memorable one for me was about the challenges behind Cloudflare&amp;rsquo;s 16 MCP servers.&lt;/p>
&lt;p>All 2500+ Cloudflare endpoints couldn&amp;rsquo;t fit into a single MCP server, since listing them all used up too many tokens. After a bit of back and forth they ended up with an architecture where the MCP only exposes two endpoints (search and execute), and the agents can figure out the rest.&lt;/p></description></item><item><title>DjangoCon Europe 2026</title><link>http://blog.pecar.me/djangocon-europe-2026/</link><pubDate>Tue, 28 Apr 2026 00:00:00 +0100</pubDate><guid>http://blog.pecar.me/djangocon-europe-2026/</guid><description>&lt;h2 id="before-the-conference">Before the conference&lt;/h2>
&lt;p>My partner and I arrived in Athens a few days before the conference. It was a convenient excuse to visit a European capital we hadn&amp;rsquo;t been to yet, and of course to eat as much delicious food as possible.&lt;/p>
&lt;div class="gallery">&lt;a href="http://blog.pecar.me/pics/athens-1_hu_3307dca299d83d05.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-1_hu_2a45a8d89adab59a.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-2_hu_e6ecdb12a5df4ab8.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-2_hu_8b77d142b034c945.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-3_hu_78868efba96a6922.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-3_hu_399145f3ac0b9cd0.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-4_hu_6b9b6fe03b2fd19.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-4_hu_e41036aede942f86.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-5_hu_7cdb073310add721.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-5_hu_d6f452628fd9b7ec.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-6_hu_d073425fa728d588.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-6_hu_90c6293738b18d3c.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-7_hu_34272096bf88286e.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-7_hu_731c48200c8eb7fa.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;a href="http://blog.pecar.me/pics/athens-8_hu_66b544373ecc58dc.webp" data-lightbox>&lt;img src="http://blog.pecar.me/pics/athens-8_hu_5b1de681e15972e9.webp" alt="" loading="lazy" width="600" height="600">&lt;/a>&lt;/div>

&lt;h2 id="django-social">Django Social&lt;/h2>
&lt;p>One day before the conference I went to the &lt;a href="https://www.linkedin.com/company/djangosocial/posts/?feedView=all">django.social&lt;/a> event organized by &lt;a href="https://www.linkedin.com/in/jongould/">Jon Gould&lt;/a> and &lt;a href="https://www.linkedin.com/in/akmiller89/">Andrew Miller&lt;/a>.&lt;/p>
&lt;p>The bar they initially picked got too crowded, so the group moved to the backup place. I came late to the first bar, found no one there, and was a bit lost until I made it to the right spot. Once I did, I felt immediately at home. I met old friends, made some new ones, and had a very fun evening. So fun, in fact, that I forgot to take any photos, so I have no social proof that I was there 😅&lt;/p></description></item><item><title>How to Safely Update Your Dependencies</title><link>http://blog.pecar.me/how-to-safely-update-your-dependencies/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0100</pubDate><guid>http://blog.pecar.me/how-to-safely-update-your-dependencies/</guid><description>&lt;p>With all the supply chain attacks happening lately (&lt;a href="https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-teampcp-supply-chain-campaign/">litellm&lt;/a> being the most recent example) keeping dependencies up to date without risk has been on my mind.&lt;/p>
&lt;p>Below is everything I do to keep my personal projects secure, what we do at &lt;a href="http://fencer.dev/">Fencer&lt;/a> to keep our own codebase secure, and what we recommend to the startups we work with.&lt;/p>
&lt;h2 id="be-hesitant-about-what-you-add">Be hesitant about what you add&lt;/h2>
&lt;p>The best way to reduce the risk of installing a compromised dependency is to avoid relying on it in the first place. Before adding a new dependency, I first make sure that implementing it ourselves would be too much work (or tokens!).&lt;/p></description></item><item><title>Speeding Up Django Startup Times with Lazy Imports</title><link>http://blog.pecar.me/speeding-up-django-startup-times-with-lazy-imports/</link><pubDate>Sun, 22 Mar 2026 18:55:25 +0000</pubDate><guid>http://blog.pecar.me/speeding-up-django-startup-times-with-lazy-imports/</guid><description>&lt;p>At &lt;a href="https://www.fencer.dev/">Fancer&lt;/a> we are building &lt;em>the&lt;/em> security suite for startups. Startups use a lot of SaaS tools and services which means we are building a lot of integrations. Most of these go through API calls but we also try to leverage SDKs to make our lives a little bit easier.&lt;/p>
&lt;p>The problem we started noticing was that loading all these 3rd party integrations has made our Django app feel very sluggish. While this was noticeable around deployments and starting scans, it hurt the most during local development. It was taking around 10s to run &lt;code>./manage.py check&lt;/code> which meant that any Django command ended up being slow. Devs felt this the most with development server restarts and when running tests.&lt;/p></description></item><item><title>Typing Your Django Project in 2026</title><link>http://blog.pecar.me/typing-your-django-project-in-2026/</link><pubDate>Thu, 12 Mar 2026 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/typing-your-django-project-in-2026/</guid><description>&lt;p>The first version of Django was released about 10 years before &lt;a href="https://peps.python.org/pep-0484/">Python standardized its type hints syntax&lt;/a>. Because of this it&amp;rsquo;s not surprising that getting type hints to work in your Django project is not going to be trivial.&lt;/p>
&lt;h2 id="django-stubs-with-mypy">&lt;code>django-stubs&lt;/code> with mypy&lt;/h2>
&lt;p>If you want your Django codebase to be type checked then &lt;a href="https://github.com/typeddjango/django-stubs">django-stubs&lt;/a> is the go to package to use. It ships both &lt;a href="https://peps.python.org/pep-0561/">type-stubs&lt;/a> for most of Django&amp;rsquo;s public APIs as well as a mypy plugin that fills in the typing information for all the dynamic black magic that we love Django for. You&amp;rsquo;ll also want to include the monkeypatch from &lt;a href="https://pypi.org/project/django-stubs-ext/">django-stubs-ext&lt;/a> for best results.&lt;/p></description></item><item><title>Claude Fixes User Bug</title><link>http://blog.pecar.me/claude-fixes-user-bug/</link><pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/claude-fixes-user-bug/</guid><description>&lt;p>I received this bug report in a toot from a Fedidevs user:&lt;/p>
&lt;blockquote>
&lt;p>Dear @fedidevs&lt;/p>
&lt;p>I think there is a bug with the starterpacks: When in &amp;ldquo;Add accounts&amp;rdquo; I search for an account that is already in the Pack, the tick-box can show empty. When I click it, it will switch to ticked, but the account is actually &lt;em>removed&lt;/em> from the pack. This is also confirmed by the number of accounts in the pack going down.&lt;/p></description></item><item><title>Jekyll to Hugo Migration</title><link>http://blog.pecar.me/jekyll-to-hugo-migration/</link><pubDate>Mon, 02 Mar 2026 22:02:24 +0000</pubDate><guid>http://blog.pecar.me/jekyll-to-hugo-migration/</guid><description>&lt;p>In my &lt;a href="http://blog.pecar.me/advent-of-code-2025/#ai-">last post&lt;/a> I mentioned that software engineering is going to be more and more AI driven and since then I&amp;rsquo;ve begrudgingly accepted this new reality. The era of handcrafted code is mostly coming to an end.&lt;/p>
&lt;p>I say mostly because I still believe there will always be places in our future codebases that require manual intervention. Little surgical removals and additions around the parts where the LLMs get confused and start spinning their wheels without results.&lt;/p></description></item><item><title>Advent of Code 2025 🎄</title><link>http://blog.pecar.me/advent-of-code-2025/</link><pubDate>Fri, 12 Dec 2025 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/advent-of-code-2025/</guid><description>&lt;p>December is the time for Advent of Code, as it has been since 2015, when the first Advent of Code event was published.&lt;/p>
&lt;p>This year, Advent of Code only had 12 days instead of the usual 25. To me, this was a relief. I always get competitive and then start waking up at 5 am every day to get more points on the leaderboards. I did the exact same thing this year as well, of course, but at least I only did it for 12 days!&lt;/p></description></item><item><title>Django bulk_update Memory Issue</title><link>http://blog.pecar.me/django-bulk-update-memory-issue/</link><pubDate>Sun, 12 Oct 2025 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/django-bulk-update-memory-issue/</guid><description>&lt;p>Recently, I had to write a Django migration to update hundreds of thousands of database objects.&lt;/p>
&lt;h2 id="loading-the-data">Loading the data&lt;/h2>
&lt;p>With some paper-napkin math I calculated that I can fit all the necessary data in memory, making the migration much simpler than it would have been otherwise.&lt;/p>
&lt;p>First I had to make sure to load only the necessary columns. Django&amp;rsquo;s &lt;a href="https://docs.djangoproject.com/en/5.2/ref/models/querysets/#only">&lt;code>only&lt;/code> queryset method&lt;/a> came in very handy:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">objs_to_update&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TheObject&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">objects&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">only&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;field1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;field2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;field3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">all&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Because I generally don&amp;rsquo;t trust my paper-napkin math, I also made sure to log how much memory each of the steps were using:&lt;/p></description></item><item><title>Migrating Gunicorn to Granian</title><link>http://blog.pecar.me/migrating-gunicorn-to-granian/</link><pubDate>Sat, 27 Sep 2025 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/migrating-gunicorn-to-granian/</guid><description>&lt;p>I migrated one of my Django apps from Gunicorn to Granian yesterday. Here is how the migration went and some of my thoughts on Granian and Gunicorn.&lt;/p>
&lt;h1 id="migration">Migration&lt;/h1>
&lt;p>This is the second time I attempted to try out Granian. The first time I got blocked because Granian didn&amp;rsquo;t support &lt;a href="https://github.com/emmett-framework/granian/issues/97">unix sockets&lt;/a>. I run several Django apps on the same host behind Nginx, and I&amp;rsquo;m using Unix sockets for communication between Nginx and Gunicorn. I could have switched to using ports, but I didn&amp;rsquo;t want to mess with Nginx for this experiment.&lt;/p></description></item><item><title>Disable Network Requests When Running Pytest</title><link>http://blog.pecar.me/disable-network-requets-when-running-pytest/</link><pubDate>Mon, 07 Jul 2025 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/disable-network-requets-when-running-pytest/</guid><description>&lt;p>Even though my team has been diligent with mocking external requests, a few web requests still managed to slip through after a few months of cranking out new features. We only noticed them when our &lt;a href="https://fosstodon.org/@anze3db/114783230227028153">tests started to fail&lt;/a>. 🫣&lt;/p>
&lt;h2 id="the-mocking-problem">The mocking problem&lt;/h2>
&lt;p>Usually, when you write a test for code that makes network requests, you mock your HTTP library of choice, either by using the built-in &lt;a href="https://docs.python.org/3/library/unittest.mock.html">unittest.mock&lt;/a> module or using something like &lt;a href="https://colin-b.github.io/pytest_httpx/">pytest_httpx&lt;/a>.&lt;/p></description></item><item><title>Disable Runserver Warning in Django 5.2</title><link>http://blog.pecar.me/disable-runserver-warning-in-django-5-2/</link><pubDate>Tue, 24 Jun 2025 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/disable-runserver-warning-in-django-5-2/</guid><description>&lt;p>&lt;a href="https://docs.djangoproject.com/en/5.2/releases/5.2/#management-commands">Django 5.2 added a new warning&lt;/a> that shows up when you start your development server with &lt;code>python manage.py runserver&lt;/code>:&lt;/p>
&lt;pre tabindex="0">&lt;code>WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead.
For more information on production servers see: https://docs.djangoproject.com/en/5.2/howto/deployment/
&lt;/code>&lt;/pre>&lt;p>Here is how it looks like in the terminal:&lt;/p>
&lt;p>&lt;img src="http://blog.pecar.me/pics/django-5-2-warning_hu_7ee6597a43b56222.webp" alt="Warning in the terminal" loading="lazy" width="902" height="480">&lt;/p>
&lt;p>The warning is helpful for newcomers because Django&amp;rsquo;s development server is neither secure nor performant enough to be exposed to the internet.&lt;/p></description></item><item><title>Autogenerating og:images with Jekyll</title><link>http://blog.pecar.me/autogenerating-og-image-with-jekyll/</link><pubDate>Tue, 10 Jun 2025 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/autogenerating-og-image-with-jekyll/</guid><description>&lt;p>This blog has been a static site powered by &lt;a href="https://jekyllrb.com/">Jekyll&lt;/a> for &lt;a href="https://blog.pecar.me/why-i-chose-jekyll">over 13 years&lt;/a>, and I&amp;rsquo;ve been happy with the setup. After all this time, I still enjoy using my code editor to write new posts and &lt;code>git commit&lt;/code> and &lt;code>git push&lt;/code> to publish them.&lt;/p>
&lt;p>However, there was one issue that often discouraged me from writing: I had to switch out of the code editor to generate the Open Graph image that appears on social media when I share the link to the blog post. For this particular blog post, this image looks like this:&lt;/p></description></item><item><title>Power Outages and Gunicorn PID Files</title><link>http://blog.pecar.me/pid-files/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/pid-files/</guid><description>After a power outage, some of my Gunicorn jobs failed to start correctly. In this blog post, I explain why it happened and how I solved it.</description></item><item><title>UV with Django</title><link>http://blog.pecar.me/uv-with-django/</link><pubDate>Thu, 29 Aug 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/uv-with-django/</guid><description>Using UV to manage dependencies of your Django application.</description></item><item><title>Go-like Error Handling Makes No Sense in JavaScript or Python</title><link>http://blog.pecar.me/go-errors-in-python/</link><pubDate>Fri, 16 Aug 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/go-errors-in-python/</guid><description>Adding special syntax to Javascript or Python to allow Go-like error handling feels like a good idea at first glance, but I think it doesn&amp;rsquo;t improve the issues with error handling in these two languages.</description></item><item><title>Packages Do Not Match the Hashes Pip Error</title><link>http://blog.pecar.me/pip-packages-do-not-match-hashes/</link><pubDate>Fri, 02 Aug 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/pip-packages-do-not-match-hashes/</guid><description>pip sometimes returns a checksum error when the urllib3 library is unable to parse a received TLS packet due to a network error. This pip issue will be resolved in 2025 when Python 3.9 is EOL, but you can get around it today by using wget or curl.</description></item><item><title>Gotchas with SQLite in Production</title><link>http://blog.pecar.me/sqlite-prod/</link><pubDate>Wed, 17 Jul 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/sqlite-prod/</guid><description>What you need to know before putting SQLite in production</description></item><item><title>Fedidevs Dev Update #2</title><link>http://blog.pecar.me/fedidevs-update-2/</link><pubDate>Mon, 17 Jun 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/fedidevs-update-2/</guid><description>June update for fedidevs.com!</description></item><item><title>Django SQLite Production Config</title><link>http://blog.pecar.me/sqlite-django-config/</link><pubDate>Fri, 14 Jun 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/sqlite-django-config/</guid><description>Optimize your Django SQLite configuration for production.</description></item><item><title>Django Streaming HTTP Responses</title><link>http://blog.pecar.me/django-streaming-responses/</link><pubDate>Thu, 21 Mar 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/django-streaming-responses/</guid><description>How and when to use Streaming HTTP responses and when not to.</description></item><item><title>Deploying a Django Project to My Raspberry Pi (Video)</title><link>http://blog.pecar.me/rpi-django-youtube/</link><pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/rpi-django-youtube/</guid><description>I made a video of me deploying a new Django project to my Raspberry Pi.</description></item><item><title>Thoughts on Code Reviews</title><link>http://blog.pecar.me/code-reviews/</link><pubDate>Wed, 06 Mar 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/code-reviews/</guid><description>My thoughts on code reviews.</description></item><item><title>Django SQLite Benchmark</title><link>http://blog.pecar.me/django-sqlite-benchmark/</link><pubDate>Tue, 06 Feb 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/django-sqlite-benchmark/</guid><description>How to configure SQLite for better throughput with Django.</description></item><item><title>Django, SQLite, and the Database Is Locked Error</title><link>http://blog.pecar.me/django-sqlite-dblock/</link><pubDate>Tue, 16 Jan 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/django-sqlite-dblock/</guid><description>Explains &lt;code>database is locked&lt;/code> errors in Django when using SQLite, and how to solve them.</description></item><item><title>No Downtime Deployments with Gunicorn</title><link>http://blog.pecar.me/gunicorn-restart/</link><pubDate>Tue, 02 Jan 2024 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/gunicorn-restart/</guid><description>This article shows how to achieve zero-downtime deploys of your Django, Flaks, or FastAPI app using only Gunicorn. It explains how to reload the Gunicorn process with the -HUP signal using systemd or the kill command directly making sure no requests are dropped during the upgrade.</description></item><item><title>SQLite Write-Ahead Logging</title><link>http://blog.pecar.me/sqlite-wal/</link><pubDate>Fri, 03 Nov 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/sqlite-wal/</guid><description>Speed up your SQLite writes and reads with this crazy trick. 🤪</description></item><item><title>Writing a Pytest Plugin</title><link>http://blog.pecar.me/pytest-plugin/</link><pubDate>Fri, 06 Oct 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/pytest-plugin/</guid><description>How to write a simple pytest plugin.</description></item><item><title>Fedidevs Dev Update #1</title><link>http://blog.pecar.me/fedidevs-posts/</link><pubDate>Sat, 16 Sep 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/fedidevs-posts/</guid><description>Discover the most favorited posts from developers on Mastodon with Fedidevs Posts.</description></item><item><title>Django-TUI: A Text User Interface for Django Commands</title><link>http://blog.pecar.me/django-tui/</link><pubDate>Fri, 25 Aug 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/django-tui/</guid><description>How I&amp;rsquo;ve built django-tui</description></item><item><title>Automate Hatch Publish with GitHub Actions</title><link>http://blog.pecar.me/automate-hatch-publish/</link><pubDate>Fri, 18 Aug 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/automate-hatch-publish/</guid><description>Scribbling down how I automated publishing to PyPI with GitHub Actions.</description></item><item><title>Words TUI: App for Daily Writing</title><link>http://blog.pecar.me/words-tui/</link><pubDate>Fri, 11 Aug 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/words-tui/</guid><description>I am coding a TUI application to help me with my daily writing.</description></item><item><title>Textual App Auto Reload</title><link>http://blog.pecar.me/textual-code-reload/</link><pubDate>Tue, 01 Aug 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/textual-code-reload/</guid><description>How to automatically reload your Textual app when code changes occur</description></item><item><title>RDS Blue/Green Deployments</title><link>http://blog.pecar.me/rds-blue-green/</link><pubDate>Sat, 01 Jul 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/rds-blue-green/</guid><description>Upgrading your database with Blue/Green deployments</description></item><item><title>Fly.io Certificate Renewal</title><link>http://blog.pecar.me/fly-ssl-error/</link><pubDate>Mon, 19 Jun 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/fly-ssl-error/</guid><description>Ensure your SSL certificate doesn&amp;rsquo;t expire to avoid downtime</description></item><item><title>Using Testing Library with Selenium in Python</title><link>http://blog.pecar.me/selenium-testing-library/</link><pubDate>Mon, 30 Jan 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/selenium-testing-library/</guid><description>Why and how to use the Testing Library with Selenium in Python.</description></item><item><title>The Fastest Way to Build a Read-only JSON API</title><link>http://blog.pecar.me/faster-api/</link><pubDate>Mon, 16 Jan 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/faster-api/</guid><description>A short story on how I managed to not overengineer a read-only JSON API.</description></item><item><title>import __hello__</title><link>http://blog.pecar.me/import-hello/</link><pubDate>Sat, 07 Jan 2023 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/import-hello/</guid><description>The &lt;code>import __hello__&lt;/code> easter egg in Python.</description></item><item><title>Enum with `str` or `int` Mixin Breaking Change in Python 3.11</title><link>http://blog.pecar.me/python-enum/</link><pubDate>Wed, 21 Dec 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/python-enum/</guid><description>A change in how Python handles &lt;code>str&lt;/code> and &lt;code>int&lt;/code> mixins in Enum classes might break your code when you upgrade to Python 3.11.</description></item><item><title>Your Code Doesn't Have to Be Perfect</title><link>http://blog.pecar.me/perfect-code/</link><pubDate>Mon, 21 Nov 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/perfect-code/</guid><description>An example of smelly code that served customers for over 6 years without issues before breaking.</description></item><item><title>Fixing _SixMetaPathImporter.find_spec() Not Found Warnings in Python 3.10</title><link>http://blog.pecar.me/six-warnings/</link><pubDate>Wed, 16 Nov 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/six-warnings/</guid><description>&lt;p>I am helping a client upgrade their Django application to Python 3.10 and we encountered this mysterious warning when running the app on the new Python version:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">frozen&lt;/span> &lt;span class="n">importlib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_bootstrap&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">914&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="ne">ImportWarning&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">_SixMetaPathImporter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_spec&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">found&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">falling&lt;/span> &lt;span class="n">back&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">find_module&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To make matters worse, this warning doesn&amp;rsquo;t only show up once, but more than 200 times when we run &lt;code>python manage.py runserver&lt;/code>. It completely floods the console output 😱&lt;/p>
&lt;p>A fair amount of googling revealed that the warnings are coming from the &lt;a href="https://pypi.org/project/six/">&lt;code>six&lt;/code> library&lt;/a>. Luckily, they patched the issue in &lt;a href="https://github.com/benjaminp/six/blob/master/CHANGES">version 1.16.0&lt;/a>. We just have to make sure we are running the latest version!&lt;/p></description></item><item><title>Upgrading Django App to Python 3.10</title><link>http://blog.pecar.me/upgrading-to-310/</link><pubDate>Thu, 11 Aug 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/upgrading-to-310/</guid><description>&lt;p>At my day job we have a Django app with almost &lt;code>500_000&lt;/code> lines of Python code that was written over the last decade. Ever since we migrated to Python 3.7 (almost seven months &lt;em>after&lt;/em> Python 2 EOL 😓), we&amp;rsquo;ve tried to keep on top on Python upgrades. We migrated to 3.9 at the end of last year, skipping 3.8 completely. It was now time for us to jump on Python 3.10.&lt;/p></description></item><item><title>Integer Overflow Error in a Python Application</title><link>http://blog.pecar.me/integer-overflow/</link><pubDate>Sat, 02 Jul 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/integer-overflow/</guid><description>How we found and fixed an integer overflow error in our Django app.</description></item><item><title>Python Dependency Management</title><link>http://blog.pecar.me/python-dependencies/</link><pubDate>Thu, 10 Feb 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/python-dependencies/</guid><description>Overview of common methods for managing Python dependencies</description></item><item><title>MySQL Performance Degradation in Django 3.1</title><link>http://blog.pecar.me/django-3-2/</link><pubDate>Fri, 21 Jan 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/django-3-2/</guid><description>Upgrading from Django 2.2 to Django 3.2 caused a severe performance degradation with MySQL 5.7 due to a bug introduced in Django 3.1.</description></item><item><title>New Features in Python 3.8 and 3.9</title><link>http://blog.pecar.me/python-3-9/</link><pubDate>Fri, 07 Jan 2022 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/python-3-9/</guid><description>Highlighting some of the new features in Python 3.8 and 3.9.</description></item><item><title>The Code Review Batch Size</title><link>http://blog.pecar.me/batch-size/</link><pubDate>Tue, 13 Aug 2019 00:00:00 +0000</pubDate><guid>http://blog.pecar.me/batch-size/</guid><description>&lt;p>In the &lt;a href="http://blog.pecar.me/the-code-review-bottleneck">last article&lt;/a> we learned how important it is to reduce the friction in code reviews, by making code reviews your top priority. Based on the &lt;a href="https://en.wikipedia.org/wiki/Theory_of_constraints">theory of constraints&lt;/a>, not working on the bottleneck is counterproductive. If your code review queue is backed up, writing more code will not make you deploy features any faster!&lt;/p>
&lt;p>The theory of constraints doesn&amp;rsquo;t only help us figure out what to focus on, but it also has a solution for increasing throughput: Decrease your batch size as much as possible. For us developers, the batch size is the number of code changes that go into each release.&lt;/p></description></item></channel></rss>