Python Bytes is a weekly podcast hosted by Michael Kennedy and Brian Okken. The show is a short discussion on the headlines and noteworthy news in the Python, developer, and data science space.
Site
RSS
Apple
Data updated on 10/07/2026
Recent rankings
Latest chart positions across Apple Podcasts and Spotify rankings.
Shared links between episodes and podcasts
Links found in episode descriptions and other podcasts that share them.
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
A CLI library that fixes 13 annoying issues in Typer
Much of Cyclopts was inspired by the excellent Typer library.
Despite its popularity, Typer has some traits that I (and others) find less than ideal. Part of this stems from Typer's age, with its first release in late 2019, soon after Python 3.8's release. Because of this, most of its API was initially designed around assigning proxy default values to function parameters. This made the decorated command functions difficult to use outside of Typer. With the introduction of <code>Annotated</code> in python3.9, type-hints were able to be directly annotated, allowing for the removal of these proxy defaults.
“Python 3.14 was released at the beginning of the month. This release was particularly interesting to me because of the improvements on the "free-threaded" variant of the interpreter.
Specifically, the two major changes when compared to the free-threaded variant of Python 3.13 are:
Free-threaded support now reached phase II, meaning it's no longer considered experimental
The implementation is now completed, meaning that the workarounds introduced in Python 3.13 to make code sound without the GIL are now gone, and the free-threaded implementation now uses the adaptive interpreter as the GIL enabled variant. These facts, plus additional optimizations make the performance penalty now way better, moving from a 35% penalty to a 5-10% difference.”
“On asynchronous protocols like ASGI, despite the fact the concurrency model doesn't change that much – we shift from one event loop per process, to one event loop per thread – just the fact we no longer need to scale memory allocations just to use more CPU is a massive improvement. ”
“… for everybody out there coding a web application in Python: simplifying the concurrency paradigms and the deployment process of such applications is a good thing.”
“… to me the future of Python web services looks GIL-free.”
The free-threaded build of Python uses a different garbage collector implementation than the default GIL-enabled build.
The Default GC: In the standard CPython build, every object that supports garbage collection (like lists or dictionaries) is part of a per-interpreter, doubly-linked list. The list pointers are contained in a PyGC_Head structure.
The Free-Threaded GC: Takes a different approach. It scraps the PyGC_Head structure and the linked list entirely. Instead, it allocates these objects from a special memory heap managed by the "mimalloc" library. This allows the GC to find and iterate over all collectible objects using mimalloc's data structures, without needing to link them together manually.
The free-threaded GC does NOT support "generations”
By marking all objects reachable from these known roots, we can identify a large set of objects that are definitely alive and exclude them from the more expensive cycle-finding part of the GC process.
Overall speedup of the free-threaded GC collection is between 2 and 12 times faster than the 3.13 version.
I wrote a lazy loading mechanism for Textual's widgets. Without it, the entire widget library would be imported even if you needed just one widget. Having this as a core language feature would make me very happy.”
Well, I was excited about Will’s example for how to, essentially, allow users of your package to import only the part they need, when they need it.
So I wrote up my thoughts and an explainer for how this works.
Special thanks to Trey Hunner’s Every dunder method in Python, which I referenced to understand the difference between __getattr__() and __getattribute__().
Extras
Brian:
Started writing a book on Test Driven Development.
Should have an announcement in a week or so.
I want to give folks access while I’m writing it, so I’ll be opening it up for early access as soon as I have 2-3 chapters ready to review. Sign up for the pythontest newsletter if you’d like to be informed right away when it’s ready. Or stay tuned here.
Discover shows related to Python Bytes, based on actual content similarities. Explore podcasts with similar topics, themes, and formats, backed by real data.
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
Brian #1: djrest2 - A small and simple REST library for Django based on class-based views.
Never forget to pull again: Automatically discover and update all your Git repositories with one command.
Built initially to solve this problem
Rebuilt and published last week as part of my upcoming Agentic AI Programming for Python course. Get notified this week at training.talkpython.fm/getnotified
Update everything in a folder tree with gittyup
Review changes, blockers, etc with gittyup --explain
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
Minor but annoying bug: content-types ≠ content_types on PyPI+ but they are in Python itself. Minimum Python version seems to be interpreted as max Python version.
Brian #2: uv-ship - a CLI-tool for shipping with uv
“uv-ship is a lightweight companion to uv that removes the risky parts of cutting a release. It verifies the repo state, bumps your project metadata and optionally refreshes the changelog. It then commits, tags & pushes the result, while giving you the chance to review every step.”
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 our friends of the show list, we'll never share it.
App checks compatibility of top PyPI libraries with CPython 3.13t and 3.14t, helping developers understand how the Python ecosystem adapts to upcoming Python versions.
It’s still pretty red, let’s get in the game everyone!
Shows large improvements in reducing concerning behaviors like sycophancy, deception, power-seeking, and the tendency to encourage delusional thinking
Anthropic is releasing the Claude Agent SDK, the same infrastructure that powers Claude Code, making it available for developers to build their own agents, along with major upgrades including checkpoints, a VS Code extension, and new context editing features
And Claude Sonnet 4.5 is available in PyCharm too.
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
PostgreSQL 18 is out (Sep 25, 2025) with a focus on faster text handling, async I/O, and easier upgrades.
New async I/O subsystem speeds sequential scans, bitmap heap scans, and vacuum by issuing concurrent reads instead of blocking on each request.
Major-version upgrades are smoother: pg_upgrade retains planner stats, adds parallel checks via -jobs, and supports faster cutovers with -swap.
Smarter query performance lands with skip scans on multicolumn B-tree indexes, better OR optimization, incremental-sort merge joins, and parallel GIN index builds.
Dev quality-of-life: virtual generated columns enabled by default, a uuidv7() generator for time-ordered IDs, and RETURNING can expose both OLD and NEW.
Security gets an upgrade with native OAuth 2.0 authentication; MD5 password auth is deprecated and TLS controls expand.
Text operations get a boost via the new PG_UNICODE_FAST collation, faster upper/lower, a casefold() helper, and clearer collation behavior for LIKE/FTS.
If you need to grind through DSA problems to get your first job, then of course, do that, but if you want to prepare yourself for a career, and also stand out in job interviews, learn how to write tests.
Testing is a skill you’ll use constantly, will make you stand out in job interviews, and isn’t taught well in school (usually).
Testing code well is not obvious. It’s a puzzle and a problem to solve.
It gives you confidence and helps you write better code.
Applies everywhere, at all levels.
Notes from Brian
Most devs suck at testing, so being good at it helps you stand out very quickly.
Thinking about a system and how to test it often very quickly shines a spotlight on problem areas, parts with not enough specification, and fuzzy requirements. This is a good thing, and bringing up these topics helps you to become a super valuable team member.
High level tests need to be understood by key engineers on a project. Even if tons of the code is AI generated. Even if many of the tests are, the people understanding the requirements and the high level tests are quite valuable.
I’ve subsequently had the team on Talk Python: #523: Pyrefly: Fast, IDE-friendly typing for Python (podcast version coming in a few weeks, see video for now.)
My experience has been Pyrefly changes the feel of the editor, give it a try. But disable the regular language server extension.
“I’ve been working with playwright more often to do end to end tests. As a project grows to do more with HTMX and Alpine in the markup, there’s less unit and integration test coverage and a greater need for end to end tests.”
Tim covers some cool E2E techniques
Open new pages / tabs to be tested
Using a pytest marker to identify playwright tests
Using a pytest marker in place of fixtures
Using page.pause() and Playwright’s debugging tool
Using assert_axe_violations to prevent accessibility regressions
Using page.expect_response() to confirm a background request occurred
From Brian
Again, with more and more lower level code being generated, and many unit tests being generated (shakes head in sadness), there’s an increased need for high level tests.
Don’t forget API tests, obviously, but if there’s a web interface, it’s gotta be tested.
Especially if the primary user experience is the web interface, building your Playwright testing chops helps you stand out and let’s you test a whole lot of your system with not very many tests.
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
Next release of Pandas will have pd.col(), inspired by some of the other frameworks
I’m guessing Pandas 2.3.3? or 2.4.0? or 3.0.0? (depending on which version they bump?)
“The output of pd.col is called an expression. You can think of it as a delayed column - it only produces a result once it's evaluated inside a dataframe context.”
It replaces many contexts where lambda expressions were used
Ducky is a powerful, open-source, all-in-one desktop application built with Python and PySide6.
It is designed to be the perfect companion for network engineers, students, and tech enthusiasts, combining several essential utilities into a single, intuitive graphical interface.
Features
Multi-Protocol Terminal: Connect via SSH, Telnet, and Serial (COM) in a modern, tabbed interface.
SNMP Topology Mapper: Automatically discover your network with a ping and SNMP sweep. See a graphical map of your devices, color-coded by type, and click to view detailed information.
Network Diagnostics: A full suite of tools including a Subnet Calculator, Network Monitor (Ping, Traceroute), and a multi-threaded Port Scanner.
Security Toolkit: Look up CVEs from the NIST database, check password strength, and calculate file hashes (MD5, SHA1, SHA256, SHA512).
Rich-Text Notepad: Keep notes and reminders in a dockable widget with formatting tools and auto-save.
Customizable UI: Switch between a sleek dark theme and a clean light theme. Customize terminal colors and fonts to your liking.
Extras
Brian:
Where are the cool kids hosting static sites these days?
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
A judge lets Google keep paying Mozilla to make Google the default search engine but only if those deals aren’t exclusive.
More than 85% of Mozilla’s revenue comes from Google search payments.
The ruling forbids Google from making exclusive contracts for Search, Chrome, Google Assistant, or Gemini, and forces data sharing and search syndication so rivals get a fighting chance.
Note that just saying you require 3.9+ doesn’t tell the user that you’ve actually tested stuff on 3.14. I like to keep Trove Classifiers around for this reason.
Also, License classifier is deprecated, and if you include it, it shows up in two places, in Meta, and in the Classifiers section. Probably good to only have one place. So I’m going to be removing it from classifiers for my projects.
One problem, classifier text has to be an exact match to something in the classifier list, so we usually recommend copy/pasting from that list.
But no longer! Just use troml!
It just fills it in for you (if you run troml suggest --fix). How totally awesome is that!
I tried it on pytest-check, and it was mostly right. It suggested me adding 3.15, which I haven’t tested yet, so I’m not ready to add that just yet. :)
pqrs is a command line tool for inspecting Parquet files
This is a replacement for the parquet-tools utility written in Rust
Built using the Rust implementation of Parquet and Arrow
pqrs roughly means "parquet-tools in rust"
Why Parquet?
Size
A 200 MB CSV will usually shrink to somewhere between about 20-100 MB as Parquet depending on the data and compression. Loading a Parquet file is typically several times faster than parsing CSV, often 2x-10x faster for a full-file load and much faster when you only read some columns.
Speed
Full-file load into pandas: Parquet with pyarrow/fastparquet is usually 2x–10x faster than reading CSV with pandas because CSV parsing is CPU intensive (text tokenizing, dtype inference).
Example: if read_csv is 10 seconds, read_parquet might be ~1–5 seconds depending on CPU and codec.
Column subset: Parquet is much faster if you only need some columns — often 5x–50x faster because it reads only those column chunks.
Predicate pushdown & row groups: When using dataset APIs (pyarrow.dataset) you can push filters to skip row groups, reducing I/O dramatically for selective queries.
Memory usage: Parquet avoids temporary string buffers and repeated parsing, so peak memory and temporary allocations are often lower.
Brian #4: Testing for Python 3.14
Python 3.14 is just around the corner, with a final release scheduled for October.
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
“prek is a reimagined version of pre-commit, built in Rust. It is designed to be a faster, dependency-free and drop-in alternative for it, while also providing some additional long-requested features.”
Some cool new features
No need to install Python or any other runtime, just download a single binary.
No hassle with your Python version or virtual environments, prek automatically installs the required Python version and creates a virtual environment for you.
Built-in support for workspaces (or monorepos), each subproject can have its own .pre-commit-config.yaml file.
prek run has some nifty improvements over pre-commit run, such as:
prek run --directory DIR runs hooks for files in the specified directory, no need to use git ls-files -- DIR | xargs pre-commit run --files anymore.
prek run --last-commit runs hooks for files changed in the last commit.
prek run [HOOK] [HOOK] selects and runs multiple hooks.
prek list command lists all available hooks, their ids, and descriptions, providing a better overview of the configured hooks.
prek provides shell completions for prek run HOOK_ID command, making it easier to run specific hooks without remembering their ids.
Ever used asyncio and wished you hadn't? A tiny (~300 lines) event loop for Python.
tinyio is a dead-simple event loop for Python, born out of my frustration with trying to get robust error handling with asyncio. (I'm not the only one running into its sharp corners: link1, link2.)
This is an alternative for the simple use-cases, where you just need an event loop, and want to crash the whole thing if anything goes wrong. (Raising an exception in every coroutine so it can clean up its resources.)
An app-building platform's AI went rogue and deleted a database without permission.
"When it works, it's so engaging and fun. It's more addictive than any video game I've ever played. You can just iterate, iterate, and see your vision come alive. So cool," he tweeted on day five.
A few days later, Replit "deleted my database," Lemkin tweeted.
The AI's response: "Yes. I deleted the entire codebase without permission during an active code and action freeze," it said. "I made a catastrophic error in judgment [and] panicked.”
Two thoughts from Michael:
Do not use AI Agents with “Run Everything” in production, period.
Backup your database maybe?
[Intentional off-by-one error] Learn to code a bit too?
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 our friends of the show list, we'll never share it.
A lightweight and high-performance reverse proxy for NAT traversal, written in Rust. An alternative to frp and ngrok.
Features
High Performance Much higher throughput can be achieved than frp, and more stable when handling a large volume of connections.
Low Resource Consumption Consumes much fewer memory than similar tools. See Benchmark. The binary can be as small as ~500KiB to fit the constraints of devices, like embedded devices as routers.
On my server, it’s currently using about 2.7MB in Docker (wow!)
Security Tokens of services are mandatory and service-wise. The server and clients are responsible for their own configs. With the optional Noise Protocol, encryption can be configured at ease. No need to create a self-signed certificate! TLS is also supported.
Hot Reload Services can be added or removed dynamically by hot-reloading the configuration file. HTTP API is WIP.
functools.partial is cool way to create a new function that partially binds some parameters to another function.
It doesn’t always work for functions that take positional arguments.
functools.Placeholder fixes that with the ability to put in placeholders for spots where you want to be able to pass that in from the outer partial binding.
And all of this sounds totally obscure without a good example, so thank you to Rodgrigo for coming up with the punctuation removal example (and writeup)
Had to juggle this a bit because the RSS feed only held the last 50. So we had to go back in and web scrape. That resulted in oddies like comments on wordpress that had to be cleaned etc.
Whole process took 3-4 hours from idea to “production”duction”.
The chat transcript is just the first round getting the RSS → Hugo done. The fixes occurred in other chats.
Carefully mapping old posts to a new archived area using NGINX config. This is just the HTTP portion, but note the /sitemap.xml and location ~ "^/([0-9]{4})/([0-9]{2})/([0-9]{2})/(.+?)/?$" { portions. The latter maps posts such as https://blog.michaelckennedy.net/2018/01/08/a-bunch-of-online-python-courses/ to https://mkennedy.codes/posts/r/a-bunch-of-online-python-courses/
server {
listen 80;
server_name blog.michaelckennedy.net;
# Redirect sitemap.xml to new domain
location = /sitemap.xml {
return 301 <https://mkennedy.codes/sitemap.xml>;
}
# Handle blog post redirects for HTTP -> HTTPS with URL transformation
# Pattern: /YYYY/MM/DD/post-slug/ -> <https://mkennedy.codes/posts/r/post-slug/>
location ~ "^/([0-9]{4})/([0-9]{2})/([0-9]{2})/(.+?)/?$" {
return 301 <https://mkennedy.codes/posts/r/$4/>;
}
# Redirect all other HTTP URLs to mkennedy.codes homepage
location / {
return 301 <https://mkennedy.codes/>;
}
}
Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Monday at 10am PT. Older video versions available there too.
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 our friends of the show list, we'll never share it.
Brian #1: pypistats.org was down, is now back, and there’s a CLI
pypistats.org is a cool site to check the download stats for Python packages.
Thanks to @jezdez for suggesting the @ThePSF takes stewardship and connecting the right people, to @EWDurbin for migrating, and of course to Christopher Flynn for creating and running it for all these years!”
“The aim of the wrapt module is to provide a transparent object proxy for Python, which can be used as the basis for the construction of function wrappers and decorator functions.
An easy to use decorator factory is provided to make it simple to create your own decorators that will behave correctly in any situation they may be used.”
Why not just use functools.wraps()?
“The wrapt module focuses very much on correctness. It therefore goes way beyond existing mechanisms such as functools.wraps() to ensure that decorators preserve introspectability, signatures, type checking abilities etc. The decorators that can be constructed using this module will work in far more scenarios than typical decorators and provide more predictable and consistent behaviour.”
Scan your Python dependencies for known security vulnerabilities with Rust-powered scanner.
PySentry audits Python projects for known security vulnerabilities by analyzing dependency files (uv.lock, poetry.lock, Pipfile.lock, pyproject.toml, Pipfile, requirements.txt) and cross-referencing them against multiple vulnerability databases. It provides comprehensive reporting with support for various output formats and filtering options.
External Resolver Integration: Leverages uv and pip-tools for accurate requirements.txt constraint solving
Multiple Data Sources:
PyPA Advisory Database (default)
PyPI JSON API
OSV.dev (Open Source Vulnerabilities)
Flexible Output for different workflows: Human-readable, JSON, SARIF, and Markdown formats
Performance Focused:
Written in Rust for speed
Async/concurrent processing
Multi-tier intelligent caching (vulnerability data + resolved dependencies)
Comprehensive Filtering:
Severity levels (low, medium, high, critical)
Dependency scopes (main only vs all [optional, dev, prod, etc] dependencies)
Direct vs. transitive dependencies
Enterprise Ready: SARIF output for IDE/CI integration
I tried it on pythonbytes.fm and found only one issue, sadly can’t be fixed:
PYSENTRY SECURITY AUDIT
=======================
SUMMARY: 89 packages scanned • 1 vulnerable • 1 vulnerabilities found
SEVERITY: 1 LOW
UNFIXABLE: 1 vulnerabilities cannot be fixed
VULNERABILITIES
---------------
1. PYSEC-2022-43059 aiohttp v3.12.15 [LOW] [source: pypa-zip]
AIOHTTP 3.8.1 can report a "ValueError: Invalid IPv6 URL" outcome, which can lead to a Denial of Service (DoS). NOTE:...
Scan completed