skip to navigation
skip to content

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:

  1. a simpler template
  2. a simpler process
  3. 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:

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:

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:

  1. the RFC process "doesn't include any sort of decision-making framework"
  2. "RFC processes tend to lead to endless discussion"
  3. the process "rewards people who can write to exhaustion"
  4. "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

Read full topic

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:

  1. works across all distributions
  2. doesn't require any software installed apart from the kernel and a boot loader (no systemd-networkd, ifupdown, NetworkManager, nothing)
  3. 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:

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:

So by "new" I mean "new to me". This option is really old. The nfsroot.txt where 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:

We're ignoring the options:

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:

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...

  1. 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.

  2. This only works for configuring a single, simple, interface. You can't configure multiple interfaces, WiFi, bridges, VLAN, bonding, etc.

  3. It does support IPv6 and feels like the best way to configure IPv6 hosts: true zero configuration.

  4. 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.

  5. 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.)

  6. It will not automatically reconfigure the interface on link changes, but ifupdown does not either.

  7. It will not write /etc/resolv.conf for you but the dns0-ip and dns1-ip do end up in /proc/net/pnp which has a compatible syntax, so a common configuration is:

    ln -s /proc/net/pnp /etc/resolv.conf
    
  8. I 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.

Table of contents

  1. The get method: lookups with a default
  2. The setdefault method: setting a default
  3. The fromkeys method: initializing defaults
  4. Caution with mutable defaults
  5. A dictionary comprehension
  6. The collections.defaultdict class
  7. The collections.Counter class
  8. Start simple with your defaulting

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.

Table of contents

  1. The power of match-case
  2. Matching iterables
  3. Pattern-matching with dictionaries
  4. Matching objects by type and attributes
  5. Nested pattern-matching
  6. Using if-elif instead of switch-case
  7. Using a dictionary instead of switch-case
  8. Keep match-case for advanced uses

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.

February 10, 2026 11:17 PM UTC