skip to navigation
skip to content

Planet Python

Last update: November 13, 2025 10:43 AM UTC

November 12, 2025


Python Software Foundation

Python is for everyone: Join in the PSF year-end fundraiser & membership drive!

November 12, 2025 05:03 PM UTC


Real Python

The Python Standard REPL: Try Out Code and Ideas Quickly

The Python REPL gives you instant feedback as you code. Learn to use this powerful tool to type, run, debug, edit, and explore Python interactively.

November 12, 2025 02:00 PM UTC


Peter Bengtsson

Using AI to rewrite blog post comments

Using AI to correct and edit blog post comments as part of the moderation process.

November 12, 2025 12:42 PM UTC


Python Morsels

Unnecessary parentheses in Python

Python's ability to use parentheses for grouping can often confuse new Python users into over-using parentheses in ways that they shouldn't be used.

Table of contents

  1. Parentheses can be used for grouping
  2. Python's if statements don't use parentheses
  3. Parentheses can go anywhere
  4. Parentheses for wrapping lines
  5. Parentheses that make statements look like functions
  6. Parentheses can go in lots of places
  7. Use parentheses sometimes
  8. Consider readability when adding or removing parentheses

Parentheses can be used for grouping

Parentheses are used for 3 things in Python: calling callables, creating empty tuples, and grouping.

Functions, classes, and other [callable][] objects can be called with parentheses:

>>> print("I'm calling a function")
I'm calling a function

Empty tuples can be created with parentheses:

>>> empty = ()

Lastly, parentheses can be used for grouping:

>>> 3 * (4 + 7)
33

Sometimes parentheses are necessary to convey the order of execution for an expression. For example, 3 * (4 + 7) is different than 3 * 4 + 7:

>>> 3 * (4 + 7)
33
>>> 3 * 4 + 7
19

Those parentheses around 4 + 7 are for grouping that sub-expression, which changes the meaning of the larger expression.

All confusing and unnecessary uses of parentheses are caused by this third use: grouping parentheses.

Python's if statements don't use parentheses

In JavaScript if statements look …

Read the full article: https://www.pythonmorsels.com/unnecessary-parentheses/

November 12, 2025 03:30 AM UTC


Seth Michael Larson

Blogrolls are the Best(rolls)

November 12, 2025 12:00 AM UTC

November 11, 2025


Ahmed Bouchefra

Let’s be honest. There’s a huge gap between writing code that works and writing code that’s actually good. It’s the number one thing that separates a junior developer from a senior, and it’s something a surprising number of us never really learn.

If you’re serious about your craft, you’ve probably felt this. You build something, it functions, but deep down you know it’s brittle. You’re afraid to touch it a year from now.

Today, we’re going to bridge that gap. I’m going to walk you through eight design principles that are the bedrock of professional, production-level code. This isn’t about fancy algorithms; it’s about a mindset. A way of thinking that prepares your code for the future.

And hey, if you want a cheat sheet with all these principles plus the code examples I’m referencing, you can get it for free. Just sign up for my newsletter from the link in the description, and I’ll send it right over.

Ready? Let’s dive in.

1. Cohesion & Single Responsibility

This sounds academic, but it’s simple: every piece of code should have one job, and one reason to change.

High cohesion means you group related things together. A function does one thing. A class has one core responsibility. A module contains related classes.

Think about a UserManager class. A junior dev might cram everything in there: validating user input, saving the user to the database, sending a welcome email, and logging the activity. At first glance, it looks fine. But what happens when you want to change your database? Or swap your email service? You have to rip apart this massive, god-like class. It’s a nightmare.

The senior approach? Break it up. You’d have:

Then, your main UserService class delegates the work to these other, specialized classes. Yes, it’s more files. It looks like overkill for a small project. I get it. But this is systems-level thinking. You’re anticipating future changes and making them easy. You can now swap out the database logic or the email provider without touching the core user service. That’s powerful.

2. Encapsulation & Abstraction

This is all about hiding the messy details. You want to expose the behavior of your code, not the raw data.

Imagine a simple BankAccount class. The naive way is to just have public attributes like balance and transactions. What could go wrong? Well, another developer (or you, on a Monday morning) could accidentally set the balance to a negative number. Or set the transactions list to a string. Chaos.

The solution is to protect your internal state. In Python, we use a leading underscore (e.g., _balance) as a signal: “Hey, this is internal. Please don’t touch it directly.”

Instead of letting people mess with the data, you provide methods: deposit(), withdraw(), get_balance(). Inside these methods, you can add protective logic. The deposit() method can check for negative amounts. The withdraw() method can check for sufficient funds.

The user of your class doesn’t need to know how it all works inside. They just need to know they can call deposit(), and it will just work. You’ve hidden the complexity and provided a simple, safe interface.

3. Loose Coupling & Modularity

Coupling is how tightly connected your code components are. You want them to be as loosely coupled as possible. A change in one part shouldn’t send a ripple effect of breakages across the entire system.

Let’s go back to that email example. A tightly coupled OrderProcessor might create an instance of EmailSender directly inside itself. Now, that OrderProcessor is forever tied to that specific EmailSender class. What if you want to send an SMS instead? You have to change the OrderProcessor code.

The loosely coupled way is to rely on an “interface,” or what Python calls an Abstract Base Class (ABC). You define a generic Notifier class that says, “Anything that wants to be a notifier must have a send() method.”

Then, your OrderProcessor just asks for a Notifier object. It doesn’t care if it’s an EmailNotifier or an SmsNotifier or a CarrierPigeonNotifier. As long as the object you give it has a send() method, it will work. You’ve decoupled the OrderProcessor from the specific implementation of the notification. You can swap them in and out interchangeably.


A quick pause. I want to thank boot.dev for sponsoring this discussion. It’s an online platform for backend development that’s way more interactive than just watching videos. You learn Python and Go by building real projects, right in your browser. It’s gamified, so you level up and unlock content, which is surprisingly addictive. The core content is free, and with the code techwithtim, you get 25% off the annual plan. It’s a great way to put these principles into practice. Now, back to it.

4. Reusability & Extensibility

This one’s a question you should always ask yourself: Can I add new functionality without editing existing code?

Think of a ReportGenerator function that has a giant if/elif/else block to handle different formats: if format == 'text', elif format == 'csv', elif format == 'html'. To add a JSON format, you have to go in and add another elif. This is not extensible.

The better way is, again, to use an abstract class. Create a ReportFormatter interface with a format() method. Then create separate classes: TextFormatter, CsvFormatter, HtmlFormatter, each with their own format() logic.

Your ReportGenerator now just takes any ReportFormatter object and calls its format() method. Want to add JSON support? You just create a new JsonFormatter class. You don’t have to touch the ReportGenerator at all. It’s extensible without being modified.

5. Portability

This is the one everyone forgets. Will your code work on a different machine? On Linux instead of Windows? Without some weird version of C++ installed?

The most common mistake I see is hardcoding file paths. If you write C:\Users\Ahmed\data\input.txt, that code is now guaranteed to fail on every other computer in the world.

The solution is to use libraries like Python’s os and pathlib to build paths dynamically. And for things like API keys, database URLs, and other environment-specific settings, use environment variables. Don’t hardcode them! Create a .env file and load them at runtime. This makes your code portable and secure.

6. Defensibility

Write your code as if an idiot is going to use it. Because someday, that idiot will be you.

This means validating all inputs. Sanitizing data. Setting safe default values. Ask yourself, “What’s the worst that could happen if someone provides bad input?” and then guard against it.

In a payment processor, don’t have debug_mode=True as the default. Don’t set the maximum retries to 100. Don’t forget a timeout. These are unsafe defaults.

And for the love of all that is holy, validate your inputs! Don’t just assume the amount is a number or that the account_number is valid. Check it. Raise clear errors if it’s wrong. Protect your system from bad data.

7. Maintainability & Testability

The most expensive part of software isn’t writing it; it’s maintaining it. And you can’t maintain what you can’t test.

Code that is easy to test is, by default, more maintainable.

Look at a complex calculate function that parses an expression, performs the math, handles errors, and writes to a log file all at once. How do you even begin to test that? There are a million edge cases.

The answer is to break it down. Have a separate OperationParser. Have simple add, subtract, multiply functions. Each of these small, pure components is incredibly easy to test. Your main calculate function then becomes a simple coordinator of these tested components.

8. Simplicity (KISS, DRY, YAGNI)

Finally, after all that, the highest goal is simplicity.

Phew, that was a lot. But these patterns are what it takes to level up. It’s a shift from just getting things done to building things that last.

If you enjoyed this, let me know. I’d love to make more advanced videos like this one. See you in the next one.

November 11, 2025 09:03 PM UTC


PyCoder’s Weekly

Issue #708: Debugging Live Code, NiceGUI, Textual, and More (Nov. 11, 2025)

November 11, 2025 07:30 PM UTC


Daniel Roy Greenfeld

Visiting Tokyo, Japan from November 12 to 24

Our first time in a new country!

November 11, 2025 02:45 PM UTC


Real Python

Python Operators and Expressions

Operators let you combine objects to create expressions that perform computations -- the core of how Python works.

November 11, 2025 02:00 PM UTC


Glyph Lefkowitz

The “Dependency Cutout” Workflow Pattern, Part I

It’s important to be able to fix bugs in your open source dependencies, and not just work around them.

November 11, 2025 01:44 AM UTC


Ahmed Bouchefra

Tired of Pip and Venv? Meet UV, Your New All-in-One Python Tool

Hey there, how’s it going?

Let’s talk about the Python world for a second. If you’ve been around for a while, you know the drill. You start a new project, and the ritual begins: create a directory, set up a virtual environment with venv, remember to activate it, pip install your packages, and then pip freeze everything into a requirements.txt file.

It works. It’s fine. But it always felt a bit… clunky. A lot of steps. A lot to explain to newcomers.

Well, I’ve been playing with a new tool that’s been gaining a ton of steam, and honestly? I don’t think I’m going back. It’s called UV, and it comes from Astral, the same team behind the super-popular linter, ruff.

The goal here is ambitious. UV wants to be the single tool that replaces pip, venv, pip-tools, and even pipx. It’s an installer, an environment manager, and a tool runner all rolled into one. And because it’s written in Rust, it’s ridiculously fast.

So, let’s walk through what a typical project setup looks like the old way… and then see how much simpler it gets with UV.

The Old Way: The Pip & Venv Dance

Okay, so let’s say we’re starting a new Flask app. The old-school workflow would look something like this:

  1. mkdir old-way-project && cd old-way-project
  2. python3 -m venv .venv (Create the virtual environment)
  3. source .venv/bin/activate (Activate it… don’t forget!)
  4. pip install flask requests (Install our packages)
  5. pip freeze > requirements.txt (Save our dependencies for later)

It’s a process we’ve all done a hundred times. But it’s also a process with a few different tools and concepts you have to juggle. For someone just starting out, it’s a lot to take in.

The New Way: Just uv

Now, let’s do the same thing with UV.

Instead of creating a directory myself, I can just run:

uv init new-app

This one command creates a new directory, cds into it, and sets up a modern Python project structure. It initializes a Git repository, creates a sensible .gitignore, and gives us a pyproject.toml file. This is the modern way to manage project metadata and dependencies.

But wait… where’s the virtual environment? Where’s the activation step?

Here’s the magic. You don’t have to worry about it.

Let’s add Flask and Requests to our new project. Instead of pip, we use uv add:

uv add flask requests

When I run this, a few amazing things happen:

  1. UV sees I don’t have a virtual environment yet, so it creates one for me automatically.
  2. It installs Flask and Requests into that environment at lightning speed.
  3. It updates my pyproject.toml file to list flask and requests as dependencies.
  4. It creates a uv.lock file, which records the exact versions of every single package and sub-dependency. This is what solves the classic “but it works on my machine!” problem.

All of that, with one command, and I never had to type source ... activate.

Running Your Code (This Is the Coolest Part)

“Okay,” you might be thinking, “but how do I run my code if the environment isn’t active?”

Simple. You just tell UV to run it for you.

uv run main.py

UV finds the project’s virtual environment and runs your script inside it, even though your main shell doesn’t have it activated.

Now, get ready for the part that really blew my mind.

Let’s say I accidentally delete my virtual environment.

rm -rf .venv

Normally, this would be a disaster. I’d have to recreate the environment, activate it, and reinstall everything from my requirements.txt file. It would be a whole thing.

But with UV? I just run the same command again:

uv run main.py

UV sees the environment is gone. It reads the uv.lock file, instantly recreates the exact same environment with the exact same packages, and then runs the code. It all happens in a couple of seconds. It’s just… seamless.

If you’re sharing the project with a teammate, they just clone it and run uv sync. That’s it. Their environment is ready to go, perfectly matching yours.

It Even Replaces Pipx for Tools

Another thing I love is how it handles command-line tools. I used to use pipx to install global tools like linters and formatters. UV has that built-in, too.

Want to install ruff?

uv tool install ruff

This installs it in an isolated environment but makes it available everywhere.

But even better is the uvx command, which lets you run a tool without permanently installing it.

Let’s say I want to quickly check my code with ruff but I don’t want to install it.

uvx ruff check .

UV will download ruff to a temporary environment, run the command, and then clean up after itself. It’s perfect for trying out new tools or running one-off commands without cluttering your system.

My Takeaway

I know, I know… another new tool to learn. It can feel overwhelming. But this one is different. It doesn’t just add another layer; it simplifies and replaces a whole stack of existing tools with something faster, smarter, and more intuitive.

The smart caching alone is a huge win. If you have ten projects that all use Flask, UV only stores it once on your disk, saving a ton of space and making new project setups almost instantaneous.

I’ve fully switched my workflow over to UV, and I can’t see myself going back. It just gets out of the way and lets me focus on the code.

November 11, 2025 12:00 AM UTC

The Anatomy of a Scalable Python Project

Ever start a Python project that feels clean and simple, only to have it turn into a tangled mess a few months later? Yeah, I’ve been there more times than I can count.

Today, I want to pull back the curtain and show you the anatomy of a Python project that’s built to last. This is the setup I use for all my production projects. It’s a blueprint that helps keep things sane, organized, and ready to grow without giving you a massive headache.

We’ll walk through everything—folder structure, config, logging, testing, and tooling. The whole package.

So, What Does “Scalable” Even Mean?

It’s a word that gets thrown around a lot, right? “Scalable.” But what does it actually mean in practice?

For me, it boils down to a few things:

  1. Scales with Size: Your codebase is going to grow. That’s a good thing! It means you’re adding features. A scalable structure means you don’t have to constantly refactor everything just to add something new. The foundation is already there.
  2. Scales with Your Team: If you bring on another developer, they shouldn’t need a two-week onboarding just to figure out where to put a new function. The boundaries should be clear, and the layout should be predictable.
  3. Scales with Environments: Moving from your local machine to staging and then to production should be… well, boring. In a good way. Your config should be centralized, making environment switching a non-event.
  4. Scales with Speed: Your local setup should be a breeze. Tests should run fast. Docker should just work. You want to eliminate friction so you can actually focus on building things.

Over the years, I’ve worked with everything from TypeScript to Java to C++, and while the specifics change, the principles of good structure are universal. This is the flavor that I’ve found works beautifully for Python.

The Blueprint: A Balanced Folder Structure

You want just enough structure to keep things organized, but not so much that you’re digging through ten nested folders to find a single file. It’s a balance.

Here’s the high-level view:

/
├── app/      # Your application's source code
├── tests/    # Your tests
├── .env      # Environment variables (for local dev)
├── Dockerfile
├── docker-compose.yml
├── pyproject.toml
└── ... other config files

Right away, you see the most important separation: your app code and your tests live in their own top-level directories. This is crucial. Don’t mix them.

Diving Into the app Folder

This is where the magic happens. Inside app, I follow a simple pattern. For this example, we’re looking at a FastAPI app, but the concepts apply anywhere.

app/
├── api/
│   └── v1/
│       └── users.py   # The HTTP layer (routers)
├── core/
│   ├── config.py    # Centralized configuration
│   └── logging.py   # Logging setup
├── db/
│   └── schema.py    # Database models (e.g., SQLAlchemy)
├── models/
│   └── user.py      # Data contracts (e.g., Pydantic schemas)
├── services/
│   └── user.py      # The business logic!
└── main.py          # App entry point

Let’s break it down.

main.py - The Entry Point

This file is kept as lean as possible. Seriously, there’s almost nothing in it. It just initializes the FastAPI app and registers the routers from the api folder. That’s it.

api/ - The Thin HTTP Layer

This is where your routes live. If you look inside api/v1/users.py, you won’t find any business logic. You’ll just see the standard GET, POST, PUT, DELETE endpoints. Their only job is to handle the HTTP request and response. They act as a thin translator, calling into the real logic somewhere else.

core/ - The Cross-Cutting Concerns

This folder is for things that are used all over your application.

db/ and models/ - The Data Layers

services/ - The Heart of Your Application

This is the most important folder, in my opinion. This is where your actual business logic lives. The UserService takes a database session and does the real work: querying for users, creating a new user, running validation logic, etc.

Why is this so great?

Let’s Talk About Testing

Your tests folder should mirror your app folder’s structure. This makes it incredibly easy to find the tests for any given piece of code.

tests/
└── api/
    └── v1/
        └── test_users.py

For testing, I use an in-memory SQLite database. This keeps my tests completely isolated from my production database and makes them run super fast.

FastAPI has a fantastic dependency injection system that makes testing a dream. In my tests, I can just “override” the dependency that provides the database session and swap it with my in-memory test database. Now, when I run a test that hits my API, it’s running against a temporary, clean database every single time.

Tooling That Ties It All Together

How It All Flows Together

So, let’s trace a request:

  1. A GET /users request hits the router in api/v1/users.py.
  2. FastAPI’s dependency injection system automatically creates a UserService instance, giving it a fresh database session.
  3. The route calls the list_users method on the service.
  4. The service runs a query against the database, gets the results, and returns them.
  5. The router takes those results, formats them as a JSON response, and sends it back to the client.

The beauty of this is the clean separation of concerns. The API layer handles HTTP. The service layer handles business logic. The database layer handles persistence.

This structure lets you start small and add complexity later without making a mess. The boundaries are clear, which makes development faster, testing easier, and onboarding new team members a whole lot smoother.

Of course, this is a starting point. You might need a scripts/ folder for data migrations or other custom tasks. But this foundation… it’s solid. It’s been a game-changer for me, and I hope it can be for you too.

November 11, 2025 12:00 AM UTC

November 10, 2025


Brian Okken

Explore Python dependencies with `pipdeptree` and `uv pip tree`

Sometimes you just want to know about your dependencies, and their dependencies.

I’ve been using pipdeptree for a while, but recently switched to uv pip tree.
Let’s take a look at both tools.

pipdeptree

pipdeptree is pip installable, but I don’t want pipdeptree itself to be reported alongside everything else installed, so I usually install it outside of a project. We can use it system wide by:

usage

The --python auto tells pipdeptree to look at the current environment.

November 10, 2025 11:24 PM UTC


Patrick Altman

Using Vite with Vue and Django

Learn how we integrate Vue and Django for a bullet proof deployment.

November 10, 2025 05:58 PM UTC


PyCharm

This blog post was brought to you by Damaso Sanoja, draft.dev. Deciding whether to use Python or Rust isn’t just a syntax choice; it’s a career bet. According to the StackOverflow Developer Survey, Python dominates in accessibility, with 66.4% of people learning to code choosing it as their entry point. Python usage skyrocketed from 32% […]

November 10, 2025 04:40 PM UTC


Real Python

Python 3.14 Released and Other Python News for November 2025

Python 3.14 is officially out, Python 3.15 begins, and Python 3.9 reaches end of life. Plus, Django 6.0 first beta released, new PEPs, and more Python news.

November 10, 2025 02:00 PM UTC


PyCharm

Rust vs. Python: Finding the right balance between speed and simplicity

November 10, 2025 12:02 PM UTC


Talk Python to Me

#527: MCP Servers for Python Devs

Today we’re digging into the Model Context Protocol, or MCP. Think LSP for AI: build a small Python service once and your tools and data show up across editors and agents like VS Code, Claude Code, and more. My guest, Den Delimarsky from Microsoft, helps build this space and will keep us honest about what’s solid versus what's just shiny. We’ll keep it practical: transports that actually work, guardrails you can trust, and a tiny server you could ship this week. By the end, you’ll have a clear mental model and a path to plug Python into the internet of agents.

November 10, 2025 08:00 AM UTC

November 09, 2025


Ned Batchelder

Three releases, one new organization

It’s been a busy, bumpy week with coverage.py. Some things did not go smoothly, and I didn’t handle everything as well as I could have.

It started with trying to fix issue 2064 about conflicts between the “sysmon” measurement core and a concurrency setting.

To measure your code, coverage.py needs to know what code got executed. To know that, it collects execution events from the Python interpreter. CPython now has two mechanisms for this: trace functions and sys.monitoring. Coverage.py has two implementations of a trace function (in C and in Python), and an implementation of a sys.monitoring listener. These three components are the measurement cores, known as “ctrace”, “pytrace”, and “sysmon”.

The fastest is sysmon, but there are coverage.py features it doesn’t yet support. With Python 3.14, sysmon is the default core. Issue 2064 complained that when the defaulted core conflicted with an explicit concurrency choice, the conflict resulted in an error. I agreed with the issue: since the core was defaulted, it shouldn’t be an error, we should choose a different core.

But I figured if you explicitly asked for the sysmon core and also a conflicting setting, that should be an error because you’ve got two settings that can’t be used together.

Implementing all that got a little involved because of “metacov”: coverage.py coverage-measuring itself. The sys.monitoring facility in Python was added in 3.12, but wasn’t fully fleshed out enough to do branch coverage until 3.14. When we measure ourselves, we use branch coverage, so 3.12 and 3.13 needed some special handling to avoid causing the error that sysmon plus branch coverage would cause.

I got it all done, and released 7.11.1 on Friday.

Soon, issue 2077 arrived. Another fix in 7.11.1 involved some missing branches when using the sysmon core. That fix required parsing the source code during execution. But sometimes the “code” can’t be parsed: Jinja templates compile html files to Python and use the html file as the file name for the code. When coverage.py tries to parse the html file as Python, of course it fails. My fix didn’t account for this. I fixed that on Saturday and released 7.11.2.

In the meantime, issue 2076 and issue 2078 both pointed out that now some settings combinations that used to produce warnings now produced errors. This is a breaking change, they said, and should not have been released as a patch version.

To be honest, my first reaction was that it wasn’t that big a deal, the settings were in conflict. Fix the settings and all will be well. It’s hard to remember all of the possibilities when making changes like this, it’s easy to make mistakes, and semantic versioning is bound to have judgement calls anyway. I had already spent a while getting 7.11.1 done, and .2 followed just a day later. I was annoyed and didn’t want to have to re-think everything.

But the more I thought about it, I decided they were right: it does break pipelines that used to work. And falling back to a different core is fine: the cores differ in speed and compatibility but (for the most part) produce the same results. Changing the requested core with a warning is a fine way to deal with the settings conflict without stopping test suites from running.

So I just released 7.11.3 to go back to the older behavior. Maybe I won’t have to do another release tomorrow!

While all this was going on, I also moved the code from my personal GitHub account to a new coveragepy GitHub organization!

Coverage.py is basically a one-man show. Maybe the GitHub organization will make others feel more comfortable chiming in, but I doubt it. I’d like to have more people to talk through changes with. Maybe I wouldn’t have had to make three releases in three days if someone else had been around as a sounding board.

I’m in the #coverage-py channel if you want to talk about any aspect of coverage.py, or I can be reached in lots of other ways. I’d love to talk to you.

November 09, 2025 11:27 PM UTC


Chris Warrick

Distro Hopping, Server Edition

I’ve recently migrated my VPS from Fedora to Ubuntu. Here’s a list of things that might be useful to keep in mind before, during, and after a migration of a server that hosts publicly accessible Web sites and applications, as well as other personal services, and how to get rid of the most annoying parts of Ubuntu.

Why switch?

Fedora is a relatively popular distro, so it’s well supported by software vendors. Its packagers adopt a no-nonsense approach, making very little changes that deviate from the upstream.

Ubuntu is not my favorite distro, far from it. While it is perhaps the most popular distro out there, its packages contain many more patches compared to Fedora, and Canonical (the company behind Ubuntu) are famous for betting on the wrong horse (Unity, upstart, Mir…). But one thing Ubuntu does well is stability. Fedora makes releases every 6 months, and those releases are supported for just 13 months, which means upgrading at least every year. Every upgrade may introduce incompatibilities, almost every upgrade requires recreating Python venvs. That gets boring fast, and it does not necessarily bring benefits. Granted, the Fedora system upgrade works quite well, and I upgraded through at least eight releases without a re-install, but I would still prefer to avoid it. That’s why I went with Ubuntu LTS, which is supported for five years, with a new release every two years, but which still comes with reasonably new software (and with many third-party repositories if something is missing or outdated).

Test your backups

I have a backup “system” that’s a bunch of Bash scripts. After upgrading one of the services that is being backed up, the responsible script started crashing, and thus backups stopped working. Another thing that broke was e-mails from cron, so I didn’t know anything was wrong.

While I do have full disk backups enabled at Hetzner (disclaimer: referral link), my custom backups are more fine-grained (e.g. important configuration files, database dumps, package lists), so they are quite useful in migrating between OSes.

So, here’s a reminder not only to test your backups regularly, but also to make sure they are being created at all, and to make sure cron can send you logs somewhere you can see them.

Bonus cron tip: set MAILFROM= and MAILTO= in your crontab if your SMTP server does not like the values cron uses by default.

Think about IP address reassignment (or pray to the DNS gods)

A new VPS or cloud server probably means a new IP address. But if you get a new IP address, that might complicate the migration of your publicly accessible applications. If you’re proxying all your Web properties through Cloudflare or something similar, that’s probably not an issue. But if you have a raw A record somewhere, things can get complicated. DNS servers and operating systems do a lot of caching. The conventional wisdom is to wait 24 or even 48 hours after changing DNS values. This might be true if your TTL is set to a long value, but if your TTL is short, the only worry are DNS servers that ignore TTL values and cache records for longer. If you plan a migration, it’s good to check your TTL well in advance, and not worry too much about broken DNS servers.

But you might not need a new IP. Carefully review your cloud provider’s IP management options before making any changes. Hetzner is more flexible than other hosts in this regard, as it is possible to move primary public IP addresses (not “floating” or “elastic” IPs) between servers, as long as you’re okay with a few minutes’ downtime (you will need to shut down the source and destination servers).

If you’re not okay with any downtime, you would probably want to leverage the floating/elastic IP feature, or hope DNS propagates quickly enough.

Trim the fat

My VPS ran a lot of services I don’t need anymore, but never really got around to decommissioning. For example, I had a full Xfce install with VNC access (the VNC server was only running when needed). I haven’t actually used the desktop for ages, so I just dropped it.

I also had an OpenVPN setup. It was useful years ago, when mobile data allowances were much smaller and speeds much worse. These days, I don’t use public WiFi networks at all, unless I’m going abroad, and I just buy one month of Mullvad VPN for €5 whenever that happens. So, add another service to the “do not migrate” list.

One thing that I could not just remove was the e-mail server. Many years ago, I ran a reasonably functional e-mail server on my VPS. I’ve since then migrated to Zoho Mail (which costs €10.80/year), in part due to IP reputation issues after changing hosting providers, and also to avoid having to fight spam. When I did that, I kept Postfix around, but as a local server for things like cron or Django to send e-mail with, and I configured it to send all e-mails via Zoho. But I did not really want to move over all the configuration, hoping that Ubuntu’s Postfix packages can work with my hacked together config from Fedora. So I replaced the server with OpenSMTPD (from the OpenBSD project), and all the Postfix configuration files with just one short configuration file:

table aliases file:/etc/aliases
table secrets file:/etc/mail-secrets

listen on localhost
listen on 172.17.0.1 # Docker

action "relay" relay host smtp+tls://smtp@smtp.example.net:587 auth <secrets> mail-from "@example.com"

match from any for any action "relay"

Dockerize everything…

My server runs a few different apps, some of which are exposed on the public Internet, while some do useful work in the background. The services I have set up most recently are containerized with the help of Docker. The only Docker-based service that was stateful (and did not just use folders mounted as volumes) was a MariaDB database. Migrating that is straightforward with a simple dump-and-restore.

Of course, not everything on my server is in Docker. The public-facing nginx install isn’t, and neither is PostgreSQL (but that was also a quick dump-and-restore migration with some extra steps).

…especially Python

But then, there are the Python apps. Python the language is cool (if a little slow), but the packaging story is a total dumpster fire.

By the way, here’s a quick recap of 2024/2025 in Python packaging: the most hyped Python package manager (uv) is written in Rust, which screams “Python is a toy language in which you can’t even write a tool as simple as a package manager”. (I know, dependency resolution is computationally expensive, so doing that in Rust makes sense, but everything else could easily be done in pure Python. And no, the package manager should not manage Python installs.) Of course, almost all the other contenders listed in my 2023 post are still being developed. On the standards front, the community finally produced a lockfile standard after years of discussions.

Anyway, I have three Python apps. One of them is Isso, which is providing the comments box below this post. I used to run a modified version of Isso a long time ago, but I don’t need to anymore. I looked at the docs, and they offer a pre-built Docker image, which means I could just quickly deploy it on my server with Docker and skip the pain of managing Python environments.

The other two apps are Django projects built by yours truly. They are not containerized, they exist in venvs created using the system Python. Moving venvs between machines is generally impossible, so I had to re-create them. Of course, I hit a deprecation, because the Python maintainers (especially in the packaging world) does not understand their responsibility as maintainers of the most popular programming language. This time, it was caused by an old editable install with setuptools (using setup.py develop, not PEP 660), and installs with more recent pip/setuptools versions would not have this error… although some people want to remove the fallback to setuptools if there is no pyproject.toml, so you need to stay up to date with the whims of the Python packaging industry if you want to use Python software.

Don’t bother with ufw

Ubuntu ships with ufw, the “uncomplicated firewall”, in the default install. I was previously using firewalld, a Red Hat-adjacent project, but I decided to give ufw a try. Since if it’s part of the default install, it might be supported better by the system.

It turns out that Docker and ufw don’t play together. Someone has built a set of rules that are supposed to fix it, but that did not work for me.

Docker does integrate with firewalld, and Ubuntu has packages for it, so I just installed it, enabled the services that need to be publicly available and things were working again.

Kill the ads (and other nonsense too)

Red Hat makes money by selling a stable OS with at least 10 years of support to enterprises, and their free offering is Fedora, with just 13 months of support; RHEL releases are branched off from Fedora. SUSE also sells SUSE Linux Enterprise and has openSUSE as the free offering (but the relationship between the paid and free version is more complicated).

Ubuntu chose a different monetization strategy: the enterprise offering is the same OS as the free offering, but it gets extra packages and extra updates. The free OS advertises the paid services. It is fairly simple to get rid of them all:

sudo apt autoremove ubuntu-pro-client
sudo chmod -x /etc/update-motd.d/*

Also, Ubuntu installs snap by default. Snap is a terrible idea. Luckily, there are no snaps installed by default on a Server install, so we can just remove snapd. We’ll also remove lxd-installer to save ~25 kB of disk space, since the installer requires snap, and lxd is another unsuccessful Canonical project.

sudo apt autoremove snapd lxd-installer

The cost of downgrading

Going from Fedora 42 (April 2025) to Ubuntu 24.04 (April 2024) means some software will be downgraded in the process. In general, this does not matter, as most software does not mind downgrades as much. One notable exception is WeeChat, the IRC client, whose config files are versioned, and Ubuntu’s version is not compatible with the one in Fedora. But here’s where Ubuntu’s popularity shines: WeeChat has its own repositories for Debian and Ubuntu, so I could just get the latest version without building it myself or trying to steal packages from a newer version.

Other than WeeChat, I haven’t experienced any other issues with software due to a downgrade. Some of it is luck (or not using new/advanced features), some of it is software caring about backwards compatibility.

Conclusion

Was it worth it? Time will tell. Upgrading Fedora itself was not that hard, and I expect Ubuntu upgrades to be OK too — the annoying part was cleaning up and getting things to work after the upgrade, and the switch means I will have to do it only every 2-4 years instead of every 6-12 months.

The switchover took a few hours, especially since I didn’t have much up-to-date documentation of what is actually installed and running, and there are always the minor details where distros differ that may require adjusting to. I think a migration like this is worth trying if rolling-release or frequently-released distros are too unstable for your needs.

November 09, 2025 06:00 PM UTC


The Python Coding Stack

The Misunderstood Hashable Types and Why Dictionaries Are Called Dictionaries • [Club]

What does hashable really mean? And what’s the real superpower in dictionaries?

November 09, 2025 01:09 PM UTC

November 07, 2025


Rodrigo Girão Serrão

Module compression overview

A high-level overview of how to use the module compression, new in Python 3.14.

This article will teach you how to use the package compression, new in Python 3.14. You will learn how to

Compression modules available

The package compression makes five compression modules available to you:

  1. bz2 – comprehensive interface for compressing and decompressing data using the bzip2 compression algorithm;
  2. gzip – adds support for working with gzip files through a simple interface to compress and decompress files like the GNU programs gzip and gunzip would;
  3. lzma – interface for compressing and decompressing data using the LZMA compression algorithm;
  4. zlib – interface for the zlib library (lower-level than gzip); and
  5. zstd – interface for compressing and decompressing data using the Zstandard compression algorithm.

Importing the modules

The first four modules (bz2, gzip, lzma, and zlib) were already available in earlier Python 3 versions as standalone modules. This means you can import these modules directly in earlier versions of Python:

# Python 3.12
>>> import bz2, gzip, lzma, zlib
>>> # No exception raised.

In Python 3.14, they continue to be importable directly and through the package compression:

# Python 3.14
>>> import bz2, gzip, lzma, zlib
>>> # No exception raised.

>>> from compression import bz2, gzip, lzma, zlib
>>> # No exception raised.

The package compression.zstd is new in Python 3.14 and can only be imported as compression.zstd:

# Python 3.14
>>> import zstd
# ModuleNotFoundError: No module named 'zstd'
>>> from compression import zstd  # ✅
>>> # No exception raised.

When possible (for example, in new programs), it is recommended that you import any of the five compression modules through the package compression.

Basic interface

At the most basic level, all five modules provide the functions compress and decompress. These functions can be given bytes-like objects to perform one-shot compression/decompression, as the snippet of code below shows:

from compression import zstd

data = ("Hello, world!" * 1000).encode()
compressed = zstd.compress(data)
print(compressed)
# b'(\xb5/\xfd`\xc81\xad\x00\x00hHello, world!\x01\x00\xb8\x12\xf8\xf9\x05'
print(zstd.decompress(compressed) == data)
# True

Using the same toy data (the string "Hello, world!" repeated 1000 times) we can use the function compress of each module to determine how well they compress this data. The table below shows the ratio of the compressed data to the original data, which means a smaller number is better:

module ratio check
bz2 0.0058
gzip 0.0060
lzma 0.0098
zlib 0.0051
zstd 0.0024

The table below shows that, for this toy example, zstd compressed the data at least twice as effectively as any other compression algorithm.

This table was produced by the following snippet of Python 3.14 code, which also proves that all five modules provide the functions compress and decompress:...

November 07, 2025 10:55 PM UTC


Real Python

The Real Python Podcast – Episode #273: Advice for Writing Maintainable Python Code

What are techniques for writing maintainable Python code? How do you make your Python more readable and easier to refactor? Christopher Trudeau is back on the show this week, bringing another batch of PyCoder's Weekly articles and projects.

November 07, 2025 12:00 PM UTC


Django Weblog

Django at PyCon FR 2025 🇫🇷

Last week, we had a great time at PyCon FR 2025 - a free (!) gathering for Pythonistas in France. Here are some of our highlights.

Sprints on Django, our website, IA, marketing

Over two days, the conference started with 27 contributors joining us to contribute to Django and our website and online presence. Half in the room were complete newcomers to open source, wanting to get a taste of what it’s like behind the scenes. We also had people who were new to Django, taking the excellent Django Girls tutorial to get up to speed with the project. The tutorial is translated in 20 languages(!), so it’s excellent in situations like this where people come from all over Europe.

Two contributors working together on a laptop pair programming

Carmen, one of our sprint contributors, took the time to test that our software for ongoing Board elections is accessible 💚

Discussing Django’s direction

At the sprints, we also organized discussions on Django’s direction - specifically on marketing, Artificial Intelligence, and technical decisions. Some recurring topics were:

We had a great time during those two days of sprints ❤️ thank you to everyone involved, we hope you stick around!

Design systems with JinjaX, Stimulus, and Cube CSS

Mads demonstrated how to bring a design-system mindset to Django projects by combining JinjaX, Stimulus JS, and Cube CSS. Supported by modern tooling like Figma, Vite, and Storybook. JinjaX in particular, allows to take a more component-driven “lego blocks” approach to front-end development with Django.

Mads on stage with title slide about design systems at PyCon FR

Three years of htmx in Django

Céline Martinet Sanchez shared her takeaways from using htmx with Django over three years. The verdict? A joyful developer experience, some (solved) challenges with testing.

Her recommended additions to make the most of the two frameworks:

Slide with libraries in use in the project stack of Céline

Becoming an open-source contributor in 2025

In her talk, Amanda Savluchinske explored how newcomers can get involved in open source—highlighting the Django community’s Djangonaut Space program. She explains why doing it is great, how to engage with busy maintainers, and specific actions people can take to get started.

We really liked her sharing a prompt she uses with AI, to iterate on questions to maintainers before hitting “send”:

“You are an expert in technical writing. I'm trying to write a message about a question I have about this open-source project I'm contributing to. Here's the link to its repo ‹Add link here›. I want to convey my question to the maintainers in a clear, concise way, at the same time that I want it to have enough context so that the communication happens with the least back and forth possible. I want this question to contain a short, max two sentence summary upfront, and then more context in the text's body. Ask me whatever questions you need about my question and context in order to produce this message.”

Amanda showcases contributor programs Google Summer of Code and Djangonaut Space

La Suite numérique: government collaboration powered by Django

PyCon FR also featured La Suite numérique, the French government’s collaborative workspace—developed with partners in Germany, the Netherlands (Mijn Bureau), and Italy. Their platform includes collaborative documents, video calls, chat, and an AI assistant — all powered by Django 🤘. This work is now part of a wider European Union initiative for sovereign digital infrastructure based on open source, for more information see: Commission to launch Digital Commons EDIC to support sovereign European digital infrastructure and technology.

Manuel on stage introducing La suite numerique

Up next…

Up next, we have the first ever Django Day India event! And closer to France, DjangoCon Europe 2026 will take place in Athens, Greece 🇬🇷🏖️🏛️☀️


We’re elated to support events like PyCon FR 2025. To help us do more of this, take a look at this great offer from JetBrains: 30% Off PyCharm Pro – 100% for Django – All money goes to the Django Software Foundation!

November 07, 2025 09:01 AM UTC

November 06, 2025


Django Weblog

2026 DSF Board Candidates

Thank you to the 19 individuals who have chosen to stand for election. This page contains their candidate statements submitted as part of the 2026 DSF Board Nominations.

Our deepest gratitude goes to our departing board members who are at the end of their term and chose not to stand for re-elections: Sarah Abderemane and Thibaud Colas; thank you for your contributions and commitment to the Django community ❤️.

Those eligible to vote in this election will receive information on how to vote shortly. Please check for an email with the subject line “2026 DSF Board Voting”. Voting will be open until 23:59 on November 26, 2025 Anywhere on Earth. There will be three seats open for election this year.

Any questions? Reach out on our dedicated forum thread or via email to foundation@djangoproject.com.

All candidate statements

To make it simpler to review all statements, here they are as a list of links. Voters: please take a moment to read all statements before voting! It will take some effort to rank all candidates on the ballot. We believe in you.

  1. Aayush Gauba (he/him) — St. Louis, MO
  2. Adam Hill (he/him) — Alexandria, VA
  3. Andy Woods (he/they) — UK
  4. Apoorv Garg (he/him) — India, now living in Japan
  5. Ariane Djeupang (she/her) — Cameroon
  6. Arunava Samaddar (he/him) — India
  7. Chris Achinga (he/him) — Mombasa, Kenya
  8. Dinis Vasco Chilundo (he/him) — Cidade de Inhambane, Mozambique
  9. Jacob Kaplan-Moss (he/him) — Oregon, USA
  10. Julius Nana Acheampong Boakye (he/him) — Ghana
  11. Kyagulanyi Allan (he/him) — Kampala, Uganda
  12. Nicole Buque (she) — Maputo, Mozambique
  13. Nkonga Morel (he/him) — Cameroun
  14. Ntui Raoul Ntui Njock (he/his) — Buea, Cameroon
  15. Priya Pahwa (she/her) — India, Asia
  16. Quinter Apondi Ochieng (she) — Kenya-Kisumu City
  17. Rahul Lakhanpal (he/him) — Gurugram, India
  18. Ryan Cheley (he/him) — California, United States
  19. Sanyam Khurana (he/him) — Toronto, Canada

Aayush Gauba (he/him) St. Louis, MO

View personal statement

I’m Aayush Gauba, a Django developer and Djangonaut Space mentee passionate about open source security and AI integration in web systems. I’ve spoken at DjangoCon US and actively contribute to the Django community through projects like AIWAF. My focus is on using technology to build safer and more inclusive ecosystems for developers worldwide.

Over the past few years, I’ve contributed to multiple areas of technology ranging from web development and AI security to research in quantum inspired computing. I’ve presented talks across these domains, including at DjangoCon US, where I spoke about AI powered web security and community driven innovation. Beyond Django, I’ve published academic papers exploring the intersection of ethics, quantum AI, and neural architecture design presented at IEEE and other research venues. These experiences have helped me understand both the technical and philosophical challenges of building responsible and transparent technology. As a Djangonaut Space mentee, I’ve been on the learning side of Django’s mentorship process and have seen firsthand how inclusive guidance and collaboration can empower new contributors. I bring a perspective that connects deep research with community growth and balancing innovation with the values that make Django strong: openness, ethics, and accessibility.

As part of the DSF board, I would like to bridge the gap between experienced contributors and new voices. I believe mentorship and accessibility are key to Django’s future. I would also like to encourage discussions around responsible AI integration, web security, and community growth ensuring Django continues to lead both technically and ethically. My goal is to help the DSF stay forward looking while staying true to its open, supportive roots.

Adam Hill (he/him) Alexandria, VA

View personal statement

I have been a software engineer for over 20 years and have been deploying Django in production for over 10. When not writing code, I'm probably playing pinball, watching a movie, or shouting into the void on social media.

I have been working with Django in production for over 10 years at The Motley Fool where I am a Staff Engineer. I have also participated in the Djangonauts program for my Django Unicorn library, gave a talk at DjangoCon EU (virtual) and multiple lightning talks at DjangoCon US conferences, built multiple libraries for Django and Python, have a semi-regularly updated podcast about Django with my friend, Sangeeta, and just generally try to push the Django ecosystem forward in positive ways.

The key issue I would like to get involved with is updating the djangoproject.com website. The homepage itself hasn't changed substantially in over 10 years and I think Django could benefit from a fresh approach to selling itself to developers who are interested in a robust, stable web framework. I created a forum post around this here: Want to work on a homepage site redesign?. I also have a document where I lay out some detailed ideas about the homepage here: Django Homepage Redesign.

Andy Woods (he/they) UK

View personal statement

I’m am based in academia and am a senior Creative Technologist and Psychologist. I have a PhD in Multisensory Perception. I make web apps and love combining new technologies. I’ve worked in academia (Sheffield, Dublin, Bangor, Manchester, Royal Holloway), industry (Unilever, NL), and founded three technology-based startups. I am proud of my neurodiversity.

I was on the review team of DjangoCon Europe 2021. I have had several blog posts included on the Django Newsletter (e.g. django htmx modal popup loveliness). I have written a scientific article on using Django for academic research (under peer review). I have several projects mentioned on Django Packages e.g. MrBenn Toolbar Plugin. I am part of a cohort of people who regularly meet to discuss python based software they are developing in the context of startups, started by Michael Kennedy. Here is an example of an opensource django-based project I am developing there: Tootology.

I am keen on strengthening the link between Django and the academic community. Django has enormous potential as a research and teaching tool, but us academics don't know about this! I would like to make amends by advocating for members of our community to appear on academic podcasts and social media platforms to promote Django’s versatility, and to reach new audiences.

In my professional life, I lead work on Equality, Diversity, and Inclusion, and am committed to creating fair and supportive environments. I will bring this to the DSF. The Django community already takes great strides in this area, and I would like to build upon this progress. Python recently turning down a $1.5 million grant, which I feels exemplifies the awesomeness of the greater community we are a part of.

Apoorv Garg (he/him) India, now living in Japan

View personal statement

I’m Apoorv Garg, a Django Software Foundation Member and open source advocate. I actively organize and volunteer for community events around Django, Grafana, and Postgres. Professionally, I work as a software engineer at a startup, focusing on building scalable backend systems and developer tools. I’m also part of the Google Summer of Code working groups with Django and JdeRobot, contributing to mentorship and open source development for over four years.

I have been actively speaking at various tech communities including Python, FOSSASIA, Django, Grafana, and Postgres. Over time, I’ve gradually shifted from just speaking to also organizing and volunteering at these community events, helping others get involved and build connections around open source technologies.

Beyond work, I’ve been mentoring students through Google Summer of Code with Django and JdeRobot. I also teach high school students the fundamentals of Python, Django, and robotics, helping them build curiosity and confidence in programming from an early stage.

Last year, I joined the Accessibility Working Group of the World Wide Web Consortium (W3C), which focuses on improving web accessibility standards and ensuring inclusive digital experiences for all users. My goal is to bring these learnings into the Django ecosystem, aligning its community and tools with global accessibility best practices.

Looking at the issues, I believe the opportunity of Google Summer of Code is currently very limited in Django. I know Django already has a lot of contributions, but being part of the core members in the JdeRobot organization, which is a small open source group, I understand the pain points we face when trying to reach that level of contribution. The way we utilize GSoC in JdeRobot has helped us grow, improve productivity, and bring in long-term contributors. I believe Django can benefit from adopting a similar approach.

Funding is another major issue faced by almost every open source organization. There are continuous needs around managing grants for conferences, supporting local communities and fellows, and sponsoring initiatives that strengthen the ecosystem. Finding sustainable ways to handle these challenges is something I want to focus on.

I also plan to promote Django across different open source programs. In my opinion, Django should not be limited to Python or Django-focused events. It can and should have a presence in database and infrastructure communities such as Postgres, Grafana, FOSSASIA, and W3C conferences around the world. This can help connect Django with new audiences and create more collaboration opportunities.

Ariane Djeupang (she/her) Cameroon

View personal statement

I’m Ariane Djeupang from Cameroon (Central Africa) , a ML Engineer, Project Manager, and Community Organizer passionate about building sustainable, inclusive tech ecosystems across Africa. As a Microsoft MVP in the Developer Technologies category, an active DSF member and a leader in open source communities, I believe in the power of collaboration, documentation, and mentorship to unlock global impact.

My efforts focus on lowering the barriers to meaningful participation. My work sits at the intersection of production engineering, clear technical communication, and community building. I’ve spent years building ML production-ready systems with Django, FastAPI, Docker, cloud platforms, and also ensuring that the knowledge behind those systems is accessible to others. I’ve turned complex workflows into approachable, accessible guides and workshops that empower others to build confidently. I’ve also collaborated with global networks to promote ethical ML/AI and sustainable tech infrastructure in resource-constrained environments.

Through my extensive experience organizing major events like: DjangoCon Africa, UbuCon Africa, PyCon Africa, DjangoCon US, EuroPython, I’ve created inclusive spaces where underrepresented voices lead, thrive and are celebrated. This has equipped me with the skills and insights needed to drive inclusivity, sustainability and community engagement. I volunteer on both the DSF's CoC and the D&I (as Chair) working groups. I also contribute to the scientific community through projects like NumPy, Pandas, SciPy, the DISCOVER COOKBOOK (under NumFOCUS' DISC Program).

As the very first female Cameroonian to be awarded Microsoft MVP, this recognition reflects years of consistent contribution, technical excellence, and community impact. The program connects me with a global network that I actively leverage to bring visibility, resources, and opportunities back to Django and Python communities, bridging local initiatives with global platforms to amplify Django’s reach and relevance. It demonstrates that my work is recognized at the highest levels of the industry.

As a young Black African woman in STEM from a region of Africa with pretty limited resources and an active DSF member, I’ve dedicated my career to fostering inclusivity and representation in the tech and scientific spaces and I am confident that I bring a unique perspective to the table.

I will push the DSF to be more than a steward of code, to be a catalyst for global belonging. My priorities are:

  • Radical inclusion: I'll work to expand resources and support for contributors from underrepresented regions, especially in Africa, Latin America, and Southeast Asia. This includes funding for local events, mentorship pipelines, and multilingual documentation sprints.
  • Sustainable community infrastructure: I’ll advocate for sustainable models of community leadership, ones that recognize invisible labor, prevent burnout, and promote distributed governance. We need to rethink how we support organizers, maintainers, and contributors beyond code.
  • Ethical tech advocacy: I’ll help the DSF navigate the ethical dimensions of Django’s growing role in AI and data-driven systems. From privacy to fairness, Django can lead by example. And I’ll work to ensure our framework reflects our values.
  • Global partnerships: I want to strengthen partnerships with regional communities and allied open-source foundations, ensuring Django’s growth is global and socially conscious.

I will bring diversity, a young and energized spirit that I think most senior boards lack. My vision is for the DSF to not only maintain Django but to set the standard for inclusive, ethical, and sustainable open source. My goal is simple: to make Django the most welcoming, resilient, and socially conscious web framework in the world.

Arunava Samaddar (he/him) India

View personal statement

Information Technology Experience 15 years

Microsoft Technology Python MongoDB Cloud Technology Testing People Manager Supervisor L2 Production Support and Maintenance

Well experience in software sales product delivery operations Agile Scrum and Marketing.

Chris Achinga (he/him) Mombasa, Kenya

View personal statement

I am a software developer, primarily using Python and Javascript, building web and mobile applications. At my workplace, I lead the Tech Department and the Data team.

I love developer communities and supported emerging developers through meetups, training, and community events including PyCon Kenya, local Django Meetup and university outreach.

At Swahilipot Hub, I built internal tools, supported digital programs, and mentored over 300 young developers through industrial attachment programs. I primarily use Django and React to development internal tools, websites (Swahilipot Hub) including our radio station site (Swahilipot FM).

I also work with Green World Campaign Kenya on the AIRS platform, where we use AI, cloud technology, and blockchain to support environmental projects and rural communities.

Outside of engineering, I write technical content and actively organise and support developer communities along the Kenyan coast to help more young people grow into tech careers - Chris Achinga’s Articles and Written Stuff

I would want to get involved more on the community side, diversity in terms of regional presentation and awareness of Django, and the Django Software Foundation. In as much as they's a lot of efforts in place. With no available African entity of the DSF, this would make it difficult for companies/organization in Africa to donate and support the DSF, I would love to champion for that and pioner towards that direction, not only for Africa but also for other under-represented geographical areas.

I wasn't so sure about this last year, but I am more confident, with a better understanding of the Django ecosystem and I know I have the capabilities of getting more contributions to Django, both financially and code-wise. I would also love to make sure that Django and the ecosystem is well know through proper communication channels, I know this differs based on different countries, the goal is to make sure that the DSF is all over, of course, where we are needed. Create the feeling that Django is for everyone, everywhere!

Dinis Vasco Chilundo (he/him) Cidade de Inhambane, Mozambique

View personal statement

I am a Rural Engineer from Universidade Eduardo Mondlane with practical experience in technology, data management, telecommunications, and sustainabilitty

In recent years, I have worked as a trainer and coach, as well as a researcher, empowering young people with programming, digital skills, and data analysis. I have also contributed to open-source projects, promoting access to technology and remote learning in several cities across Mozambique. These experiences have strengthened my belief in the power of open-source communities to create opportunities, foster collaboration, and drive innovation in regions with limited resources.

The thing I want the DSF to do is to expand its support for students and early career professionals.Personally, what I want to achieve is collaboration and transparency in actions as integrity is non negotiable.

Jacob Kaplan-Moss (he/him) Oregon, USA

View personal statement

I was one of the original maintainers of Django, and was the original founder and first President of the DSF. I re-joined the DSF board in 2023, and have served as Treasurer since 2024. I used to be a software engineer and security consultant (REVSYS, Latacora, 18F, Heroku), before mostly retiring from tech in 2025 to become an EMT.

I've been a member of the DSF Board for 3 years, so I bring some institutional knowledge there. I've been involved in the broader Django community as long as there has been a Django community, though the level of my involvement has waxed and waned. The accomplishments I'm the most proud of in the Django community are creating our Code of Conduct (djangoproject.com/conduct/), and more recently establishing the DSF's Working Groups model (django/dsf-working-groups).

Outside of the Django community, I have about 15 years of management experience, at companies small and large (and also in the US federal government).

I'm running for re-election with three goals for the DSF: (a) hire an Executive Director, (b) build more ""onramps"" into the DSF and Django community, and (c) expand and update our Grants program.

Hire an ED: this is my main goal for 2026, and the major reason I'm running for re-election. The DSF has grown past the point where being entirely volunteer-ran is working; we need transition the organization towards a more professional non-profit operation. Which means paid staff. Members of the Board worked on this all throughout 2025, mostly behind the scenes, and we're closer than ever -- but not quite there. We need to make this happen in 2026.

Build ""onramps"": this was my main goal when I ran in 2024 (see my statement at 2024 DSF Board Candidates). We've had some success there: several Working Groups are up and running, and over on the technical side we helped the Steering Council navigate a tricky transition, and they're now headed in a more positive direction. I'm happy with our success there, but there's still work to do; helping more people get involved with the DSF and Django would continue to be a high-level goal of mine. And, I'd like to build better systems for recognition of people who contribute to the DSF/Django — there are some incredible people working behind the scenes that most of the community has heard of.

Expand and update our grants program: our grants program is heavily overdue for a refresh. I'd like to update our rules and policies, make funding decisions clearer and less ad-hoc, increase the amount of money we're giving per grant, and (funding allowing) expand to to other kinds of grants (e.g. travel grants, feature grants, and more). I'd also like to explore turning over grant decisions to a Working Group (or subcommittee of the board), to free up Board time for more strategic work.

Julius Nana Acheampong Boakye (he/him) Ghana

View personal statement

I’m a proud Individual Member of the Django Software Foundation and a full-stack software engineer with a strong focus on Django and mobile development. Beyond code, I’m deeply involved in the global Python and Django , Google & FlutterFlow communities, actively contributing to the organization of several major conferences around the world.

I am a passionate full-stack software engineer with a strong focus on Django and mobile development. Over the years, I’ve contributed to the global Python and Django communities through volunteering, organizing, and speaking. I served as the Opportunity Grant Co-Chair for DjangoCon US (2024 & 2025), where I help ensure accessibility and inclusion for underrepresented groups. I also helped Organise DjangoCon Europe, where my impact was felt (see LinkedIn post)

I was also the as Design Lead for PyCon Africa 2024 and PyCon Ghana 2025 , where i worked everything designs to make the conference feel like home (see LinkedIn post) and I also helped organise other regional events, including DjangoCon Africa, PyCon Namibia, PyCon Portugal and etc. Beyond organising, I’ve spoken at several local and international conferences, sharing knowledge and promoting community growth including PyCon Africa, DjangoCon Africa, PyCon Nigeria, and PyCon Togo.

I’m also an Individual Member of the Django Software Foundation, and my work continues to center on empowering developers, building open communities, and improving access for newcomers in tech.

As a board member, I want to help strengthen Django’s global community by improving accessibility, diversity, and engagement especially across regions where Django adoption is growing but still lacks strong community infrastructure, such as Africa and other underrepresented areas.

My experience as Opportunity Grant Co-Chair for DjangoCon US and Design Lead for PyCon Africa has shown me how powerful community-driven support can be when it’s backed by inclusion and transparency. I want the DSF to continue building bridges between developers, organizers, and contributors making sure that everyone, regardless of location or background, feels seen and supported.

I believe the DSF can take a more active role in empowering local communities, improving mentorship pathways, and creating better visibility for contributors who work behind the scenes. I also want to support initiatives that make Django more approachable to new developers through clearer learning materials and global outreach programs.

Personally, I want to help the DSF improve communication with international communities, expand partnerships with educational programs and tech organizations, and ensure the next generation of developers see Django as not just a framework, but a welcoming and sustainable ecosystem.

My direction for leadership is guided by collaboration, empathy, and practical action building on Django’s strong foundation while helping it evolve for the future

Kyagulanyi Allan (he/him) Kampala, Uganda

View personal statement

I am Kyagulanyi Allan, a software developer, and co-founder at Grin Mates. Grin Mates is an eco-friendly EVM dApp with an inbuilt crypto wallet that awards Green points for verified sustainable activities. Ii am very excited about the potential of web3 and saddened by some other parts of it.

I am a developer, and I have been lucky to volunteer and also contribute. I worked on diverse projects like AROC and Grin Mates. I volunteered as a Google student developer lead at my university, when i was working at after query experts on project pluto. I used Python to train the LLM mode on bash/linux commands.

My position on key issues is on advancing and advocating for inclusiveness, with priority on children from rural areas.

Nicole Buque (she) Maputo, Mozambique

View personal statement

My name is Nicole Buque, a 20-year-old finalist student in Computer Engineering from Mozambique. I am deeply passionate about data analysis, especially in the context of database systems, and I love transforming information into meaningful insights that drive innovation.

During my academic journey, I have worked with Vodacom, contributing to website development projects that improved digital communication and accessibility. I also participated in the WT Bootcamp for Data Analysis, where I gained strong analytical, technical, and teamwork skills. As an aspiring IT professional, I enjoy exploring how data, systems, and community collaboration can create sustainable solutions. My experience has helped me develop both technical expertise and a people-centered approach to technology — understanding that real progress comes from empowering others through knowledge

Nkonga Morel (he/him) Cameroun

View personal statement

Curious, explorer, calm, patient

My experience on Django is medium

My direction for the DSF is one of growth, mentorship, and openness ,ensuring Django remains a leading framework not just technically, but socially.

Ntui Raoul Ntui Njock (he/his) Buea, Cameroon

View personal statement

I'm a software engineer posionate about AI/ML and solving problems in the healthcare sector in collaboration with others.

I'm a skilled software engineer in the domain of AI/ML, Django, Reactjs, TailwindCSS. I have been building softwares for over 2 years now and growing myself in this space has brought some level of impact in the community as I have been organizing workshops in the university of Buea, teaching people about the Django framework, I also had the privilege to participate at the deep learning indaba Cameroon where I was interviewed by CRTV to share knowledge with respect to deep learning. You could see all these on my LinkedIn profile (Ntui Raoul).

I believe that in collaboration with others at the DSF, I'll help the DSF to improve in it's ways to accomplish its goals. I believe we shall improve on the codebase of Django framework, it's collaboration with other frameworks so as to help the users of the framework to find it more easy to use the Django framework. Also I'll help to expand the Django framework to people across the world.

Priya Pahwa (she/her) India, Asia

View personal statement

I'm Priya Pahwa (she/her), an Indian woman who found both community and confidence through Django. I work as a Software Engineer (Backend and DevOps) at a fintech startup and love volunteering in community spaces. From leading student communities as a GitHub Campus Expert to contributing as a GitHub Octern and supporting initiatives in the Django ecosystem, open-source is an integral part of my journey as a developer.

My belonging to the Django community has been shaped by serving as the Session Organizer of the global Djangonaut Space program, where I work closely with contributors and mentors from diverse geographies, cultures, age groups, and both coding and non-coding backgrounds. Being part of the organizing team for Sessions 3, 4, and ongoing 5, each experience has evolved my approach towards better intentional community stewardship and collaboration.

I also serve as Co-Chair of the DSF Fundraising Working Group since its formation in mid-2024. As we enter the execution phase, we are focused on establishing additional long-term funding streams for the DSF. I intend to continue this work by:

  • Running sustained fundraising campaigns rather than one-off appeals
  • Building corporate sponsorship relationships for major donations
  • Focusing on the funding of the Executive Director for financial resilience

My commitment to a supportive ecosystem guides my work. I am a strong advocate of psychological safety in open-source, a topic I've publicly talked about (“Culture Eats Strategy for Breakfast” at PyCon Greece and DjangoCongress Japan). This belief led me to join the DSF Code of Conduct Working Group because the health of a community is determined not only by who joins, but by who feels able to stay.

If elected to the board, I will focus on:

  • Moving fundraising WG from “effort” to infrastructure (already moving in the direction by forming the DSF prospectus)
  • Initiating conference travel grants to lower barriers and increase participation for active community members
  • Strengthening cross-functional working groups' collaboration to reduce organizational silos
  • Designing inclusive contributor lifecycles to support pauses for caregiving or career breaks
  • Highlighting diverse user stories and clearer “here’s how to get involved” community pathways
  • Amplifying DSF’s public presence and impact through digital marketing strategies

Quinter Apondi Ochieng (she) Kenya-Kisumu City

View personal statement

my name is Quinter Apondi Ochieng from Kisumu city , i am a web developer from kisumu city , Django has been part of my development professional journey for the past two years , i have contributed to local meetups as a community leader, developed several website one being an e-commerce website , also organized Django Girls kisumu workshop which didn't come to success due to financial constrains, workshop was to take place 1st November but postponed it.

In my current position, i lead small team building Django based applications, i have also volunteered as python kisumu community committee member which i served as a non-profit tech boards driven by passion.The experience have strengthen my skills in collaborations , decision making , long-term project planning and governance.I understand how important it is for the DSF to balance technical progress with sustainability and transparency.

The challenge I can help to negotiate is limited mentorship and unemployment. It has always blown my mind why IT, computer science, and SWE graduates struggle after campus life. In my country, SWE,IT and comp sci courses have final year projects that they pass and that have not been presented to any educational institute. I believe that if those projects are shipped, unemployment will be cut by over 50 %.

Rahul Lakhanpal (he/him) Gurugram, India

View personal statement

I am a software architect working for over 13 years in the field of software development based out of Gurugram, India. For the past 8 years, I have been working 100% remotely, working as an independent contractor under my own company deskmonte

As a kid I was always the one breaking more toys than I played with and was super curious. Coming from a normal family background, we always had a focus on academics. Although I did not break into the top tier colleges, the intent and curiosity to learn more stayed.

As of now, I am happily married with an year old kid.

My skills are primarily Python and Django, have been using the same tech stack since the last decade. Have used it to create beautiful admin interfaces for my clients, have written APIs in both REST using django rest framework package along with GraphQL using django-graphene. Alongside, have almost always integrated Postgres and Celery+Redis with my core tech stack.

In terms of volunteering, I have been an active code mentor at Code Institute, Ireland and have been with them since 2019, helping students pick up code using Python and Django for the most part.

I love the django rest framework and I truly believe that the admin interface is extremely powerful and the utility of the overall offering is huge.

I would love to take django to people who are just starting up, support and promote for more meetups/conferences that can focus on django along with advancing django's utility in the age of AI.

Ryan Cheley (he/him) California, United States

View personal statement

I'm Ryan and I’m running for the DSF Board in the hopes of being the Treasurer. I've been using Django since 2018. After several years of use, I finally had a chance to attend DjangoCon US in 2022. I felt like I finally found a community where I belonged and knew that I wanted to do whatever I could to give back.

My involvement with the community over the last several years includes being a:

If elected to the board, I would bring valuable skills to benefit the community, including:

  • Managing technical teams for nearly 15 years
  • Nearly 20 years of project management experience
  • Overseeing the financial operations for a team of nearly 30
  • Consensus-building on large projects

I'm particularly drawn to the treasurer role because my background in financial management and budgeting positions me to help ensure the DSF's continued financial health and transparency.

For more details on my implementation plan, see my blog post Details on My Candidate Statement for the DSF.

If elected to the DSF Board I have a few key initiatives I'd like to work on:

  1. Getting an Executive Director to help run the day-to-day operations of the DSF
  2. Identifying small to midsized companies for sponsorships
  3. Implementing a formal strategic planning process
  4. Setting up a fiscal sponsorship program to allow support of initiatives like Django Commons

I believe these are achievable in the next 2 years.

Sanyam Khurana (he/him) Toronto, Canada

View personal statement

I’m Sanyam Khurana (“CuriousLearner”), a seasoned Django contributor and member of the djangoproject.com Website Working Group, as well as a CPython bug triager and OSS maintainer. I’ve worked in India, the U.K., and Canada, and I’m focused on inclusion, dependable tooling, and turning first-time contributors into regulars.

I’ve contributed to Django and the wider Python ecosystem for years as a maintainer, reviewer, and issue triager. My Django-focused work includes django-phone-verify (auth flows), django-postgres-anonymizer (privacy/data handling), and Django-Keel (a production-ready project template). I also build developer tooling like CacheSniper (a tiny Rust CLI to sanity-check edge caching).

Repos: django-phone-verify , django-postgres-anonymizer , django-keel , cache_sniper

CPython & Django contributions: django commits, djangoproject.com commits, CPython commits

Beyond code, I’ve supported newcomers through docs-first guidance, small PR reviews, and patient issue triage. I’m a CPython bug triager and listed in Mozilla credits, which taught me to balance openness with careful review and clear process. I’ve collaborated across India, UK, and Canada, so I’m used to async work, time-zones, and transparent communication.

I owe my learnings to the community and want to give back. I understand the DSF Board is non-technical leadership like fundraising, grants/sponsorships, community programs, CoC support, and stewardship of Django’s operations and not deciding framework features. That’s exactly where I want to contribute.

I’ll push for an easy, skimmable annual “Where your donation went” report (fellows, events, grants, infra) plus lightweight quarterly updates. Clear storytelling helps retain individual and corporate sponsors and shows impact beyond core commits.

I want to grow contributors globally by turning their first PR into regular contributions. I want to make this path smoother by funding micro-grants for mentorship/sprints and backing working groups with small, delegated budgets under clear guardrails - so they can move fast without waiting on the Board.

I propose a ready-to-use “starter kit” for meetups/sprints: budget templates, venue ask letters, CoC, diversity travel-grant boilerplates, and a sponsor prospectus. We should prioritize regions with high Django usage but fewer historic DSF touchpoints (South Asia, Africa, LATAM). This comes directly from organizing over 120 meetups and annual conference like PyCon India for 3 years.

  • Your move now

    That’s it, you’ve read it all 🌈! Be sure to vote if you’re eligible, by using the link shared over email. To support the future of Django, donate to the Django Software Foundation on our website or via GitHub Sponsors. We also have our 30% Off PyCharm Pro – 100% for Django 💚.

  • November 06, 2025 05:00 AM UTC