Planet Python
Last update: February 17, 2026 10:44 AM UTC
February 17, 2026
Python Software Foundation
Join the Python Security Response Team!
February 17, 2026 02:30 AM UTC
February 16, 2026
Chris Warrick
I Wrote YetAnotherBlogGenerator
Writing a static site generator is a developer rite of passage. For the past 13 years, this blog was generated using Nikola. This week, I finished implementing my own generator, the unoriginally named YetAnotherBlogGenerator. Why would I do that? Why would I use C# for it? And how fast is it? Continue reading to find out.
February 16, 2026 09:15 PM UTC
Anarcat
Keeping track of decisions using the ADR model
In the Tor Project system Administrator's team (colloquially known as TPA), we've recently changed how we take decisions, which means you'll get clearer communications from us about upcoming changes or targeted questions about a proposal.
Note that this change only affects the TPA team. At Tor, each team has its own way of coordinating and making decisions, and so far this process is only used inside TPA. We encourage other teams inside and outside Tor to evaluate this process to see if it can improve your processes and documentation.
The new process
We had traditionally been using a "RFC" ("Request For Comments") process and have recently switched to "ADR" ("Architecture Decision Record").
The ADR process is, for us, pretty simple. It consists of three things:
- a simpler template
- a simpler process
- communication guidelines separate from the decision record
The template
As team lead, the first thing I did was to propose a new template (in ADR-100), a variation of the Nygard template. The TPA variation of the template is similarly simple, as it has only 5 headings, and is worth quoting in full:
Context: What is the issue that we're seeing that is motivating this decision or change?
Decision: What is the change that we're proposing and/or doing?
Consequences: What becomes easier or more difficult to do because of this change?
More Information (optional): What else should we know? For larger projects, consider including a timeline and cost estimate, along with the impact on affected users (perhaps including existing Personas). Generally, this includes a short evaluation of alternatives considered.
Metadata: status, decision date, decision makers, consulted, informed users, and link to a discussion forum
The previous RFC template had 17 (seventeen!) headings, which encouraged much longer documents. Now, the decision record will be easier to read and digest at one glance.
An immediate effect of this is that I've started using GitLab issues more for comparisons and brainstorming. Instead of dumping in a document all sorts of details like pricing or in-depth alternatives comparison, we record those in the discussion issue, keeping the document shorter.
The process
The whole process is simple enough that it's worth quoting in full as well:
Major decisions are introduced to stakeholders in a meeting, smaller ones by email. A delay allows people to submit final comments before adoption.
Now, of course, the devil is in the details (and ADR-101), but the point is to keep things simple.
A crucial aspect of the proposal, which Jacob Kaplan-Moss calls the one weird trick, is to "decide who decides". Our previous process was vague about who makes the decision and the new template (and process) clarifies decision makers, for each decision.
Inversely, some decisions degenerate into endless discussions around trivial issues because too many stakeholders are consulted, a problem known as the Law of triviality, also known as the "Bike Shed syndrome".
The new process better identifies stakeholders:
- "informed" users (previously "affected users")
- "consulted" (previously undefined!)
- "decision maker" (instead of the vague "approval")
Picking those stakeholders is still tricky, but our definitions are more explicit and aligned to the classic RACI matrix (Responsible, Accountable, Consulted, Informed).
Communication guidelines
Finally, a crucial part of the process (ADR-102) is to decouple the act of making and recording decisions from communicating about the decision. Those are two radically different problems to solve. We have found that a single document can't serve both purposes.
Because ADRs can affect a wide range of things, we don't have a specific template for communications. We suggest the Five Ws method (Who? What? When? Where? Why?) and, again, to keep things simple.
How we got there
The ADR process is not something I invented. I first stumbled upon it in the Thunderbird Android project. Then, in parallel, I was in the process of reviewing the RFC process, following Jacob Kaplan-Moss's criticism of the RFC process. Essentially, he argues that:
- the RFC process "doesn't include any sort of decision-making framework"
- "RFC processes tend to lead to endless discussion"
- the process "rewards people who can write to exhaustion"
- "these processes are insensitive to expertise", "power dynamics and power structures"
And, indeed, I have been guilty of a lot of those issues. A verbose writer, I have written extremely long proposals that I suspect no one has ever fully read. Some proposals were adopted by exhaustion, or ignored because not looping in the right stakeholders.
Our discussion issue on the topic has more details on the issues I found with our RFC process. But to give credit to the old process, it did serve us well while it was there: it's better than nothing, and it allowed us to document a staggering number of changes and decisions (95 RFCs!) made over the course of 6 years of work.
What's next?
We're still experimenting with the communication around decisions, as this text might suggest. Because it's a separate step, we also have a tendency to forget or postpone it, like this post, which comes a couple of months late.
Previously, we'd just ship a copy of the RFC to everyone, which was easy and quick, but incomprehensible to most. Now we need to write a separate communication, which is more work but, hopefully, worth the as the result is more digestible.
We can't wait to hear what you think of the new process and how it works for you, here or in the discussion issue! We're particularly interested in people that are already using a similar process, or that will adopt one after reading this.
Note: this article was also published on the Tor Blog.
February 16, 2026 08:21 PM UTC
PyBites
We’re launching 60 Rust Exercises Designed for Python Devs
“Rust is too hard.” We hear it all the time from Python developers. But after building 60 Rust exercises specifically designed for Pythonistas, we’ve come to a clear conclusion: Rust isn’t harder than Python per se, it’s just a different challenge. And with the right bridges, you can learn it faster than you think. Why… Continue reading We’re launching 60 Rust Exercises Designed for Python Devs
February 16, 2026 03:41 PM UTC
Real Python
TinyDB: A Lightweight JSON Database for Small Projects
If you're looking for a JSON document-oriented database that requires no configuration for your Python project, TinyDB could be exactly what you need.
February 16, 2026 02:00 PM UTC
Quiz: TinyDB: A Lightweight JSON Database for Small Projects
If you're looking for a JSON document-oriented database that requires no configuration for your Python project, TinyDB could be what you need.
February 16, 2026 12:00 PM UTC
Tryton News
End of Windows 32-bit Builds
The MSYS2 project has discontinued building cx-Freeze for the mingw32 platform. We depend on these packages to build our Windows client, and we currently do not have the resources to maintain the required packages for Windows 32-bit ourselves.
As a result, we will no longer publish Windows 32-bit builds for new releases of the supported series.
1 post - 1 participant
February 16, 2026 07:00 AM UTC
Anarcat
Kernel-only network configuration on Linux
What if I told you there is a way to configure the network on any Linux server that:
- works across all distributions
- doesn't require any software installed apart from the kernel and a
boot loader (no
systemd-networkd,ifupdown,NetworkManager, nothing) - is backwards compatible all the way back to Linux 2.0, in 1996
It has literally 8 different caveats on top of that, but is still totally worth your time.
Known options in Debian
People following Debian development might have noticed there are now four ways of configuring the network Debian system. At least that is what the Debian wiki claims, namely:
ifupdown(/etc/network/interfaces): traditional static configuration system, mostly for workstations and servers that has been there forever in Debian (since at least 2000), documented in the Debian wikiNetworkManager: self-proclaimed "standard Linux network configuration", mostly used on desktops but technically supports servers as well, see the Debian wiki page (introduced in 2004)
systemd-network: used more for servers, see Debian reference Doc Chapter 5 (introduced some time around Debian 8 "jessie", in 2015)Netplan: latest entry (2018), YAML-based configuration abstraction layer on top of the above two, see also Debian reference Doc Chapter 5 and the Debian wiki
At this point, I feel ifupdown is on its way out, possibly replaced
by systemd-networkd. NetworkManager already manages most desktop
configurations.
A "new" network configuration system
The method is this:
ip=on the Linux kernel command line: for servers with a single IPv4 or IPv6 address, no software required other than the kernel and a boot loader (since 2002 or older)
So by "new" I mean "new to me". This option is really old. The
nfsroot.txtwhere it is documented predates the git import of the Linux kernel: it's part of the 2005 git import of 2.6.12-rc2. That's already 20+ years old already.The oldest trace I found is in this 2002 commit, which imports the whole file at once, but the option might goes back as far as 1996-1997, if the copyright on the file is correct and the option was present back then.
What are you doing.
The trick is to add an ip= parameter to the kernel's
command-line. The syntax, as mentioned above, is in nfsroot.txt
and looks like this:
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>:<ntp0-ip>
Most settings are pretty self-explanatory, if you ignore the useless ones:
<client-ip>: IP address of the server<gw-ip>: address of the gateway<netmask>: netmask, in quad notation<device>: interface name, if multiple available<autoconf>: how to configure the interface, namely:offornone: no autoconfiguration (static)onorany: use any protocol (default)dhcp, essentially likeonfor all intents and purposes
<dns0-ip>,<dns1-ip>: IP address of primary and secondary name servers, exported to/proc/net/pnp, can by symlinked to/etc/resolv.conf
We're ignoring the options:
<server-ip>: IP address of the NFS server, exported to/proc/net/pnp<hostnname>: Name of the client, typically sent over the DHCP requests, which may lead to a DNS record to be created in some networks<ntp0-ip>: exported to/proc/net/ipconfig/ntp_servers, unused by the kernel
Note that the Red Hat manual has a different opinion:
ip=[<server-id>]:<gateway-IP-number>:<netmask>:<client-hostname>:inteface:[dhcp|dhcp6|auto6|on|any|none|off]
It's essentially the same (although server-id is weird), and the
autoconf variable has other settings, so that's a bit odd.
Examples
For example, this command-line setting:
ip=192.0.2.42::192.0.2.1:255.255.255.0:::off
... will set the IP address to 192.0.2.42/24 and the gateway to 192.0.2.1. This will properly guess the network interface if there's a single one.
A DHCP only configuration will look like this:
ip=::::::dhcp
Of course, you don't want to type this by hand every time you boot the machine. That wouldn't work. You need to configure the kernel commandline, and that depends on your boot loader.
GRUB
With GRUB, you need to edit (on Debian), the file /etc/default/grub
(ugh) and find a line like:
GRUB_CMDLINE_LINUX=
and change it to:
GRUB_CMDLINE_LINUX=ip=::::::dhcp
systemd-boot and UKI setups
For systemd-boot UKI setups, it's simpler: just add the setting to
the /etc/kernel/cmdline file. Don't forget to include anything
that's non-default from /proc/cmdline.
This assumes that is the Cmdline=@ setting in
/etc/kernel/uki.conf. See 2025-08-20-luks-ukify-conversion for
my minimal documentation on this.
Other systems
This is perhaps where this is much less portable than it might first look, because of course each distribution has its own way of configuring those options. Here are some that I know of:
- Arch (11 options, mostly
/etc/default/grub,/boot/loader/entries/arch.confforsystemd-bootor/etc/kernel/cmdlinefor UKI) - Fedora (mostly
/etc/default/grub, may be more RHEL mentions grubby, possibly somesystemd-bootthings here as well) - Gentoo (5 options, mostly
/etc/default/grub,/efi/loader/entries/gentoo-sources-kernel.confforsystemd-boot, or/etc/kernel/install.d/95-uki-with-custom-opts.install)
It's interesting that /etc/default/grub is consistent across all
distributions above, while the systemd-boot setups are all over the
place (except for the UKI case), while I would have expected those be
more standard than GRUB.
dropbear-initramfs
If dropbear-initramfs is setup, it already requires you to have
such a configuration, and it might not work out of the box.
This is because, by default, it disables the interfaces configured in the kernel after completing its tasks (typically unlocking the encrypted disks).
To fix this, you need to disable that "feature":
IFDOWN="none"
This will keep dropbear-initramfs from disabling the configured
interface.
Why?
Traditionally, I've always setup my servers with ifupdown on servers
and NetworkManager on laptops, because that's essentially the
default. But on some machines, I've started using systemd-networkd
because ifupdown has ... issues, particularly with reloading network
configurations. ifupdown is a old hack, feels like legacy, and is
Debian-specific.
Not excited about configuring another service, I figured I would try something else: just configure the network at boot, through the kernel command-line.
I was already doing such configurations for dropbear-initramfs (see this documentation), which requires the network the be up for unlocking the full-disk encryption keys.
So in a sense, this is a "Don't Repeat Yourself" solution.
Caveats
Also known as: "wait, that works?" Yes, it does! That said...
This is useful for servers where the network configuration will not change after boot. Of course, this won't work on laptops or any mobile device.
This only works for configuring a single, simple, interface. You can't configure multiple interfaces, WiFi, bridges, VLAN, bonding, etc.
It does support IPv6 and feels like the best way to configure IPv6 hosts: true zero configuration.
It likely does not work with a dual-stack IPv4/IPv6 static configuration. It might work with a dynamic dual stack configuration, but I doubt it.
I don't know what happens when a DHCP lease expires. No daemon seems to be running so I assume leases are not renewed, so this is more useful for static configurations, which includes server-side reserved fixed IP addresses. (A non-renewed lease risks getting reallocated to another machine, which would cause an addressing conflict.)
It will not automatically reconfigure the interface on link changes, but
ifupdowndoes not either.It will not write
/etc/resolv.conffor you but thedns0-ipanddns1-ipdo end up in/proc/net/pnpwhich has a compatible syntax, so a common configuration is:ln -s /proc/net/pnp /etc/resolv.confI have not really tested this at scale: only a single, test server at home.
Yes, that's a lot of caveats, but it happens to cover a lot of machines for me, and it works surprisingly well. My main doubts are about long-term DHCP behaviour, but I don't see why that would be a problem with a statically defined lease.
Cleanup
Once you have this configuration, you don't need any "user" level network system, so you can get rid of everything:
apt purge systemd-networkd ifupdown network-manager netplan.io
Note that ifupdown (and probably others) leave stray files in (e.g.)
/etc/network which you might want to cleanup, or keep in case all
this fails and I have put you in utter misery. Configuration files for
other packages might also be left behind, I haven't tested this, no
warranty.
Credits
This whole idea came from the A/I folks (not to be confused with AI) who have been doing this forever, thanks!
February 16, 2026 04:18 AM UTC
PyBites
How to Automate Python Performance Benchmarking in Your CI/CD Pipeline
The issue with traditional performance tracking is that it is often an afterthought. We treat performance as a debugging task, (something we do after users complain), rather than a quality gate. Worse, when we try to automate it, we run into the “Noisy Neighbour” problem. If you run a benchmark in a GitHub Action, and… Continue reading How to Automate Python Performance Benchmarking in Your CI/CD Pipeline
February 16, 2026 12:42 AM UTC
February 13, 2026
Python Morsels
Setting default dictionary values in Python
There are many ways to set default values for dictionary key lookups in Python. Which way you should use will depend on your use case.
The get method: lookups with a default
The get method is the classic way to look up a value for a dictionary key without raising an exception for missing keys.
>>> quantities = {"pink": 3, "green": 4}
Instead of this:
try:
count = quantities[color]
except KeyError:
count = 0
Or this:
if color in quantities:
count = quantities[color]
else:
count = 0
We can do this:
count = quantities.get(color, 0)
Here's what this would do for a key that's in the dictionary and one that isn't:
>>> quantities.get("pink", 0)
3
>>> quantities.get("blue", 0)
0
The get method accepts two arguments: the key to look up and the default value to use if that key isn't in the dictionary.
The second argument defaults to None:
>>> quantities.get("pink")
3
>>> quantities.get("blue")
None
The setdefault method: setting a default
The get method doesn't modify …
Read the full article: https://www.pythonmorsels.com/default-dictionary-values/
February 13, 2026 04:45 PM UTC
Real Python
The Real Python Podcast – Episode #284: Running Local LLMs With Ollama and Connecting With Python
Would you like to learn how to work with LLMs locally on your own computer? How do you integrate your Python projects with a local model? Christopher Trudeau is back on the show this week with another batch of PyCoder's Weekly articles and projects.
February 13, 2026 12:00 PM UTC
Peter Hoffmann
Garmin Inreach Mini 2 Leaflet checkin map
February 13, 2026 12:00 AM UTC
Armin Ronacher
The Final Bottleneck
February 13, 2026 12:00 AM UTC
February 12, 2026
Real Python
Quiz: Python's list Data Type: A Deep Dive With Examples
Check your Python list skills with quick tasks on indexing, slicing, methods, copies, comprehensions, and pitfalls.
February 12, 2026 12:00 PM UTC
Python Software Foundation
Python is for Everyone: Inside the PSF's D&I Work Group
February 12, 2026 07:53 AM UTC
PyBites
The Vibe Coding trap
One of my readers replied to an email I sent a couple of weeks ago and we got into a brief discussion on what I’ll call, Skills Erosion. They brought up the point that by leaning too heavily on AI to generate code, people were losing their edge. It’s a good point that’s top of mind… Continue reading The Vibe Coding trap
February 12, 2026 12:15 AM UTC
Seth Michael Larson
Automated public shaming of open source maintainers
February 12, 2026 12:00 AM UTC
February 11, 2026
PyCharm
Python Unplugged on PyTV – A Free Online Python Conference for Everyone
The PyCharm team loves being part of the global Python community. From PyCon US to EuroPython to every PyCon in between, we enjoy the atmosphere at conferences, as well as meeting people who are as passionate about Python as we are. This includes everyone: professional Python developers, data scientists, Python hobbyists and students. However, we […]
February 11, 2026 04:37 PM UTC
Django Weblog
Django Steering Council 2025 Year in Review
The members of the Steering Council wanted to provide you all with a quick TL;DR of our work in 2025.
First off, we were elected at the end of 2024 and got started in earnest in early 2025 with the mission to revive and dramatically increase the role of the Steering Council.
We're meeting for a video conference at least monthly, you can deep dive into the meeting notes to see what we've been up to. We also have set up Slack channels we use to communicate in between meetings to keep action items moving along.
One of the first things we did was temporarily suspend much of the process around DEP 10. Its heart is in the right place, but it's just too complex and cumbersome day-to-day with a primarily volunteer organization. We're slowly making progress on a revamped and simplified process that addresses our concerns. It is our goal to finish this before our terms expire.
New Features Process
We've moved the process for proposing new features out of the Django Forum and mailing lists to new-features Github repository.
We made this change for a variety of reasons, but the largest being to reduce the workload for the Django Fellows in shepherding the process and answering related questions.
Community Ecosystem Page
One of our main goals is to increase the visibility of the amazing Django third-party package ecosystem. Long time Django users know which packages to use, which you can trust, and which ones may be perfect for certain use cases. However, MANY newer or more casual Django users are often unaware of these great tools and not sure where to even begin.
As a first step, we've added the Community Ecosystem page which highlights several amazing resources to keep in touch with what is going on with Django, how to find recommended packages, and a sample list of those packages the Steering Council itself recommends and uses frequently.
Administrative bits
There has been work on better formalizing and documenting our processes and building documentation to make it much easier for the next Steering Council members.
There has also been fair bit of work around helping organize Google Summer of Code participants to help ensure the projects undertaken are ones that will ultimately be accepted smoothly into Django.
Another area we have focused on is a simplified DEP process. We're still formalizing this, but the idea is to have the Steering Council do the majority of the heavy lifting on writing these and in a format that is shorter/simpler to reduce the friction of creating larger more complicated DEPs.
We have also been in discussions with various third parties about acquiring funding for some of the new features and updates on the horizon.
It's been a productive year and we're aiming to have 2026 be as productive if not more so. We're still setting all of our 2026 goals and will report on those soon.
Please reach out to the Steering Council directly if you have any questions or concerns.
February 11, 2026 02:44 PM UTC
Real Python
What Exactly Is the Zen of Python?
The Zen of Python is a collection of 19 guiding principles for writing good Python code. Learn its history, meaning, and hidden jokes.
February 11, 2026 02:00 PM UTC
Quiz: What Exactly Is the Zen of Python?
Learn and test the Zen of Python, its guiding aphorisms, and tips for writing clearer, more readable, and maintainable code.
February 11, 2026 12:00 PM UTC
Nicola Iarocci
Eve 2.2.5
Eve v2.2.5 was just released on PyPI. It brings the pagination fix discussed in a previous post. Many thanks to Calvin Smith per contributing to the project.
February 11, 2026 09:44 AM UTC
Python Morsels
Need switch-case in Python? It's not match-case!
Python's match-case is not a switch-case statement. If you need switch-case, you can often use a dictionary instead.
The power of match-case
Python's match statement is for structural pattern-matching, which sounds complicated because it is a bit complicated.
The match statement has a different way of parsing expressions within its case statements that's kind of an extension of the way that Python parses code in general.
And again, that sounds complex because it is.
I'll cover the full power of match-case another time, but let's quickly look at a few examples that demonstrate the power of match-case.
Matching iterables
Python's match statement can be …
Read the full article: https://www.pythonmorsels.com/switch-case-in-python/
February 11, 2026 12:00 AM UTC
Seth Michael Larson
Cooler Analytics
February 11, 2026 12:00 AM UTC
February 10, 2026
Talk Python to Me
#536: Fly inside FastAPI Cloud
You've built your FastAPI app, it's running great locally, and now you want to share it with the world. But then reality hits -- containers, load balancers, HTTPS certificates, cloud consoles with 200 options. What if deploying was just one command? That's exactly what Sebastian Ramirez and the FastAPI Cloud team are building. On this episode, I sit down with Sebastian, Patrick Arminio, Savannah Ostrowski, and Jonathan Ehwald to go inside FastAPI Cloud, explore what it means to build a "Pythonic" cloud, and dig into how this commercial venture is actually making FastAPI the open-source project stronger than ever.


