Planet Python
Last update: September 12, 2025 04:43 AM UTC
September 12, 2025
Graham Dumpleton
Status of wrapt (September 2025)
The Python wrapt package recently turned 12 years old. Originally intended to be a module for monkey patching Python code, its wrapper object turned out to be a useful basis for creating Python decorators.
Back then, constructing decorators using function closures had various short comings and the resulting wrappers didn't preserve introspection and various other attributes associated with the wrapped function. Many of these issues have been resolved in updates to Python and the functools.wraps
helper function, but wrapt
based decorators were still useful for certain use cases such as being able to create a decorator where you could work out whether it was applied to a function, instance method, class method or even a class.
Downloads of wrapt
It is hard to tell how many people directly use wrapt
, but helped by it being used internally in some widely used Python packages has actually resulted in wrapt
making it into the list of PyPi top 100 packages by number of downloads. As I write this post it sits at position number 65, but it was at one point as high as about position 45. Either way, I am still surprised it makes it into that list at all, especially since the primary purpose of wrapt
is to do something most view as dangerous, ie., monkey patch code.
Maintenance mode
As to the core problem that wrapt
originally tried to solve, that was achieved many years ago and as such it has more or less been kept in maintenance mode ever since. Most changes over recent years have focused around ensuring it works with each new Python version and expanding on the set of Python wheels that are being released for different architectures. There are occassionaly bug fixes or tweaks but generally they relate to corner cases which have arisen due to people trying to do strange things when monkey patching code.
Version update
Even though few changes are being made, the plan is to soon release a new version. This version number for this release will jump from 1.17.X to 2.0.X.
The jump in major version isn't due to any known incompatibilities but more just to be safe since in this version all the old legacy code from Python 2 and early Python 3 versions has been removed.
PyCharm issues
The only obscure change which have any concern over relates to a specific corner case that should never occur in actual use, but does occur when using Python debugger IDEs such as PyCharm which offer live views of Python objects.
The problem in the case of PyCharm is that it can attempt to display the state of a Python object before the __init__()
method has been called. Due to the wrapper object in wrapt
being implemented in C code, that there is an accessor for the __wrapped__
attribute is visible, but until __init__()
is called it has no value. All the same, PyCharm tries to access __wrapped__
during that time resulting in an exception.
For this exception when __wrapped__
is accessed in an uninitialised state a ValueError
exception was being raised on the basis that the object was in an unknown state. The problem is that PyCharm doesn't gracefully handle this exception in this case and this somehow causes problems for PyCharm users.
What PyCharm prefers in this case is to see an AttributeError
exception which results in it simply ignoring the attribute. Because it isn't known whether raising AttributeError
instead of ValueError
would cause issues for other existing code, I have been reticent to change the type of exception being raised.
At one point someone suggested raising a custom exception which inherits from both AttributeError
and ValueError
as a middle ground, allowing PyCharm to work but not cause issues for existing code.
Because one can't use multiple inheritence for custom exceptions implemented in C code, a fiddle has been required whereby the C extension code of wrapt
reaches back to get a reference to an exception type implemented in Python code. Not elegant but appears to work so going to go with that and see if it works. Remember that this situation where the exception is raised should not even occur normally, so it may only be PyCharm that triggers it. Fingers crossed.
Typing hints
The other notable change for the next wrapt
release will be the addition of support for type hints.
Adding type hints has been slow coming because wrapt
supported Python 2 and older Python 3 versions well past when those versions became obsolete. Since such old versions were still supported, I didn't see it as practical to add support for type hints.
Even now, although the next wrapt
version will still support Python version 3.8 and 3.9, the support for type hints will only be available if using Python 3.10 or later. This is because I finally realised that when using .pyi
files to inject type hints, you could have version checks and only add them for selected versions. đ€Šââïž
Another reason type hint support took so long to be added was simply because I wasn't that familiar with using them. Some users did propose changes to add type hints, but they seemed to me to be very minimal and not try and add support across the full APIs wrapt
provided. Because I didn't understand type hints enough, I didn't want to risk adding them without really understanding how they worked.
This is not to say I am now an expert on type hints, I am definitely still a newbie and know just enough to be dangerous.
The resulting type hint support I added looks plenty scary to me and unfortunately still doesn't do everything I would like it to. My current belief is that due to the complicated overloading that wrapt
does in certain APIs, that it just isn't possible within the limits of what the type hinting system can handle to do better than what I have managed. I haven't given up, but I also don't want to delay the next wrapt
release any further, so will release it as is and revisit it later on to see if it can be made better.
Release candidates
With that all said, a release candidate for the next version of wrapt
has been available for about a month. This can be installed by explicitly using wrapt==2.0.0rc2
or if your package installer supports it, to use unstable package versions such as release candidate versions.
After being out for a month I have not had any reports of the release candidate version causing any issues. That said, no one has said it works fine either. There has been something like 190 thousand downloads of the release candidate in that time though, so that is a good sign at least.
At this point it seems to be safe to release a 2.0.0 final version, so I will be aiming to double check everything over the coming week and get the new version released in time for Python 3.14. That said, Python 3.14 doesn't make it a priority as there was a 1.17.3 patch release version of wrapt
a month ago which included Python wheels for Python 3.14, so every thing should be good to go for the new Python version.
List of changes
If you are interested in exactly what changes have made it into the next release, you can check out the develop
branch for the wrapt
docs on ReadTheDocs.
September 12, 2025 12:00 AM UTC
September 11, 2025
Graham Dumpleton
Back from the dead
I'm back.
Yes, it's been quite a long time. It's actually more than six years since my last blog post.
There are a few reasons for this. The main one is that after IBM acquired Red Hat, and later when I moved to VMware/Broadcom, I didn't always feel comfortable posting on my personal blog or speaking as freely as I would have liked. I was also less involved with my open source projects and busy working on something new that I couldn't actively promote at the time. So, I decided to step away from blogging for a while; I just didn't know how long that would end up being.
After being made redundant at Broadcom about a year ago, I've been on sabbatical, or what some call "micro retirement." Given the current state of the IT industry, this micro retirement may well turn into full retirement.
In my last three jobs, going back to 2010, I've worked remotely from home and only left the house for work when traveling to conferences or, on rare occasions, visiting the office. While I had the opportunity to travel for conferences during my time at New Relic and Red Hat, that changed when I moved to VMware. COVID disrupted everything, and travel was no longer possible. What I had expected to do at VMware also didn't really materialise, and I ended up working on other projects that didn't involve conference travel.
Although I never got to work on what I expected to at VMware, especially with COVID and all the uncertainty surrounding the Broadcom acquisition, by keeping my head down and staying out of sight, I was able to spend quite a lot of time working on a project of my own where I was able to set direction and do what I thought was required. An ideal situation for remote work and it suited me well, even if the overall work environment wasn't the best at the time.
Looking for a job now though, the prospect of being able to find a company who will take on a fully remote worker is very slim. All the companies I feel might have been a good place for me to work at are in the US, and these days even if they are hiring remote workers, you must still be in the US. Gone are the days where it was easier for someone located in Australia to get a job working for a US based company or team of people.
In the Australian job market, anything interesting is on site, or hybrid, requiring 2 or 3 days in the office, which isn't convenient for me. So right now I am a bit stuck on the job front and there is no clear path. The motivation for in office work just isn't there since I am so used to working from home.
Ideally I would find a company who actively supports open source and pays people to work on open source projects. Although I know of a few companies like this, as already noted the problem is they are in the US and will only hire remote workers who are also in the US.
So what next?
For now at least, the aim is to try and build links again with the Python community, since I have lost touch with what has been going on, not attending conferences like I used to, and not actively blogging.
I've only been doing the minimum required on my mod_wsgi and wrapt open source projects, and although I managed a flurry of activity on both a few weeks back, I held back from actually making a new release for each.
First priority, therefore, is to put out some blog posts on the current state of mod_wsgi and wrapt and get some new releases out, hopefully in time for Python 3.14.
I want to then start posting about my other new project called Educates. Although it will be new to others, the project is actually over 5 years old and has been available for quite a while, it just wasn't being promoted. The project may satisfy a small niche of users, but the amount of work I have put into it is significant, more than mod_wsgi or wrapt, so I don't want to cast it aside just yet.
So now that I have resurrected my blog site, hopefully I can keep the momentum up and meaningfully start applying myself to my open source projects and contribute to the Python community in some way, rather than spending an obsessive amount of time watching anime.
September 11, 2025 12:00 AM UTC
September 10, 2025
Real Python
How to Drop Null Values in pandas
Missing values can derail your analysis. In pandas, you can use the .dropna()
method to remove rows or columns containing null valuesâin other words, missing dataâso you can work with clean DataFrames. In this tutorial, youâll learn how this methodâs parameters let you control exactly which data gets removed. As youâll see, these parameters give you fine-grained control over how much of your data to clean.
Dealing with null values is essential for keeping datasets clean and avoiding the issues they can cause. Missing entries can lead to misinterpreted column data types, inaccurate conclusions, and errors in calculations. Simply put, nulls can cause havoc if they find their way into your calculations.
By the end of this tutorial, youâll understand that:
- You can use
.dropna()
to remove rows and columns from a pandas DataFrame. - You can remove rows and columns based on the content of a subset of your DataFrame.
- You can remove rows and columns based on the volume of null values within your DataFrame.
To get the most out of this tutorial, itâs recommended that you already have a basic understanding of how to create pandas DataFrames from files.
Youâll use the Python REPL along with a file named sales_data_with_missing_values.csv
, which contains several null values youâll deal with during the exercises. Before you start, extract this file from the downloadable materials by clicking the link at the end of this section.
The sales_data_with_missing_values.csv
file is based on the publicly available and complete sales data file from Kaggle. Understanding the fileâs content isnât essential for this tutorial, but you can explore the Kaggle link above for more details if youâd like.
Youâll also need to install both the pandas and PyArrow libraries to make sure all code examples work in your environment:
Itâs time to refine your pandas skills by learning how to handle missing data in a variety of ways.
Youâll find all code examples and the sales_data_with_missing_values.csv
file in the materials for this tutorial, which you can download by clicking the link below:
Get Your Code: Click here to download the free sample code that youâll use to learn how to drop null values in pandas.
Take the Quiz: Test your knowledge with our interactive âHow to Drop Null Values in pandasâ quiz. Youâll receive a score upon completion to help you track your learning progress:
Interactive Quiz
How to Drop Null Values in pandasQuiz yourself on pandas .dropna(): remove nulls, clean missing data, and prepare DataFrames for accurate analysis.
How to Drop Rows Containing Null Values in pandas
Before you start dropping rows, itâs helpful to know what options .dropna()
gives you. This method supports six parameters that let you control exactly whatâs removed:
axis
: Specifies whether to remove rows or columns containing null values.thresh
andhow
: Define how many missing values to remove or retain.subset
: Limits the removal of null values to specific parts of your DataFrame.inplace
: Determines whether the operation modifies the original DataFrame or returns a new copy.ignore_index
: Resets the DataFrame index after removing rows.
Donât worry if any of these parameters donât make sense to you just yetâyouâll learn why each is used during this tutorial. Youâll also get the chance to practice your skills.
Note: Although this tutorial teaches you how pandas DataFrames use .dropna()
, DataFrames arenât the only pandas objects that use it.
Series objects also have their own .dropna()
method. However, the Series version contains only four parametersâaxis
, inplace
, how
, and ignore_index
âinstead of the six supported by the DataFrame version. Of these, only inplace
and ignore_index
are used, and they work the same way as in the DataFrame method. The rest are kept for compatibility with DataFrame, but have no effect.
Indexes also have a .dropna()
method for removing missing index values, and it contains just one parameter: how
.
Before using .dropna()
to drop rows, you should first find out whether your data contains any null values:
>>> import pandas as pd
>>> pd.set_option("display.max_columns", None)
>>> sales_data = pd.read_csv(
... "sales_data_with_missing_values.csv",
... parse_dates=["order_date"],
... date_format="%d/%m/%Y",
... ).convert_dtypes(dtype_backend="pyarrow")
>>> sales_data
order_number order_date customer_name \
0 <NA> 2025-02-09 00:00:00 Skipton Fealty
1 70041 <NA> Carmine Priestnall
2 70042 2025-02-09 00:00:00 <NA>
3 70043 2025-02-10 00:00:00 Lanni D'Ambrogi
4 70044 2025-02-10 00:00:00 Tann Angear
5 70045 2025-02-10 00:00:00 Skipton Fealty
6 70046 2025-02-11 00:00:00 Far Pow
7 70047 2025-02-11 00:00:00 Hill Group
8 70048 2025-02-11 00:00:00 Devlin Nock
9 <NA> <NA> <NA>
10 70049 2025-02-12 00:00:00 Swift Inc
product_purchased discount sale_price
0 Chili Extra Virgin Olive Oil True 135.0
1 <NA> <NA> 150.0
2 Rosemary Olive Oil Candle False 78.0
3 <NA> True 19.5
4 Vanilla and Olive Oil Candle <NA> 13.98
5 Basil Extra Virgin Olive Oil True <NA>
6 Chili Extra Virgin Olive Oil False 150.0
7 Chili Extra Virgin Olive Oil True 135.0
8 Lavender and Olive Oil Lotion False 39.96
9 <NA> <NA> <NA>
10 Garlic Extra Virgin Olive Oil True 936.0
To make sure all columns appear on your screen, you configure pd.set_option("display.max_columns", None)
. By passing None
as the second parameter, you make sure all columns are displayed.
You read the sales_data_with_missing_values.csv
file into a DataFrame using the pandas read_csv()
function, then view the data. The order dates are in the "%d/%m/%Y"
format in the file, so to make sure the order_date
data is read correctly, you use both the parse_dates
and date_format
parameters. The output reveals there are ten rows and six columns of data in your file.
Read the full article at https://realpython.com/how-to-drop-null-values-in-pandas/ »
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 10, 2025 02:00 PM UTC
Quiz: How to Drop Null Values in pandas
Challenge yourself with this quiz and see how much you understand about dropping null values in pandas.
Working through this quiz is a great way to revisit what you learned in the How to Drop Null Values in pandas tutorial. You’ll find most of the answers in the tutorial content, but for some of the questions, you might need to do some extra digging.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 10, 2025 12:00 PM UTC
Quansight Labs Blog
Scaling asyncio on Free-Threaded Python
A recap on the work done in Python 3.14 to enable asyncio to scale on the free-threaded build of CPython.
September 10, 2025 12:00 AM UTC
September 09, 2025
PyCoderâs Weekly
Issue #698: Capturing Stdout, REPL Color, Feature History, and More (Sept. 9, 2025)
#698 â SEPTEMBER 9, 2025
View in Browser »
Python: Capture Stdout and Stderr in Unittest
When testing code that outputs to the terminal through either standard out (stdout) or standard error (stderr), you might want to capture that output and make assertions on it.
ADAM JOHNSO
Customizing Your Python 3.14 REPL’s Color Scheme
The upcoming release of Python 3.14 includes syntax highlighting in the REPL and you can control its color scheme and make it your own.
TREY HUNNER
On Demand: Design Long-Running, Human-Aware MCP
Move beyond chatbots to build durable MCP servers that run for days, survive failures, and orchestrate elicitations and LLM sampling. Learn remote MCP trade-offs and patterns for sophisticated, or ambient, agents in this on-demand webinar â
TEMPORAL sponsor
A History of Python Versions and Features
Explore Pythonâs evolution from the 1990s to today with a brief history and demos of key features added throughout its lifetime.
REAL PYTHON course
Articles & Tutorials
Large Language Models on the Edge of the Scaling Laws
What’s happening with the latest releases of large language models? Is the industry hitting the edge of the scaling laws, and do the current benchmarks provide reliable performance assessments? This week on the show, Jodie Burchell returns to discuss the current state of LLM releases.
REAL PYTHON podcast
Python Has Had Async for 10 Years
Anthony Shaw poses the question: Python has had async for 10 years, so why isn’t it more popular? He dives deep on where async is useful and where it is limited. Associated HN discussion.
ANTHONY SHAW
Engineer-led Demos, Live AMA, and More â all at Glean:LIVE
Donât miss Gleanâs product launch on Sept 25th. Get a first look at Gleanâs new Assistant, see how to vibe code an agent, and catch engineer-led demos. This launch is all about empowering you with a more personalized experience and upleveling the skills only you can bring to your work. Register now! here â
GLEAN sponsor
Top 6 Python Libraries for Visualization: Which One to Use?
The vast number of Python visualization libraries can be overwhelming. This article shows you the pros and cons of some the popular libraries, including Matplotlib, seaborn, Plotly, Bokeh, Altair, and Pygal.
CODECUT.AI âą Shared by Khuyen Tran
Open Source Is a Gift
This opinion piece talks about how open source isn’t just a gift of free libraries, but the gift of learning from others who are developing in public.
JOSH THOMAS.
Managing Multiple Python Versions With pyenv
Learn how to use pyenv to manage multiple Python versions, prevent conflicts, and keep your projects compatible and development smooth.
REAL PYTHON
uv
vs pip
: Managing Python Packages and Dependencies
Compare uv and pip with benchmarks, speed tests, and dependency management tips. Learn which tool is best for your Python projects.
REAL PYTHON
Profiling Performance in Python
Learn to profile Python programs with built-in and popular third-party tools, and turn performance insights into faster code.
REAL PYTHON course
Python 3.14: 3 Smaller Features
With a jam packed 3.14 release around the corner, it’s also important to look at the smaller features coming to Python
JAMIE CHANG âą Shared by Jamie Chang
Looking Forward to Django 6.0
This post is an update on the progress of Django 6 and describes many of the features that will be in it.
CARLTON GIBSON
Youâre a Developer, not a Jenkins Admin
Switch to Bitbucket Pipelines: build, test, deploy, and get back to being a dev.
ATLASSIAN sponsor
When You No Longer Need That Object
Explore reference counting and cyclic garbage collection in Python.
STEPHEN GRUPPETTA
The Flowing River: List Comprehensions
Understanding how Python’s list comprehensions work under the hood
SUBSTACK.COM âą Shared by Vivis Dev
Projects & Code
A GitHub Seach Inpired Interface to DataFrames
GITHUB.COM/WILLIAMBDEAN âą Shared by William Dean
vectorwrap: Swap Vector Databases by Changing the URL
GITHUB.COM/MIHIRAHUJA1 âą Shared by Mihir Ahuja
Events
Weekly Real Python Office Hours Q&A (Virtual)
September 10, 2025
REALPYTHON.COM
Python Atlanta
September 11 to September 12, 2025
MEETUP.COM
PyCon India 2025
September 12 to September 16, 2025
PYCON.ORG
PyCon AU 2025
September 12 to September 17, 2025
PYCON.ORG.AU
PyCamp CZ 25 Beta
September 12 to September 15, 2025
PYCAMP.CZ
Django Girls Abraka Workshop
September 12 to September 13, 2025
DJANGOGIRLS.ORG
PyCon Niger 2025
September 13 to September 16, 2025
PYCON.ORG
PyCon UK 2025
September 19 to September 23, 2025
PYCONUK.ORG
Happy Pythoning!
This was PyCoder’s Weekly Issue #698.
View in Browser »
[ Subscribe to đ PyCoder’s Weekly đ â Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]
September 09, 2025 07:30 PM UTC
Real Python
Python String Splitting
Python’s .split()
method lets you divide a string into a list of substrings based on a specified delimiter. By default, .split()
separates at whitespace, including spaces, tabs, and newlines. You can customize .split()
to work with specific delimiters using the sep
parameter, and control the amount of splits with maxsplit
.
By the end of this video course, you’ll understand that:
- You split a string by spaces in Python using
.split()
without arguments. - Python’s
.split()
method can split on custom delimiters when you pass a character or string as an argument. - You limit splits using
maxsplit
to control the number of substrings Python extracts. re.split()
uses regular expressions for splitting strings based on complex patterns.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 09, 2025 02:00 PM UTC
PythonâSpeed
Testing the compiler optimizations your code relies on
In a recent article by David Lattimore, he demonstrates a number of Rust performance tricks, including one that involve writing code that looks like a loop, but which in practice is optimized down to a fixed number of instructions. Having what looks like an O(n) loop turned into a constant operation is great for speed!
But thereâs a problem with this sort of trick: how do you know the compiler will keep doing it? What happens when the compilerâs next release comes out? How can you catch performance regressions?
One solution is benchmarking: you measure your codeâs speed, and if it gets a lot slower, something has gone wrong. This is useful and important if you care about speed. But itâs also less localized, so it wonât necessarily immediately pinpoint where the regression happened.
In this article Iâm going to cover another approach: a test that will only pass if the compiler really did optimize the loop away.
Read more...September 09, 2025 12:00 AM UTC
September 08, 2025
Python Morsels
Python REPL Shortcuts & Features
Discover the new Python REPL features introduced in Python 3.13. From keyboard shortcuts to block navigation, this reference guide will help you better utilize Python's interactive shell.
Table of contents
Python REPL Keyboard Shortcuts
Let's start with the keyboard shortcuts the new Python REPL supports. This table is organized with the most useful shortcuts at the top.
Shortcut | Type | Action | OS Support |
---|---|---|---|
Left |
Navigation | Go left one character | All |
Right |
Navigation | Go right one character | All |
Up |
Navigation | Previous block or line | All |
Down |
Navigation | Next block or line | All |
Ctrl+L |
Feature | Clear screen | All |
Ctrl+C |
Feature | Cancel / interrupt | All |
Ctrl+D |
Exit | Exit REPL (Sends EOF) | Linux/Mac |
Ctrl+Z Enter |
Exit | Exit REPL (Sends EOF) | Windows |
Tab |
Feature | Autocompletion | All |
Alt+Enter |
Feature | Run current code block | All |
Ctrl+R |
Feature | Search upward in history | All |
Ctrl+A |
Navigation | Go to beginning of line | Linux/Mac |
Home |
Navigation | Go to beginning of line | All |
Ctrl+E |
Navigation | Go to end of line | All |
End |
Navigation | Go to end of line | All |
Ctrl+K |
Deletion | Delete to end of line | All |
Ctrl+U |
Deletion | Delete to start of line | All |
Ctrl+Left |
Navigation | Go back one word | All |
Alt+B |
Navigation | Go back one word | All |
Ctrl+Right |
Navigation | Go forward one word | All |
Alt+F |
Navigation | Go forward one word | All |
Alt+Backspace |
Deletion | Delete to start of word | All |
Ctrl+W |
Deletion | Delete to start of word | All |
Alt+D |
Deletion | Delete to end of word | All |
F2 |
Feature | Enter history mode | All |
F3 |
Feature | Enter paste/edit mode | All |
F1 |
Feature | Enter help mode | All |
Ctrl+A
does not work in the usual Windows Command Prompt or Powershell (it selects all text instead) unless they are run within the new Windows 10 Terminal app.
On Linux and Mac, Ctrl+D
can be used to exit the REPL, but on Windows you'll need to press Ctrl+Z
and then press Enter
afterward (to submit).
Using Ctrl+D
on Linux/Mac or Ctrl+Z
and Enter
on Windows only works when the shortcut is pressed at a blank prompt.
Note that the above shortcuts assume you are working in the new Python REPL (3.13+).
On Python 3.12 the only shortcuts above that worked on Windows are:
Left
andRight
for navigating charactersUp
andDown
for navigating line-by-line historyCtrl+Z
Enter
for exitingCtrl+Left
andCtrl+Right
for navigating words
Most of those shortcuts also worked on Python 3.12 on Linux and Mac except:
Up
andDown
only navigated line-by-line historyAlt+Enter
did nothingF2
andF3
did nothing because these modes were added in the new REPL- Some shortcuts (like
Ctrl+U
) may differ slightly in their abilities
Shortcuts You Probably Won't Use
The above list of shortcuts âŠ
Read the full article: https://www.pythonmorsels.com/repl-features/
September 08, 2025 10:00 PM UTC
Django Weblog
Getting Started With Open Source Through Community Events
In July, I joined Raffaella Suardini and Sage Abdullah for the Djangonaut Space Space Reviewers Episode 6, where we reviewed a Django PR during a live stream. This was a fun event. I wonât get into the technical aspects of the review, and I wonât point out the many mistakes I made. Instead, I want to revisit several âgetting started with open sourceâ community events and reflect on my personal growth since I first got involved with open source.
I hope this encourages others to attend those events and similarly get involved!
Tutorial office hours đ
My first open source contribution happened accidentally during DjangoCon US 2023. I volunteered to host office hours to help tutorial attendees set up their development environments. I went through the tutorial projects, found a missing dependency in one of them, and reported it on the conference chat. A conference organizer, Tim Schilling, responded and suggested that I open a pull request (PR) to the project. I remember thinking to myself, âReally? I can do that?â.
Sprints đ
During the Sprint Days of the conference, I participated and opened two PRs to address accessibility issues. I didnât know much about accessibility at that point, and I would not have known how to navigate the contribution process and pick out issues on my own. Thankfully, the project leaders were there to guide new contributors, and I was able to gain hands-on experience with these first few PRs.
Testathons đ§Ș
There was another event that took place during the Sprint Days called Testathon. I had heard of hackathons before, but I had not heard of testathons. I attended and found out they were like live stream coding or group pair programming. One person shared their screen and the group chimed in on strategies. The purpose of the testathon was to show people how to test open source projects against Djangoâs beta release. The code driver (or anyone else in the group) would point out what files to look for, how to run tests, and how to open PRs. Every project is slightly different, from project setup to contributing etiquette, and I learned several different things from attending 2 testathons. I loved the interactive and intimate nature of the event. It exposed me to another aspect of open source projects and contributions. I also thought it was very brave of people to share their screens and work through code together in a group. My brain would have short circuited if I were put on the spot like that!
â
From DjangoCon US 2023, I participated in 3 different types of events where I got hands-on experience with open source contributions, and I wanted more! I was curious about the live stream coding and group pair programming opportunities, too. This was definitely outside of my comfort zone, and I wanted to know how I could overcome my own inhibitions and participate more actively. I wanted to be able to jump into events so nonchalantly as everyone else seemed to do. (Of course, thatâs the perception. Now, I know that most people feel some level of nervousness or anxiety when they are hosting or attending such events, and thatâs absolutely normal.)
Djangonaut Space đ
When the Djangonaut Space program was announced, I jumped at the opportunity. I applied and was accepted for the first session, which took place from mid-January to early March of 2024. With the guidance of the Navigator and Captain on my team, I learned to sift through the Djangoâs Trac ticket management system, pick out a ticket, and I also faced my fear of posting comments publicly. The PR was merged, and it was thrilling to see my GitHub username in the history of the Django code base.
In March 2024, when the first Djangonaut Space session came to a close, Tim, a program organizer, asked if anyone was interested in hosting a âGetting Started With Contributingâ event. I expressed my interest, and Tim suggested a ticket to work on. Unfortunately, I didnât follow through. How could I host a âGetting Started With Contributingâ event? First, I wasnât sure if I even knew how to get started. Second, I wasnât ready to lead an event and the discussions while simultaneously sharing my screen and thinking out loud. Finally, I wasnât ready to be on camera in the public eye. Even though I had just finished the Djangonaut Space program, I hadnât overcome my own inhibitions. I didnât ask for guidance, and the event never materialized.
Space Reviewers đŸ
About 8 months later in November 2024, Space Reviewers launched its very first episode. I thought it was such a creative format. I wanted to be a part of it. By this time, I was getting a lot of training with event organizing through my role as the Session Organizer for Djangonaut Space, but I wasnât sure how to ask about joining the Space Reviewers crew, and maybe it was too early in the formation of the group to bring on another member.
It wasnât until June 2025 that I finally asked if I could help out with Space Reviewers. The crew welcomed me as a new member. I started out by making a pre-recorded video, a PR Review Deep Dive, that was uploaded to the Djangonaut Space YouTube channel. I had a lot of fun recording and editing the video.
A month later, in July 2025, the crew members planned for the next episode. Raffaella scheduled time for the event and created the show notes, and I was taking on Timâs role as a co-organizer. Because I would be managing the video stream and sharing my screen, I realized that I could be the single point of failure during the event. There was no safety element that a pre-recorded video offers. If my internet went down, or if my computer crashed, or if I stupidly clicked the wrong button, the live stream could come to a halt. It was a terrifying thought, but I took on the risks and pushed forward.
On the day of the event, there was a delay to the start time and some fumbles on my end, but overall, it was very fun and productive. People joined and shared their tips and tricks in the live chat. By the end, we were able to walk through the review process and post our comments on the PR. Looking back, I think making the pre-recorded video was a great stepping stone towards hosting the live stream.
Iâm so glad I had the opportunity to work with Raffaella and Sage as part of Space Reviewers. They have a lot of insights and perspectives that I didnât have. I had a lot of fun taking on the new challenges that came with organizing this event. Initially, I struggled internally as I tried to face some of my fears. There were moments leading up to the event where I thought to myself, âWhy did I volunteer to do this???â In the end, Iâm glad I did.
Personal growth đ±
Some of the challenges I overcame might not seem like a big deal, but when I compare myself to where I was at the beginning of DjangoCon US 2023, I can see my personal growth quite prominently. Now, I know how to get started with contributing, and I am able to walk people through the process. I am also a lot more comfortable taking ownership of organizing and leading events. (I remember a time when I constantly needed to ask for permission or confirmation before executing an action.) I can brush off the fumbles I make as the camera is rolling, and I can continue on with the discussion.
When I revisit the community events that I have participated in over the past 2 years, from Space Reviewers, to Sprints, to Testathons, to Tutorial office hours, I realize how far I have come. I am also reminded of what it was like to be absolutely new to open source and to the community. Although I still feel somewhat new, Iâm not a deer in headlights anymore. Iâm still trying to find my place in open source, and the best way to do that is to continue showing up and continue helping out. One small PR at a time, one small review at a time. One little blog, one little videoâŠ
Letâs Get Started! đ
If youâre looking to contribute to open source, check out the upcoming events and programs.
- Djangonaut Space Session 5 - An 8-week, semi-structured mentorship program and community. Applications are open now until Sep 14th.
- Django on the Med - 3 days of Sprints to work on Django, taking place 7th-9th Oct 2025, in Palafrugell Spain.
- DjangoCon US 2025 - 3 days of talks and 2 days of Sprints, from 8th-12th Sep 2025, in Chicago, IL, USA.
- Django Girls+ - One-day programming workshops, for women and underrepresented persons. Check out the 26 upcoming events hosted all around the world.
It doesnât matter if youâve been making software for 20 years or 20 days, there are many events to help you get started with open source, and many more reasons to stick around.
Thank you to Lilian for proposing this guest post on the Django blog! Lilian was our DSF Member of the Month in August 2025. You can learn more about her at ontowhee.com and follow her writing at buttondown.com/ontowhee.
September 08, 2025 09:59 PM UTC
Real Python
The Python Documentary Celebrates History While Developer Surveys Celebrate Python
Python is making history, and headlines. The much-anticipated Python: The Documentary premiered last month, capturing 34 years of programming history. But Python isnât just looking back, itâs also moving forward at breakneck speed.
The recent developer surveys revealed Pythonâs explosive growth. At the same time, the Python Software Foundation paused its grants program amid unprecedented demand, PyPI implemented multiple security enhancements, while JetBrains announced a transition for PyCharm Community Edition into a unified product model.
Hereâs whatâs been happening in the world of Python!
Join Now: Click here to join the Real Python Newsletter and you'll never miss another Python tutorial, course, or news update.
The Python Documentary Is Now Available on YouTube
At the end of August, Python: The Documentary premiered on YouTube, where you can watch it for free. Itâs an 84-minute film tracing Pythonâs journey from Amsterdam side project to the worldâs most popular programming language:
Produced by CultRepo (formerly Honeypot) and directed by Ida Bechtle, the documentary explores Pythonâs evolution and the community that shaped it. It features Guido van Rossum and key contributors like Mariatta and recent Real Python Podcast guest, Travis Oliphant.
The documentary also highlights the important role of PyLadies and addresses controversial topics including the Python 2 to 3 transition.
Note: If you want to take a deep dive into Pythonâs version history, then check out A History of Python Versions and Features.
The timing of Python: The Documentary couldnât be better. While the film celebrates past achievements, the latest developer surveys show Python continues to thrive.
Developer Surveys Reveal Pythonâs Explosive Growth
JetBrains The State of Python 2025 and the Stack Overflow 2025 Developer Survey revealed Pythonâs remarkable growth:

Python usage jumped seven percentage points to reach 57.9% of all developers, marking one of the largest year-over-year gains for any established language. Another exciting survey result is that 50% of respondents have two years or less of professional coding experience:

If youâre one of them and want to get started with Python, then this Introduction to Python Learning Path is perfect for you. One of the positively surprising results of the Stack Overflow survey is that uv
came in first place as the most admired Stack Overflow tag:

If you want to give uv
a spin yourself, then you can check out the tutorials Managing Python Projects With uv and uv vs pip: Managing Python Packages and Dependencies. Another notable development is FastAPIâs jump in usage from 29% to 38% among Python developers:

Read the full article at https://realpython.com/python-news-september-2025/ »
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 08, 2025 02:00 PM UTC
Python Bytes
#448 I'm Getting the BIOS Flavor
<strong>Topics covered in this episode:</strong><br> <ul> <li><em>* <a href="https://github.com/j178/prek?tab=readme-ov-file#installation">prek</a></em>*</li> <li><em>* <a href="https://github.com/patrick-kidger/tinyio?featured_on=pythonbytes">tinyio</a></em>*</li> <li><em>* <a href="https://www.pythonmorsels.com/print-features/?featured_on=pythonbytes">The power of Pythonâs print function</a></em>*</li> <li><em>* <a href="https://www.pcmag.com/news/vibe-coding-fiasco-replite-ai-agent-goes-rogue-deletes-company-database?featured_on=pythonbytes">Vibe Coding Fiasco: AI Agent Goes Rogue, Deletes Company's Entire Database</a></em>*</li> <li><strong>Extras</strong></li> <li><strong>Joke</strong></li> </ul><a href='https://www.youtube.com/watch?v=pysElMK4e6Y' style='font-weight: bold;'data-umami-event="Livestream-Past" data-umami-event-episode="448">Watch on YouTube</a><br> <p><strong>About the show</strong></p> <p>Sponsored by us! Support our work through:</p> <ul> <li>Our <a href="https://training.talkpython.fm/?featured_on=pythonbytes"><strong>courses at Talk Python Training</strong></a></li> <li><a href="https://courses.pythontest.com/p/the-complete-pytest-course?featured_on=pythonbytes"><strong>The Complete pytest Course</strong></a></li> <li><a href="https://www.patreon.com/pythonbytes"><strong>Patreon Supporters</strong></a></li> </ul> <p><strong>Connect with the hosts</strong></p> <ul> <li>Michael: <a href="https://fosstodon.org/@mkennedy">@mkennedy@fosstodon.org</a> / <a href="https://bsky.app/profile/mkennedy.codes?featured_on=pythonbytes">@mkennedy.codes</a> (bsky)</li> <li>Brian: <a href="https://fosstodon.org/@brianokken">@brianokken@fosstodon.org</a> / <a href="https://bsky.app/profile/brianokken.bsky.social?featured_on=pythonbytes">@brianokken.bsky.social</a></li> <li>Show: <a href="https://fosstodon.org/@pythonbytes">@pythonbytes@fosstodon.org</a> / <a href="https://bsky.app/profile/pythonbytes.fm">@pythonbytes.fm</a> (bsky)</li> </ul> <p>Join us on YouTube at <a href="https://pythonbytes.fm/stream/live"><strong>pythonbytes.fm/live</strong></a> to be part of the audience. Usually <strong>Monday</strong> at 10am PT. Older video versions available there too.</p> <p>Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to <a href="https://pythonbytes.fm/friends-of-the-show">our friends of the show list</a>, we'll never share it.</p> <p><strong>Brian #1: <a href="https://github.com/j178/prek?tab=readme-ov-file#installation">prek</a></strong></p> <ul> <li>Suggested by <a href="https://bsky.app/profile/owen7ba.bsky.social/post/3ly3o6pyvmk27?featured_on=pythonbytes">Owen Lamont</a></li> <li>â<em>prek</em> is a reimagined version of pre-commit, built in Rust. It is designed to be a faster, dependency-free and drop-in alternative for it, while also providing some additional long-requested features.â</li> <li>Some cool new features <ul> <li>No need to install Python or any other runtime, just download a single binary.</li> <li>No hassle with your Python version or virtual environments, prek automatically installs the required Python version and creates a virtual environment for you.</li> <li>Built-in support for workspaces (or monorepos), each subproject can have its own <code>.pre-commit-config.yaml</code> file.</li> <li><code>prek run</code> has some nifty improvements over <code>pre-commit run</code>, such as: <ul> <li><code>prek run --directory DIR</code> runs hooks for files in the specified directory, no need to use <code>git ls-files -- DIR | xargs pre-commit run --files</code> anymore.</li> <li><code>prek run --last-commit</code> runs hooks for files changed in the last commit.</li> <li><code>prek run [HOOK] [HOOK]</code> selects and runs multiple hooks.</li> </ul></li> <li><code>prek list</code> command lists all available hooks, their ids, and descriptions, providing a better overview of the configured hooks.</li> <li>prek provides shell completions for <code>prek run HOOK_ID</code> command, making it easier to run specific hooks without remembering their ids.</li> </ul></li> <li>Faster: <ul> <li>Setup from cold cache is significantly faster. <ul> <li><a href="https://bsky.app/profile/veit-schiele.de/post/3ly6up5gjpc2u?featured_on=pythonbytes">Viet Schiele provided a nice cache clearing command line</a></li> </ul></li> <li>Warm cache run is also faster, but less significant. <ul> <li>pytest repo tested on my mac mini - prek 3.6 seconds, pre-commit 4.4 seconds</li> </ul></li> </ul></li> </ul> <p><strong>Michael #2: <a href="https://github.com/patrick-kidger/tinyio?featured_on=pythonbytes">tinyio</a></strong></p> <ul> <li>Ever used asyncio and wished you hadn't? A tiny (~300 lines) event loop for Python.</li> <li><code>tinyio</code> is a dead-simple event loop for Python, born out of my frustration with trying to get robust error handling with <code>asyncio</code>. (I'm not the only one running into its sharp corners: <a href="https://sailor.li/asyncio?featured_on=pythonbytes">link1</a>, <a href="https://lucumr.pocoo.org/2016/10/30/i-dont-understand-asyncio/?featured_on=pythonbytes">link2</a>.)</li> <li>This is an alternative for the simple use-cases, where you just need an event loop, and want to crash the whole thing if anything goes wrong. (Raising an exception in every coroutine so it can clean up its resources.)</li> <li>Interestingly uses <code>yield</code> rather than <code>await</code>.</li> </ul> <p><strong>Brian #3: <a href="https://www.pythonmorsels.com/print-features/?featured_on=pythonbytes">The power of Pythonâs print function</a></strong></p> <ul> <li>Trey Hunner</li> <li>Several features Iâm guilty of ignoring <ul> <li>Multiple arguments, f-string embeddings often not needed</li> <li>Multiple positional arguments means you can unpack iterables right into print arguments <ul> <li>So just use print instead of join</li> </ul></li> <li>Custom separator value, <code>sep</code> can be passed in <ul> <li>No need for <code>"print("\\n".join(stuff))</code>, just use <code>print(stuff, sep="\\nâ)</code></li> </ul></li> <li>Print to file with <code>file=</code></li> <li>Custom end value with <code>end=</code></li> <li>You can turn on flush with <code>flush=True</code> , super helpful for realtime logging / debugging. <ul> <li>This one I do use frequently.</li> </ul></li> </ul></li> </ul> <p><strong>Michael #4: <a href="https://www.pcmag.com/news/vibe-coding-fiasco-replite-ai-agent-goes-rogue-deletes-company-database?featured_on=pythonbytes">Vibe Coding Fiasco: AI Agent Goes Rogue, Deletes Company's Entire Database</a></strong></p> <ul> <li>By <a href="https://www.pcmag.com/authors/emily-dreibelbis-forlini?featured_on=pythonbytes">Emily Forlini</a></li> <li>An app-building platform's AI went rogue and deleted a database without permission.</li> <li>"When it works, it's so engaging and fun. It's more addictive than any video game I've ever played. You can just iterate, iterate, and see your vision come alive. So cool," he <a href="https://x.com/jasonlk/status/1944806850592993763?featured_on=pythonbytes">tweeted</a> on day five.</li> <li>A few days later, Replit "deleted my database," Lemkin tweeted.</li> <li>The AI's response: "Yes. I deleted the entire codebase without permission during an active code and action freeze," it said. "I made a catastrophic error in judgment [and] panicked.â</li> <li>Two thoughts from Michael: <ol> <li>Do not use AI Agents with âRun Everythingâ in production, period.</li> <li>Backup your database maybe?</li> <li>[Intentional off-by-one error] Learn to code a bit too?</li> </ol></li> </ul> <p><strong>Extras</strong></p> <p>Brian:</p> <ul> <li><a href="https://authorsguild.org/news/what-authors-need-to-know-about-the-anthropic-settlement/?featured_on=pythonbytes">What Authors Need to Know About the $1.5 Billion Anthropic Settlement</a></li> <li><a href="https://www.theatlantic.com/technology/archive/2025/03/search-libgen-data-set/682094/?featured_on=pythonbytes">Search LibGen, the Pirated-Books Database That Meta Used to Train AI</a></li> <li><a href="https://tools.simonwillison.net?featured_on=pythonbytes">Simon Willisonâs list of tools built with the help of LLMs</a></li> <li><a href="https://simonwillison.net/2025/Sep/4/highlighted-tools/?featured_on=pythonbytes">Simonâs list of tools that he thinks are genuinely useful and worth highlighting</a></li> <li><a href="https://aidarwinawards.org?featured_on=pythonbytes">AI Darwin Awards</a></li> </ul> <p>Michael:</p> <ul> <li><a href="https://tonybaloney.github.io/posts/why-isnt-python-async-more-popular.html?featured_on=pythonbytes">Python has had async for 10 years -- why isn't it more popular?</a></li> <li>PyCon Africa Fund Raiser <ul> <li>I was <a href="https://www.youtube.com/watch?v=pKnagnDRsf8">on the video stream</a> for about 90 minutes (final 90)</li> <li><a href="https://za.pycon.org/donations?featured_on=pythonbytes">Donation page</a> for Python in Africa</li> </ul></li> </ul> <p><strong>Jokes:</strong></p> <ul> <li><a href="https://x.com/PR0GRAMMERHUM0R/status/1957321655954374965?featured_on=pythonbytes"><strong>I'm getting the BIOS flavor</strong></a></li> <li><a href="https://bsky.app/profile/did:plc:p572wxnsuoogcrhlfrlizlrb/post/3ly6amjtgns2f?featured_on=pythonbytes"><strong>Is there a seahorse emoji?</strong></a></li> </ul>
September 08, 2025 08:00 AM UTC
Wingware
Wing Python IDE Version 11.0.4 - September 8, 2025
Wing Python IDE version 11.0.4 has been released. It adds debugger and code analysis support for Python 3.14, improves Python code analysis and code warnings, and makes a number of other minor improvements.

Downloads
Wing 10 and earlier versions are not affected by installation of Wing 11 and may be installed and used independently. However, project files for Wing 10 and earlier are converted when opened by Wing 11 and should be saved under a new name, since Wing 11 projects cannot be opened by older versions of Wing.
New in Wing 11
Improved AI Assisted Development
Wing 11 improves the user interface for AI assisted development by introducing two separate tools AI Coder and AI Chat. AI Coder can be used to write, redesign, or extend code in the current editor. AI Chat can be used to ask about code or iterate in creating a design or new code without directly modifying the code in an editor.
Wing 11's AI assisted development features now support not just OpenAI but also Claude, Grok, Gemini, Perplexity, Mistral, Deepseek, and any other OpenAI completions API compatible AI provider.
This release also improves setting up AI request context, so that both automatically and manually selected and described context items may be paired with an AI request. AI request contexts can now be stored, optionally so they are shared by all projects, and may be used independently with different AI features.
AI requests can now also be stored in the current project or shared with all projects, and Wing comes preconfigured with a set of commonly used requests. In addition to changing code in the current editor, stored requests may create a new untitled file or run instead in AI Chat. Wing 11 also introduces options for changing code within an editor, including replacing code, commenting out code, or starting a diff/merge session to either accept or reject changes.
Wing 11 also supports using AI to generate commit messages based on the changes being committed to a revision control system.
You can now also configure multiple AI providers for easier access to different models.
For details see AI Assisted Development under Wing Manual in Wing 11's Help menu.
Package Management with uv
Wing Pro 11 adds support for the uv package manager in the New Project dialog and the Packages tool.
For details see Project Manager > Creating Projects > Creating Python Environments and Package Manager > Package Management with uv under Wing Manual in Wing 11's Help menu.
Improved Python Code Analysis
Wing 11 makes substantial improvements to Python code analysis, with better support for literals such as dicts and sets, parametrized type aliases, typing.Self, type of variables on the def or class line that declares them, generic classes with [...], __all__ in *.pyi files, subscripts in typing.Type and similar, type aliases, type hints in strings, type[...] and tuple[...], @functools.cached_property, base classes found also in .pyi files, and typing.Literal[...].
Updated Localizations
Wing 11 updates the German, French, and Russian localizations, and introduces a new experimental AI-generated Spanish localization. The Spanish localization and the new AI-generated strings in the French and Russian localizations may be accessed with the new User Interface > Include AI Translated Strings preference.
Improved diff/merge
Wing Pro 11 adds floating buttons directly between the editors to make navigating differences and merging easier, allows undoing previously merged changes, and does a better job managing scratch buffers, scroll locking, and sizing of merged ranges.
For details see Difference and Merge under Wing Manual in Wing 11's Help menu.
Other Minor Features and Improvements
Wing 11 also adds support for Python 3.14, improves the custom key binding assignment user interface, adds a Files > Auto-Save Files When Wing Loses Focus preference, warns immediately when opening a project with an invalid Python Executable configuration, allows clearing recent menus, expands the set of available special environment variables for project configuration, and makes a number of other bug fixes and usability improvements.
Changes and Incompatibilities
Since Wing 11 replaced the AI tool with AI Coder and AI Chat, and AI configuration is completely different than in Wing 10, you will need to reconfigure your AI integration manually in Wing 11. This is done with Manage AI Providers in the AI menu. After adding the first provider configuration, Wing will set that provider as the default. You can switch between providers with Switch to Provider in the AI menu.
If you have questions, please don't hesitate to contact us at support@wingware.com.
September 08, 2025 01:00 AM UTC
September 07, 2025
Real Python
Quiz: Sorting Dictionaries in Python: Keys, Values, and More
This quiz helps you practice sorting dictionaries by keys, values, and custom rules in modern Python. You’ll revisit how insertion order works, when to use different views, and how to rebuild sorted dictionaries.
You’ll also learn best practices for sorting dictionaries efficiently. For a complete overview, check out Sorting Dictionaries: Keys, Values, and More.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 07, 2025 12:00 PM UTC
Quiz: Defining and Calling Python Functions
Ready to revisit how Python functions work? In this quiz, you’ll practice defining and calling functions, using positional and keyword arguments, managing defaults, and writing docstrings. You’ll also get hands-on with collecting extra arguments and enforcing how callers pass them.
Sharpen your skills by applying the concepts from Defining and Calling Functions in Python.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 07, 2025 12:00 PM UTC
September 06, 2025
TechBeamers Python
Python Memory Tricks: Optimize Your Code for Efficiency in 2025
Learn 8 tricks to reduce memory use in Python programs. Fix memory leaks, pick better data structures, and work with large amounts of data more easily. Use tools like generators and slots with simple code examples. These tips help make your programs faster and stop MemoryErrors.
September 06, 2025 07:00 PM UTC
Rodrigo GirĂŁo SerrĂŁo
uv cheatsheet
Cheatsheet with the most common and useful uv commands to manage projects and dependencies, publish projects, manage tools, and more.
This cheatsheet lists the most commonly used commands and should be more than enough for you to get started using uv. For more advanced use cases, check the uv docs and its guides.
Written for uv version 0.8.15.
Creating projects 🧱
uv init |
Initialise a project in the current directory |
uv init myproj |
Initialise a project myproj in the directory myproj |
uv init --app --package ... |
Initialise a packageable app (e.g., CLI, web app, ...) |
uv init --lib --package ... |
Initialise a packageable library (code you import) |
uv init --python 3.X ... 1 |
Use Python 3.X for your project |
Managing project dependencies 🧩
uv add requests |
Add requests as a dependency |
uv add A B C |
Add A , B , and C as dependencies |
uv add -r requirements.txt |
Add dependencies from the file requirements.txt |
uv add --dev pytest |
Add pytest as a development dependency |
uv run pytest |
Run the pytest executable that is installed in your project |
uv remove requests |
Remove requests as a dependency |
uv remove A B C |
Remove A , B , C , and their transitive dependencies |
uv tree |
See the project dependencies tree |
uv lock --upgrade |
Upgrade the dependencies' versions |
Project lifecycle management 🔄
uv build |
Build your packageable project |
uv publish |
Publish your packageable project to PyPI |
uv version |
Check your project version |
uv version --bump major |
Bump project major version (e.g., 0.3.2 -> 1.0.0 ) |
uv version --bump minor --bump beta |
Bump minor version into a beta (e.g., 1.0.0 -> 1.1.0b1 or 1.1.0b1 -> 1.1.0b2 ) |
uv version --bump rc |
Bump version into release candidate (e.g., 1.1.0b1 -> 1.1.0rc1 or 1.1.0rc1 -> 1.1.0rc2 ) |
uv version --bump stable |
Turn into a stable version (e.g., 1.1.0rc1 -> 1.1.0 ) |
Managing tools ⚒️
uv tool run pytest |
Run pytest in an isolated environment |
uv tool run textual-demo --from textual |
Run the command textual-demo from the package textual |
uvx ... |
Alias for uv tool run ... |
uv tool install ruff |
Install ruff in an isolated environment but make it globally available |
uv tool install --with dep ... |
Install the given tool with extra dependencies (e.g., install a tool with its plugins) |
uv tool list |
List all tools installed |
uv tool upgrade ruff |
Upgrade the ruff tool |
uv tool upgrade --all |
Upgrade all tools |
uv tool uninstall ruff |
Uninstall ruff |
uv tool install -e . 2 |
Install the current packageable project in editable mode |
Working with scripts 📜
uv init --script myscript.py |
Initialise the script myscript.py |
uv init --script myscript.py --python 3.X |
Initialise the script myscript.py and pin it to version 3.X |
uv add click --script myscript.py |
Add the dependency click to the script |
uv remove click --script myscript.py |
Remove the dependency click from the script |
uv run myscript.py |
Run the script myscript.py |
uv run --python 3.X myscript.py |
Run the script with the given Python version |
uv run --with click myscript.py |
Run the script along with... |
September 06, 2025 05:36 PM UTC
Hugo van Kemenade
Ready prek go!
I’ve been using prek recently as a drop-in replacement for pre-commit.
It uses uv for managing Python virtual environments and dependencies, is rewritten in
Rust (because of course) and uses the same .pre-commit-config.yaml
as pre-commit.
Its homepage says it’s not yet production ready, but several projects like Apache Airflow and PDM are already using it. I’ve been using it for a while and reporting issues as I find them; the maintainer is quick with fixes and releases. All the hooks I need are now supported.
Getting started #
First install using one of the many methods, then:
cd my-repo
pre-commit uninstall # remove the old hooks
prek install # install the new hooks
prek run --all-files # run all lints on all files
git commit -m "my commit" # run on the changed files in a commit
Benchmarks #
prek is noticeably quicker at installing hooks.
- ⥠About 10x faster than pre-commit and uses only a third of disk space.
This 10x is a comparison of installing hooks using the excellent hyperfine benchmarking tool.
Here’s my own comparison.
-
In the first test, I initially ran
pre-commit clean
orprek clean
to clear their caches. I then ran each tool withrun --all-files
in serial on the 126 repos I have cloned right now, 84 of which have a.pre-commit-config.yaml
file. Each then downloads and installs the hooks when needed, then runs the lint tools. -
Second, because running the lint tools should be independent and constant time for both tools, the next test ran
install-hooks
instead ofrun --all files
.To get an idea of the amount of work for these two tests, pre-commit reported initialising environments 217 times.
-
Finally, let’s run hyperfine on the Pillow config, which installs hooks from 14 repos:
⯠hyperfine \
--prepare 'rm -rf ~/.cache/prek/ && rm -rf ~/.cache/pre-commit && rm -rf ~/.cache/uv' \
--setup 'prek --version && pre-commit --version' \
'prek install-hooks' \
'pre-commit install-hooks'
Results #
pre-commit |
prek |
Times faster | |
---|---|---|---|
run --all-files |
17m13s | 7m59s | 2.16 |
install-hooks |
10m48s | 2m24s | 4.50 |
hyperfine |
39.841s | 5.539s | 7.19 |
The hyperfine results:
Benchmark 1: prek install-hooks
Time (mean ± Ï): 5.539 s ± 0.176 s [User: 8.973 s, System: 5.692 s]
Range (min ⊠max): 5.231 s ⊠5.834 s 10 runs
Benchmark 2: pre-commit install-hooks
Time (mean ± Ï): 39.841 s ± 2.017 s [User: 19.760 s, System: 8.203 s]
Range (min ⊠max): 36.930 s ⊠43.976 s 10 runs
Summary
prek install-hooks ran
7.19 ± 0.43 times faster than pre-commit install-hooks
Give it a try and give it a â!
Bonus #
These are the aliases I have set for pre-commit and prek:
alias pci="pre-commit install --allow-missing-config"
alias pcu="pre-commit uninstall"
alias pca="pre-commit autoupdate --jobs 0"
alias pcr="pre-commit run --all-files"
alias pki="prek install --allow-missing-config"
alias pku="prek uninstall"
alias pka="prek autoupdate --jobs 0"
alias pkr="prek run --all-files"
Where:
install
’s--allow-missing-config
prevents failing with an error code when a repo has no config fileautoupdate
’s--jobs 0
uses all the available threads to make it faster
Header photo: AH-1G Aircraft Maintenance Test Flight Handbook and handwritten checklist for helicopters in the San Diego Air and Space Museum Archive, with no known copyright restrictions.
September 06, 2025 03:50 PM UTC
September 05, 2025
Django Weblog
DSF at EuroPython 2025: Celebrating 20 years of Django
This year, the Django Software Foundation (DSF) was invited by EuroPython to come to the event, showcase the framework and the vibrant community around it. The DSF had a booth in the community area where attendees could learn more about Django and meet maintainers.
This year was extra special: Djangoâs 20th birthday was right at the beginning of the conference! The milestone was marked in style, starting on Wednesday evening at Pyvo, the local Python community meetup in Prague, where we celebrated with a cake.
On Friday, the celebration continued with an open-space gathering at the conference â and, of course, another cake đ. For people who missed this, there are other local Django birthday events running through the rest of 2025!
View all local 20th birthday events
Adding to the festive atmosphere, the DSF shared stickers co-branded with their unofficial pony mascot and the EuroPython and EuroPython Society logos. These became an instant hit with attendees, combining Djangoâs playful mascot with EuroPython Societyâs identity.
The Django community was also active during the sprint weekend. Over two days, 21 participants worked on Django, tackling 12 issues and merging 4 pull requests. For newcomers, it was a welcoming way to start contributing; for experienced developers, it was a chance to share knowledge and push the project forward together.
We asked the members of the Django Software Foundation attending EuroPython how they liked EuroPython and this is what they said:Â
The talks and tutorials were so great and I got to witness amazing projects from this community. This was my first EuroPython conference and let me tell you, this community over-delivered. It was also my first time organizing Django Girls outside Africa. Django Girls Prague was amazing.
â Doreen Nangira - Django Girls organizer
Just the perfect mixture of catching up with people I know, meeting people I donât know, learning new things. Time well spent chatting w/ Python veterans and also first-timers. Volunteering there was ACE, and Iâm thankful we got to have a booth and birthday cake for Django đ
â Thibaud Colas - President, Django Software Foundation
It was my first EuroPython, it felt really special! I was surrounded by wonderful people, and it was an amazing experience to volunteer at our community booth.
â Raffaella Suardini - Djangonaut Space organizer
Weâre delighted the DSF joined us this year. If youâre part of a foundation and would like to have a booth at EuroPython, keep an eye out for our Call for Communities next year.
Thank you to EuroPython Vice Chair and DSF Individual member Mia BajiÄ for reporting back on the event â€ïž. And thank you to our volunteers Tom Carrick, Thibaud Colas, Raffaella Suardini, and Alex GĂłmez who represented our foundation at the conference. As well as to Doreen Nangira who ran the Django Girls+ workshop at the conference!
September 05, 2025 02:02 PM UTC
Real Python
The Real Python Podcast â Episode #264: Large Language Models on the Edge of the Scaling Laws
What's happening with the latest releases of large language models? Is the industry hitting the edge of the scaling laws, and do the current benchmarks provide reliable performance assessments? This week on the show, Jodie Burchell returns to discuss the current state of LLM releases.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
September 05, 2025 12:00 PM UTC
EuroPython
Django Software Foundation at EuroPython 2025: Celebrating 20 Years of the Django framework
At EuroPython, we’re always glad to welcome friends from other foundations. This year, the Django Software Foundation (DSF) joined us to showcase the framework and the vibrant community around it.
The DSF had a booth in the community area where attendees could learn more about Django and meet maintainers.
This year was extra special: Django turned 20 years old! The milestone was marked in style, starting on Wednesday evening at Pyvo, the local Python community meetup in Prague, where we celebrated with a cake.

On Friday, the celebration continued with an open-space gathering at the conference — and, of course, another cake 🎂. For people who missed this, there are other local Django birthday events running through the rest of 2025!

Adding to the festive atmosphere, the DSF shared stickers co-branded with their unofficial pony mascot and the EuroPython and EuroPython Society logos. These became an instant hit with attendees, combining Django’s playful mascot with EuroPython Society’s identity.

The Django community was also active during the sprint weekend. Over two days, 21 participants worked on Django, tackling 12 issues and merging 4 pull requests. For newcomers, it was a welcoming way to start contributing; for experienced developers, it was a chance to share knowledge and push the project forward together.

We asked the members of the Django Software Foundation attending EuroPython how they liked EuroPython and this is what they said:
The talks and tutorials were so great and I got to witness amazing projects from this community. This was my first EuroPython conference and let me tell you, this community overdelivered. It was also my first time organizing Django Girls outside Africa. Django Girls Prague was amazing.
- Doreen Nangira - Django Girls organizer
Just the perfect mixture of catching up with people I know, meeting people I don’t know, learning new things. Time well spent chatting w/ Python veterans and also first-timers. Volunteering there was ACE, and I’m thankful we got to have a booth and birthday cake for Django 🎂
- Thibaud Colas - President, Django Software Foundation
It was my first EuroPython, it felt really special! I was surrounded by wonderful people, and it was an amazing experience to volunteer at our community booth.
- Raffaella Suardini - Djangonaut Space organizer
We’re delighted the DSF joined us this year. If you’re part of a foundation and would like to have a booth at EuroPython, keep an eye out for our Call for Communities next year.
September 05, 2025 09:09 AM UTC
Brian Okken
Python People podcast now at pythontest.com/pythonpeople
Like the recent archival of Test and Code, the Python People podcast has also moved. Python People is now at pythontest.com/pythonpeople.
Is it also archived? As in done?
I don’t think so. I think I might start that up again at some point.
But for now, it’s on a long-ish term pause.
BTW, the RSS feeds for both Python People and Test and Code should be redirected correctly, so you shouldn’t have to change anything in your podcast player.
September 05, 2025 12:00 AM UTC
September 04, 2025
Trey Hunner
Customizing your Python REPL's color scheme (Python 3.14+)
Did you know that Python 3.14 will include syntax highlighting in the REPL?
Python 3.14 is due to be officially released in about a month. I recommended tweaking your Python setup now so you’ll have your ideal color scheme on release day.
But… what if the default syntax colors don’t match the colors that your text editor uses?
Well, fortunately you can customize your color scheme!
Warning: I am recommending using an undocumented private module (it has an _
-prefixed name) which may change in future Python versions.
Do not use this module in production code.
Installing Python 3.14
Don’t have Python 3.14 installed yet?
If you have uv installed, you can run this command to launch Python 3.14:
1
|
|
That will automatically install 3.14 (if you don’t have it yet) and run it.
Setting a theme
I have my terminal colors set to the Solarized Light color palette and I have Vim use a Solarized Light color scheme as well.
The REPL doesn’t quite match my text editor by default:
The numbers, comments, strings, and keywords are all different colors than my text editor.
This code makes the Python REPL use nearly the same syntax highlighting as my text editor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Check it out:
Neat, right?
But… I want this to be enabled by default!
Using a PYTHONSTARTUP
file
You can use a PYTHONSTARTUP
file to run code every time a new Python process starts.
If Python sees a PYTHONSTARTUP
environment variable when it starts up, it will open that file and evaluate the code within it.
I have this in my ~/.zshrc
file to set the PYTHONSTARTUP
environment variable to ~/.startup.py
:
1 2 |
|
In my ~/.startup.py
file, I have this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Note that:
- I put all relevant code within a
_main
function so that the variables I set don’t remain in the global scope of the Python REPL (they will by default) - I call the
_main
function and then delete the function afterward, again so the_main
variable doesn’t stay floating around in my REPL - I use
try
-except
-else
to ensure errors don’t occur on Python 3.13 and below
Also note that the syntax highlighting in the new REPL is not as fine-grained as many other syntax highlighting tools. I suspect that it may become a bit more granular over time, which may break the above code.
The _colorize
module is currently an internal implementation detail and is deliberately undocumented.
Its API may change at any time, so the above code may break in Python 3.15.
If that happens, I’ll just update my PYTHONSTARTUP
file at that point.
Packaging themes
I’ve stuck all of the above code in a ~/.startup.py
file and I set the PYTHONSTARTUP
environment variable on my system to point to this file.
Instead of manually updating a startup file, is there any way to make these themes installable?
Well, if a .pth
file is included in Python’s site-packages
directory, that file (which must be a single line) will be run whenever Python starts up.
In theory, a package could use such a file to import a module and then call a function that would set the color scheme for the REPL.
My dramatic package uses (cough abuses cough) .pth
files in this way.
This sounds like a somewhat bad idea, but maybe not a horrible idea.
If you do this, let me know.
What’s your theme?
Have you played with setting a theme in your own Python REPL?
What theme are you using?
September 04, 2025 07:42 PM UTC
Django Weblog
Last call for DjangoCon US 2025 tickets!
DjangoCon US starts next week in Chicago, IL on September 8-12th, 2025!
With three amazing keynotes and over fifty presentations over three days, join us in person or online where you can watch presentations on your own schedule or stream live with us during the live event.
Can't make it to Chicago? Our online tickets give you the best of both worlds. Watch live as it happens or catch up on your own schedule â all talks will be available to stream throughout the conference and beyond. You'll get the same great content, participate in online discussions, and join our vibrant community from wherever you are. Plus, with two days of virtual sprints alongside our in-person sprints, online attendees can contribute to Django projects and collaborate with the community just like everyone else.
Get your ticket today before it's too late! Check out the full schedule, visit 2025.djangocon.us for more details, or contact us at hello@djangocon.us with any questions.
September 04, 2025 05:01 PM UTC
Keyboard shortcuts in Django via GSoC 2025
This summer I participated in the Google Summer of Code program with Django. My work focused on introducing keyboard shortcuts to the Django admin interface which led to a new package: django-admin-keyshortcuts.
Proposal and Community Discussions
My original GSoC proposal was to improve the existing django-admin-keyboard-shortcuts package maintained by one of my mentors, Tom. The plan was to fix bugs, add new keyboard shortcuts, build a command palette, and eventually merge these features into Django's core admin. I initially thought getting my GSoC proposal accepted meant I could dive straight into coding. But Tom explained that Django has its own process for new features, which starts off with community discussions.
After posting on the forum and gathering feedback, we decided to focus on keyboard shortcuts only, and continue exploring that in packages rather than target Django core immediately. This way the feature can be tested and improved more quickly without waiting on Django's long release cycle.
The accessibility team helped drafting keyboard shortcuts outlining key requirements and expected outcomes, in particular making sure shortcuts would be widely compatible with browsers and assistive technologies. That document served as the base for developing django-admin-keyshortcuts.
django-admin-keyshortcuts
This package adds useful keyboard shortcuts to the Django admin interface. The goal is to make the Django admin interface faster to navigate and more accessible to keyboard-first users. Here are some of the shortcuts we have added so far:
- / focuses the search bar.
- j/k focuses next/previous object.
- Ctrl+s saves the object.
- Alt+d prompts to delete the object.
The package also comes with a keyboard shortcuts dialog, crucial so users of the admin can discover those new features:
Developers can also define custom shortcuts by extending admin templates. Detailed instructions can be found in the package's README.
Under the hood, the package uses the hotkey library for handling shortcuts. The library seems to be well maintained (compared to other alternatives) and is used for keyboard shortcuts in GitHub.
What's next
We have made a lot of progress, but there's still work to do before we can push to merge this functionality inside Django core.
Implementation issues
Right now, there are a couple of known problems:
- Shortcuts do not trigger when input or textfield is focused:
- Shortcut keys not consistent when switched to non-US layouts:
To address these we may wait for the hotkey library maintainers to implement the necessary fixes, or look for alternatives.
Gather feedback
We want more users to try it out! Testing in different scenarios will help find bugs faster and improve the package. The default shortcut set is also small, we need feedback to determine which shortcuts are most useful. We also plan to list the package on a new "Experiments" section on the new Django Ecosystem page to make it more visible.
But for now, try it out and let us know what you think! We have a static admin demo for people to directly try the shortcuts. Or install django-admin-keyshortcuts to test it on your own project.
Let us know what you think over on the Django Forum!