skip to navigation
skip to content

Planet Python

Last update: August 14, 2025 01:42 AM UTC

August 13, 2025


Ari Lamstein

🚀 Join Me Tonight for a Hands-On Streamlit Workshop!

I’m excited to announce that I’ll be running a live workshop tonight on Streamlit—the Python framework that makes it easy to build interactive web apps for data projects.

This session is designed for those with an interest in data apps and no prior experience with Streamlit. You will walk through the fundamentals with a practical, beginner-friendly tutorial. We’ll cover:

All participants will leave with a finished app deployed to the internet, which you can share with friends.

The workshop is hosted by SF Python and kicks off tonight. You can RSVP and find all the event details here.

To follow along or preview the content, check out the workshop’s GitHub repo. This repo includes the full codebase, setup instructions, and exercises we’ll be working through. Feel free to fork and clone it ahead of time and come with questions!

Looking forward to seeing you there and building something great together.

August 13, 2025 04:37 PM UTC


Django Weblog

Building better APIs: from Django to client libraries with OpenAPI

tl;dr

A summary of resources and learnings related to building REST API I put together over the last couple of years. Complete API development workflow from Django backend to frontend clients using Django REST Framework, drf-spectacular for OpenAPI spec generation, and automated client generation with openapi-generator. Big productivity boost!

There is a lot of discussion about frameworks for building REST APIs, some of them being even able to generate OpenAPI specs directly for you. Django is not quite known for that, but there are ways of doing this by automating most of the process while being very productive and offering your team a clean developer experience.

Overview

The stack I prefer makes use of several additional modules you will require: django-rest-framework and drf-spectacular alongside Django. REST Framework helps you extend your application in order to have a REST API, while drf-spectacular will help you the ability to generate the OpenAPI spec (standalone post: Create OpenAPI spec for Django REST Framework APIs.

After having the OpenAPI spec, you can generate clients with openapi-generator. Here is an example I mapped out of generating an Angular client:

Diagram of the flow from OpenAPI, to code via openapi-generator, then npm publish, live on npm, them npm install api-client, then Angular

Step-by-step process

There is also a recording from my GLT 2025 talk where I summarize most of these ideas.

Building better APIs from Django to Client Libraries with OpenAPI by Harald Nezbeda Building Better APIs - From Django to Client Libraries with OpenAPI

In case you want to follow along, here is a step-by-step guide from the repository I showed during the presentation:

From the last step, you can generate the API clients for the platform you require. You can follow the README and the examples available in my glt25-client repository.

Maintaining compatibility over time

The final tool you can use is openapi-diff, which will help you keep your documentation compatible. This is very important once your REST API is used in production:

Example of a compatible change: glt25-demo v1 to v2

docker run --rm -t openapitools/openapi-diff:latest https://github.com/nezhar/glt25-demo/releases/download/v1/openapi.yaml https://github.com/nezhar/glt25-demo/releases/download/v2/openapi.yaml

Example of a breaking change: glt25-demo v2 to v3

docker run --rm -t openapitools/openapi-diff:latest https://github.com/nezhar/glt25-demo/releases/download/v2/openapi.yaml https://github.com/nezhar/glt25-demo/releases/download/v3/openapi.yaml

Automating the maintenance

The process can be automated even further using GitHub Actions and Dependabot. Here are what the steps look like with this full continuous delivery setup:

GitHub Release Published, then Generate OpenAPI Schema, then Upload Schema to Release, then Build Client, then Publish to npm

Takeways

Building a complete API development workflow from Django to client libraries using OpenAPI creates a powerful and maintainable development experience. By combining Django REST Framework with drf-spectacular for automatic OpenAPI spec generation and openapi-generator for client creation, you can eliminate manual API documentation and reduce integration errors.

If you want to go even further, you can automate the integration of error codes inside the OpenAPI spec. This way you can better support languages that are even more strict when consuming the REST API!


Thank you to Harald Nezbeda for proposing this guest post on the Django blog!

August 13, 2025 02:03 PM UTC


Real Python

Python's with Statement: Manage External Resources Safely

Python’s with statement allows you to manage external resources safely by using objects that support the context manager protocol. These objects automatically handle the setup and cleanup phases of common operations.

By using the with statement alongside appropriate context managers, you can focus on your core logic while the context managers prevent resource leaks like unclosed files, unreleased memory, or dangling network connections.

By the end of this tutorial, you’ll understand that:

  • Python’s with statement automates the process of setting up and tearing down computational resources using context managers.
  • Using with reduces code complexity and prevents resource leaks by ensuring proper resource release, even if exceptions occur.
  • A context manager in Python is an object that implements .__enter__() and .__exit__() methods to manage resources safely.

Get ready to learn how Python’s with statement and context managers streamline the setup and teardown phases of resource management so you can write safer, more reliable code.

Get Your Code: Click here to download the free sample code that shows you how to use Python’s with statement to manage external resources safely.

Take the Quiz: Test your knowledge with our interactive “Context Managers and Python's with Statement” quiz. You’ll receive a score upon completion to help you track your learning progress:


Interactive Quiz

Context Managers and Python's with Statement

Test your knowledge of Python's with statement and context managers to write cleaner code and manage resources safely and efficiently.

Managing External Resources in Python

Properly managing external resources, such as files, locks, and network connections, is a common requirement in programming. Sometimes, a program uses a given resource and doesn’t release the associated memory when it no longer needs the resource. This kind of issue is called a memory leak because the available memory shrinks every time you create a new instance of a resource without releasing the unneeded ones.

Managing resources properly is often a tricky task. It requires setup and teardown phases. The latter phase requires you to perform cleanup actions, like closing a file, releasing a lock, or closing a network connection. If you forget to perform these cleanup actions, then your application keeps the resource occupied. This behavior might compromise valuable system resources, such as memory and network bandwidth.

For example, say that a program that uses databases keeps creating new connections without releasing the old ones or reusing them. In that case, the database back end can stop accepting new connections. This might require an administrator to log in and manually terminate those stale connections to make the database usable again.

Another common issue occurs when developers work with files. Writing text to files is usually a buffered operation. This means that calling .write() on a file won’t immediately result in writing text to the physical file, but to a temporary buffer. Sometimes, when the buffer isn’t full, developers forget to call .close() and part of the data can be lost.

Another possibility is that your application runs into errors or exceptions that cause the control flow to bypass the code responsible for releasing the resource at hand. Here’s an example where you use the built-in open() function to write some text to a file:

Python
file = open("hello.txt", "w")
file.write("Hello, World!")
file.close()
Copied!

This code doesn’t guarantee the file will be closed if an exception occurs during the call to .write(). In this situation, the code might never call .close(), and your program will leak a file descriptor. Failing to release a file descriptor on some operating systems can prevent other programs from accessing the underlying file.

Note: To learn more about closing files, check out the Why Is It Important to Close Files in Python? tutorial.

In Python, you can use a couple of general approaches to deal with resource management. You can wrap your code in:

  1. A tryfinally construct
  2. A with construct

The first approach is quite generic and allows you to provide setup and teardown code to manage any kind of resource. However, it’s a little bit verbose, and you might forget some cleanup actions if you use this construct in several places.

The second approach provides a straightforward way to provide and reuse setup and teardown code. In this case, you’ll have the limitation that the with statement only works with context managers. In the next two sections, you’ll learn how to use both approaches in your code.

The tryfinally Construct

Working with files is probably the most common example of resource management in programming. In Python, you can use a tryfinally construct to handle opening and closing files properly:

Python
file = open("hello.txt", "w")

try:
    file.write("Hello, World!")
finally:
    file.close()
Copied!

In this example, you open the hello.txt file using open(). To write some text into the file, you wrap the call to .write() in a try statement with a finally clause. This clause guarantees that the file is properly closed by calling .close(), even if an exception occurs during the call to .write() in the try clause. Remember that the finally clause always runs.

When managing external resources in Python, you can use the construct in the previous example to handle setup and teardown logic. The setup logic might include opening the file and writing content to it, while the teardown logic might consist of closing the file to release the acquired resources.

Read the full article at https://realpython.com/python-with-statement/ »


[ 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 ]

August 13, 2025 02:00 PM UTC


PyCharm

Lightning-Fast Python: Mastering the uv Package Manager

Check out our recent livestream from August 7 on uv, a next-generation Python package manager revolutionizing Python development with speeds 10-100x faster than pip. Released just last year and written in Rust, uv replaces long-standing Python dependency management challenges with a single, lightning-fast tool that just works.


Our speakers:

* Michael Kennedy, host of Talk Python and Python Bytes podcasts, founder of Talk Python Training

* William Vincent, PyCharm Developer Advocate, Django Chat podcast host

Join us as we demonstrate uv‘s game-changing capabilities live, explore practical migration strategies, and discuss advanced features. We’ll show you why Python developers are rapidly adopting this breakthrough tool as their go-to package manager.

August 13, 2025 01:13 PM UTC


Ned Batchelder

Starting with pytest’s parametrize

Writing tests can be difficult and repetitive. Pytest has a feature called parametrize that can make it reduce duplication, but it can be hard to understand if you are new to the testing world. It’s not as complicated as it seems.

Let’s say you have a function called add_nums() that adds up a list of numbers, and you want to write tests for it. Your tests might look like this:

def test_123():
    assert add_nums([1, 2, 3]) == 6

def test_negatives():
    assert add_nums([1, 2, -3]) == 0

def test_empty():
    assert add_nums([]) == 0

This is great: you’ve tested some behaviors of your add_nums() function. But it’s getting tedious to write out more test cases. The names of the function have to be different from each other, and they don’t mean anything, so it’s extra work for no benefit. The test functions all have the same structure, so you’re repeating uninteresting details. You want to add more cases but it feels like there’s friction that you want to avoid.

If we look at these functions, they are very similar. In any software, when we have functions that are similar in structure, but differ in some details, we can refactor them to be one function with parameters for the differences. We can do the same for our test functions.

Here the functions all have the same structure: call add_nums() and assert what the return value should be. The differences are the list we pass to add_nums() and the value we expect it to return. So we can turn those into two parameters in our refactored function:

def test_add_nums(nums, expected_total):
    assert add_nums(nums) == expected_total

Unfortunately, tests aren’t run like regular functions. We write the test functions, but we don’t call them ourselves. That’s the reason the names of the test functions don’t matter. The test runner (pytest) finds functions named test_* and calls them for us. When they have no parameters, pytest can call them directly. But now that our test function has two parameters, we have to give pytest instructions about how to call it.

To do that, we use the @pytest.mark.parametrize decorator. Using it looks like this:

import pytest

@pytest.mark.parametrize(
    "nums, expected_total",
    [
        ([1, 2, 3], 6),
        ([1, 2, -3], 0),
        ([], 0),
    ]
)
def test_add_nums(nums, expected_total):
    assert add_nums(nums) == expected_total

There’s a lot going on here, so let’s take it step by step.

If you haven’t seen a decorator before, it starts with @ and is like a prologue to a function definition. It can affect how the function is defined or provide information about the function.

The parametrize decorator is itself a function call that takes two arguments. The first is a string (“nums, expected_total”) that names the two arguments to the test function. Here the decorator is instructing pytest, “when you call test_add_nums, you will need to provide values for its nums and expected_total parameters.”

The second argument to parametrize is a list of the values to supply as the arguments. Each element of the list will become one call to our test function. In this example, the list has three tuples, so pytest will call our test function three times. Since we have two parameters to provide, each element of the list is a tuple of two values.

The first tuple is ([1, 2, 3], 6), so the first time pytest calls test_add_nums, it will call it as test_add_nums([1, 2, 3], 6). All together, pytest will call us three times, like this:

test_add_nums([1, 2, 3], 6)
test_add_nums([1, 2, -3], 0)
test_add_nums([], 0)

This will all happen automatically. With our original test functions, when we ran pytest, it showed the results as three passing tests because we had three separate test functions. Now even though we only have one function, it still shows as three passing tests! Each set of values is considered a separate test that can pass or fail independently. This is the main advantage of using parametrize instead of writing three separate assert lines in the body of a simple test function.

What have we gained?

August 13, 2025 10:14 AM UTC


Seth Michael Larson

Transferring “UTF8.XYZ”

I'm transferring the UTF8.XYZ domain and service to Trey Hunner, a friend and beloved member of the Python community. Trey and I have talked about making this transfer many times at PyCon US's across the years, and now it's finally happening!

I've taken the opportunity to refresh the service and publish one last revision introducing support for Unicode 17.0.0 and Python 3.13. Big thank you to Trey for taking this on.

Wait... what's UTF8.XYZ?

If this is your first time hearing of the service, that's okay! I created this simple service in 2020 because I wanted to easily grab emojis, em-dashes, and other Unicode characters that I used frequently throughout the day. There aren't any ads, pesky pop-ups, or fluff: only a button to copy the character into your buffer.

You can use curl from the terminal to grab characters easily there, too:

$ curl https://utf8.xyz/waving-hand-sign
👋

Simple, right?



Thanks for keeping RSS alive! ♥

August 13, 2025 12:00 AM UTC


Quansight Labs Blog

Python Wheels: from Tags to Variants

The story of how the Python Wheel Variant design was developed

August 13, 2025 12:00 AM UTC

August 12, 2025


PyCoder’s Weekly

Issue #694: Performance, Classes, t-strings, and More (Aug. 12, 2025)

#694 – AUGUST 12, 2025
View in Browser »

The PyCoder’s Weekly Logo


Python Performance Myths and Fairy Tales

This post summarizes a talk by Antonio Cuni who is a long time contributor to PyPy, the alternate Python interpreter. The talk spoke about the challenges and limits of performance in Python and how the flexibility of dynamic languages comes at a cost. See also the associated HN discussion.
JAKE EDGE

You Might Not Need a Python Class

Coming from other languages, you might think a class is the easiest way to do something, but Python has other choices. This post shows you some alternatives and why you might choose them.
ADAM GRANT

Deep Dive: Going Beyond Chatbots with Durable MCP

alt

Join our August 19th webinar to explore long-running, human-in-the-loop MCP servers, sampling with LLMs, and how Python fits into scalable agent workflows with Temporal →
TEMPORAL sponsor

Exploring Python T-Strings

Python 3.14 introduces t-strings: a safer, more flexible alternative to f-strings. Learn how to process templates securely and customize string workflows.
REAL PYTHON course

PyCon NL 2025 Call for Proposals

PYCON-NL.ORG

Python 3.13.6 Released

PYTHON.ORG

Django Rest Framework Release v3.16.1

GITHUB.COM/ENCODE

Django 5.2.5 Released

DJANGO SOFTWARE FOUNDATION

Articles & Tutorials

Harnessing the Power of Python Polars

What are the advantages of using Polars for your Python data projects? When should you use the lazy or eager APIs, and what are the benefits of each? This week on the show, we speak with Jeroen Janssens and Thijs Nieuwdorp about their new book, Python Polars: The Definitive Guide.
REAL PYTHON podcast

Python Text Matching Beyond Regex

Text similarity is a fundamental challenge in data science. For data that contains duplicates, clustering content, or building search systems, this article explores using 4 different tools to solve this Regex, difflib, RapidFuzz, and Sentence Transformers
KHUYEN TRAN • Shared by Khuyen Tran

Preventing ZIP Parser Confusion Attacks

Python packaging wheels use the ZIP format and it was recently discovered that due to ambiguities in the specification, there could be a vulnerability when unpacking them. To prevent this, PyPI has added extra constraints.
SETH LARSON

Tools to Setup Great Python Projects

A guide to using uv, ruff, reorder-python-imports and pytest to manage packages, formatting, static analysis and testing - all under a centralized configuration that is easy to re-use across CI/CDs, CLIs, IDEs and scripts.
GITHUB.COM/DUARTE-POMPEU • Shared by Duarte Pompeu

Speed Up Your Python Data Science Workflows

This guide shows 7 popular Python libraries (pandas, Polars, scikit-learn, XGBoost, and more) — each accelerated with a simple flag or parameter change. Includes example demos and Colab notebooks.
JAMIL SEMAAN • Shared by Jamil Semaan

How Python Grew From a Language to a Community

This interview with Paul Everitt discusses the upcoming documentary on how Python went from a group of developers collaborating to having its own foundation and user conference.
DAVID CASSEL

Surprising Things With Python’s collections

This tutorial explores ten practical applications of the Python collections module, including use of Counter, namedtuple, defaultdict, and much more.
MATTHEW MAYO

Skip Ahead in Loops With Python’s Continue Keyword

Learn how Python’s continue statement works, when to use it, common mistakes to avoid, and what happens under the hood in CPython byte code.
REAL PYTHON

Quiz: Skip Ahead in Loops With Python’s Continue Keyword

REAL PYTHON

asyncio: A Library With Too Many Sharp Corners

asyncio has a few gotchas and this post describes five different problems, including: cancellation, disappearing tasks, and more.
SAILOR.LI

What Are Mixin Classes in Python?

Learn how to use Python mixin classes to write modular, reusable, and flexible code with practical examples and design tips.
REAL PYTHON

Quiz: What Are Mixin Classes in Python?

REAL PYTHON

The Forgetful Calligrapher

Understanding Late Binding in Python Closures
VIVIS DEV • Shared by Vivis Dev

Projects & Code

robinzhon: Concurrent S3 Object Downloads

GITHUB.COM/ROHAQUINLOP

archivey: Read Zip, Tar, Rar, 7z and Other Archives

GITHUB.COM/DAVITF

hvplot: Plotting API for Pandas, Dask, and More

GITHUB.COM/HOLOVIZ

tinyio: A Tiny Event Loop for Python

GITHUB.COM/PATRICK-KIDGER

Erys: Terminal Interface for Jupyter Notebooks

GITHUB.COM/NATIBEK

Events

Weekly Real Python Office Hours Q&A (Virtual)

August 13, 2025
REALPYTHON.COM

PyCon Somalia 2025

August 13 to August 15, 2025
PYCON.ORG.SO

Python Atlanta

August 14 to August 15, 2025
MEETUP.COM

PyCon Korea 2025

August 15 to August 18, 2025
PYCON.KR

Chattanooga Python User Group

August 15 to August 16, 2025
MEETUP.COM

EuroSciPy 2025

August 18 to August 23, 2025
EUROSCIPY.ORG

PyCon Togo 2025

August 23 to August 24, 2025
PYTOGO.ORG


Happy Pythoning!
This was PyCoder’s Weekly Issue #694.
View in Browser »

alt

[ 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 ]

August 12, 2025 07:30 PM UTC


Python Morsels

Checking for string prefixes and suffixes in Python

Python's strings have methods for checking whether a string starts or ends with specific text and for removing prefixes and suffixes.

Table of contents

  1. Slicing works, but there's a better way
  2. The startswith and endswith methods
  3. Checking for multiple string prefixes/suffixes
  4. Removing a string prefix or a suffix in Python
  5. How is this different from the strip method?
  6. Finding and removing string prefixes and suffixes

Slicing works, but there's a better way

We have a couple strings and we'd like to check whether one string is a prefix of another:

>>> filename = "report_housing_2030.pdf"
>>> prefix = "report_"

We could do that by getting the length of the prefix string and then slicing the other string to get the same prefix from it, and then comparing those strings to see whether they're equal:

>>> filename[:len(prefix)] == prefix
True

If we wanted to check whether one string was a suffix of another, we could do the same thing using negative indexes and slicing from the end of the string:

>>> tag = "app:v2.1.0-alpine"
>>> suffix = "-alpine"
>>> tag[-len(suffix):] == suffix
True

This all works, but this code is more awkward that it needs to be.

The startswith and endswith methods

Strings in Python have a …

Read the full article: https://www.pythonmorsels.com/prefixes-and-suffixes/

August 12, 2025 02:15 PM UTC


Real Python

Working With Python's .__dict__ Attribute

Python’s .__dict__ is a special attribute in classes and instances that acts as a namespace, mapping attribute names to their corresponding values. You can use .__dict__ to inspect, modify, add, or delete attributes dynamically, which makes it a versatile tool for metaprogramming and debugging.

In this video course, you’ll learn about using .__dict__ in various contexts, including classes, instances, and functions. You’ll also explore its role in inheritance with practical examples and comparisons to other tools for manipulating attributes.

By the end of this video course, you’ll understand that:


[ 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 ]

August 12, 2025 02:00 PM UTC


Python Engineering at Microsoft

mssql-python vs pyodbc: Benchmarking SQL Server Performance

c1014e61 a66d 4807 ab58 655671044f49 image

Reviewed by Imran Masud and Sumit Sarabhai

When it comes to working with Microsoft SQL Server in Python, pyodbc has long been the de facto driver. It’s mature, trusted and has been serving the community well for years.

But as applications scale and Python becomes more central to modern data workflows — from microservices to data engineering and platforms like Microsoft Fabric — there’s a growing need to modernize and improve the developer experience. 

So, can we take this further?

Meet mssql-python – a modern SQL Server driver for Python that rethinks the architecture from the ground up while preserving a familiar experience for developers. It is purpose-built for:

  • Security
  • Performance
  • Memory safety
  • Cross-platform support

Calling all Python + SQL developers! We invite the community to try out mssql-python and help us shape the future of high-performance SQL Server connectivity in Python.!

To evaluate how it stacks up against pyodbc, we ran a comprehensive suite of performance benchmarks using the excellent Richbench tool. The results? Let’s just say they speak volumes.

What makes mssql-python different?

Powered by DDBC – Direct Database Connectivity

Most Python SQL Server drivers, including pyodbc, route calls through the Driver Manager, which has slightly different implementations across Windows, macOS, and Linux. This results in inconsistent behavior and capabilities across platforms. Additionally, the Driver Manager must be installed separately, creating friction for both new developers and when deploying applications to servers. 

With mssql-python, we made a bold decision. At the heart of the driver is DDBC (Direct Database Connectivity) — a lightweight, high-performance C++ layer that replaces the platform’s Driver Manager.

Key Advantages:

Why This Architecture Matters?

By owning the layer that the ODBC driver depends on, DDBC delivers:

This architecture gives mssql-python its core advantages – speed, control and simplicity.

Built with PyBind11 + Modern C++ for Performance and Safety

To expose the DDBC engine to Python, mssql-python uses PyBind11 – a modern C++ binding library, instead of ctypes. Why is that important?

With ctypes, every call between Python and the ODBC driver involved costly type conversions, manual pointer management, and is slow and unsafe.

PyBind11 solves all of this. It provides:

Benchmark Setup

image 4 image

Benchmark Script

If you want to reproduce or extend our tests, checkout the complete script on GitHub.

Benchmark Summary

mssql-python outperforms pyodbc across most operations:

Category
mssql-python vs. pyodbc
Core SQL (SELECT, INSERT, UPDATE, DELETE) 2× to 4× faster
Join, Nested, and Complex Queries 3.6× to 4× faster
Fetch Operations (One & Many) 3.6 to ~3.7× faster
Stored Procedures, Transactions ~2.1× to ~2.6× faster
Batch Inserts 🔥~8.6x faster
1000 Connections 🔥16.5x faster

Across the board, the mssql-python driver demonstrated significantly faster execution times for common SQL operations, especially on:

These results indicate highly efficient execution paths, minimal overhead, and strong connection reuse capabilities.

Disclaimer on Performance Benchmarks

The performance tests comparing mssql-python and pyodbc were conducted using a controlled set of queries designed to evaluate core driver capabilities. Real-world results may vary based on query patterns, data volumes, and system configurations.

We welcome feedback and real-world usage insights from the community. If you encounter performance issues or have suggestions, please raise issues on Github, we’re actively listening and committed to improving the experience.

Visual Snapshot

We captured this benchmark data in a clean tabular format using richbench tool. Here’s a quick glance at the relative performance:

undefined image

Analysis & Insights

What’s Next?

We’re actively improving the driver and here’s what’s in the pipeline:

Performance tuning is a key priority, and we’re committed to delivering consistent improvements in upcoming releases.

Join the Journey

If you’re building high-performance apps with SQL Server in Python, mssql-python is a fast, modern and compelling alternative to pyodbc. It is:

Join the Early Customer Program

If you’re interested in becoming an early dogfooder and showcase your journey at Microsoft Ignite – we’d love to hear from you!

Apply here to join the Early Customer Program.

🚀Get early access, influence the roadmap, and work directly with the team!

Try It and Share Your Feedback! 

We invite you to: 

  1. Check-out the mssql-python driver and integrate it into your projects. 
  2. Share your thoughts: Open issues, suggest features, and contribute to the project. 
  3. Join the conversation: GitHub Discussions | SQL Server Tech Community

Use Python Driver with Free Azure SQL Database

You can use the Python Driver with the free version of Azure SQL Database!

✅ Deploy Azure SQL Database for free

✅ Deploy Azure SQL Managed Instance for free Perfect for testing, development, or learning scenarios without incurring costs.

The post mssql-python vs pyodbc: Benchmarking SQL Server Performance appeared first on Microsoft for Python Developers Blog.

August 12, 2025 11:10 AM UTC

August 11, 2025


Test and Code

237: FastAPI Cloud - Sebastián Ramírez

In this episode, Brian interviews Sebastián Ramírez, creator of FastAPI, about its rapid rise in developer popularity and the launch of FastAPI Cloud. Sebastian explains how FastAPI Cloud addresses deployment challenges small teams face. He shares his transition from open-source to startup founder, focusing on simplifying deployment against the complexity of tools like Kubernetes.

Links:


Help support the show AND learn pytest: 

★ Support this podcast on Patreon ★ <p>In this episode, Brian interviews Sebastián Ramírez, creator of FastAPI, about its rapid rise in developer popularity and the launch of FastAPI Cloud. Sebastian explains how FastAPI Cloud addresses deployment challenges small teams face. He shares his transition from open-source to startup founder, focusing on simplifying deployment against the complexity of tools like Kubernetes.</p><p>Links:</p><ul><li><a href="https://fastapicloud.work">FastAPI Cloud</a></li><li><a href="https://fastapi.tiangolo.com">FastAPI</a></li><li><a href="https://sqlmodel.tiangolo.com">SQLModel</a></li><li><a href="https://typer.tiangolo.com">Typer</a></li><li><a href="https://www.openapis.org">OpenAPI</a></li><li><a href="https://docs.pydantic.dev/latest/">Pydantic</a></li><li><a href="https://sequoiacap.com/oss/">Sequoia Open Source Fellowship</a></li></ul> <br><p><strong>Help support the show AND learn pytest: </strong></p><ul><li><a href="https://file+.vscode-resource.vscode-cdn.net/Users/brianokken/projects/test_and_code_notes/new_ad.md">The Complete pytest course</a> is now a bundle, with each part available separately.<ul><li><a href="https://courses.pythontest.com/pytest-primary-power">pytest Primary Power</a> teaches the super powers of pytest that you need to learn to use pytest effectively.</li><li><a href="https://courses.pythontest.com/using-pytest-with-projects">Using pytest with Projects</a> has lots of "when you need it" sections like debugging failed tests, mocking, testing strategy, and CI</li><li>Then <a href="https://courses.pythontest.com/pytest-booster-rockets">pytest Booster Rockets</a> can help with advanced parametrization and building plugins.</li></ul></li><li>Whether you need to get started with pytest today, or want to power up your pytest skills, <a href="https://courses.pythontest.com">PythonTest</a> has a course for you.<p></p></li></ul> <strong> <a href="https://www.patreon.com/c/testpodcast" rel="payment" title="★ Support this podcast on Patreon ★">★ Support this podcast on Patreon ★</a> </strong>

August 11, 2025 10:10 PM UTC


Everyday Superpowers

Get started with event sourcing today

I hope this series has inspired you to try event sourcing. In this article, I will give you some suggestions on how to start using it.

The mechanics of event sourcing are not complicated. They’re different, and it takes some getting used to.

When I learned event sourcing, I was told to create my own code to implement the pattern. That has been a great learning experience, but there are so many decisions to factor in that I frequently felt stuck. Instead of following my path, I advise you to see how the pattern works with a framework that someone else wrote, and then feel free to adventure on your own.

I suggest you start by using the `eventsourcing` Python package on a few toy projects. By leveraging it, you can see how the patterns come together. John Bywater and team have done a lot of hard work to make it easy to hit the ground running when you decide to use event sourcing.

To introduce you to the framework, I’ll explore the main components of the package, especially since the package uses terminology that you might not be familiar with.

Understand the components

The main terms you'll need to understand are Event, Aggregate, and Application. Let’s start with the Application.

Application

This is the outer shell of your event sourcing program. It exposes functionality to the outside world. APIs, web apps, or CLIs will call methods on your `Application` to perform tasks or retrieve data.

Applications in the `eventsourcing` package have a repository responsible for saving and retrieving events from the event store.

An incomplete application for a shopping cart could look like this:

from eventsourcing.application import Application

class CartApplication(Application):
    def add_item(self, item_id, quantity, price, cart_id=None):  
        cart = self.repository.get(cart_id) if cart_id else Cart()  
        cart.add_item(item_id, quantity, price)  
        self.save(cart)  
        return cart.id

In domain-driven design terms, I think of the `add_item` method as a command. It represents the intention to change the system by adding an item to a cart. If given a `cart_id`, it’ll create a `Cart` object from the events in the event store. Otherwise it’ll create a new `Cart`. Then it will tell that object to add an item to itself, save the resulting events to the event store, and return the cart id.

I imagine this code looks somewhat similar to the code you’d write in a traditional app.

This is one thing I like about the `eventsourcing` package, it abstracts the mechanics away so your code can focus on the business logic.

But what is this Cart object? Let’s dive into that next.

Aggregate

The `Cart` object in the previous example is an aggregate. Aggregates are analogous to the term “model” in a traditional application, in that models represent some kind of entity that changes over time.

In traditional apps, creating a new `Cart` object would create a new row in a database with the values for that new object. Changing the `Cart` object would result in changing the same row in the database.

In an event-sourced app, creating an aggregate would create an event in the event store that represents the creating of the aggregate with the values for the new object. Changing the `Cart` object would result in adding a new event to the event store with an event representing that change.

This is a different approach, but your code probably won’t look much different.

An aggregate that represents a shopping cart can look like this:

from eventsourcing.domain import event, Aggregate

class Cart(Aggregate):  
    def __init__(self):  
        self._items = []  
 
    @event("ItemAdded")  
    def add_item(self, item_id, quantity, price):  
        self._items.append((item_id, quantity, price))

The application object we discussed above would call the `__init__` and `add_item` methods of this aggregate.

This code shows how well the `eventsourcing` package allows you to focus on your business logic. Calling one of these methods would result in creating events. Calling the `__init__` method will create a `Cart.Created` event. Calling the `add_item` method would create a `Cart.ItemAdded` event.

In an event-sourced app, aggregate methods are responsible for changing the system and preventing situations that would clash with the business rules.

So, if the business wanted to prevent people from having more than five items in their cart, we would need to implement that in the `add_item` method. Maybe something like this:

class Cart(Aggregate):  
    ...
    @event("ItemAdded")  
    def add_item(self, item_id, quantity, price):
	    if len(self._items) >= 5:
	        raise MaxCartItemsException
        self._items.append((item_id, quantity, price))

As such, aggregates will hold the majority of your business logic.

Finally, let’s talk about events.

Event

An event represents a change that occurred in the system. Once created, it lives in the event store, usually in a database.

If I were to call the `add_item` method above and call `repr()` on the resulting event it could look like this:

Cart.ItemAdded(
    originator_id=UUID('5e2c3aa2-86e6-4729-b751-13adc23d8da4'), 
    originator_version=2, 
    timestamp=datetime.datetime(2025, 3, 28, 1, 51, 32, 827273, tzinfo=datetime.timezone.utc), 
    item_id=324, 
    quantity=1, 
    price=3499
)

This framework uses the term "originator" in its events to describe what other frameworks would call a model or entity. In this case, `originator_id` is akin to saying `cart_id`.

Events in the same event stream will have the same `originator_id` and a unique `originator_version`.

Another thing I like about the `eventsourcing` framework is that it does the work of defining the events for you from the parameters you provide in the aggregate’s methods. You can still define them yourself as well, to be more explicit, but I like that you have the option not to.

It’s your turn

This is enough to give you a quick overview of the package components. From here, I suggest you follow the package’s tutorial.

The tutorial spends most of its time working with in-memory “Plain Old Python Objects.” If you want to see the events in a database, you’ll have to configure the package to do so through environmental variables.


Read more...

August 11, 2025 07:37 PM UTC


Django Weblog

Welcome Our New Fellow - Jacob Tyler Walls

We are pleased to welcome Jacob Tyler Walls as the newest member of the Django Fellowship team. Jacob joins Natalia Bidart and Sarah Boyce, who continue in their roles as Django Fellows.

Jacob is a full-stack developer and open-source maintainer with five years of experience using and contributing to Django. He got involved in open source thanks to music technology. After majoring in music and philosophy at Williams College, Jacob earned a Ph.D. in music composition from the University of Pennsylvania. Programming coursework both fed into his creative output and also led to roles as a Python generalist working on music information retrieval and as a developer for an interactive music theory instruction site using Django.

As a member of Django’s Triage & Review Team, Jacob is passionate about software testing and eager to pay forward the mentorship he received as a contributor. Jacob also co-maintains the Python projects music21 and pylint.

Most recently, as part of his work as a core developer of Arches, an open-source Django/Vue framework for managing cultural heritage data, Jacob had the opportunity to explore the expressive potential of Django’s ORM. He gave a DjangoCon talk on his experience adapting QuerySets to work with highly generic data access patterns and an analogous talk for an audience of Arches developers. Since 2022, he has focused on developing GIS-powered Django apps at Azavea and later Farallon Geographics.

When time permits, Jacob continues to teach music theory, including most recently as an adjunct faculty member at the University of Delaware. (Perhaps another time Django Reinhardt will end up on the syllabus.)

You can find Jacob on GitHub as @jacobtylerwalls and follow occasional musical updates at jacobtylerwalls.com


Thank you to all the applicants to the Fellowship. We hope to expand the program in the future, and knowing there are so many excellent candidates gives us great confidence as we work toward that goal.

August 11, 2025 07:30 PM UTC


Ari Lamstein

New Tutorial: Building Data Apps in Python With Streamlit

I just created a tutorial on building data apps in Python with Streamlit. In many ways, this is the resource I wish I had when I started working with Streamlit two years ago. You can take it for free here!

The tutorial is in a github repo. All the instructions are in the repo’s README file. You can go through the course at your own pace. I expect that most people will finish the course within a few hours.

Demo App

The first milestone in the course is running a demo app that is already in the repo. This app lets you select a state. It then creates a graph that shows how that state’s population has changed over time. The app also displays a dataframe with data on all the states:

Exercises

The core of the tutorial are 4 exercises to improve the app. These exercises cover the most common tasks I do when working with Streamlit:

  1. Create another graph.
  2. Create another select box.
  3. Use the value from the select boxes to determine which graph to show.
  4. Separate the two visualizations (graph and table) using tabs.

Below is a screenshot of the final app you will create. Note that users can now select which demographic to view. And the table which shows all the data is on a separate tab:

Deployment

Finally, the tutorial walks you through deploying the app to the web. This is also free, and allows your friends and family to see the app you created.

Click here to take the course!

August 11, 2025 04:00 PM UTC


Real Python

Python 3.14 Release Candidate Lands: Faster Code, Smarter Concurrency

Last month, Python 3.14 reached its first release candidate, pushing the interpreter past beta and onto the home stretch toward its final release on October 7. But that headline was only the start—new library releases also landed, Django celebrated its 20th birthday, and EuroPython brought the community together in Prague.

What follows is a quick-read digest of everything that mattered, from core-language breakthroughs to tooling upgrades and community milestones. Feel free to skip straight to whatever interests you most.

Join Now: Click here to join the Real Python Newsletter and you'll never miss another Python tutorial, course, or news update.

Python 3.14 Hits Its First Release Candidate

Last month’s biggest headline is the release of Python 3.14.0rc1, the first candidate for Python 3.14. This marks the penultimate step before the final release, which is scheduled for October 7, 2025.

Core developers are now focused on final documentation updates, while library maintainers are encouraged to test their projects with 3.14 and publish wheels to the Python Package Index (PyPI). Since this is a release candidate, there will be no further ABI changes, meaning that wheels built for this version will work with the final release.

Note: In the context of Python, ABI (Application Binary Interface) refers to the low-level binary compatibility between compiled Python extension modules and the CPython interpreter.

Python 3.14 comes with some exciting new features:

Topping the feature list is free-threaded Python, a long-awaited improvement that ushers in the free‑threaded era. The officially supported free‑threaded build lifts the long‑standing Global Interpreter Lock (GIL), allowing CPU-bound threads to run truly in parallel on separate cores. As a result, data‑science workloads, web servers, and other concurrency‑heavy apps can scale more cleanly without resorting to multiprocessing.

Existing single‑threaded code keeps working unchanged, but projects that embrace the new model can expect simpler concurrency patterns and better performance.

Other refinements include improved error messages, enhanced debugging tools, and new command-line interface (CLI) features for asyncio introspection.

The release also includes experimental just-in-time (JIT) compilation in the official macOS and Windows binaries, and a new Windows install manager that can be downloaded from the Microsoft Store.

Library and Tooling Highlights

The latest batch of releases brings fresh updates across the Python ecosystem, from cutting-edge data science libraries to faster installers and frameworks. Whether you’re looking for better performance, smarter APIs, or new tools for your workflow, these updates have something for every Pythonista. Here are the key highlights you won’t want to miss.

PyPy 7.3.20 Brings Bug Fixes and Cython Compatibility

Read the full article at https://realpython.com/python-news-august-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 ]

August 11, 2025 02:00 PM UTC


Talk Python to Me

#515: Durable Python Execution with Temporal

What if your code was crash-proof? That's the value prop for a framework called Temporal. Temporal is a durable execution platform that enables developers to build scalable applications without sacrificing productivity or reliability. The Temporal server executes units of application logic called Workflows in a resilient manner that automatically handles intermittent failures, and retries failed operations. We have Mason Egger from Temporal on to dive into durable execution.<br/> <br/> <strong>Episode sponsors</strong><br/> <br/> <a href='https://talkpython.fm/ppm'>Posit</a><br> <a href='https://talkpython.fm/pybay'>PyBay</a><br> <a href='https://talkpython.fm/training'>Talk Python Courses</a><br/> <br/> <h2 class="links-heading">Links from the show</h2> <div><strong>Just Enough Python for Data Scientists Course</strong>: <a href="https://training.talkpython.fm/courses/just-enough-python-for-data-scientists" target="_blank" >talkpython.fm</a><br/> <br/> <strong>Temporal Durable Execution Platform</strong>: <a href="https://temporal.io?featured_on=talkpython" target="_blank" >temporal.io</a><br/> <strong>Temporal Learn Portal</strong>: <a href="https://learn.temporal.io/?featured_on=talkpython" target="_blank" >learn.temporal.io</a><br/> <strong>Temporal GitHub Repository</strong>: <a href="https://github.com/temporalio/temporal?featured_on=talkpython" target="_blank" >github.com</a><br/> <strong>Temporal Python SDK GitHub Repository</strong>: <a href="https://github.com/temporalio/sdk-python?featured_on=talkpython" target="_blank" >github.com</a><br/> <strong>What Is Durable Execution, Temporal Blog</strong>: <a href="https://temporal.io/blog/what-is-durable-execution?featured_on=talkpython" target="_blank" >temporal.io</a><br/> <strong>Mason on Bluesky Profile</strong>: <a href="https://bsky.app/profile/mason.dev?featured_on=talkpython" target="_blank" >bsky.app</a><br/> <strong>Mason on Mastodon Profile</strong>: <a href="https://fosstodon.org/@masonegger" target="_blank" >fosstodon.org</a><br/> <strong>Mason on Twitter Profile</strong>: <a href="https://twitter.com/masonegger?featured_on=talkpython" target="_blank" >twitter.com</a><br/> <strong>Mason on LinkedIn Profile</strong>: <a href="https://www.linkedin.com/in/mason-egger?featured_on=talkpython" target="_blank" >linkedin.com</a><br/> <strong>X Post by @skirano</strong>: <a href="https://x.com/skirano/status/1922651912156897284?featured_on=pythonbytes" target="_blank" >x.com</a><br/> <strong>Temporal Docker Compose GitHub Repository</strong>: <a href="https://github.com/temporalio/docker-compose?featured_on=talkpython" target="_blank" >github.com</a><br/> <strong>Building a distributed asyncio event loop (Chad Retz) - PyTexas 2025</strong>: <a href="https://www.youtube.com/watch?v=wEbUzMYlAAI&ab_channel=PyTexas" target="_blank" >youtube.com</a><br/> <strong>Watch this episode on YouTube</strong>: <a href="https://www.youtube.com/watch?v=xcxQ1f-Oj2M" target="_blank" >youtube.com</a><br/> <strong>Episode #515 deep-dive</strong>: <a href="https://talkpython.fm/episodes/show/515/durable-python-execution-with-temporal#takeaways-anchor" target="_blank" >talkpython.fm/515</a><br/> <strong>Episode transcripts</strong>: <a href="https://talkpython.fm/episodes/transcript/515/durable-python-execution-with-temporal" target="_blank" >talkpython.fm</a><br/> <strong>Developer Rap Theme Song: Served in a Flask</strong>: <a href="https://talkpython.fm/flasksong" target="_blank" >talkpython.fm/flasksong</a><br/> <br/> <strong>--- Stay in touch with us ---</strong><br/> <strong>Subscribe to Talk Python on YouTube</strong>: <a href="https://talkpython.fm/youtube" target="_blank" >youtube.com</a><br/> <strong>Talk Python on Bluesky</strong>: <a href="https://bsky.app/profile/talkpython.fm" target="_blank" >@talkpython.fm at bsky.app</a><br/> <strong>Talk Python on Mastodon</strong>: <a href="https://fosstodon.org/web/@talkpython" target="_blank" ><i class="fa-brands fa-mastodon"></i>talkpython</a><br/> <strong>Michael on Bluesky</strong>: <a href="https://bsky.app/profile/mkennedy.codes?featured_on=talkpython" target="_blank" >@mkennedy.codes at bsky.app</a><br/> <strong>Michael on Mastodon</strong>: <a href="https://fosstodon.org/web/@mkennedy" target="_blank" ><i class="fa-brands fa-mastodon"></i>mkennedy</a><br/></div>

August 11, 2025 08:00 AM UTC


Python Bytes

#444 Begone Python of Yore!

<strong>Topics covered in this episode:</strong><br> <ul> <li><strong><a href="https://nedbatchelder.com/blog/202507/coveragepy_regex_pragmas.html?featured_on=pythonbytes">Coverage.py regex pragmas</a></strong></li> <li><em>* <a href="https://pypi.org/project/yore/?featured_on=pythonbytes">Python of Yore</a></em>*</li> <li><em>* <a href="https://github.com/dantebben/nox-uv?featured_on=pythonbytes">nox-uv</a></em>*</li> <li><em>* A couple Django items</em>*</li> <li><strong>Extras</strong></li> <li><strong>Joke</strong></li> </ul><a href='https://www.youtube.com/watch?v=HCRfjkbSbmE' style='font-weight: bold;'data-umami-event="Livestream-Past" data-umami-event-episode="444">Watch on YouTube</a><br> <p><strong>About the show</strong></p> <p>Sponsored by DigitalOcean: <a href="https://pythonbytes.fm/digitalocean-gen-ai"><strong>pythonbytes.fm/digitalocean-gen-ai</strong></a> Use code <strong>DO4BYTES</strong> and get $200 in free credit</p> <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:</strong> <a href="https://nedbatchelder.com/blog/202507/coveragepy_regex_pragmas.html?featured_on=pythonbytes">Coverage.py regex pragmas</a></p> <ul> <li><p>Ned Batchelder</p></li> <li><p>The regex implementation of how <a href="http://coverage.py?featured_on=pythonbytes">coverage.py</a> recognizes pragmas is pretty amazing.</p></li> <li><p>It’s extensible through plugins</p> <ul> <li><a href="https://pypi.org/project/covdefaults/?featured_on=pythonbytes">covdefaults</a> adds a bunch of default exclusions, and also platform- and version-specific comment syntaxes.</li> <li><a href="https://pypi.org/project/coverage-conditional-plugin/?featured_on=pythonbytes">coverage-conditional-plugin</a> gives you a way to create comment syntaxes for entire files, for whether other packages are installed, and so on.</li> </ul></li> <li><p>A change from last year (as part of coverage.py 7.6 allows multiline regexes, which let’s us do things like:</p> <ul> <li>Exclude an entire file with <code>\\A(?s:.*# pragma: exclude file.*)\\Z</code></li> <li>Allow start and stop delimiters with <code># no cover: start(?s:.*?)# no cover: stop</code></li> <li>Exclude empty placeholder methods with <code>^\\s*(((async )?def .*?)?\\)(\\s*-&gt;.*?)?:\\s*)?\\.\\.\\.\\s*(#|$)</code></li> <li>See Ned’s article for explanations of these</li> </ul></li> </ul> <p><strong>Michael #2: <a href="https://pypi.org/project/yore/?featured_on=pythonbytes">Python of Yore</a></strong></p> <ul> <li>via Matthias</li> <li>Use <code>YORE: ...</code> comments to highlight CPython version dependencies. <div class="codehilite"> <pre><span></span><code><span class="c1"># YORE: EOL 3.8: Replace block with line 4.</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">version_info</span> <span class="o">&lt;</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">9</span><span class="p">):</span> <span class="kn">from</span><span class="w"> </span><span class="nn">astunparse</span><span class="w"> </span><span class="kn">import</span> <span class="n">unparse</span> <span class="k">else</span><span class="p">:</span> <span class="kn">from</span><span class="w"> </span><span class="nn">ast</span><span class="w"> </span><span class="kn">import</span> <span class="n">unparse</span> </code></pre> </div></li> </ul> <p>Then check when they go out of support:</p> <div class="codehilite"> <pre><span></span><code>$<span class="w"> </span>yore<span class="w"> </span>check<span class="w"> </span>--eol-within<span class="w"> </span><span class="s1">&#39;5 months&#39;</span> ./src/griffe/agents/nodes/_values.py:11:<span class="w"> </span>Python<span class="w"> </span><span class="m">3</span>.8<span class="w"> </span>will<span class="w"> </span>reach<span class="w"> </span>its<span class="w"> </span>End<span class="w"> </span>of<span class="w"> </span>Life<span class="w"> </span>within<span class="w"> </span>approx.<span class="w"> </span><span class="m">4</span><span class="w"> </span>months </code></pre> </div> <p>Even fix them with <code>fix</code> .</p> <p><strong>Michael #3: <a href="https://github.com/dantebben/nox-uv?featured_on=pythonbytes">nox-uv</a></strong></p> <ul> <li>via John Hagen</li> <li>What nox-uv does is make it very simple to install uv extras and/or dependency groups into a nox session's virtual environment.</li> <li>The versions installed are constrained by uv's lockfile meaning that everything is deterministic and pinned.</li> <li>Dependency groups make it very easy to install only want is necessary for a session (e.g., only linting dependencies like Ruff, or main dependencies + mypy for type checking).</li> </ul> <p><strong>Brian #4: A couple Django items</strong></p> <ul> <li><strong>Stop Using Django's squashmigrations: There's a Better Way</strong> <ul> <li>Johnny Metz</li> <li>Resetting migrations is sometimes the right thing.</li> <li>Overly simplified summary: delete migrations and start over</li> </ul></li> <li><strong>dj-lite</strong> <ul> <li>Adam Hill</li> <li>Use SQLite in production with Django</li> <li>“Simplify deploying and maintaining production Django websites by using SQLite in production. <code>dj-lite</code> helps enable the best performance for SQLite for small to medium-sized projects. It requires Django 5.1+.”</li> </ul></li> </ul> <p><strong>Extras</strong></p> <p>Brian:</p> <ul> <li><a href="https://testandcode.com/237?featured_on=pythonbytes">Test &amp; Code 237 with Sebastian Ramirez on FastAPI Cloud</a></li> <li><a href="https://pythontest.com/pytest-fixtures-nuts-bolts-revisited/?featured_on=pythonbytes">pythontest.com: pytest fixtures nuts and bolts - revisited</a></li> </ul> <p>Michael:</p> <ul> <li>New course: <a href="https://training.talkpython.fm/courses/just-enough-python-for-data-scientists?featured_on=pythonbytes"><strong>Just Enough Python for Data Scientists</strong></a></li> <li><a href="https://www.youtube.com/watch?v=Uh8CMtaWPpc">My live stream about uv</a> is now on YouTube</li> <li><a href="https://cursor.com/en/cli?featured_on=pythonbytes">Cursor CLI</a>: Built to help you ship, right from your terminal.</li> </ul> <p><strong>Joke: <a href="https://www.reddit.com/r/programminghumor/s/90oFJlauGv?featured_on=pythonbytes">Copy/Paste</a></strong></p>

August 11, 2025 08:00 AM UTC

August 10, 2025


Go Deh

Go Deh celebrations!

 


 

 This year it's: 

  1. Fifty years since I first learned to program!
  2. Thirty years of programming Python!
  3. And In July, this blog topped one million views since its inception! 

I first learned to program by crashing an after-school class I saw the private school geeks disappearing to from Central library  in Nottingham. One of the Trent Polytechnic lecturers I now see sometimes on Computerphile - he mentioned how the council payed something towards the cost of the computer on the understanding that they have a class for students, but somehow only the guys from the fee paying Nottingham High School for Boys seemed to get the memo, hmm.
That was s long ago, Paper tape and teletypes.

Forward to 1995: A new job, amongst engineers where the few of them that could program, programmed in Perl. Perl was big within the chip design industry back then, but Aargh! I thought Perl was awful - for me it did not gel! I went looking for an alternative and found this little known language called Python. 
The community on comp.lang.python seemed so nice, they valued readability and "One obvious way to do it" over Perls more than one way. I was hooked, and did my little bit of evangelizing. (OK, I was known as that Python guy - but they couldn't fault the code).

Was it eleven years ago that I started the blog? It has been one of two main places where I have shown my work - the other is on site rosettacode.org which, no doubt, has been scraped to death for AI's - it is one of the few places online showing different programming languages solving the same task. I wrote 199 of those RosettaCode tasks over the years, and many more of the examples solving those tasks; (mainly  Python and Awk language examples). Most, if not all of those task descriptions were my own work - not copied off other sites - if there are similarities in text then they probably copied from me or the task is so simple that there is going to be convergence).

 Lately, as you can tell from the pictures above, I have been dabbling in AI. AI is the future, but who knows how AI will affect that future? I am a programmer who can describe coding tasks to other people for them to complete the task. AI is an ever changing field, I think that I am learning to use it better, as it gets better too - I am both more and less precise in my prompting and finding out what the AI remembers and does best. I experiment with the  amount of description in the code to cut and paste into new sessions to cut the mistakes and continue from a clean base. I experiment with coding from pseudo-code. I have found that some abilities are universal: when exploring the use of SQL - which I am a hunt-n-peck coder in, I can still spot redundancies "You recompute the first query as part of the second and the second as part of the third, can't you reuse prior results", lead to the AI introducing common table expressions I think it was, and telling me all about them.

I'm still scripting  😊

 

August 10, 2025 05:22 PM UTC

August 09, 2025


Peter Bengtsson

Combining Django signals with in-memory LRU cache

It's easy to combine functools.lru_cache with Django signals to get a good memoization pattern on Django ORM queries.

August 09, 2025 06:33 PM UTC


Django Weblog

Django’s accessibility contributing guide

The Django accessibility team is excited to announce that our accessibility contribution guidelines are now live in the documentation 🎉

These new guidelines are designed to support contributors in making Django more accessible to all users — including those who navigate the web using screen readers, keyboard-only inputs, and other assistive technologies.

They outline practical steps for designing and testing accessible user interfaces, how to contribute, follow up on ongoing accessibility issues, and contact the team. For beginners, we also recommend resources like The A11Y Project to get started.

We welcome your feedback and contributions as we continue to improve accessibility across the Django ecosystem! Come say hi on the Django Forum: Accessibility contributing guide.

Four Django ponies flying in the clouds around the Django logo. One has a leg in a cast, one has dark glasses and a cane, one is in a wheelchair, and one has a hidden disability sunflower. The ponies are white, with purple highlights and pink mane and hooves. They have wings and are smiling

August 09, 2025 09:38 AM UTC


Glyph Lefkowitz

R0ML’s Ratio

My father, also known as “R0ML” once described a methodology for evaluating volume purchases that I think needs to be more popular.

If you are a hardcore fan, you might know that he has already described this concept publicly in a talk at OSCON in 2005, among other places, but it has never found its way to the public Internet, so I’m giving it a home here, and in the process, appropriating some of his words.1


Let’s say you’re running a circus. The circus has many clowns. Ten thousand clowns, to be precise. They require bright red clown noses. Therefore, you must acquire a significant volume of clown noses. An enterprise licensing agreement for clown noses, if you will.

If the nose plays, it can really make the act. In order to make sure you’re getting quality noses, you go with a quality vendor. You select a vendor who can supply noses for $100 each, at retail.

Do you want to buy retail? Ten thousand clowns, ten thousand noses, one hundred dollars: that’s a million bucks worth of noses, so it’s worth your while to get a good deal.

As a conscientious executive, you go to the golf course with your favorite clown accessories vendor and negotiate yourself a 50% discount, with a commitment to buy all ten thousand noses.

Is this a good deal? Should you take it?

To determine this, we will use an analytical tool called R0ML’s Ratio (RR).

The ratio has 2 terms:

  1. the Full Undiscounted Retail List Price of Units Used (FURLPoUU), which can of course be computed by the individual retail list price of a single unit (in our case, $100) multiplied by the number of units used
  2. the Total Price of the Entire Enterprise Volume Licensing Agreement (TPotEEVLA), which in our case is $500,000.

It is expressed as:

1
RR = TPotEEVLA / FURLPoUU

Crucially, you must be able to compute the number of units used in order to complete this ratio. If, as expected, every single clown wears their nose at least once during the period of the license agreement, then our Units Used is 10,000, our FURLPoUU is $1,000,000 and our TPotEEVLA is $500,000, which makes our RR 0.5.

Congratulations. If R0ML’s Ratio is less than 1, it’s a good deal. Proceed.

But… maybe the nose doesn’t play. Not every clown’s costume is an exact clone of the traditional, stereotypical image of a clown. Many are avant-garde. Perhaps this plentiful proboscis pledge was premature. Here, I must quote the originator of this theoretical framework directly:

What if the wheeze doesn’t please?

What if the schnozz gives some pause?

In other words: what if some clowns don’t wear their noses?

If we were to do this deal, and then ask around afterwards to find out that only 200 of our 10,000 clowns were to use their noses, then FURLPoUU comes out to 200 * $100, for a total of $20,000. In that scenario, RR is 25, which you may observe is substantially greater than 1.

If you do a deal where R0ML’s ratio is greater than 1, then you are the bozo.


I apologize if I have belabored this point. As R0ML expressed in the email we exchanged about this many years ago,

I do not mind if you blog about it — and I don't mind getting the credit — although one would think it would be obvious.

And yeah, one would think this would be obvious? But I have belabored it because many discounted enterprise volume purchasing agreements still fail the R0ML’s Ratio Bozo Test.2

In the case of clown noses, if you pay the discounted price, at least you get to keep the nose; maybe lightly-used clown noses have some resale value. But in software licensing or SaaS deals, once you’ve purchased the “discounted” software or service, once you have provisioned the “seats”, the money is gone, and if your employees don’t use it, then no value for your organization will ever result.

Measuring number of units used is very important. Without this number, you have no idea if you are a bozo or not.

It is often better to give your individual employees a corporate card and allow them to make arbitrary individual purchases of software licenses and SaaS tools, with minimal expense-reporting overhead; this will always keep R0ML’s Ratio at 1.0, and thus, you will never be a bozo.

It is always better to do that the first time you are purchasing a new software tool, because the first time making such a purchase you (almost by definition) have no information about “units used” yet. You have no idea — you cannot have any idea — if you are a bozo or not.

If you don’t know who the bozo is, it’s probably you.

Acknowledgments

Thank you for reading, and especially thank you to my patrons who are supporting my writing on this blog. Of course, extra thanks to dad for, like, having this idea and doing most of the work here beyond my transcription. If you like my dad’s ideas and you’d like to post more of them, or you’d like to support my various open-source endeavors, you can support my work as a sponsor!


  1. One of my other favorite posts on this blog was just stealing another one of his ideas, so hopefully this one will be good too. 

  2. This concept was first developed in 2001, but it has some implications for extremely recent developments in the software industry; but that’s a post for another day. 

August 09, 2025 04:41 AM UTC

August 08, 2025


Real Python

Quiz: Python Basics: Setting Up Python

In this quiz, you will review the key steps for installing Python on Windows, macOS, and Ubuntu Linux. You will recall what the PATH environment variable is for, and what Python distribution to choose.

Note: The explanations in the questions will link back to the Windows installation lesson, but all question are kept general, so you’ll be able to answer them independent of which operating system you use.

You’ll also revisit how to use IDLE, and enter commands at the Python prompt. Brush up on these essentials before you start the quiz by reviewing Setting Up 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 ]

August 08, 2025 12:00 PM UTC

The Real Python Podcast – Episode #260: Harnessing the Power of Python Polars

What are the advantages of using Polars for your Python data projects? When should you use the lazy or eager APIs, and what are the benefits of each? This week on the show, we speak with Jeroen Janssens and Thijs Nieuwdorp about their new book, _Python Polars: The Definitive Guide_.


[ 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 ]

August 08, 2025 12:00 PM UTC


Tryton News

Newsletter August 2025

During the last month we focused on fixing bugs, improving the behaviour of things, speeding-up performance issues - building on the changes from our last release. We also added some new features which we would like to introduce to you in this newsletter.

Changes for the User

User Interface

We now slugify the file names of email attachments as some mail servers forbid the use of more than one . in a filename.

New Documentation

We’ve reworked the documentation for the web_shop_shopify module and now use the actual Shopify API terminology.

New Releases

We released bug fixes for the currently maintained long term support series 7.0 and 6.0, and for the penultimate series 7.6 and 7.4. Also we closed the 7.2 series.

Authors: @dave @pokoli @udono

1 post - 1 participant

Read full topic

August 08, 2025 09:00 AM UTC