skip to navigation
skip to content

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

July 18, 2026 12:00 AM UTC


Python Insider

Python 3.15.0 beta 4 is here!

The final 3.15 beta is out!

July 18, 2026 12:00 AM UTC

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 17, 2026 01:00 PM UTC

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:

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

Read full topic

July 16, 2026 04:42 PM UTC

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:

GooCalendar is available on PyPI: GooCalendar · PyPI
The documentation is available at goocalendar — Calendar widget — A calendar widget for GTK

1 post - 1 participant

Read full topic

July 16, 2026 04:25 PM UTC


Seth Michael Larson

EuroPython 2026: Learning from the “not-so-secret” Python security cabal

July 16, 2026 12:00 AM UTC

July 15, 2026


Python Software Foundation

Affirm Your PSF Membership Voting Status

July 15, 2026 11:06 AM UTC


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:

  1. PUT, PATCH, and DELETE methods for forms — completing HTML's HTTP vocabulary.
  2. Button actions — buttons that make HTTP requests without a wrapping form. This is the current focus.
  3. 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 15, 2026 11:00 AM UTC

July 14, 2026


PyCoder’s Weekly

Issue #743: Stacks & Queues, Django F-Expressions, MCP Clients, and More (2026-07-14)

July 14, 2026 07:30 PM UTC


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()

July 14, 2026 01:14 PM UTC


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.

July 14, 2026 01:05 PM UTC


PyPodcats

Trailer: Episode 12 With Juanita Gomez

A preview of our chat with Juanita Gomez. Watch the full episode on July 17, 2026

July 14, 2026 01:00 PM UTC


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 14, 2026 08:00 AM UTC

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!

July 13, 2026 10:51 PM UTC


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:

2007-2024 all below 20 per year. 2025 and year-to-date 2026 had just over 20, with 2026 extrapolated to around 65.

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:

Chart of new security reports. Single digits or zero per month from 2024, increasing to around 40 in 2026.

GHSAs by year #

Here is the same thing by year, and remembering we’re only halfway through 2026:

18 in 2024, 41 in 2025, 175 so far in 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:

Number of discussions and participants per month follow each other closely. Single digits from 2014, around 20 by 2019, 40 by 2021 and 2022, a dip to 15 for 2023 to 2025, up to 50 for 2026 so far.

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.

July 13, 2026 08:44 PM UTC


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.

July 13, 2026 05:07 PM UTC


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.

Download this cheatsheet

A4 itertools cheatsheet shown in light and dark themes.

A4 itertools cheatsheet shown in light and dark themes.

Download this cheatsheet

July 13, 2026 02:28 PM UTC


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.

July 13, 2026 01:53 AM UTC


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.

July 13, 2026 12:00 AM UTC


Armin Ronacher

The Tower Keeps Rising

July 13, 2026 12:00 AM UTC

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:

bsbingo GitHub 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:

  1. Project scaffolding
  1. Backend implementation
  1. Frontend implementation

Django Without the JavaScript Framework

The application uses:

HTMX turned out to be an excellent fit for this type of application.

Most interactions consist of:

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:

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 with Final or Literal fields) over Any, untyped dict or list, 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:

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

July 12, 2026 09:23 PM UTC


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 12, 2026 08:55 PM UTC

July 11, 2026


Python⇒Speed

8× faster binary search: from compiled code to mechanical sympathy

July 11, 2026 12:00 AM UTC

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.

July 10, 2026 03:13 PM UTC


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.

July 10, 2026 05:10 AM UTC