<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Zahlblog</title><link>https://zahlman.github.io/</link><description>Ramblings of a veteran Pythonista with a passion for refactoring and education.</description><atom:link href="https://zahlman.github.io/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2022-2026 &lt;a href="mailto:zahlman@proton.me"&gt;Karl Knechtel&lt;/a&gt; </copyright><lastBuildDate>Wed, 25 Feb 2026 22:08:14 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Meta-automation</title><link>https://zahlman.github.io/posts/meta-automation/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;One of the really fun things about &lt;a href="https://zahlman.github.io/posts/leaning-in-to-my-ux"&gt;switching to Linux&lt;/a&gt; is realizing just how much you can accomplish with a few lines of Bash. Especially when those lines are taking advantage of, not just built-in programs, but other things you made before.&lt;/p&gt;
&lt;p&gt;Today I &lt;a href="https://github.com/zahlman/func2cmd/"&gt;published&lt;/a&gt; a couple of tiny tools I use to make my life easier, and I'd like to talk about them a little bit.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/meta-automation/"&gt;Read more…&lt;/a&gt; (9 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>bash</category><category>dev-philosophy</category><category>linux</category><category>python</category><guid>https://zahlman.github.io/posts/meta-automation/</guid><pubDate>Wed, 25 Feb 2026 05:00:00 GMT</pubDate></item><item><title>Python Packaging 外伝１: Oxidation and Radiation - The Rise of uv in 2025</title><link>https://zahlman.github.io/posts/oxidation/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;Today I'm offering a sort of &lt;a href="https://en.wikipedia.org/wiki/Spinoff_%28media%29#Sidequels"&gt;"side story"&lt;/a&gt; to my main series on Python packaging. The main thrust of the series has been that everything is broken or historically has been broken; but I've also been trying to fight some common misconceptions and defend some things that people don't seem to like but which are actually quite reasonable in context.&lt;/p&gt;
&lt;p&gt;But I've been doing this in the shadow of &lt;code&gt;uv&lt;/code&gt; existing, and &lt;code&gt;uv&lt;/code&gt;'s &lt;a href="https://www.star-history.com/#astral-sh/uv&amp;amp;type=date&amp;amp;legend=top-left"&gt;momentum has been unstoppable this year&lt;/a&gt;. Of course there were many adopters in 2024 as well, but we're now seeing more and more evidence in PyPI stats, surveys, CI pipelines etc. that &lt;a href="https://old.reddit.com/r/Python/comments/1isv37n/is_uv_package_manager_taking_over/"&gt;people are switching&lt;/a&gt; away from &lt;code&gt;pip&lt;/code&gt; (and other tools) to &lt;code&gt;uv&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Which is unsurprising, given how positive the coverage has been overall. There have been &lt;a href="https://hn.algolia.com/?dateRange=pastYear&amp;amp;page=0&amp;amp;prefix=false&amp;amp;query=uv&amp;amp;sort=byPopularity&amp;amp;type=story"&gt;many&lt;/a&gt; popular posts about it on Hacker News this year (I wouldn't mind adding to the pile!) and everyone is touting its features and praising their experience with it.&lt;/p&gt;
&lt;p&gt;So before the year is out, I really wanted to write down some thoughts about &lt;code&gt;uv&lt;/code&gt;'s success so far and the impact it's had on me — which as it turns out is mostly &lt;em&gt;not&lt;/em&gt; about actually using it. This will mostly be gathering things that I've already said repeatedly in the aforementioned threads, but I think there's value to that.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/oxidation/"&gt;Read more…&lt;/a&gt; (12 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>design</category><category>python</category><category>uv</category><guid>https://zahlman.github.io/posts/oxidation/</guid><pubDate>Wed, 31 Dec 2025 05:00:00 GMT</pubDate></item><item><title>Python packaging: Why we can't have nice things - Part 3: Premature Compilation</title><link>https://zahlman.github.io/posts/python-packaging-3/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;Pip 25.0 &lt;a href="https://discuss.python.org/t/_/78392"&gt;has been out&lt;/a&gt; for &lt;a href="https://github.com/pypa/pip/releases/tag/25.0"&gt;a bit over a month now&lt;/a&gt;; and we now also have an &lt;a href="https://ichard26.github.io/blog/2025/01/whats-new-in-pip-25.0/"&gt;official blog post&lt;/a&gt; about the release, as well as a 25.0.1 patch for a regression.&lt;/p&gt;
&lt;p&gt;Pip 25.0 has what I consider a very serious security vulnerability. In the Python ecosystem, it's normal and expected that third-party packages provide their own, arbitrary "setup" code for installation (for example, to run C compilers in project-specific ways, when the code uses a C extension). But Pip will run such code &lt;em&gt;in many more situations than you might naively expect&lt;/em&gt;. I think it's obvious that running arbitrary code &lt;em&gt;when you aren't expecting it and prepared for it&lt;/em&gt; is a much bigger problem. The user should have a chance to decide whether to trust the code, first.&lt;/p&gt;
&lt;p&gt;I believe that warnings are more important than baiting people to read the post, so here's the PSA up front:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Never use Pip to download, test, "dry-run" etc. an untrusted source distribution (sdist).&lt;/strong&gt; &lt;a href="https://github.com/pypa/pip/issues/1884"&gt;It will try to build the package&lt;/a&gt;, &lt;strong&gt;potentially running arbitrary code&lt;/strong&gt; (as building an sdist always entails). Instead, use the &lt;a href="https://pypi.org"&gt;PyPI website&lt;/a&gt; directly, or the &lt;a href="https://docs.pypi.org/api/json/"&gt;API&lt;/a&gt; it provides.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Never use &lt;code&gt;sudo&lt;/code&gt; to run Pip&lt;/strong&gt; (nor run it with administrative privileges on Windows). Aside from the potential problems caused by conflicting with the system package manager, Pip &lt;a href="https://github.com/pypa/pip/issues/11034"&gt;&lt;strong&gt;will not drop privileges&lt;/strong&gt;&lt;/a&gt; when it runs as root and attempts to build an sdist - which again, &lt;strong&gt;potentially runs arbitrary code&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you expect wheels to be available for the packages you want to install with Pip, &lt;strong&gt;strongly consider adding &lt;code&gt;--only-binary=:all:&lt;/code&gt; to the Pip command&lt;/strong&gt; to ensure that only wheels are used. If you really need to use sdists, it's wise to inspect them first, which by definition isn't possible with a fully automated installation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you release Python packages, &lt;a href="https://pradyunsg.me/blog/2022/12/31/wheels-are-faster-pure-python/"&gt;please try to provide wheels for them&lt;/a&gt;, even if - no, &lt;em&gt;especially&lt;/em&gt; if your package includes only Python code and doesn't require explicitly "compiling" anything. An sdist is &lt;em&gt;much&lt;/em&gt; slower to install than a wheel even in these cases, and making a wheel available allows your users to demand wheels from Pip - raising the overall baseline for trust and safety in the Python ecosystem.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Okay, I did clickbait a bit. This security issue &lt;em&gt;isn't&lt;/em&gt; some new discovery. In fact, it has plagued Pip &lt;em&gt;for its entire history&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Please enjoy my detailed analysis below.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/python-packaging-3/"&gt;Read more…&lt;/a&gt; (33 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>pip</category><category>python</category><category>security</category><category>setuptools</category><guid>https://zahlman.github.io/posts/python-packaging-3/</guid><pubDate>Fri, 28 Feb 2025 05:00:00 GMT</pubDate></item><item><title>Leaning IN to my U/X</title><link>https://zahlman.github.io/posts/leaning-in-to-my-ux/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;stat&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Birth&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="m"&gt;2022&lt;/span&gt;-01-24
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Today (although this won't go live until the 25th in my time zone) is three years since the day I finally kicked Windows to the curb and installed Linux on my home desktop. I'd used Linux before, but all my life I'd had a habit of just using whatever OS was provided to me, without really giving it much thought.&lt;/p&gt;
&lt;p&gt;In late 2021, Windows Update told me - entirely unprompted - that my system didn't meet minimum specs to run Windows 11. (Perhaps it would now - I understand that the declared requirements have been relaxed, even if nothing has been optimized or stripped down - but I don't care to check. I'm also told that people still on Windows 10 are under increasing pressure to switch, even though they're &lt;a href="https://www.pcworld.com/article/2508289/windows-11-market-share-grows-but-windows-10-still-twice-as-popular.html"&gt;still comfortably in the majority&lt;/a&gt; - unless something has radically changed in the last few months.)&lt;/p&gt;
&lt;p&gt;I found this impolite - as I hadn't asked, and didn't consider anything wrong or inadequate about my computer - and a bit absurd (whatever they're offering now that requires more computing power, I'm not interested; especially not if it's anything to do with Cortana). So I took that as my queue to switch. I bought a new SSD (figuring I would need the space anyway) and attempted to set up a dual boot - GRUB never worked properly for me, but I could still use the BIOS screen to boot Windows from the old SSD.&lt;/p&gt;
&lt;p&gt;And I never looked back.&lt;/p&gt;
&lt;p&gt;Today, I'd like to relate a few anecdotes about that experience.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/leaning-in-to-my-ux/"&gt;Read more…&lt;/a&gt; (10 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>linux</category><category>personal</category><guid>https://zahlman.github.io/posts/leaning-in-to-my-ux/</guid><pubDate>Fri, 24 Jan 2025 05:00:00 GMT</pubDate></item><item><title>A Brief Annotation</title><link>https://zahlman.github.io/posts/a-brief-annotation/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;p&gt;I've been quite busy working on both the next article in my &lt;a href="https://zahlman.github.io/tags-and-series/series-python-packaging"&gt;packaging series&lt;/a&gt; and on the overall appearance of the blog (I wasn't able to keep that confined to the weekend, apparently).&lt;/p&gt;
&lt;p&gt;So, today, just a quick note, on the occasion of the 4th anniversary of the creation of &lt;a href="https://peps.python.org/pep-0649/"&gt;PEP 649&lt;/a&gt; "Deferred Evaluation Of Annotations Using Descriptors".&lt;/p&gt;
&lt;p&gt;Yes, that's a mouthful, but in short: starting in Python 3.14, if you use annotations, you'll be able to defer the evaluation of the annotation code. (The feature &lt;a href="https://discuss.python.org/t/_/21331/43"&gt;was supposed to be added for 3.13, but didn't make it in&lt;/a&gt;.) That means you don't have to rely on strings for forward references in your type annotations, but you can still make full use of annotations at runtime (you'll have a proper object for the annotation itself, rather than just a string). Thank you to core Python developer Mr. Larry Hastings for putting a tremendous amount of effort into refining this proposal.&lt;/p&gt;
&lt;p&gt;Now, I don't personally use type annotations very much - I don't use a type checker at all; I only write annotations as a form of documentation. But as it happened, &lt;a href="https://zahlman.github.io/tags-and-series/series-python-discourse-ban"&gt;when I was new to the Python Discourse forum&lt;/a&gt;, I came across Mr. Hastings' post, puzzling over the best way to name what will soon become the &lt;code&gt;__annotate__&lt;/code&gt; attribute of annotated objects.&lt;/p&gt;
&lt;p&gt;The name &lt;code&gt;__annotate__&lt;/code&gt; &lt;a href="https://discuss.python.org/t/_/25672/4"&gt;was my suggestion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was not credited in the PEP, and I &lt;a href="https://discuss.python.org/t/_/25672/61"&gt;was ignored&lt;/a&gt; when I tried to point this out. So it falls to me to draw attention to my contribution.&lt;/p&gt;
&lt;p&gt;This is all very niche stuff, of course - but I'm happy to have been able to leave this mark on the Python language itself, as opposed to just making useful things with it.&lt;/p&gt;</description><category>python</category><guid>https://zahlman.github.io/posts/a-brief-annotation/</guid><pubDate>Sat, 11 Jan 2025 05:00:00 GMT</pubDate></item><item><title>Python Packaging: Why we can't have nice things - Part 2: Stupid Pipx Tricks</title><link>https://zahlman.github.io/posts/python-packaging-2/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;Pip has a lot of problems (that I'll be discussing in future posts in this series), but the good news is that you don't have to resort to heavyweight third-party tools to improve your experience with Python packaging. &lt;a href="https://pipx.pypa.io/stable/"&gt;Pipx&lt;/a&gt; (now &lt;a href="https://packaging.python.org/en/latest/key_projects/#pipx"&gt;under&lt;/a&gt; the &lt;a href="https://www.pypa.io/en/latest/"&gt;Python Packaging Authority (PyPA)&lt;/a&gt; umbrella) is a focused wrapper around Pip that handles the major pain points without trying to take over your entire workflow.&lt;/p&gt;
&lt;p&gt;In this post I'll talk about Pipx's major use cases, its limitations, and how to get more mileage out of it with a few simple tweaks.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/python-packaging-2/"&gt;Read more…&lt;/a&gt; (9 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>pip</category><category>pipx</category><category>python</category><guid>https://zahlman.github.io/posts/python-packaging-2/</guid><pubDate>Tue, 07 Jan 2025 05:00:00 GMT</pubDate></item><item><title>New year, new blog</title><link>https://zahlman.github.io/posts/new-year-new-blog/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;You're not imagining things - the blog has a whole new look, in large part as a result of switching to the &lt;a href="https://getnikola.com"&gt;Nikola&lt;/a&gt; site generator.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/new-year-new-blog/"&gt;Read more…&lt;/a&gt; (2 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>jekyll</category><category>meta</category><category>nikola</category><category>python</category><guid>https://zahlman.github.io/posts/new-year-new-blog/</guid><pubDate>Wed, 01 Jan 2025 05:00:00 GMT</pubDate></item><item><title>fixup! added list - The rest of the TODOwl</title><link>https://zahlman.github.io/posts/todo-list-2/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;Happy new year to all.&lt;/p&gt;
&lt;p&gt;Today's post is about a folder on my desktop named &lt;code&gt;dev&lt;/code&gt;. It's where I've kept (for many years, well into my Windows-using days, even into the era when I used SVN rather than Git) all my working copies for my own projects (and forks of others'), mostly Python code of course. (I'm not sure how I organized things at the time, but there are projects in there dating back to 2006.)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/todo-list-2/"&gt;Read more…&lt;/a&gt; (20 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>meta</category><category>personal</category><category>python</category><guid>https://zahlman.github.io/posts/todo-list-2/</guid><pubDate>Tue, 31 Dec 2024 05:00:00 GMT</pubDate></item><item><title>Python packaging: Why we can't have nice things - Part 1: The Old Refrain</title><link>https://zahlman.github.io/posts/python-packaging-1/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;This post is a start of a series I've planned about how packaging currently works in Python, what's wrong with it, and how to cope with the problems. But before I get into the meat of it, I want to talk about common complaints that &lt;em&gt;don't&lt;/em&gt; resonate with me.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/python-packaging-1/"&gt;Read more…&lt;/a&gt; (21 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>pip</category><category>python</category><category>virtual-environments</category><guid>https://zahlman.github.io/posts/python-packaging-1/</guid><pubDate>Tue, 24 Dec 2024 05:00:00 GMT</pubDate></item><item><title># TODO: finish todo list</title><link>https://zahlman.github.io/posts/todo-finish-todo-list/</link><dc:creator>Karl Knechtel</dc:creator><description>&lt;div&gt;&lt;p&gt;This is a difficult post to write, largely because of the self-critique involved. Which is part of why I've been putting it off. For months, if I'm honest with myself.&lt;/p&gt;
&lt;p&gt;But putting it off has only made it harder to write. I also seem to have reached a point where it psychologically feels impossible to publish anything else here first. So, I'm finally forcing myself to write it now - during the holiday season, to prove to myself that I can.&lt;/p&gt;
&lt;p&gt;It's no secret that the history of this blog so far has been dominantly one of false starts. Please allow me a moment to explain how that came to be.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zahlman.github.io/posts/todo-finish-todo-list/"&gt;Read more…&lt;/a&gt; (7 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>meta</category><category>personal</category><guid>https://zahlman.github.io/posts/todo-finish-todo-list/</guid><pubDate>Fri, 20 Dec 2024 05:00:00 GMT</pubDate></item></channel></rss>