Planet Python
Last update: July 18, 2026 09:47 PM UTC
July 18, 2026
Core Dispatch
Core Dispatch #8
Welcome back to Core Dispatch! This edition covers July 5 through July 18, 2026. Python 3.15.0 beta 4 landed today, July 18 (we just released it at the EuroPython sprints!), with 3.13.15, 3.14.7 and the first 3.15 release candidate following on August 4. It's EuroPython week! Much of the core team
Python Insider
Python 3.15.0 beta 4 is here!
The final 3.15 beta is out!
July 17, 2026
PyPodcats
Episode 12: With Juanita Gomez
Learn about Juanita Gomez, a Ph.D. candidate at UC Santa Cruz researching open source security. From developing the Spyder IDE to leading community efforts for Scientific Python and singing on stage at SciPy, Juanita shares her journey in open source.
July 16, 2026
Tryton News
Release 1.0.0 of Relatorio
We are proud to announce the release of Relatorio version 1.0.0.
Relatorio is a templating library for OpenDocument using also OpenDocument as source format.
In addition to bug-fixes, this release contains the following improvements:
- Replace python-magic dependency by puremagic
- Remove support for chart template
- Remove support for PDF
The package is available at Client Challenge
The documentation is available at Relatorio — A templating library able to output odt files
1 post - 1 participant
Release 1.0.0 of GooCalendar
We are proud to announce the release 1.0.0 of GooCalendar.
GooCalendar is a Python library that implements a calendar widget for GTK+.
In addition to bug-fixes, this release contains this following improvements:
- Remove GooCanvas dependency
- Remove support for Python older than 3.9
- Upgrade to pyproject
GooCalendar is available on PyPI: GooCalendar · PyPI
The documentation is available at goocalendar — Calendar widget — A calendar widget for GTK
1 post - 1 participant
Seth Michael Larson
EuroPython 2026: Learning from the “not-so-secret” Python security cabal
July 15, 2026
Python Software Foundation
Affirm Your PSF Membership Voting Status
Django Weblog
Supporting the Triptych Project
The Django Steering Council — in its role as the DSF's arm for technical governance — has provided a Letter of Collaboration in support of a funding application by Carson Gross and Alex Petros to advance the Triptych Project: three proposals to make HTML itself more expressive, in every browser, by default.
Here's why, and how you can help.
HTML over the wire, and Django
The last few years have seen a move back towards serving multipage applications, with server-rendered templates. The HTMX library has probably had the biggest impact in the Django space, but Unpoly, Turbo, and others are part of the same story: send HTML over the wire, let the browser do what browsers do, and skip the client-side application layer where you don't really need it. It's a simpler model of the web — and it's one that speaks to Django's heart.
This isn't a movement Django has watched from the sidelines. Template partials, added in Django 6.0, were directly inspired by the patterns these libraries make natural.
The Triptych Project
The Triptych Project takes the core insights from HTMX (and the related libraries) and proposes them for the HTML standard itself. Three small additions:
- PUT, PATCH, and DELETE methods for forms — completing HTML's HTTP vocabulary.
- Button actions — buttons that make HTTP requests without a wrapping form. This is the current focus.
- Partial page replacement — links, forms, and buttons that target part of the DOM.
Together these aim to make it possible to build far more of the web with plain HTML — no JavaScript dependency, no library, nothing to ship or maintain.
Button actions
The current proposal (WHATWG #12330, full proposal) adds the action and method attributes to <button>. The canonical example is logout. Today there's no semantic way to write a logout button; you have to wrap it in a form:
<form action=/logout method=POST>
<button>Logout</button>
</form>
Every Django developer has written this kind of thing. With button actions we could write the simpler single line:
<button action=/logout method=POST>Logout</button>
This isn't abstract for us. The Django admin's submit row holds multiple buttons, and a link disguised as a button:
<div class="submit-row">
<input type="submit" value="Save" class="default" name="_save">
<input type="submit" value="Save and add another" name="_addanother">
<input type="submit" value="Save and continue editing" name="_continue">
<a href="/admin/auth/user/.../delete/" class="deletelink">Delete</a>
</div>
Here, all the save inputs lead to the same action URL from the wrapping form. The view then branches on the submitted name value. That, of course, works, but we can imagine simpler, more flexible ideas being enabled via the Multi-Action Pages examples in the proposal.
The disguised submit link leads to the deletion confirmation page, where we then submit a form to confirm the action. That's the correct behaviour, but the markup confuses the intent: this isn't (really) a navigation to a new page, it's the first step of an action — deleting the object. The proposal's discussion of Buttons vs Links describes situations we come up against writing applications regularly.
The goal here is simpler patterns that will help us write better markup.
Why we're supporting this
The Django Software Foundation's mission includes a commitment to "advance the state of the art in Web development". Standards work is that in its purest form: an improvement to HTML lands for everyone, in every framework, in every browser, indefinitely.
It's also slow, painstaking work — specification, implementer engagement, web platform tests — that needs sustained attention. Carson and Alex are applying for funds so that people can devote real time to it. Our Letter of Collaboration is a concrete contribution to that application.
How you can help
If your company builds on Django, or indeed any other framework — with HTMX, Unpoly, Turbo, or plain HTML forms — this work benefits you directly. Carson and Alex are seeking non-binding letters of support on official letterhead for the funding application. Details and contacts are on the Triptych Project site.
Individually, do read the proposals, weigh in constructively on the WHATWG issues, and spread the word.
A simpler web is a better web. We're glad to support work that moves HTML in that direction.
July 14, 2026
PyCoder’s Weekly
Issue #743: Stacks & Queues, Django F-Expressions, MCP Clients, and More (2026-07-14)
Peter Bengtsson
How to use a list/tuple/array in Django with a raw SQL cursor
This does not work:
from django.db import connection
list_of_values = [1, 2, 3]
with connection.cursor() as cursor:
cursor.execute("""
SELECT *
FROM my_model_table
WHERE some_value IN %s
""", [
tuple(list_of_values),
])
results = cursor.fetchall()
It will give you:
django.db.utils.ProgrammingError: syntax error at or near "'(1,2,3)'" LINE 4: WHERE id IN '(1,2,3)'
It used to work with psycopg v2. Now, in psycopg v3, you have to use the ANY operator. See "You cannot use IN %s with a tuple"
This will work:
from django.db import connection
list_of_values = [1, 2, 3]
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT *
FROM my_model_table
WHERE some_value = ANY(%s)
""",
[
list_of_values,
],
)
results = cursor.fetchall()
Note the ANY(%s), and instead of a list that has a tuple, it's a list that has a list.
What About a List of Strings
Consider...
from django.db import connection
-list_of_values = [1, 2, 3]
+list_of_values = ['foo', 'bar', 'fiz']
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT *
FROM my_model_table
WHERE some_value = ANY(%s)
""",
[
list_of_values,
],
)
results = cursor.fetchall()
That will result in:
django.db.utils.DataError: invalid input syntax for type integer: "foo"
LINE 4: WHERE some_value = ANY('{foo,bar,fiz}')
My solution was to rewrite the SQL string itself and treat each value as a parameter each. In other words, the SQL string, before being sent to cursor.execute(...) will contain something like this:
AND (
some_value = % OR
some_value = % OR
some_value = % OR
some_value = % OR
-- ...etc...
some_value = %
)
This will work and is safe:
from django.db import connection
list_of_values = ["foo", "bar", "fiz"]
with connection.cursor() as cursor:
cursor.execute(
f"""
SELECT *
FROM my_model_table
WHERE ({" OR ".join(["some_value = %s" for _ in list_of_values])})
""",
list_of_values,
)
results = cursor.fetchall()
Mike Driscoll
Python 101 3rd Edition Kickstarter Launch
Learn Python with a Book Designed for Beginners Hello! I’m Michael Driscoll, and I’m excited to announce the third edition of Python 101. For years, Python 101 has helped readers take their first steps into programming. Whether you’re a complete beginner, a student, or someone looking to learn Python for work or personal projects, the […]
The post Python 101 3rd Edition Kickstarter Launch appeared first on Mouse Vs Python.
PyPodcats
Trailer: Episode 12 With Juanita Gomez
A preview of our chat with Juanita Gomez. Watch the full episode on July 17, 2026
Python Bytes
#488 tau - it's 2pi and it writes code
Topics include , JupyterLab 4.6 and Notebook 7.6 are out!, Tau, and Django Tasks and Django 6.1.
July 13, 2026
Django Weblog
Explore the DjangoCon US 2026 Speaker Lineup and Reserve Your Spot
DjangoCon US 2026 is just around the corner, and now is the perfect time to start planning your conference experience.
Our speaker lineup is now available, featuring talks from Django contributors, maintainers, educators, and community members covering everything from web development and APIs to deployment, security, testing, AI, and the future of the Django ecosystem.
Whether you're attending your first DjangoCon US or returning to reconnect with friends and colleagues, you'll find opportunities to learn, share ideas, and meet people from across the global Django community.
Beyond the talks, your conference registration includes access to tutorials, Open Spaces, community sprints, hallway conversations, and social events that make DjangoCon US a unique experience.
If you haven't registered yet, there's still time to join us in Chicago, August 24–28.
Register for DjangoCon US 2026: https://2026.djangocon.us
Browse the speaker lineup: https://2026.djangocon.us/news/announcing-lineup/
We'll be sharing more updates in the coming weeks, including the full conference schedule, travel reminders, and everything you need to make the most of your time at DjangoCon US.
We look forward to seeing you in Chicago this August!
Hugo van Kemenade
Security: line goes up
Like many other projects, CPython is experiencing a huge increase in security reports.
CVEs per year #
Last month, PSF Security Developer-in-Residence Seth Larson posted a chart of CVEs per year, showing a large increase in 2026:
But this only represents the output of security work, and doesn’t show all the work dealing with incoming reports. Many are closed and dealt with as non-security bug reports instead; many are closed as neither security nor bug reports.
Let’s reveal some of this unseen work by the Python Security Response Team (PSRT).
GHSAs by month #
Here are the number of incoming GitHub Security Advisories (GHSA) reports created since July 2024:
GHSAs by year #
Here is the same thing by year, and remembering we’re only halfway through 2026:
Email reports by month #
We’ve only fairly recently been encouraging new reports be made via GHSA. Before this, they were usually made by email. The next chart is the number of email discussions (or threads) and participants by month:
Thanks #
Big thanks to Seth for all his work as Security Developer-in-Residence: helping shepherd all these reports, developing a security policy to improve the quality of incoming reports and help us assess them, and defining PSRT membership and responsibilities via PEP 811 to build an active team. All this would be much harder without his guidance! And thanks to Alpha-Omega for sponsoring his position at the PSF.
Talk Python to Me
#555: Marimo Pair - A Canvas for Agent + Developers Collaboration
Coding agents have gotten really good at one kind of work. You scope a feature, edit some files, run the tests, ship it. It all happens on disk. But that is not how data work feels. You load something, you look at it, you run a cell, you watch how it responds, and you decide the next move from whatever is sitting in memory. And until now, your agent couldn't see any of that. It only saw the files. Never the live state. This episode, that wall comes down. marimo pair drops a coding agent right inside a running notebook, with full access to every variable Python is holding in memory. The notebook becomes a shared canvas. You point, it runs the code. You tell it to zoom in on the Picasso paintings, and the chart just updates. No MCP tools to wire up, no schema to describe. Just Python, and an agent that can finally see what you see. Trevor Manz is back to walk us through it.
Rodrigo Girão Serrão
itertools cheatsheet
Cheatsheet with visual diagrams that explain how the iterables from itertools work.
This cheatsheet contains diagrams that explain how the iterables from the module itertools work in a visual way.


Mike C. Fletcher
PyVRML97 2.3.4b1
Continuing on with the Open Source work. PyVRML97 2.3.4b1 is almost all build and CI process updates. There are a few minor fixes for modern Python's where bool can't be used as a list index and a change for NumPy 2.x array comparison failures. This beta is mostly just so that we can pull it from OpenGLContext's alpha when it's released.
Bob Belderbos
Learning New Skills in the AI Era (vBrownBag)
I joined the vBrownBag podcast with Damian to talk about how to actually learn a new language or skill when an agent can write the code before you finish typing the prompt.
Armin Ronacher
The Tower Keeps Rising
July 12, 2026
Christian Ledermann
Buzzword Bingo: An Experiment in Spec-Driven AI Development
This is a submission for Weekend Challenge: Passion Edition
What I Built
I built Buzzword Bingo, a multiplayer bingo game for conferences, webinars and meetings where players mark off the inevitable buzzwords as they appear.
The application allows someone to create a game, share a link with participants, and let everyone play along on their own unique bingo board. The first player to complete a row, column or diagonal wins.
Under the hood, though, the game itself was almost secondary.
The real goal was to answer a question I had been wondering about for a while:
How far can I push Claude with specification-driven development while still achieving reliable type coverage and maintaining the coding standards I expect from a production Python project?
The project became an experiment in AI-assisted software engineering, strict typing, and how much guidance modern coding agents actually need to produce maintainable software.
Demo
There is no live demo, but you can have a look at the screenshots taken by playwright during testing
Code
Repository:
How I Built It
Specification Driven Development
The project followed a specification-driven approach using Speckit.
Rather than iterating directly in code, I created specifications describing what the system should do and allowed Claude to implement them.
A big accelerator for the project was using scaf for the initial bootstrap. Rather than spending the first few hours wiring together repository structure, CI, containerization, infrastructure, and developer tooling, I started from a production-oriented foundation and focused on shaping it to match my own preferences. Having Kubernetes manifests, Terraform, deployment pipelines, and modern Python tooling available from day one made it much easier to concentrate on the actual experiment: how far specification-driven development and AI coding agents could take the application.
I ended up needing three major specifications:
- Project scaffolding
- Starting from a project generated with
scaf. - Refining the generated structure to match my personal preferences.
- Adding all the infrastructure and tooling I typically expect in a modern project.
- Backend implementation
- Django models and business logic.
- Server-rendered templates.
- HTMX interactions.
- Capability URL based authorization.
- Frontend implementation
- Visual styling and user experience.
- Responsive layouts.
- End-to-end testing using Playwright.
Django Without the JavaScript Framework
The application uses:
- Django
- HTMX
- Django templates
- PostgreSQL
HTMX turned out to be an excellent fit for this type of application.
Most interactions consist of:
- clicking a square,
- sending a POST request,
- returning an updated HTML fragment,
- swapping it into the page.
No client-side state management was required.
Capability URLs
One design decision I particularly liked was using capability URLs instead of authentication.
Each board receives a unique UUID:
/board/5b97b663-1f2f-4e54-8d2f-f45f3272f870/
Possession of the URL grants access to that board.
This removes the need for:
- user accounts,
- sessions,
- authentication,
- authorization logic.
For a lightweight conference game this felt like the right trade-off.
Going All-In On Type Safety
I care a lot about clean code and strong typing in Python, so I decided to push the type system as far as possible.
Instead of relying on a single type checker, I combined:
This was paired with a strict ruff configuration with almost every rule enabled.
One of the goals of the experiment was to see whether Claude could operate effectively within these constraints.
What Worked
This instruction worked well:
Prefer precise, narrow types (
Enum,NewType,TypedDict, dataclasses withFinalorLiteralfields) overAny, untypeddictorlist, or stringly-typed values. Illegal states should be unrepresentable in the type system rather than guarded against only at runtime.
Once Claude had a few examples to follow, it started producing significantly better type annotations and more expressive domain models.
Pre-commit hooks proved to be the first line of defence, catching issues before they ever reached CI. Linters, formatters, and all three type checkers ran automatically on every commit, providing rapid feedback and keeping the codebase consistent throughout the experiment.
To avoid spending time hand-crafting the configuration, I used pc-init to generate a strict .pre-commit-config.yaml tailored for modern Python projects. This ensured that formatting, linting, and type checking became part of the development workflow rather than an afterthought.
What Didn't Work
Claude struggled with this instruction:
All Python code MUST be fully type-annotated; untyped function signatures and untyped module-level values are not permitted.
Instead of fixing missing annotations, it occasionally attempted to disable checks in pyproject.toml.
Some manual intervention and code review were required to steer it back towards the desired standards.
The experience reinforced an observation I've made repeatedly with coding agents:
Agents optimize for making the error disappear, not necessarily for preserving your engineering constraints.
If you care about those constraints, you still need strong feedback loops.
Type Checker Observations
Running all three type checkers together was still faster than a single mypy run.
Interestingly, they complemented each other rather than duplicating effort:
-
tyfound some issues the others missed. -
pyreflyfound different classes of problems. -
zubanfelt the closest tomypyand was by far the easiest to configure.
The newer type-checking ecosystem is still catching up with mypy in terms of documentation and examples, so reaching the level of strictness I wanted involved a fair amount of experimentation.
Prize Categories
Not submitting for any specific prize category.
The real prize was finding out how far AI-assisted, specification-driven development can be pushed before human review becomes the limiting factor. 😉️
Mike C. Fletcher
PyOpenGL 4.0.0a1
I've been trying to make some time for Open Source projects again. I've been using LLMs for much of the coding because the vast bulk of it at this point is just grunt work. First up is PyOpenGL. The tests the LLM produced turned up a bunch of bugs in the core that have lain dormant for years because the endpoints weren't getting used. The LLM tests are not particularly fun or interesting, but they did a pretty good job of finding wrapping errors. They also exercised GLES and EGL enough to make it far more reasonable to actually use those two interfaces.
Shout out to glfw python library for working cleanly on the Wayland only environment. Definitely helped to find the hidden GLX dependencies we had throughout the Linux platform implementation. One of the biggest ones there was the GLUT library. The other thing that came out was the GLE library being legacy (compatibility) OpenGL.
PyOpenGL 4.0.0a1 is classified as a major release mostly because of the abandonment of old Pythons (<3.9) and old Numpy (<2). Other than that there's mostly just bug-fixes that came from the new test suites.
GLU
* gluUnProject4 missing arguments
* gluNewQuadric/gluQuadricCallback fix the callback mechanism to work like Nurbs code
* gluTessVertex/gluTessBeginPolygon and combine callback, original object return fixes
* gluGetNurbsProperty added, allocates the output
* gluNurbsCallbackData(EXT) argtype fix
glGet Sizes
* sizing tables regenerated based on results from size probing, lots of incorrect sizes fixed; note that these fixes are constrained to extensions I happen to have access to on my platforms
* fix the code generator's constant generation
* glGetPolygonStipple fixed size output
* glGetCompressedTexImage glGetTexImageCompressed was ignoring level and using an ARB constant
Wrappers
* remove double wrapping on glGetHistogramParameter{f,i}vEXT, glGenVertexArrays, glDrawBuffersEXT (which was also mis-named glDrawBuffers)
* glHistogram double wrapped as well, which was crashing vertex_array_object on import which was then causing higher level code to treat the extension as unsupported
64-bit Integer Arrays
* GL_INT64 / GL_UNSIGNED_INT64 new array types for all of the array handlers
No-Numpy Operation
* ctypesarrays zeros/ones handler
* a few spots where GLchar arrays were needed as return types
* gl(Get)ProgramNamedParameter*NV input size fix
* glGetActiveAttribARB optional bufSize parameter added
* ARB.vertex_shader allow passign in size parameter
* allow passing a ctypes char_p as shader-text
GLES
* images module for GLES
* friendly wrappers mimicing the GL ones for lots of endpoints
* glGetString/glGetStringi restype fix
* Normalising of GLES extension names to the GL_* form (same as GL)
General Bug Fixes
* Large constant wrapping fix
* Caching of extension/version data per-context
* Core/version extension handles cases where "VERSION" is not the *first* token
* ShaderProgram.retrieve() fix for unpacking glGetProgramBinary
* input-or-output converter for args that can be either
* ArrayDatatype.get_ffi_argtype etc PyPy specific mechanisms for array interactions
Logging
* make the log decorator more type-check friendly
Packaging
* License declaration fixes for more modern packaging tools
There shouldn't be many significant regressions, as almost everything is a correctness fix, but there's a lot of new code, particularly for the GLES improvements. The alpha is up now for those who want to test the changes against their codebase, but this is an alpha release, so there may be more significant code changes as we move toward a 4.0.0 final release.
There's still some work to do on the OpenGLContext release, but the teaser image above should give you an idea where it's going. It's a direct render of the Khronos sample asset A Beautiful Game
July 11, 2026
Python⇒Speed
8× faster binary search: from compiled code to mechanical sympathy
July 10, 2026
Mike Driscoll
An Intro to Spiel – Creating Presentations in Your Terminal with Python
Have you ever wanted to create a presentation in your computer’s terminal? While this is an uncommon need, a clever open source developer has provided a solution to this problem! The project is called Spiel, and while it is currently archived, the idea is pretty cool. Spiel uses the Rich package to create the slides […]
The post An Intro to Spiel – Creating Presentations in Your Terminal with Python appeared first on Mouse Vs Python.
Talk Python to Me
#554: Trustworthy AI in Healthcare and Longevity
You ask an AI a question and it answers with total confidence. Most of the time, a confidently wrong answer is just an annoyance. But what if the question is medical, and there's a real patient on the other end? In that world, a hallucination isn't a bug, it's a patient-safety event. Sumit Gundawar is a London-based software engineer who builds the clinical platform for a UK longevity and aesthetic-medicine clinic, and his whole argument is that in high-stakes AI, the model is the easy part. Earning trust is the real engineering. We dig into grounding, refusal logic, human-in-the-loop design, and the messy frontier of longevity and biohacking, plus a live demo of an assistant that refuses to answer when it can't back up the claim. Let's get into it.
