{"@attributes":{"version":"2.0"},"channel":{"title":"Zahlblog","link":"https:\/\/zahlman.github.io\/","description":"Ramblings of a veteran Pythonista with a passion for refactoring and education.","language":"en","copyright":"Contents \u00a9 2022-2026 <a href=\"mailto:zahlman@proton.me\">Karl Knechtel<\/a> ","lastBuildDate":"Wed, 25 Feb 2026 22:08:14 GMT","generator":"Nikola (getnikola.com)","docs":"http:\/\/blogs.law.harvard.edu\/tech\/rss","item":[{"title":"Meta-automation","link":"https:\/\/zahlman.github.io\/posts\/meta-automation\/","description":"<div><p>One of the really fun things about <a href=\"https:\/\/zahlman.github.io\/posts\/leaning-in-to-my-ux\">switching to Linux<\/a> 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.<\/p>\n<p>Today I <a href=\"https:\/\/github.com\/zahlman\/func2cmd\/\">published<\/a> a couple of tiny tools I use to make my life easier, and I'd like to talk about them a little bit.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/meta-automation\/\">Read more\u2026<\/a> (9 min remaining to read)<\/p><\/div>","category":["bash","dev-philosophy","linux","python"],"guid":"https:\/\/zahlman.github.io\/posts\/meta-automation\/","pubDate":"Wed, 25 Feb 2026 05:00:00 GMT"},{"title":"Python Packaging \u5916\u4f1d\uff11: Oxidation and Radiation - The Rise of uv in 2025","link":"https:\/\/zahlman.github.io\/posts\/oxidation\/","description":"<div><p>Today I'm offering a sort of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Spinoff_%28media%29#Sidequels\">\"side story\"<\/a> 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.<\/p>\n<p>But I've been doing this in the shadow of <code>uv<\/code> existing, and <code>uv<\/code>'s <a href=\"https:\/\/www.star-history.com\/#astral-sh\/uv&amp;type=date&amp;legend=top-left\">momentum has been unstoppable this year<\/a>. 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 <a href=\"https:\/\/old.reddit.com\/r\/Python\/comments\/1isv37n\/is_uv_package_manager_taking_over\/\">people are switching<\/a> away from <code>pip<\/code> (and other tools) to <code>uv<\/code>.<\/p>\n<p>Which is unsurprising, given how positive the coverage has been overall. There have been <a href=\"https:\/\/hn.algolia.com\/?dateRange=pastYear&amp;page=0&amp;prefix=false&amp;query=uv&amp;sort=byPopularity&amp;type=story\">many<\/a> 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.<\/p>\n<p>So before the year is out, I really wanted to write down some thoughts about <code>uv<\/code>'s success so far and the impact it's had on me \u2014 which as it turns out is mostly <em>not<\/em> 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.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/oxidation\/\">Read more\u2026<\/a> (12 min remaining to read)<\/p><\/div>","category":["design","python","uv"],"guid":"https:\/\/zahlman.github.io\/posts\/oxidation\/","pubDate":"Wed, 31 Dec 2025 05:00:00 GMT"},{"title":"Python packaging: Why we can't have nice things - Part 3: Premature Compilation","link":"https:\/\/zahlman.github.io\/posts\/python-packaging-3\/","description":"<div><p>Pip 25.0 <a href=\"https:\/\/discuss.python.org\/t\/_\/78392\">has been out<\/a> for <a href=\"https:\/\/github.com\/pypa\/pip\/releases\/tag\/25.0\">a bit over a month now<\/a>; and we now also have an <a href=\"https:\/\/ichard26.github.io\/blog\/2025\/01\/whats-new-in-pip-25.0\/\">official blog post<\/a> about the release, as well as a 25.0.1 patch for a regression.<\/p>\n<p>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 <em>in many more situations than you might naively expect<\/em>. I think it's obvious that running arbitrary code <em>when you aren't expecting it and prepared for it<\/em> is a much bigger problem. The user should have a chance to decide whether to trust the code, first.<\/p>\n<p>I believe that warnings are more important than baiting people to read the post, so here's the PSA up front:<\/p>\n<ol>\n<li>\n<p><strong>Never use Pip to download, test, \"dry-run\" etc. an untrusted source distribution (sdist).<\/strong> <a href=\"https:\/\/github.com\/pypa\/pip\/issues\/1884\">It will try to build the package<\/a>, <strong>potentially running arbitrary code<\/strong> (as building an sdist always entails). Instead, use the <a href=\"https:\/\/pypi.org\">PyPI website<\/a> directly, or the <a href=\"https:\/\/docs.pypi.org\/api\/json\/\">API<\/a> it provides.<\/p>\n<\/li>\n<li>\n<p><strong>Never use <code>sudo<\/code> to run Pip<\/strong> (nor run it with administrative privileges on Windows). Aside from the potential problems caused by conflicting with the system package manager, Pip <a href=\"https:\/\/github.com\/pypa\/pip\/issues\/11034\"><strong>will not drop privileges<\/strong><\/a> when it runs as root and attempts to build an sdist - which again, <strong>potentially runs arbitrary code<\/strong>.<\/p>\n<\/li>\n<li>\n<p>If you expect wheels to be available for the packages you want to install with Pip, <strong>strongly consider adding <code>--only-binary=:all:<\/code> to the Pip command<\/strong> 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.<\/p>\n<\/li>\n<li>\n<p>If you release Python packages, <a href=\"https:\/\/pradyunsg.me\/blog\/2022\/12\/31\/wheels-are-faster-pure-python\/\">please try to provide wheels for them<\/a>, even if - no, <em>especially<\/em> if your package includes only Python code and doesn't require explicitly \"compiling\" anything. An sdist is <em>much<\/em> 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.<\/p>\n<\/li>\n<\/ol>\n<p>Okay, I did clickbait a bit. This security issue <em>isn't<\/em> some new discovery. In fact, it has plagued Pip <em>for its entire history<\/em>.<\/p>\n<p>Please enjoy my detailed analysis below.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/python-packaging-3\/\">Read more\u2026<\/a> (33 min remaining to read)<\/p><\/div>","category":["pip","python","security","setuptools"],"guid":"https:\/\/zahlman.github.io\/posts\/python-packaging-3\/","pubDate":"Fri, 28 Feb 2025 05:00:00 GMT"},{"title":"Leaning IN to my U\/X","link":"https:\/\/zahlman.github.io\/posts\/leaning-in-to-my-ux\/","description":"<div><div class=\"code\"><pre class=\"code literal-block\">$<span class=\"w\"> <\/span>stat<span class=\"w\"> <\/span>\/<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>grep<span class=\"w\"> <\/span>Birth<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>cut<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span><span class=\"s1\">' '<\/span><span class=\"w\"> <\/span>-f<span class=\"w\"> <\/span><span class=\"m\">3<\/span>\n<span class=\"m\">2022<\/span>-01-24\n<\/pre><\/div>\n\n<p>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.<\/p>\n<p>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 <a href=\"https:\/\/www.pcworld.com\/article\/2508289\/windows-11-market-share-grows-but-windows-10-still-twice-as-popular.html\">still comfortably in the majority<\/a> - unless something has radically changed in the last few months.)<\/p>\n<p>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.<\/p>\n<p>And I never looked back.<\/p>\n<p>Today, I'd like to relate a few anecdotes about that experience.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/leaning-in-to-my-ux\/\">Read more\u2026<\/a> (10 min remaining to read)<\/p><\/div>","category":["linux","personal"],"guid":"https:\/\/zahlman.github.io\/posts\/leaning-in-to-my-ux\/","pubDate":"Fri, 24 Jan 2025 05:00:00 GMT"},{"title":"A Brief Annotation","link":"https:\/\/zahlman.github.io\/posts\/a-brief-annotation\/","description":"<p>I've been quite busy working on both the next article in my <a href=\"https:\/\/zahlman.github.io\/tags-and-series\/series-python-packaging\">packaging series<\/a> and on the overall appearance of the blog (I wasn't able to keep that confined to the weekend, apparently).<\/p>\n<p>So, today, just a quick note, on the occasion of the 4th anniversary of the creation of <a href=\"https:\/\/peps.python.org\/pep-0649\/\">PEP 649<\/a> \"Deferred Evaluation Of Annotations Using Descriptors\".<\/p>\n<p>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 <a href=\"https:\/\/discuss.python.org\/t\/_\/21331\/43\">was supposed to be added for 3.13, but didn't make it in<\/a>.) 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.<\/p>\n<p>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, <a href=\"https:\/\/zahlman.github.io\/tags-and-series\/series-python-discourse-ban\">when I was new to the Python Discourse forum<\/a>, I came across Mr. Hastings' post, puzzling over the best way to name what will soon become the <code>__annotate__<\/code> attribute of annotated objects.<\/p>\n<p>The name <code>__annotate__<\/code> <a href=\"https:\/\/discuss.python.org\/t\/_\/25672\/4\">was my suggestion<\/a>.<\/p>\n<p>I was not credited in the PEP, and I <a href=\"https:\/\/discuss.python.org\/t\/_\/25672\/61\">was ignored<\/a> when I tried to point this out. So it falls to me to draw attention to my contribution.<\/p>\n<p>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.<\/p>","category":"python","guid":"https:\/\/zahlman.github.io\/posts\/a-brief-annotation\/","pubDate":"Sat, 11 Jan 2025 05:00:00 GMT"},{"title":"Python Packaging: Why we can't have nice things - Part 2: Stupid Pipx Tricks","link":"https:\/\/zahlman.github.io\/posts\/python-packaging-2\/","description":"<div><p>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. <a href=\"https:\/\/pipx.pypa.io\/stable\/\">Pipx<\/a> (now <a href=\"https:\/\/packaging.python.org\/en\/latest\/key_projects\/#pipx\">under<\/a> the <a href=\"https:\/\/www.pypa.io\/en\/latest\/\">Python Packaging Authority (PyPA)<\/a> umbrella) is a focused wrapper around Pip that handles the major pain points without trying to take over your entire workflow.<\/p>\n<p>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.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/python-packaging-2\/\">Read more\u2026<\/a> (9 min remaining to read)<\/p><\/div>","category":["pip","pipx","python"],"guid":"https:\/\/zahlman.github.io\/posts\/python-packaging-2\/","pubDate":"Tue, 07 Jan 2025 05:00:00 GMT"},{"title":"New year, new blog","link":"https:\/\/zahlman.github.io\/posts\/new-year-new-blog\/","description":"<div><p>You're not imagining things - the blog has a whole new look, in large part as a result of switching to the <a href=\"https:\/\/getnikola.com\">Nikola<\/a> site generator.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/new-year-new-blog\/\">Read more\u2026<\/a> (2 min remaining to read)<\/p><\/div>","category":["jekyll","meta","nikola","python"],"guid":"https:\/\/zahlman.github.io\/posts\/new-year-new-blog\/","pubDate":"Wed, 01 Jan 2025 05:00:00 GMT"},{"title":"fixup! added list - The rest of the TODOwl","link":"https:\/\/zahlman.github.io\/posts\/todo-list-2\/","description":"<div><p>Happy new year to all.<\/p>\n<p>Today's post is about a folder on my desktop named <code>dev<\/code>. 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.)<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/todo-list-2\/\">Read more\u2026<\/a> (20 min remaining to read)<\/p><\/div>","category":["meta","personal","python"],"guid":"https:\/\/zahlman.github.io\/posts\/todo-list-2\/","pubDate":"Tue, 31 Dec 2024 05:00:00 GMT"},{"title":"Python packaging: Why we can't have nice things - Part 1: The Old Refrain","link":"https:\/\/zahlman.github.io\/posts\/python-packaging-1\/","description":"<div><p>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 <em>don't<\/em> resonate with me.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/python-packaging-1\/\">Read more\u2026<\/a> (21 min remaining to read)<\/p><\/div>","category":["pip","python","virtual-environments"],"guid":"https:\/\/zahlman.github.io\/posts\/python-packaging-1\/","pubDate":"Tue, 24 Dec 2024 05:00:00 GMT"},{"title":"# TODO: finish todo list","link":"https:\/\/zahlman.github.io\/posts\/todo-finish-todo-list\/","description":"<div><p>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.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<p><a href=\"https:\/\/zahlman.github.io\/posts\/todo-finish-todo-list\/\">Read more\u2026<\/a> (7 min remaining to read)<\/p><\/div>","category":["meta","personal"],"guid":"https:\/\/zahlman.github.io\/posts\/todo-finish-todo-list\/","pubDate":"Fri, 20 Dec 2024 05:00:00 GMT"}]}}