<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">

<channel>
	<title>Planet Python</title>
	<link>http://planetpython.org/</link>
	<language>en</language>
	<description>Planet Python - http://planetpython.org/</description>

<item>
	<title>Anarcat: The people vs the AI overlords</title>
	<guid>https://anarc.at/blog/2026-08-18-people-vs-ai-overlords/</guid>
	<link>https://anarc.at/blog/2026-08-18-people-vs-ai-overlords/</link>
	<description>&lt;blockquote&gt;&lt;p&gt;Previously in this series: &lt;a href=&quot;https://anarc.at/blog/2026-05-16-four-horsemen/&quot;&gt;The Four Horsemen of the LLM
Apocalypse&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In a &lt;a href=&quot;https://lwn.net/ml/all/87o6fmdgs6.fsf@hope.eyrie.org/&quot;&gt;post to oss-security&lt;/a&gt;, my (Debian) co-developer Russ Allbery
stated that &quot;open source software [OSS] is coming face to face with a
motivation crisis that has been building for a long time&quot;. His point
is essentially that large language models (LLMs&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;https://anarc.at/tag/python-planet/#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;) are making the
existing OSS community crisis worse. For him, it's the flood of code
reviews, but he argues that varies according to people's desires, for
others it's security issues and so on.&lt;/p&gt;

&lt;p&gt;I think Russ is right, but I would argue there's something much bigger
than our open &lt;em&gt;communities&lt;/em&gt; going on here, and it's about the entire
&lt;em&gt;field&lt;/em&gt; of computing. This pressure is on &lt;em&gt;all&lt;/em&gt; of us, regardless of
whether we work on open source software or not.&lt;/p&gt;

&lt;h1 id=&quot;how-people-use-models&quot;&gt;How people use models&lt;/h1&gt;

&lt;p&gt;People using LLMs in their workflow have &lt;em&gt;radically&lt;/em&gt; changed how
programming works, even for &lt;a href=&quot;https://www.spurint.org/journal/2026/07/llms-and-xfwl4&quot;&gt;people who claim to avoid
vibe-coding&lt;/a&gt;. And I'm sorry to single out one poor maintainer here:
it's not you, Brian, you're just one example among many. But this is
typical use of those models nowadays:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Once it’s done, I’ll use &lt;code&gt;/code-review&lt;/code&gt; and let Claude spawn
sub-agents to do a full review of the new code. This usually finds
some problems, even problems that the “main” Claude instance didn’t
find during its validation. I usually keep running &lt;code&gt;/code-review&lt;/code&gt;
again and again after finding and fixing issues, until there aren’t
any left.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Think about what that means for a minute. This is automation built to
fire up dozens of agents crunching at a problem for minutes if not
hours of GPU compute time, in parallel. This is essentially a couple
of shelves in a datacenter rack, totally maxed out on power and
cooling, abstracted behind a cute little &lt;code&gt;/code-review&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;The author, here, is rightly concerned that &quot;Anthropic could pull the
rug out and require API pricing&quot;, which is perhaps a code word for
&quot;charging something closer to actual costs&quot;. Brian also pays lip
service to environmental and societal costs but those are largely
abstracted away, so let's keep that conversation aside here as well,
as we have &lt;a href=&quot;https://anarc.at/blog/2026-05-16-four-horsemen/&quot;&gt;discussed it before anyways&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But clearly, this way of working has an (&lt;a href=&quot;https://drewdevault.com/blog/Stop-externalizing-your-costs-on-me/&quot;&gt;externalized&lt;/a&gt;) cost, to
say the least.&lt;/p&gt;

&lt;h1 id=&quot;paying-for-non-free-tools&quot;&gt;Paying for non-free tools&lt;/h1&gt;

&lt;p&gt;For decades my work has been focused on free and open source
software. I've long stopped using proprietary operating systems like
Windows or Mac, and even before that switch, I was mostly using free
software on those platforms, partly out of principle, but also because
I was too poor. So the tools of my trade are free, and I build free
tools with them.&lt;/p&gt;

&lt;p&gt;It feels like we're going backwards: when I was in school, a millennia
ago, my classmates didn't have access to a compiler and were wondering
how they would scrape the money to buy a compiler like &lt;a href=&quot;https://en.wikipedia.org/wiki/Borland_C%2B%2B&quot;&gt;Borland's&lt;/a&gt;
or &lt;a href=&quot;https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B&quot;&gt;Microsoft's&lt;/a&gt;. I had a compiler built into my operating system
(&lt;a href=&quot;https://www.freebsd.org/&quot;&gt;FreeBSD&lt;/a&gt; at the time), so that wasn't a problem for me. For them,
it was a significant expense, but at least those expenses (or more
&lt;a href=&quot;https://en.wikipedia.org/wiki/Warez&quot;&gt;shady sourcing of programs&lt;/a&gt;) were a one-shot deal.&lt;/p&gt;

&lt;p&gt;Fast forward 30 years, and software is rented: you pay monthly for
Adobe's Photoshop and Microsoft's office suite just like you pay for
Netflix, Disney+ or Spotify&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;https://anarc.at/tag/python-planet/#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. And now you need to add dozens (if not
hundreds of dollars) of monthly credits to access LLMs on top of that.&lt;/p&gt;

&lt;p&gt;So, now we have to &lt;em&gt;pay&lt;/em&gt; to get anything done? This is peak
&lt;a href=&quot;https://craphound.com/category/enshittification/&quot;&gt;enshitification&lt;/a&gt; of our job: first they steal our work to train their
models, and then they sell it back to us at a profit.&lt;/p&gt;

&lt;h1 id=&quot;attacking-the-engineers&quot;&gt;Attacking the engineers&lt;/h1&gt;

&lt;p&gt;AI is coming for our jobs, as engineers, if not &lt;em&gt;everyone&lt;/em&gt;, according
to the narrative. For a while now, our job market has deteriorated:
less jobs, for less pay. Lots of skilled engineers looking for work
and finding crap jobs then still looking while working.&lt;/p&gt;

&lt;p&gt;This is not by accident.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;https://anarc.at/tag/python-planet/#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; We engineers have a &lt;em&gt;lot&lt;/em&gt; of power, it is not
organized, but that's just a couple of unions away (&lt;a href=&quot;https://www.ibtimes.sg/wikimedia-foundation-declines-voluntary-union-recognition-labor-dispute-grows-91377&quot;&gt;easy&lt;/a&gt;!). Tech
overlords know this, so they are attacking our profession, directly,
by forcing us to train and use models that &lt;em&gt;they&lt;/em&gt; can control.&lt;/p&gt;

&lt;p&gt;Even in environments where programmers are not &lt;em&gt;forced&lt;/em&gt; to use LLMs,
the mere pressure of other people's LLM-generated work is huge. One can
be forced to review LLM outputs, or just peer pressured you into
producing more.&lt;/p&gt;

&lt;p&gt;We're now supposed to accelerate delivery, because models can
&lt;em&gt;presumably&lt;/em&gt; do things so much better and faster. With supply chain
security becoming such a large vector that we now have &lt;a href=&quot;https://unit42.paloaltonetworks.com/chaindrop-npm-worm-analysis/&quot;&gt;worms crawling
around developers accounts on NPM&lt;/a&gt;, increasing the delivery cadence
seems like a really bad idea.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;https://anarc.at/tag/python-planet/#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The LLM hype is part of the larger wave of cyberwar against workers,
against water, against the Earth, against all the people. This is not
a matter of individually &quot;adapting to the reality&quot; or personal choice,
but a political, social, hard problem we need to address collectively.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Previously in this series: &lt;a href=&quot;https://anarc.at/blog/2026-05-16-four-horsemen/&quot;&gt;The Four Horsemen of the LLM
Apocalypse&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;





&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
I again prefer the term LLM to &quot;AI&quot; because models do &lt;em&gt;not&lt;/em&gt;
possess &lt;a href=&quot;https://en.wikipedia.org/wiki/Intelligence&quot;&gt;intelligence&lt;/a&gt;. I did use it in the title because
click baiting is apparently important, but I stopped short of
calling this one &quot;Rage Against the Machines&quot; because that would be
the title of every blog post I have ever made.&lt;a href=&quot;https://anarc.at/tag/python-planet/#fnref:1&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
Yes, I know that &lt;a href=&quot;https://en.wikipedia.org/wiki/Visual_Studio&quot;&gt;Visual Studio&lt;/a&gt; is kind of free now, but I
wouldn't be surprised if they turn that into a rental as well,
because why not.&lt;a href=&quot;https://anarc.at/tag/python-planet/#fnref:2&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;
Beyond sabotaging the job market, Sam Altman event wants to
sell &quot;&lt;a href=&quot;https://gizmodo.com/sam-altman-says-intelligence-will-be-a-utility-and-hes-just-the-man-to-collect-the-bills-2000732953&quot;&gt;intelligence as a utility&lt;/a&gt;&quot; something that is just a
&lt;a href=&quot;https://www.psychologytoday.com/us/blog/the-digital-self/202603/intelligence-as-a-commodity&quot;&gt;really bad idea&lt;/a&gt; but especially shows how megalomaniac those
people are.&lt;a href=&quot;https://anarc.at/tag/python-planet/#fnref:3&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;
This brings back memories of &lt;a href=&quot;https://en.wikipedia.org/wiki/Morris_worm&quot;&gt;another era&lt;/a&gt;, walking us
back decades in terms of computer security.&lt;a href=&quot;https://anarc.at/tag/python-planet/#fnref:4&quot; rev=&quot;footnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Wed, 19 Aug 2026 14:14:42 +0000</pubDate>
</item>
<item>
	<title>Python Software Foundation: How AWS Powers PyPI and the PSF</title>
	<guid>https://pyfound.blogspot.com/2026/08/how-aws-powers-pypi-and-psf.html</guid>
	<link>https://pyfound.blogspot.com/2026/08/how-aws-powers-pypi-and-psf.html</link>
	<description>&lt;p&gt;&lt;i&gt;Written by Jacob Coffee, Director of Engineering at the Python Software Foundation&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Working on infrastructure at the Python Software Foundation (PSF) as the Director of Engineering is a broad job with many hats. Python turns up everywhere. It's in healthcare systems and government agencies, in research labs and classrooms, in one-person side projects and in infrastructure at companies with six-figure headcounts. Somebody is using it to analyze a genome right now and somebody else is using it to automate a spreadsheet they hate arranging by hand. That range has always been the interesting part of the PSF's work, and it's only broadened in the last couple of years as AI continues to pull people from many disciplines into writing Python.&lt;/p&gt;

&lt;p&gt;At the PSF we support and maintain the infrastructure behind PyPI, Python.org, PyCon US, CPython, and a growing number of community services. The majority of the PSF's infrastructure runs on &lt;a href=&quot;https://aws.amazon.com/opensource/&quot;&gt;AWS&lt;/a&gt;, and nearly all of that bill is covered by credits from the &lt;a href=&quot;https://aws.amazon.com/blogs/opensource/aws-cloud-credits-for-open-source-projects-affirming-our-commitment/&quot;&gt;AWS Open Source Credits Program&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;The shape of it&lt;/h3&gt;

&lt;p&gt;PyPI takes over six billion requests a day and about thirteen billion counting file downloads. Package egress runs around 10 petabytes a day.&lt;/p&gt;

&lt;p&gt;Almost none of that reaches AWS. Fastly serves it at the edge through their Fast Forward program at a hit ratio just under 99%, so only about one request in seventy makes it to origin. That caching is the core reason our AWS bill is not measured in the millions of dollars a year.&lt;/p&gt;

&lt;p&gt;What does reach us is the part that is not cached, including things like user uploads, logins, and account management. That work runs on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Amazon EC2&lt;/b&gt; for the application fleet, almost entirely Graviton at this point. We're &lt;a href=&quot;https://newsroom.arm.com/blog/how-the-python-software-foundation-future-proofed-its-infrastructure-with-arm&quot;&gt;huge fans of Arm-based hardware&lt;/a&gt; at the PSF!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Amazon RDS&lt;/b&gt; for the Postgres database behind Warehouse, which is the application you're looking at when you're on pypi.org.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Amazon OpenSearch Service&lt;/b&gt; for project search.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Amazon S3&lt;/b&gt; holds ~100 TB of package archives, plus the release history (that nobody ever wants to need).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Amazon EKS&lt;/b&gt;, newly stood up, as the target for migrating the whole fleet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;What changed this year&lt;/h3&gt;

&lt;p&gt;Our AWS spend is up about 69% comparing July 2026 to July 2025, and 40% across the trailing twelve months. That's new.&lt;/p&gt;

&lt;p&gt;For context on how new: last October, Ee Durbin, our former Director of Infrastructure, noted that &lt;a href=&quot;https://pyfound.blogspot.com/2025/10/open-infrastructure-is-not-free-pypi.html&quot;&gt;PSF's AWS credit usage had grown 25% over eight years&lt;/a&gt; while daily requests went from millions to billions. Eight years of holding that line. 2026 is the first year it broke.&lt;/p&gt;

&lt;p&gt;Some of it is simply more of everything. Compute, search, and load balancing all climbed from 30% to 80%, which is the profile of more people and machines using the service. There are certainly more of both. A lot more Python being written, a lot more agents installing packages on someone's behalf, and a lot more CI runs from all the projects those people and agents are creating. Package repositories were designed around the assumption that a human decides to run pip install some number of times a day. That assumption is well past its expiration.&lt;/p&gt;

&lt;h3&gt;What we do about it&lt;/h3&gt;

&lt;p&gt;At the PSF, we take the credits seriously, which means spending real engineering time on utilizing what we have in an optimal way so our usage doesn't increase. Being frugal with the credits entrusted to us is vital.&lt;/p&gt;

&lt;p&gt;When a widely used GitHub Action makes requests it doesn't need to make, fixing the Action beats anything we can do on our side. As an example, &lt;a href=&quot;https://github.com/astral-sh/setup-uv/issues/745#issuecomment-3867334064&quot;&gt;the PSF pushed for exactly that in astral-sh/setup-uv&lt;/a&gt;, which is &lt;a href=&quot;https://github.com/astral-sh/setup-uv/pull/967&quot;&gt;now live&lt;/a&gt; and will shave off usage as people upgrade.&lt;/p&gt;

&lt;p&gt;On the PSF side, the EKS migration is the big one. Once we're there, autoscaling lets capacity track demand instead of sitting provisioned for peak at 3 AM (San Francisco time) on a Sunday.&lt;/p&gt;

&lt;p&gt;There's just one little (read: major) constraint: Ee left the PSF earlier this year, and I'm currently the only person here working full time on infrastructure. Every item on that list is real and every one is slower than it should be. &lt;a href=&quot;https://jobs.pyfound.org/&quot;&gt;The PSF is hiring&lt;/a&gt;, and that hiring is possible in part because we aren't spending the same money on servers.&lt;/p&gt;

&lt;p&gt;That said, hiring has a ceiling set by funding, and PyPI should be considered a supply chain risk until the PSF is able to hire more engineering staff. There is a very large amount of the software industry that sits on top of our services. Feature development, a rising volume of security reports, and day to day maintenance are currently being carried by one and a half full-time employees and one full-time employee on PyPI support requests. If your company installs from PyPI, ask internally about what your organization would be willing to fund. That question can be worth much more coming from inside a company than from the PSF. If you are interested in securing a service agreement with PyPI, please &lt;a href=&quot;https://www.surveymonkey.com/r/H53HHSS&quot;&gt;fill out our survey&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;What the funding actually bought&lt;/h3&gt;

&lt;p&gt;AWS has backed PyPI two different ways, and both are worth outlining.&lt;/p&gt;

&lt;p&gt;A very exciting investment was made in 2023, when AWS became &lt;a href=&quot;https://blog.pypi.org/posts/2023-05-09-announcing-pypi-safety-and-security-engr-role/&quot;&gt;PyPI's inaugural Security Sponsor&lt;/a&gt;, putting $144,000 into creating the PyPI Safety &amp;amp; Security Engineer role. That role is now funded by &lt;a href=&quot;http://alpha-omega.dev/&quot;&gt;Alpha-Omega&lt;/a&gt;, and it's the reason malware comes down off PyPI in hours instead of whenever a volunteer has a spare moment. This investment also followed a pattern AWS had already established, having helped fund the rewrite, internationalization, and 2FA support for PyPI.&lt;/p&gt;

&lt;p&gt;The credits do something quieter. They hold the infrastructure bill near zero, which means the PSF's general fund goes to employees, PyCon US, and other operational costs instead of servers. That's what pays for support staff handling the account recovery and project ownership requests that arrive every single day, and what makes it possible to ship things like Trusted Publishing, digital attestations, and organization accounts, instead of just keeping the lights on.&lt;/p&gt;

&lt;p&gt;PyPI is free to use and will stay free to use at reasonable levels. Core publishing and installing stay free, permanently. What we are doing is building out real benefits for Organization accounts, and looking at sensible rate limits for the heaviest consumers at the top of the curve.&lt;/p&gt;

&lt;p&gt;Which is exactly why in-kind support isn't just a line item to us. A sponsor choosing not to renew would mean an emergency migration or tens of thousands of dollars a month, either of which comes straight out of the work above. AWS has renewed every year since 2018, and the predictability of that is worth as much as the amount. The same goes for Fastly, Google Cloud, Datadog, Sentry, Depot, and PagerDuty, who carry other parts of this mountain of infrastructure.&lt;/p&gt;

&lt;h3&gt;How you can help&lt;/h3&gt;

&lt;p&gt;Four things, in order of how much they matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Cache your installs.&lt;/b&gt; If your CI pulls from PyPI on every run with a cold cache, you're a meaningful part of the graph. The PSF uses Docker cache mounts and pip's cache on our own builds, and npm and apt caching too, because it's faster for us and cheaper for everyone. &lt;a href=&quot;https://pyfound.blogspot.com/2025/10/open-infrastructure-is-not-free-pypi.html&quot;&gt;Free package repositories aren't a limitless resource&lt;/a&gt;, and the fix is usually about six lines of config.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://pypi.org/manage/organizations/&quot;&gt;Sign up for a PyPI Organization&lt;/a&gt;&lt;/b&gt; if your company publishes to PyPI. Recurring revenue from Organizations is the most sustainable funding base we have, and Community organizations remain free. Look forward to announcements about future features for PyPI organization accounts soon.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Interested in a PyPI service agreement?&lt;/b&gt; Enhanced options like annual bulk seat purchases, higher project size limits, and prioritized support are available. The revenue helps fund the broader PyPI ecosystem while giving your organization benefits at scale. Fill out &lt;a href=&quot;https://www.surveymonkey.com/r/H53HHSS&quot;&gt;our service agreement interest survey&lt;/a&gt; and we'll follow up.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ask your infrastructure vendors for multi-year commitments with open source foundations.&lt;/b&gt; Annual renewal cycles carry real risk for projects like ours. The five-year agreement the PSF signed with Fastly in 2024 is a sustainable model, and we'd like more of them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href=&quot;https://openssf.org/blog/2025/09/23/open-infrastructure-is-not-free-a-joint-statement-on-sustainable-stewardship/&quot;&gt;open letter the PSF co-signed last year&lt;/a&gt; called this a critical inflection point rather than a crisis. A year on, with our first real break in eight years of flat infrastructure costs, that still reads about right.&lt;/p&gt;

&lt;p&gt;A big thanks to Mila Zhou and the AWS Open Source team, who have made the credits process about as painless as an annual funding renewal can be, and to everyone at AWS who's kept this program going for so long. PyPI would look very different without it.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;This blog was recently edited to more accurately reflect numbers presented and work done.&lt;/i&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 19 Aug 2026 11:20:12 +0000</pubDate>
</item>
<item>
	<title>Python GUIs: Creating PySide6 UI without .ui / Qt Designer — Build your entire GUI in pure Python code, no .ui files required</title>
	<guid>https://www.pythonguis.com/faq/creating-pyside2-ui-without-ui-qt-designer/</guid>
	<link>https://www.pythonguis.com/faq/creating-pyside2-ui-without-ui-qt-designer/</link>
	<description>&lt;blockquote&gt;
&lt;p&gt;Is it possible to write a PySide6 application without using .ui files or Qt Designer? How can I create widgets and lay out a window entirely in Python code?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, absolutely. While &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyside6-first-steps-qt-designer/&quot;&gt;Qt Designer is a helpful visual tool for building interfaces&lt;/a&gt;, you never need to use it. You can create every part of your GUI &amp;mdash; windows, buttons, labels, layouts, and more &amp;mdash; directly in Python. Many developers prefer working this way because it keeps everything in one place and gives you full control over your interface.&lt;/p&gt;
&lt;p&gt;In this tutorial, we'll walk through building a PySide6 interface entirely in code, starting from a basic window and gradually adding widgets and layouts.&lt;/p&gt;
&lt;h2 id=&quot;a-minimal-pyside6-window&quot;&gt;A minimal PySide6 window&lt;/h2&gt;
&lt;p&gt;Every PySide6 application needs two things: a &lt;code&gt;QApplication&lt;/code&gt; instance, and at least one widget to display. Here's the simplest possible window:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)

window = QWidget()
window.setWindowTitle(&quot;My App&quot;)
window.show()

app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Run this and you'll see an empty window with the title &quot;My App&quot;. &lt;code&gt;QWidget&lt;/code&gt; is the base class for all UI elements in Qt, and on its own it gives you a blank window to work with.&lt;/p&gt;
&lt;h2 id=&quot;adding-a-single-widget&quot;&gt;Adding a single widget&lt;/h2&gt;
&lt;p&gt;Let's add a button to the window. You can create any widget and place it inside your window by passing the window as the widget's &lt;em&gt;parent&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import QApplication, QPushButton, QWidget

app = QApplication(sys.argv)

window = QWidget()
window.setWindowTitle(&quot;My App&quot;)

button = QPushButton(&quot;Click me!&quot;, window)

window.show()

app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;QPushButton&lt;/code&gt; is created with two arguments: the text to display, and the parent widget (&lt;code&gt;window&lt;/code&gt;). This tells Qt that the button belongs inside the window.&lt;/p&gt;
&lt;p&gt;This works, but the button just sits at position (0, 0) in the top-left corner. To arrange multiple widgets neatly, you'll want to use a &lt;em&gt;layout&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;using-layouts-to-arrange-widgets&quot;&gt;Using layouts to arrange widgets&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.pythonguis.com/tutorials/pyside6-layouts/&quot;&gt;Layouts&lt;/a&gt; handle the positioning and resizing of widgets for you. Qt provides several layout types, including &lt;code&gt;QVBoxLayout&lt;/code&gt; (vertical), &lt;code&gt;QHBoxLayout&lt;/code&gt; (horizontal), and &lt;code&gt;QGridLayout&lt;/code&gt; (grid-based).&lt;/p&gt;
&lt;p&gt;Here's how to stack a few widgets vertically:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import (
    QApplication, QLabel, QLineEdit, QPushButton,
    QVBoxLayout, QWidget,
)

app = QApplication(sys.argv)

window = QWidget()
window.setWindowTitle(&quot;My App&quot;)

layout = QVBoxLayout()
layout.addWidget(QLabel(&quot;Enter your name:&quot;))
layout.addWidget(QLineEdit())
layout.addWidget(QPushButton(&quot;Submit&quot;))

window.setLayout(layout)
window.show()

app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here we create a &lt;code&gt;QVBoxLayout&lt;/code&gt;, add three widgets to it, and then apply the layout to the window with &lt;code&gt;setLayout()&lt;/code&gt;. The layout takes care of stacking the label, text input, and button from top to bottom, and it will resize them sensibly if the user resizes the window.&lt;/p&gt;
&lt;h2 id=&quot;subclassing-qwidget-for-your-own-windows&quot;&gt;Subclassing QWidget for your own windows&lt;/h2&gt;
&lt;p&gt;As your interface grows, putting everything at the top level of your script becomes hard to manage. The standard approach is to create your own window class by subclassing &lt;code&gt;QWidget&lt;/code&gt; (or &lt;code&gt;QMainWindow&lt;/code&gt; for more complex apps). This lets you set up the interface inside the &lt;code&gt;__init__&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import (
    QApplication, QLabel, QLineEdit, QPushButton,
    QVBoxLayout, QWidget,
)


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;My App&quot;)

        layout = QVBoxLayout()

        self.label = QLabel(&quot;Enter your name:&quot;)
        layout.addWidget(self.label)

        self.name_input = QLineEdit()
        layout.addWidget(self.name_input)

        self.submit_button = QPushButton(&quot;Submit&quot;)
        layout.addWidget(self.submit_button)

        self.setLayout(layout)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;By storing the widgets as attributes on &lt;code&gt;self&lt;/code&gt;, you can refer to them later &amp;mdash; for example, to read the text from the input field or to connect a button click to a function.&lt;/p&gt;
&lt;h2 id=&quot;connecting-signals-to-make-it-interactive&quot;&gt;Connecting signals to make it interactive&lt;/h2&gt;
&lt;p&gt;Widgets in Qt communicate using &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyside6-signals-slots-events/&quot;&gt;&lt;em&gt;signals and slots&lt;/em&gt;&lt;/a&gt;. When something happens &amp;mdash; like a button being clicked &amp;mdash; the widget emits a signal. You can connect that signal to any Python function to respond to the event.&lt;/p&gt;
&lt;p&gt;Let's make the Submit button print a greeting:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import (
    QApplication, QLabel, QLineEdit, QPushButton,
    QVBoxLayout, QWidget,
)


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;My App&quot;)

        layout = QVBoxLayout()

        self.label = QLabel(&quot;Enter your name:&quot;)
        layout.addWidget(self.label)

        self.name_input = QLineEdit()
        layout.addWidget(self.name_input)

        self.submit_button = QPushButton(&quot;Submit&quot;)
        self.submit_button.clicked.connect(self.greet)
        layout.addWidget(self.submit_button)

        self.greeting_label = QLabel(&quot;&quot;)
        layout.addWidget(self.greeting_label)

        self.setLayout(layout)

    def greet(self):
        name = self.name_input.text()
        self.greeting_label.setText(f&quot;Hello, {name}!&quot;)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The line &lt;code&gt;self.submit_button.clicked.connect(self.greet)&lt;/code&gt; tells Qt: &quot;When this button is clicked, call the &lt;code&gt;greet&lt;/code&gt; method.&quot; Inside &lt;code&gt;greet&lt;/code&gt;, we read the text from the input and update the greeting label.&lt;/p&gt;
&lt;h2 id=&quot;using-qmainwindow-for-menus-and-status-bars&quot;&gt;Using QMainWindow for menus and status bars&lt;/h2&gt;
&lt;p&gt;If your application needs a menu bar, toolbars, or a status bar, you can subclass &lt;code&gt;QMainWindow&lt;/code&gt; instead of &lt;code&gt;QWidget&lt;/code&gt;. &lt;code&gt;QMainWindow&lt;/code&gt; provides a built-in structure with these elements ready to use.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;QMainWindow&lt;/code&gt;, you place your content inside a &lt;em&gt;central widget&lt;/em&gt; rather than setting a layout directly on the window:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import (
    QApplication, QLabel, QLineEdit, QMainWindow,
    QPushButton, QVBoxLayout, QWidget,
)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;My App&quot;)

        # Create a central widget and set it
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        layout = QVBoxLayout()
        central_widget.setLayout(layout)

        self.label = QLabel(&quot;Enter your name:&quot;)
        layout.addWidget(self.label)

        self.name_input = QLineEdit()
        layout.addWidget(self.name_input)

        self.submit_button = QPushButton(&quot;Submit&quot;)
        self.submit_button.clicked.connect(self.greet)
        layout.addWidget(self.submit_button)

        self.greeting_label = QLabel(&quot;&quot;)
        layout.addWidget(self.greeting_label)

        # Add a status bar message
        self.statusBar().showMessage(&quot;Ready&quot;)

    def greet(self):
        name = self.name_input.text()
        self.greeting_label.setText(f&quot;Hello, {name}!&quot;)
        self.statusBar().showMessage(f&quot;Greeted {name}&quot;)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The pattern is the same &amp;mdash; create widgets, add them to a layout, connect signals &amp;mdash; but now you also get a status bar at the bottom of the window for free.&lt;/p&gt;
&lt;h2 id=&quot;nesting-layouts-for-complex-interfaces&quot;&gt;Nesting layouts for complex interfaces&lt;/h2&gt;
&lt;p&gt;You can combine layouts to create more sophisticated designs. For example, you might have a horizontal layout inside a vertical layout to place two buttons side by side:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import (
    QApplication, QHBoxLayout, QLabel, QLineEdit,
    QPushButton, QVBoxLayout, QWidget,
)


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;My App&quot;)

        outer_layout = QVBoxLayout()

        self.label = QLabel(&quot;Enter your name:&quot;)
        outer_layout.addWidget(self.label)

        self.name_input = QLineEdit()
        outer_layout.addWidget(self.name_input)

        # A horizontal row of buttons
        button_layout = QHBoxLayout()
        self.submit_button = QPushButton(&quot;Submit&quot;)
        self.submit_button.clicked.connect(self.greet)
        button_layout.addWidget(self.submit_button)

        self.clear_button = QPushButton(&quot;Clear&quot;)
        self.clear_button.clicked.connect(self.clear)
        button_layout.addWidget(self.clear_button)

        outer_layout.addLayout(button_layout)

        self.greeting_label = QLabel(&quot;&quot;)
        outer_layout.addWidget(self.greeting_label)

        self.setLayout(outer_layout)

    def greet(self):
        name = self.name_input.text()
        self.greeting_label.setText(f&quot;Hello, {name}!&quot;)

    def clear(self):
        self.name_input.clear()
        self.greeting_label.clear()


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Notice that we use &lt;code&gt;addLayout()&lt;/code&gt; (not &lt;code&gt;addWidget()&lt;/code&gt;) to nest one layout inside another. You can combine &lt;code&gt;QVBoxLayout&lt;/code&gt;, &lt;code&gt;QHBoxLayout&lt;/code&gt;, and &lt;code&gt;QGridLayout&lt;/code&gt; in any arrangement to build whatever interface you need.&lt;/p&gt;
&lt;h2 id=&quot;complete-working-example&quot;&gt;Complete working example&lt;/h2&gt;
&lt;p&gt;Here's the final version bringing everything together &amp;mdash; a &lt;code&gt;QMainWindow&lt;/code&gt; with nested layouts, interactive widgets and a status bar.&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PySide6.QtWidgets import (
    QApplication, QHBoxLayout, QLabel, QLineEdit,
    QMainWindow, QPushButton, QVBoxLayout, QWidget,
)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;Greeter App&quot;)
        self.setMinimumWidth(300)

        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        outer_layout = QVBoxLayout()
        central_widget.setLayout(outer_layout)

        self.label = QLabel(&quot;Enter your name:&quot;)
        outer_layout.addWidget(self.label)

        self.name_input = QLineEdit()
        self.name_input.setPlaceholderText(&quot;Your name here...&quot;)
        outer_layout.addWidget(self.name_input)

        button_layout = QHBoxLayout()

        self.submit_button = QPushButton(&quot;Submit&quot;)
        self.submit_button.clicked.connect(self.greet)
        button_layout.addWidget(self.submit_button)

        self.clear_button = QPushButton(&quot;Clear&quot;)
        self.clear_button.clicked.connect(self.clear)
        button_layout.addWidget(self.clear_button)

        outer_layout.addLayout(button_layout)

        self.greeting_label = QLabel(&quot;&quot;)
        outer_layout.addWidget(self.greeting_label)

        self.statusBar().showMessage(&quot;Ready&quot;)

    def greet(self):
        name = self.name_input.text()
        if name:
            self.greeting_label.setText(f&quot;Hello, {name}!&quot;)
            self.statusBar().showMessage(f&quot;Greeted {name}&quot;)
        else:
            self.greeting_label.setText(&quot;Please enter a name.&quot;)
            self.statusBar().showMessage(&quot;No name entered&quot;)

    def clear(self):
        self.name_input.clear()
        self.greeting_label.clear()
        self.statusBar().showMessage(&quot;Cleared&quot;)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Copy, paste, and run this file. You'll get a fully functional window with a text input, two buttons, a dynamic greeting label, and a status bar &amp;mdash; all created without Qt Designer or any .ui files.&lt;/p&gt;
&lt;p&gt;Everything you can do in Qt Designer, you can do in code. As your applications grow, you might find that building the interface programmatically makes it easier to manage, debug, and keep in version control alongside the rest of your Python code. To explore more of the available widgets, take a look at the &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyside6-widgets/&quot;&gt;PySide6 widgets tutorial&lt;/a&gt;.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PySide6 see my book, &lt;a href=&quot;https://www.pythonguis.com/pyside6-book/&quot;&gt;Create GUI Applications with Python &amp;amp; Qt6.&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 19 Aug 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>PyCoder’s Weekly: Issue #748: Line Breaks, OpenCode, Segfaults, and More (2026-08-18)</title>
	<guid>https://pycoders.com/issues/748</guid>
	<link>https://pycoders.com/issues/748</link>
	<description>&lt;p&gt; &lt;span&gt;#748 – AUGUST 18, 2026&lt;/span&gt;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/issues/748/feed&quot;&gt;View in Browser »&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://pycoders.com&quot;&gt;&lt;img alt=&quot;The PyCoder&amp;rsquo;s Weekly Logo&quot; src=&quot;https://cdn.pycoders.com/37bdf31dc645f968ffb90196e5d38ff5&quot; /&gt;&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16936/feed&quot; target=&quot;_blank&quot;&gt;Breaking Up (Lines) Is Hard to Do&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Here’s a seemingly simple question: given a chunk of multi-line text, how do you split it and return an array? Unicode makes everything harder than it might first seem.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16936/feed&quot; target=&quot;_blank&quot;&gt;B-LIST.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16916/feed&quot; target=&quot;_blank&quot;&gt;Coding With OpenCode: AI-Assisted Python&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn how to use OpenCode for AI-assisted Python coding, using a free Gemini API key to analyze and refactor code right in your terminal.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16916/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;span&gt;course&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16937/feed&quot; target=&quot;_blank&quot;&gt;Quiz: Coding With OpenCode: AI-Assisted Python&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16937/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16946/feed&quot; target=&quot;_blank&quot;&gt;The Top Open-Source Code Reviewer on Code-Review-Bench&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; PR-AF places #2 of 42 overall on Martian&amp;rsquo;s Code-Review-Bench, ahead of CodeRabbit, Copilot, and Devin. Roughly 3x more valid findings than the commercial tools, at ~10x lower cost per review. Verified findings only. Apache 2.0, self-hosted, runs on any open or closed model. &lt;a href=&quot;https://pycoders.com/link/16946/feed&quot; target=&quot;_blank&quot;&gt;Star &amp;amp; Deploy →&lt;/a&gt;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16946/feed&quot; target=&quot;_blank&quot;&gt;AGENTFIELD&lt;/a&gt;&lt;/span&gt; &lt;span&gt;sponsor&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16918/feed&quot; target=&quot;_blank&quot;&gt;Two Lines of Python That Segfault the Interpreter&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Two lines of plain Python segfaulted every CPython with lazy annotations: PEP 749 gave SET_ADD an operand that user code can rebind.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16918/feed&quot; target=&quot;_blank&quot;&gt;TIMOFEI IVANKOV&lt;/a&gt; • Shared by &lt;a href=&quot;https://pycoders.com/link/16939/feed&quot; target=&quot;_blank&quot;&gt;Timofei Ivankov&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16938/feed&quot; target=&quot;_blank&quot;&gt;Packaging Council Election Candidates for 2026!&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16938/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16914/feed&quot; target=&quot;_blank&quot;&gt;Announcing the PSF Board Candidates for 2026!&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16914/feed&quot; target=&quot;_blank&quot;&gt;PYTHON SOFTWARE FOUNDATION&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16931/feed&quot; target=&quot;_blank&quot;&gt;Django Is Moving to an Annual Release Cycle&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16931/feed&quot; target=&quot;_blank&quot;&gt;DJANGO SOFTWARE FOUNDATION&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16927/feed&quot; target=&quot;_blank&quot;&gt;PEP 844: &lt;code&gt;public&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; Builtins (Draft)&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16927/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16917/feed&quot; target=&quot;_blank&quot;&gt;Python 3.12.14, 3.11.16 and 3.10.21 Released&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16917/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16943/feed&quot; target=&quot;_blank&quot;&gt;Django Rest Framework Release 3.18.0&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16943/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/ENCODE&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;h2&gt;Articles &amp;amp; Tutorials&lt;/h2&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16910/feed&quot; target=&quot;_blank&quot;&gt;OAuth 2.0 in Python: The Authorization Code Flow Explained&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; OAuth&amp;rsquo;s authorization code flow, explained from the four roles up: the redirect, the code-for-token exchange, state, PKCE, and refresh tokens, with a complete runnable Python script and a table of the OAuth errors you&amp;rsquo;ll actually hit.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16910/feed&quot; target=&quot;_blank&quot;&gt;ENDPOINT51.COM&lt;/a&gt; • Shared by Simon O&amp;rsquo;Connor&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16926/feed&quot; target=&quot;_blank&quot;&gt;The Problem With pandas Isn&amp;rsquo;t Performance&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; This opinion piece argues that pandas’ biggest everyday cost is often cognitive overhead rather than execution time and explores whether a backend-independent data-analysis DSL could reduce it&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16926/feed&quot; target=&quot;_blank&quot;&gt;NEAL HUGHES&lt;/a&gt; • Shared by &lt;a href=&quot;https://pycoders.com/link/16934/feed&quot; target=&quot;_blank&quot;&gt;Neal Hughes&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16947/feed&quot; target=&quot;_blank&quot;&gt;🐍 Object-Oriented Python, Taught Live&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; The Object-Oriented Python live cohort begins August 24. Five 2-hour Zoom sessions Mon to Fri build one growing application end to end, with OOP features introduced as the code starts needing them: classes, the data model, inheritance vs composition, properties, dataclasses. &lt;a href=&quot;https://pycoders.com/link/16947/feed&quot; target=&quot;_blank&quot;&gt;Learn more →&lt;/a&gt;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16947/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;span&gt;sponsor&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16919/feed&quot; target=&quot;_blank&quot;&gt;Security of Everything at PyCon 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; This year&amp;rsquo;s PyCon US added a dedicated security track. Talk Python interviews some of the key folks from the center of it: Juanita Gomez, Mike Fiedler, and Seth Michael Larson.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16919/feed&quot; target=&quot;_blank&quot;&gt;TALK PYTHON&lt;/a&gt;&lt;/span&gt; &lt;span&gt;podcast&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16935/feed&quot; target=&quot;_blank&quot;&gt;The HTML Representation of the Index API Is Now Frozen&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &amp;lsquo;PyPI has adopted PEP 833, which &amp;ldquo;freezes&amp;rdquo; the HTML representation of the index API, which is also sometimes called the &amp;ldquo;simple API&amp;rdquo; or the &amp;ldquo;simple repository API.&amp;rdquo;&amp;rsquo;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16935/feed&quot; target=&quot;_blank&quot;&gt;PYPI.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16912/feed&quot; target=&quot;_blank&quot;&gt;How to Integrate OpenTelemetry With a FastAPI App&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn how to integrate OpenTelemetry with a FastAPI app in Python to instrument endpoints, export traces, add custom spans, and correlate logs.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16912/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16921/feed&quot; target=&quot;_blank&quot;&gt;Quiz: How to Integrate OpenTelemetry With a FastAPI App&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16921/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16932/feed&quot; target=&quot;_blank&quot;&gt;Qt Designer and Python: Build Your GUI Applications Faster&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn how to use Qt Designer to build Python GUIs with PyQt6. Create your main windows and dialogs visually, then load them in your app.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16932/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16929/feed&quot; target=&quot;_blank&quot;&gt;Admin Form Injection&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn about a hidden Django admin feature for passing values between pop-up windows on the web.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16929/feed&quot; target=&quot;_blank&quot;&gt;TIM SCHILLING&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16915/feed&quot; target=&quot;_blank&quot;&gt;Caller-Specific Coverage&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; An idea for a new feature for coverage measurement: per-caller coverage&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16915/feed&quot; target=&quot;_blank&quot;&gt;NED BATCHELDER&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;h2&gt;Projects &amp;amp; Code&lt;/h2&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16908/feed&quot; target=&quot;_blank&quot;&gt;pytest-leak-finder: Find Leaking Test Before the One That Fails&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16908/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/MGAITAN&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16920/feed&quot; target=&quot;_blank&quot;&gt;num2words: Convert Numbers to Words. 42 &amp;ndash;&amp;gt; Forty-Two&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16920/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/SAVOIRFAIRELINUX&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16945/feed&quot; target=&quot;_blank&quot;&gt;marimo-book: Static Site Generator for &lt;code&gt;marimo&lt;/code&gt; Notebooks&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16945/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/LJCHANG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16940/feed&quot; target=&quot;_blank&quot;&gt;pyrig: Aautomate Python Project Setup&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16940/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/WINIPEDIA&lt;/a&gt; • Shared by Winipedia&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16933/feed&quot; target=&quot;_blank&quot;&gt;cog: Embedded Graph Database for Python&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16933/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/ARUN1729&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;h2&gt;Events&lt;/h2&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16941/feed&quot; target=&quot;_blank&quot;&gt;Weekly Real Python Office Hours Q&amp;amp;A (Virtual)&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 19, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16941/feed&quot; target=&quot;_blank&quot;&gt;REALPYTHON.COM&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16925/feed&quot; target=&quot;_blank&quot;&gt;PyCon Ghana 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 20 to August 23, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16925/feed&quot; target=&quot;_blank&quot;&gt;PYCON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16930/feed&quot; target=&quot;_blank&quot;&gt;PyCon Latam 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 20 to August 24, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16930/feed&quot; target=&quot;_blank&quot;&gt;PYLATAM.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16909/feed&quot; target=&quot;_blank&quot;&gt;PyLadies: Getting Started With Tabular Foundation Models With TabPFN&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 20, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16909/feed&quot; target=&quot;_blank&quot;&gt;MEETUP.COM&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16922/feed&quot; target=&quot;_blank&quot;&gt;PyData Bristol Meetup&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 20, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16922/feed&quot; target=&quot;_blank&quot;&gt;MEETUP.COM&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16913/feed&quot; target=&quot;_blank&quot;&gt;OSS Security Meetup: Mike Fiedler, PyPI Safety and Security Engineer&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Wednesday, August 26&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16913/feed&quot; target=&quot;_blank&quot;&gt;LUMA.COM&lt;/a&gt; • Shared by Mila Zhou&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16923/feed&quot; target=&quot;_blank&quot;&gt;PyCon JP 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 21 to August 24, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16923/feed&quot; target=&quot;_blank&quot;&gt;PYCON.JP&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16924/feed&quot; target=&quot;_blank&quot;&gt;DjangoCon US 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 24 to August 29, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16924/feed&quot; target=&quot;_blank&quot;&gt;DJANGOCON.US&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16911/feed&quot; target=&quot;_blank&quot;&gt;PyCon AU 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 26 to August 31, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16911/feed&quot; target=&quot;_blank&quot;&gt;PYCON.ORG.AU&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16928/feed&quot; target=&quot;_blank&quot;&gt;PyCon PL 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 27 to August 31, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16928/feed&quot; target=&quot;_blank&quot;&gt;PYCON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16944/feed&quot; target=&quot;_blank&quot;&gt;PyCon Kenya 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 28 to August 30, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16944/feed&quot; target=&quot;_blank&quot;&gt;PYCON.KE&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/16942/feed&quot; target=&quot;_blank&quot;&gt;PyCon Togo 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; August 28 to August 30, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/16942/feed&quot; target=&quot;_blank&quot;&gt;PYTOGO.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;hr /&gt; &lt;p&gt;Happy Pythoning!&lt;br /&gt;This was PyCoder&amp;rsquo;s Weekly Issue #748.&lt;br /&gt;&lt;a href=&quot;https://pycoders.com/issues/748/feed&quot;&gt;View in Browser »&lt;/a&gt;&lt;/p&gt; &lt;img src=&quot;https://pycoders.com/issues/748/open/feed&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;alt&quot; /&gt; 
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Subscribe to 🐍 PyCoder&amp;rsquo;s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week &lt;a href=&quot;https://pycoders.com/?utm_source=pycoders&amp;utm_medium=feed&amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 18 Aug 2026 19:30:00 +0000</pubDate>
</item>
<item>
	<title>Python Bytes: #492 Codeberg Puts Head in Sand</title>
	<guid>https://pythonbytes.fm/episodes/show/492/codeberg-puts-head-in-sand</guid>
	<link>https://pythonbytes.fm/episodes/show/492/codeberg-puts-head-in-sand</link>
	<description>&amp;lt;strong&amp;gt;Topics covered in this episode:&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;

&amp;lt;ul&amp;gt;
	&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Python 3.12.14, 3.11.16, 3.10.21 - security releases&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://lucumr.pocoo.org/2026/7/24/codeberg-divides/?featured_on=pythonbytes&quot;&amp;gt;Codeberg’s AI-code ban tests its role as a GitHub alternative&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Brett Cannon: what's missing for reproducible builds on PyPI&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;nothing records the source code a distribution came from. &amp;lt;code&amp;gt;direct_url.json&amp;lt;/code&amp;gt; captures it when you install from a repo or archive, so the fix is putting the same info in sdist/wheel metadata.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;recording the build tools. Wheels can already do this via PEP 770 SBOMs in &amp;lt;code&amp;gt;.dist-info/sboms/&amp;lt;/code&amp;gt; - sdists can't, since they're a tarball plus a precalculated &amp;lt;code&amp;gt;PKG-INFO&amp;lt;/code&amp;gt; with nowhere to hang extra metadata. Either &quot;don't use sdists&quot; or an sdist v2.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Extra extra extra, hear all about it&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Extras&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Joke&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;

&amp;lt;/ul&amp;gt;&amp;lt;a href='https://www.youtube.com/watch?v=5wBExYOSx0A' style='font-weight: bold;'data-umami-event=&quot;Livestream-Past&quot; data-umami-event-episode=&quot;492&quot;&amp;gt;Watch on YouTube&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;

&amp;lt;p&amp;gt;Sponsored by &amp;lt;strong&amp;gt;Logfire from Pydantic&amp;lt;/strong&amp;gt; &amp;lt;a href=&quot;https://pythonbytes.fm/logfire&quot;&amp;gt;pythonbytes.fm/logfire&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;This episode is brought to you by Pydantic Logfire. It's observability for AI apps from the team behind Pydantic - agents, LLMs, APIs, database, and infrastructure in a single trace, queried with Postgres-compatible SQL. Your coding agent can query it too, through their MCP server. I'll tell you more later.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Connect with the hosts&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Michael: &amp;lt;a href=&quot;https://fosstodon.org/@mkennedy&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/mkennedy.codes?featured_on=pythonbytes&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/mkennedy?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://www.linkedin.com/in/mkennedy/?featured_on=pythonbytes&quot;&amp;gt;LinkedIn&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Calvin: &amp;lt;a href=&quot;https://sixfeetup.social/@calvin?featured_on=pythonbytes&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/calvinhp.com?featured_on=pythonbytes&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/calvinhp?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://www.linkedin.com/in/calvinhp/?featured_on=pythonbytes&quot;&amp;gt;LinkedIn&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Show: &amp;lt;a href=&quot;https://fosstodon.org/@pythonbytes&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/pythonbytes.fm&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/PythonBytes?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
Join us on YouTube at &amp;lt;a href=&quot;https://pythonbytes.fm/stream/live&quot;&amp;gt;&amp;lt;strong&amp;gt;pythonbytes.fm/live&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt; to be part of the audience. Usually &amp;lt;strong&amp;gt;Tuesday at 7am PT&amp;lt;/strong&amp;gt;. Older video versions available there too.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;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 &amp;lt;a href=&quot;https://pythonbytes.fm/friends-of-the-show&quot;&amp;gt;our friends of the show list&amp;lt;/a&amp;gt;, we'll never share it.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Calvin #1: Python 3.12.14, 3.11.16, 3.10.21 - security releases&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;https://blog.python.org/2026/08/python-31214-31116-31021/&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Source-only security releases for the three branches now in security-fix-only mode; release team blamed the European solar eclipse for the timing.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;tarfile&amp;lt;/code&amp;gt; hardening. Multiple path-traversal bypasses of the &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; filter closed, including a symlink escape that bypassed the CVE-2025-4330 fix; &amp;lt;code&amp;gt;extract()&amp;lt;/code&amp;gt; now applies the filter to link targets too.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Four fresh CVEs: CVE-2026-2297 (&amp;lt;code&amp;gt;SourcelessFileLoader&amp;lt;/code&amp;gt; not using &amp;lt;code&amp;gt;io.open_code()&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;.pyc&amp;lt;/code&amp;gt;), CVE-2026-4224 (expat crash on deeply nested content models), CVE-2026-3644 (control chars in &amp;lt;code&amp;gt;http.cookies.Morsel&amp;lt;/code&amp;gt;), plus the completed CVE-2021-4189 fix in &amp;lt;code&amp;gt;ftplib.ftpcp&amp;lt;/code&amp;gt;.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Quadratic-complexity DoS cleanup across the stdlib: &amp;lt;code&amp;gt;HTMLParser&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;configparser&amp;lt;/code&amp;gt; regexes, &amp;lt;code&amp;gt;unicodedata.normalize()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;csv.Sniffer.sniff()&amp;lt;/code&amp;gt;, and ElementTree XPath index predicates.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Header/injection fixes: CR/LF rejected in &amp;lt;code&amp;gt;HTTPConnection.set_tunnel()&amp;lt;/code&amp;gt;, control chars blocked in &amp;lt;code&amp;gt;wsgiref.handlers&amp;lt;/code&amp;gt; status, and &amp;lt;code&amp;gt;webbrowser&amp;lt;/code&amp;gt; now rejects leading dashes (plus a &amp;lt;code&amp;gt;%action&amp;lt;/code&amp;gt; prefix bypass).&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;http.client&amp;lt;/code&amp;gt; now caps chunked trailer lines and 1xx interim responses at 100 each - a hostile server could previously hang the client forever despite a socket timeout.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Memory-safety odds and ends: stale pointers in lzma/bz2/zlib decompressors after &amp;lt;code&amp;gt;MemoryError&amp;lt;/code&amp;gt;, a bz2 stack overflow on reuse-after-error, and bundled libexpat bumped to 2.8.3.
If you're still on 3.10, 3.11, or 3.12 - and you extract tarballs from anywhere you don't fully control - this one's not optional.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Michael #2: &amp;lt;a href=&quot;https://lucumr.pocoo.org/2026/7/24/codeberg-divides/?featured_on=pythonbytes&quot;&amp;gt;Codeberg’s AI-code ban tests its role as a GitHub alternative&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Armin’s article “&amp;lt;a href=&quot;https://lucumr.pocoo.org/2026/7/24/codeberg-divides/?featured_on=pythonbytes&quot;&amp;gt;Codeberg Divides&amp;lt;/a&amp;gt;”&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Armin Ronacher argues that Codeberg’s new terms, which prohibit projects mostly written with generative AI, create a vague and difficult-to-enforce boundary. His larger concern is that a democratically governed host can still be unpredictable or ideologically narrow, weakening Codeberg’s potential as a broad European alternative to GitHub.
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;The strongest question for Python developers is whether repository hosting should judge legal open source by how code was produced, or focus on behavior and resource abuse.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;“Mostly generated” is hard to measure in modern codebases where developers mix handwritten code, completions, agents, and generated refactors.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Ronacher suggests clearer alternatives: ban all LLM involvement, or target autonomous repository spam, abusive resource use, and low-quality generated contributions directly.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Codeberg is free to choose a values-driven community, but that may conflict with being predictable, neutral infrastructure and a serious GitHub competitor.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Worth discussing: can open-source communities set meaningful AI boundaries without driving maintainers and projects into opposing camps?&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Very first search for these &amp;lt;a href=&quot;https://xn--gckvb8fzb.com/i-regret-migrating-to-codeberg/?featured_on=pythonbytes&quot;&amp;gt;terms lands on this page&amp;lt;/a&amp;gt;.
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;em&amp;gt;Codeberg looked like a viable alternative. … Unfortunately, the latest update to its terms of service seems to mark a first step in changing one part I moved there for, namely the “freedom” part.&amp;lt;/em&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Sponsor&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://pythonbytes.fm/logfire&quot;&amp;gt;Logfire from Pydantic&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Your AI agent failed at 2am. Was it the model? A tool call? The database? Most observability tools can't tell you, because they only see part of your stack.
Pydantic Logfire sees all of it. One trace across your agents, LLMs, APIs, and database. Down to the infrastructure: services, Kubernetes, and hosts.
It's built on OpenTelemetry, with SDKs for Python, TypeScript, and Rust, and it works with any OTel-compatible language.
Every prompt, token count, and cost, right next to your vector searches and API calls.
You query everything with Postgres-compatible SQL. And so can your coding agent, through the Logfire MCP server.
Stop guessing. Read the trace.
Pydantic Logfire. AI, it's still just engineering.
Visit &amp;lt;a href=&quot;http://pythonbytes.fm/logfire&quot;&amp;gt;pythonbytes.fm/logfire&amp;lt;/a&amp;gt; today and sign up today. Get 10M records free every month, no card required. You can even click “Onboard with your coding agent” to copy a prompt to have claude or codex integrate Logfire into your app.
Thanks to Pydantic for supporting the show.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Calvin #3: Brett Cannon: what's missing for reproducible builds on PyPI&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Framing came out of his 2026 Python Packaging Council nomination - the secure-supply-chain gap he found is that Python has no defined way to do reproducible builds at all.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Design goal is zero friction: producers uploading to PyPI shouldn't have to do anything. The work lands on build backends and installers.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Gap #1: nothing records the source code a distribution came from. &amp;lt;code&amp;gt;direct_url.json&amp;lt;/code&amp;gt; captures it when you install from a repo or archive, so the fix is putting the same info in sdist/wheel metadata.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Gap #2: recording the build tools. Wheels can already do this via PEP 770 SBOMs in &amp;lt;code&amp;gt;.dist-info/sboms/&amp;lt;/code&amp;gt; - sdists can't, since they're a tarball plus a precalculated &amp;lt;code&amp;gt;PKG-INFO&amp;lt;/code&amp;gt; with nowhere to hang extra metadata. Either &quot;don't use sdists&quot; or an sdist v2.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The replay mechanism already exists: &amp;lt;code&amp;gt;[build-system]&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;pyproject.toml&amp;lt;/code&amp;gt; is a defined entry point, so if backends recorded their own environment, you could reinstall and re-run the build.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Payoff idea: trusted third parties report successful reproductions back to PyPI, which displays &quot;independently reproduced by X&quot; - surfaced in the index API so installers could prefer reproduced files.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Explicitly framed as a perk, not a requirement - roughly SLSA build level 1, no shaming projects that don't opt in.
Verbal kicker option: &quot;And don't think pure-Python wheels are off the hook. Something built that wheel, and if that something was compromised, so is your wheel. SolarWinds was a build-process attack.&quot;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Michael #4: Extra extra extra, hear all about it&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&quot;https://docs.python.org/release/3.14.7/whatsnew/changelog.html?featured_on=pythonbytes&quot;&amp;gt;Python 3.14.7&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Upgraded the MCP servers to 2026-07-28 v2 protocols (&amp;lt;a href=&quot;https://talkpython.fm/ai-integration?featured_on=pythonbytes&quot;&amp;gt;talk python&amp;lt;/a&amp;gt;, &amp;lt;a href=&quot;https://pythonbytes.fm/ai-integration&quot;&amp;gt;python bytes&amp;lt;/a&amp;gt;)&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Got agentsview running &amp;lt;a href=&quot;https://www.agentsview.io/pg-sync/?featured_on=pythonbytes&quot;&amp;gt;synced via postgres&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Talk Python courses, &amp;lt;a href=&quot;https://training.talkpython.fm/team-trial?featured_on=pythonbytes&quot;&amp;gt;teams trial offering&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Talk Python courses, &amp;lt;a href=&quot;https://training.talkpython.fm/government?featured_on=pythonbytes&quot;&amp;gt;government procurement offering&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&quot;https://www.audible.com/pd/Lean-TDD-Audiobook/B0HDV6DM5S?eac_link=kbTXxf8oGNDB&amp;amp;ref=web_search_eac_asin_1&amp;amp;eac_selected_type=asin&amp;amp;eac_selected=B0HDV6DM5S&amp;amp;qid=VQkJQUTSmK&amp;amp;eac_id=141-5188421-6797858_VQkJQUTSmK&amp;amp;sr=1-1&amp;amp;featured_on=pythonbytes&quot;&amp;gt;Lean TDD audio book is out&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Extras&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Calvin:&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;uv now prefers post-quantum key exchange -&amp;lt;/strong&amp;gt; https://github.com/astral-sh/uv/releases/tag/0.12.4&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Joke: &amp;lt;a href=&quot;https://turnoff.us/geek/beware-of-dog/?featured_on=pythonbytes&quot;&amp;gt;Beware of dog&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;</description>
	<pubDate>Tue, 18 Aug 2026 18:07:27 +0000</pubDate>
</item>
<item>
	<title>Bob Belderbos: Guardrails Protect Your Codebase. What Protects Your Judgment?</title>
	<guid>https://belderbos.dev/blog/ai-skill-atrophy-keep-the-friction/</guid>
	<link>https://belderbos.dev/blog/ai-skill-atrophy-keep-the-friction/</link>
	<description>&lt;p&gt;Cal Newport's &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://calnewport.com/on-ai-coding-and-its-discontents/&quot;&gt;On AI Coding and Its Discontents&lt;/a&gt; lands on an uncomfortable point: the speed AI gives you is paid for with the thinking that made us good engineers in the first place.&lt;/p&gt;
&lt;p&gt;Read code instead of writing it and you get passive recognition where you used to have an active model of the code.&lt;/p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;
&lt;p&gt;The vendors sell one answer to this: more AI. The nostalgic answer is the opposite: go back to writing everything by hand. I am searching for a midway.&lt;/p&gt;
&lt;h2 id=&quot;no-right-answer-but-at-least-a-direction-to-pursue&quot;&gt;No right answer, but at least a direction to pursue&lt;/h2&gt;
&lt;p&gt;When I posted about this recently, I offered 3 options: write more code manually, double down on AI, or find some middle with more friction. I got some valuable comments from developers picking the middle. And that's where I've landed too.&lt;/p&gt;
&lt;p&gt;The more I read and think about it, the more the middle stops looking like a compromise. It seems the way forward, but only if you specify what &lt;em&gt;friction&lt;/em&gt; to keep.&lt;/p&gt;
&lt;p&gt;Skill atrophy isn't caused by using AI per se. It's caused by delegating the part that builds your internal model.&lt;/p&gt;
&lt;p&gt;I've argued that &lt;a href=&quot;https://belderbos.dev/blog/dont-delegate-the-friction/&quot;&gt;the friction is where the learning lives&lt;/a&gt;, and nothing about agents changes that. What changes is that it's now easier to bypass friction and it's on us to keep it in.&lt;/p&gt;
&lt;p&gt;It helps to separate two problems here, because AI creates both and they aren't the same. One is skill atrophy: stop doing the thinking and your mental model fades. The other is correctness: AI writes plausible code that can be subtly wrong.&lt;/p&gt;
&lt;p&gt;Let's look at each in turn.&lt;/p&gt;
&lt;h2 id=&quot;do-you-own-the-code&quot;&gt;Do you 'own' the code?&lt;/h2&gt;
&lt;p&gt;A sharp reply came from someone on Bluesky:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;agents draft, but re-derive the hard path before merge. If you can't explain a weird branch without re-reading the whole file, you rewrote too little.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not all code is created equal. The boundary conditions, error paths, and testing assumptions are where we as engineers pull our weight.&lt;/p&gt;
&lt;p&gt;For every diff, can you explain the change? What are the edge cases and risks?&lt;/p&gt;
&lt;p&gt;In practice I find that this gets easier when you scope the agent to narrow, well-defined tasks instead of blanket features. Small tasks keep you in the loop, stop the agent from drifting, and prevent giant code reviews nobody wants to read.&lt;/p&gt;
&lt;p&gt;I also like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://youtu.be/tHh0UaL_V4w?si=lLP4cZxvcikLo1yA&amp;t=1155&quot;&gt;how Corey Schafer summarized how he keeps the friction&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use detailed prompts, not one-liners: spec the tools, architecture, and reuse saved research prompts that force citing official docs.&lt;/li&gt;
&lt;li&gt;Review everything: read and understand all generated code like a junior's PR you'd never merge blindly.&lt;/li&gt;
&lt;li&gt;Interrogate unfamiliar code / concepts: make the AI explain things in plain English, pull docs, and justify the approach and trade-offs.&lt;/li&gt;
&lt;li&gt;Push back: offer your own approach, ask if the AI's is better/worse/different, and fold what you learn into your own toolkit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;push-the-rest-into-the-system&quot;&gt;Push the rest into the system&lt;/h2&gt;
&lt;p&gt;Those four habits are all manual. They keep your judgment in the loop, but they run on your attention, and attention is finite. You can't re-read every branch on every diff forever. So whatever those habits can't cover by hand, you push into the system and let it enforce the rest automatically.&lt;/p&gt;
&lt;p&gt;A commenter on Threads put it well:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the real fix is correctness by design, stronger types, compile-time assertions, more &quot;faff in the way.&quot; We never fully adopted that stuff because it takes patience humans run out of. AI doesn't. It learns your constraints once, then works inside them on every diff after.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And on Fosstodon:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I feel like all these systems have too many surprises, and making invalid states illegal is the best defensive alternative to not using them, which would be the first choice. Once you get guarantees, if you can type faster with gen ai than your fingers, maybe thats worth the squeeze depending on your morals.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's why Rust is so appealing to me. Making invalid states unrepresentable and the agent has to comply with this. I discussed this &lt;a href=&quot;https://belderbos.dev/blog/rust-compiler-ai-agent-guardrail/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Python gives you less strict guarantees, but we can approximate it. Your &lt;a href=&quot;https://belderbos.dev/blog/modern-python-tooling-uv-ruff-ty/&quot;&gt;type checker (ty, pyrefly, mypy)&lt;/a&gt; catches the class of type errors the model would otherwise slip past you. Pydantic models validate at the boundary, so bad data fails loudly instead of drifting three functions deep. And well-thought out test cases can challenge plausible looking code. And for AI generated tests you can use mutation testing (an article on this soon here ...)&lt;/p&gt;
&lt;p&gt;So balancing responsible AI use has two sides. Re-derive the decisions that matter, which keeps your judgment sharp. And encode stricter rules to keep your agent accountable to higher standards. One protects your mental model, the other protects the code base. Both protect peace of mind.&lt;/p&gt;
&lt;p&gt;As said before: the tooling / way of working has changed, but &lt;a href=&quot;https://belderbos.dev/blog/ai-doesnt-change-what-software-engineering-is/&quot;&gt;AI doesn't change what software engineering is&lt;/a&gt;; we can automate some of the boring parts, but the majority of the work (including the code-producing part) is a lot of back-and-forth and applying experience and judgment.&lt;/p&gt;
&lt;h2 id=&quot;keep-reading&quot;&gt;Keep reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://belderbos.dev/blog/dont-delegate-the-friction/&quot;&gt;How to Keep Your Developer Instincts When AI Writes the Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://belderbos.dev/blog/ai-accelerator-needs-direction/&quot;&gt;AI Is an Accelerator, Not a Compass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://belderbos.dev/blog/design-over-code/&quot;&gt;From 1,069 to 156 LOC: Design Over Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;Newport's worry is right: outsourced thinking atrophies. The escape isn't more or less AI. It's identifying, every time you build software, the small set of decisions you refuse to let the model make for you.&lt;/p&gt;
&lt;p&gt;Can you explain each change? Do you truly own it? Did you keep making the hard decisions yourself? And are strict guardrails in place to protect the codebase when AI writes more of the code?&lt;/p&gt;
&lt;p&gt;Reach out to me if you want to chat about this. It feels a bit like the wild west right now, and nobody has final answers. I'm really keen to hear how you're navigating the fast pace of change our industry is going through.&lt;/p&gt;</description>
	<pubDate>Tue, 18 Aug 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Seth Michael Larson: When str.lower() is a security vulnerability in Python</title>
	<guid>https://sethmlarson.dev/when-str-lower-is-a-security-vulnerability?utm_campaign=rss</guid>
	<link>https://sethmlarson.dev/when-str-lower-is-a-security-vulnerability?utm_campaign=rss</link>
	<description>&lt;p&gt;Some internet standards only support ASCII characters, but the world uses
much more than the Latin alphabet. Thus, a mapping from Unicode to
ASCII for use in domain names is required.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Nameprep&quot;&gt;NamePrep&lt;/a&gt; was part of that solution,
defined in &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3491&quot;&gt;RFC 3491&lt;/a&gt; as a profile of StringPrep,
and is crucially a component of Internationalizing Domain Names in Applications
(IDNA), also known as “IDNA 2003”. The StringPrep algorithm is defined in
&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3454&quot;&gt;RFC 3454&lt;/a&gt;. IDNA 2003
has been obsoleted by IDNA 2008 defined in &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc5890&quot;&gt;RFC
 5890&lt;/a&gt;,
&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc5891&quot;&gt;5891&lt;/a&gt;,
&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc5892&quot;&gt;5892&lt;/a&gt;, and 
&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc5893&quot;&gt;5893&lt;/a&gt;.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;Python supports IDNA 2003 through the &lt;code&gt;idna&lt;/code&gt; codec (&lt;code&gt;str.encode('idna')&lt;/code&gt;) and
IDNA 2008 is supported by the &lt;a href=&quot;https://pypi.org/project/idna/&quot;&gt;&lt;code&gt;idna&lt;/code&gt; package on the Python package Index&lt;/a&gt;. 
Python's implementation of StringPrep is implemented in the &lt;a href=&quot;https://docs.python.org/3/library/stringprep.html&quot;&gt;&lt;code&gt;stringprep&lt;/code&gt; module&lt;/a&gt;
in the standard library. In general, you should be using the &lt;code&gt;idna&lt;/code&gt; package (IDNA 2008)
and not &lt;code&gt;.encode(&quot;idna&quot;)&lt;/code&gt; (IDNA 2003), but sometimes you
do need the older behavior.&lt;/p&gt;

&lt;p&gt;md5-240e0a066fbd28891db9e76043276e9f&lt;/p&gt;

&lt;p&gt;StringPrep defines the “case folding” step (case folding is approximately “how to lowercase/uppercase a codepoint”) in &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3454#section-3.2&quot;&gt;Section 3.2&lt;/a&gt;, enabling case-insensitive
comparisons of strings, by mapping all characters through mapping &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3454#appendix-B.2&quot;&gt;tables B.2&lt;/a&gt; and &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3454#appendix-B.3&quot;&gt;B.3&lt;/a&gt;.
B.2 is effectively &lt;code&gt;str.lower()&lt;/code&gt;, lowercasing all characters according to
Unicode rules and B.3 contains the exceptions. The Python code implementing
this (and assuming B.3 table is captured correctly) is the following code below:&lt;/p&gt;

&lt;p&gt;md5-4f979c536cfd56d696221cec539cf01c&lt;/p&gt;

&lt;p&gt;And that might seem fine... and the title probably gave it away already.
The &lt;code&gt;str.lower()&lt;/code&gt; call in this function is a vulnerability!&lt;/p&gt;

&lt;p&gt;Why? Because &lt;code&gt;str&lt;/code&gt; uses whatever Unicode data that the particular Python
interpreter is shipped with, you can figure out what Unicode version your
Python interpreter uses by accessing &lt;code&gt;unicodedata.unidata_version&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;md5-4546488f0cbcfe00d7f3a1769cb9a0b9&lt;/p&gt;

&lt;p&gt;There's also a database of Unicode 3.2.0 data available on every version
of Python (&lt;a href=&quot;https://docs.python.org/3/library/unicodedata.html#unicodedata.ucd_3_2_0&quot;&gt;&lt;code&gt;unicodedata.ucd_3_2_0&lt;/code&gt;&lt;/a&gt;) specifically for the StringPrep and IDNA algorithms:&lt;/p&gt;

&lt;p&gt;md5-56b84a927fc32234b9d0f638c01c98c7&lt;/p&gt;

&lt;p&gt;This is important! StringPrep depends on this specific version of Unicode
to operate consistently, the B.2 and B.3 tables in RFC 3454 are essentially
Unicode 3.2.0 case-folding rules encoded into
a table. So we need to use Unicode 3.2.0 case-folding rules, not newer
Unicode case-folding rules. This is why calling &lt;code&gt;str.lower()&lt;/code&gt; represents
a difference in the implementation and the specification,
and therefore a vulnerability:&lt;/p&gt;

&lt;p&gt;md5-a56c9c32b9ebeff41b4204e7dd201499&lt;/p&gt;

&lt;p&gt;The fix was to create new exceptions so that &lt;code&gt;str.lower()&lt;/code&gt; would behave
as if it was using Unicode 3.2.0 for only particular function. So, we
go through &lt;a href=&quot;https://github.com/python/cpython/pull/155293/changes#diff-83ae79799190e9f5924d155d940386cb7adce6470c053997791ed79e9370bf20R206-R215&quot;&gt;each Unicode codepoint&lt;/a&gt; and record when the behavior of
&lt;code&gt;str.lower()&lt;/code&gt; is different when comparing the Unicode version shipped with Python and Unicode 3.2.0.
And that's all, now IDNA 2003 is consistent with the specification.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/TheShiftedBit&quot;&gt;Bitshift&lt;/a&gt; for reporting the vulnerability, &lt;a href=&quot;https://github.com/StanFromIreland&quot;&gt;Stan Ulbrych&lt;/a&gt; for co-developing
the remediation, and &lt;a href=&quot;https://github.com/malemburg&quot;&gt;Marc-Andre Lemburg&lt;/a&gt; and &lt;a href=&quot;https://github.com/encukou&quot;&gt;Petr Viktorin&lt;/a&gt; for reviewing the
remediation. See &lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-17084&quot;&gt;CVE-2026-17084&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;md5-530571d20754d44d4ee009954881e467&lt;/p&gt;
&lt;br /&gt;&lt;hr /&gt;&lt;p&gt;Thanks for reading ♥ I would love to hear your thoughts! Contact me via &lt;a href=&quot;https://mastodon.social/@sethmlarson&quot;&gt;Mastodon&lt;/a&gt;, &lt;a href=&quot;https://bsky.app/profile/sethmlarson.dev&quot;&gt;Bluesky&lt;/a&gt;, or &lt;a href=&quot;mailto:sethmichaellarson@gmail.com&quot;&gt;email&lt;/a&gt;. Browse the &lt;a href=&quot;https://sethmlarson.dev/&quot;&gt;blog archive&lt;/a&gt;. Check out my &lt;a href=&quot;https://sethmlarson.dev/blogroll&quot;&gt;blogroll&lt;/a&gt;.&lt;/p&gt;&lt;hr /&gt;&lt;br /&gt;</description>
	<pubDate>Tue, 18 Aug 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>The Python Coding Stack: Back From Holidays • SOLID Ideas, Agents, Rust</title>
	<guid>https://www.thepythoncodingstack.com/p/back-from-holidays-solid-ideas-agents</guid>
	<link>https://www.thepythoncodingstack.com/p/back-from-holidays-solid-ideas-agents</link>
	<description>&lt;p&gt;&lt;span&gt;It feels good to be back from holiday. Feeling refreshed, mostly.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;The to-do list is longer, the inbox is noisier, and home has thoughtfully provided its own backlog: a replacement car, a new school uniform, and a garden that has staged a minor coup.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;I may need another holiday already.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;And that&amp;#8217;s before even talking about programming and the revolution it is currently going through. I&amp;#8217;m a Python educator. Somewhat unusually for Python educators, I&amp;#8217;ve been a &lt;/span&gt;&lt;em&gt;&lt;span&gt;full-time&lt;/span&gt;&lt;/em&gt;&lt;span&gt; Python educator for over a decade.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;But AI is changing &lt;/span&gt;&lt;em&gt;&lt;span&gt;how&lt;/span&gt;&lt;/em&gt;&lt;span&gt; people learn and &lt;/span&gt;&lt;em&gt;&lt;span&gt;what&lt;/span&gt;&lt;/em&gt;&lt;span&gt; people need to learn. Like many others, I find myself fascinated by what I can now do with AI, while also aware that it is changing the economics of work that has supported me for years.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;It&amp;#8217;s time to find out how anti-fragile I am. Over the coming weeks and months, I&amp;#8217;ll write about using AI, I&amp;#8217;ll share my thoughts about programming in 2026 and beyond, and I&amp;#8217;ll tell you what I think about how learning and teaching are changing.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;So I am going to explore this in public: how we learn, teach, write, and assess code in an AI-shaped world.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;Here is some signposting for what else you will read on these pages in the coming months:&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;SOLID Ideas&lt;/span&gt;&lt;/strong&gt;&lt;span&gt; &amp;#8226; I have been wanting to write a series on SOLID programming principles for a while. They matter more than ever when we want AI agents to write robust code for us rather than plausible-looking but brittle code. The series will look not only at what the principles are, but why they matter and what can go wrong when we ignore them.&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;Agents Unpacked&lt;/span&gt;&lt;/strong&gt;&lt;span&gt; &amp;#8226; Before going on holiday, I started this new section on this publication. I am thinking about republishing the first two posts in a significantly updated form, then carrying on at pace. Perhaps it will become a book, too. Agents are here, and I want to understand what they are, how they differ from LLM chat interfaces, and how to use them efficiently. You can join me on that learning journey.&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;span&gt;Learning Rust in Public&lt;/span&gt;&lt;/strong&gt;&lt;span&gt; &amp;#8226; I also want to learn Rust and will set up another section here to do that in public, as they say these days. I will use a similar format to &lt;/span&gt;&lt;em&gt;&lt;span&gt;Agents Unpacked&lt;/span&gt;&lt;/em&gt;&lt;span&gt;, in which my personal learning agent and I have a discussion as I learn from it.&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;button-wrapper&quot;&gt;&lt;a class=&quot;button primary&quot; href=&quot;https://www.thepythoncodingstack.com/subscribe&quot;&gt;&lt;span&gt;Subscribe now&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;So there is plenty on the horizon here at &lt;/span&gt;&lt;em&gt;&lt;span&gt;The Python Coding Stack&lt;/span&gt;&lt;/em&gt;&lt;span&gt;: plenty of Python, and plenty of Python-adjacent stuff, too. And some other stuff, too. I hope you will join me for the journey.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 17 Aug 2026 15:14:17 +0000</pubDate>
</item>
<item>
	<title>Brian Okken: Lean TDD Book Launch</title>
	<guid>https://pythontest.com/lean-tdd-launch/</guid>
	<link>https://pythontest.com/lean-tdd-launch/</link>
	<description>&lt;p&gt;Hey all. I&amp;rsquo;m super excited to announce the launch of my new book.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s &lt;a href=&quot;https://leantdd.com&quot;&gt;Lean TDD: TDD Without the Waste&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That link in the last sentence is a link to &lt;a href=&quot;https://leantdd.com&quot;&gt;leantdd.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There you&amp;rsquo;ll find links to all the places you can read or listen to it.&lt;/p&gt;
&lt;p&gt;Right now, it&amp;rsquo;s available at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Lean-TDD-Without-Waste/dp/B0HCHDVPBZ/?tag=testandcode-20&quot;&gt;Amazon as a paperback&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/dp/B0HC2YQ18H?tag=testandcode-20&quot;&gt;Amazon as an ebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Lean-TDD-Without-Waste/dp/B0HDV78XD5/?tag=testandcode-20&quot;&gt;Audible as an audio book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Other platforms to come later &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the next few months, it will get onto other platforms.
I&amp;rsquo;ve already had requests for Kobo, and just raw files sold through my site, and I&amp;rsquo;d also like to get it onto library platforms.&lt;/p&gt;</description>
	<pubDate>Mon, 17 Aug 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Brett Cannon: What's missing to have reproducible builds on PyPI</title>
	<guid>https://snarky.ca/whats-missing-to-have-reproducible-builds-on-pypi/</guid>
	<link>https://snarky.ca/whats-missing-to-have-reproducible-builds-on-pypi/</link>
	<description>&lt;p&gt;While writing the section of my &lt;a href=&quot;https://snarky.ca/my-nomination-statement-for-the-2026-python-packaging-council/&quot;&gt;2026 Python Packaging Council (PPC) nomination&lt;/a&gt; on secure supply chain, I realized that one thing related to having a secure supply chain that we lack is a defined way to perform &lt;a href=&quot;https://reproducible-builds.org/&quot;&gt;reproducible builds&lt;/a&gt;. The reason I like the idea of making reproducible builds work is that I think it can be done in such a way as to not require any work on the part of the producer of a distribution (which is a technical term for &lt;a href=&quot;https://packaging.python.org/en/latest/specifications/source-distribution-format/&quot;&gt;sdists&lt;/a&gt; or &lt;a href=&quot;https://packaging.python.org/en/latest/specifications/binary-distribution-format/&quot;&gt;wheels&lt;/a&gt;, i.e., the people who upload stuff to PyPI), and thus make reproducible builds very low-friction for people to opt into supporting.&lt;/p&gt;&lt;h1 id=&quot;why-you-should-care&quot;&gt;Why you should care&lt;/h1&gt;&lt;p&gt;In terms of secure supply chain, reproducible builds can let independent 3rd parties verify that the bits in a distribution match what&amp;amp;aposs expected based on the source code the distribution was made from. That lets you potentially detect if anyone tampered with the code during the build process. As well, there&amp;amp;aposs a side-effect that from having to record the software involved in the build process means you can more easily detect if some known, compromised tool was used even if you don&amp;amp;apost do everything necessary to verify the bits are exactly the same. And this isn&amp;amp;apost some hypothetical benefit: &lt;a href=&quot;https://www.cisa.gov/eviction-strategies-tool/dialog-content/TMPL0002&quot;&gt;SolarWinds was compromised&lt;/a&gt; due to malicious code being injected into the build process.&lt;/p&gt;&lt;p&gt;And don&amp;amp;apost let the word &amp;quot;build&amp;quot; fool you into thinking that pure Python wheels aren&amp;amp;apost vulnerable. There&amp;amp;aposs a &lt;a href=&quot;https://packaging.python.org/en/latest/specifications/pyproject-toml/#declaring-build-system-dependencies-the-build-system-table&quot;&gt;build backend&lt;/a&gt; that was used to make that wheel, and if that build back-end was compromised then it may inject some malicious code into the wheel. So there isn&amp;amp;apost some area in Python packaging that gets to ignore these risks.&lt;/p&gt;&lt;h1 id=&quot;whats-missing-from-the-specs&quot;&gt;What&amp;amp;aposs missing from the specs&lt;/h1&gt;&lt;h2 id=&quot;wheres-the-source-code&quot;&gt;Where&amp;amp;aposs the source code?&lt;/h2&gt;&lt;p&gt;So what do we need in Python packaging to make reproducible builds possible? First, we need to record what source code was used. This isn&amp;amp;apost recorded in sdists or wheels, but if you install directly from a source repository or an archive then it&amp;amp;aposs recorded in a &lt;a href=&quot;https://packaging.python.org/en/latest/specifications/direct-url/&quot;&gt;direct_url.json file&lt;/a&gt; by your installer. If we were to record the same information in sdists and wheels (such as in the metadata), then we would know the location of the source code used to make the distribution.&lt;/p&gt;&lt;h2 id=&quot;what-software-was-used-to-make-the-distribution&quot;&gt;What software was used to make the distribution?&lt;/h2&gt;&lt;p&gt;But the next tricky bit is recording all the tools used to create the distribution. For wheels, we have support for &lt;a href=&quot;https://packaging.python.org/en/latest/specifications/binary-distribution-format/#the-dist-info-sboms-directory&quot;&gt;recording software bill of materials&lt;/a&gt; (SBOMs). And as &lt;a href=&quot;https://peps.python.org/pep-0770/#build-tools-environment-and-reproducibility&quot;&gt;PEP 770&lt;/a&gt;, which added that support, says (disclaimer: I was the PEP delegate), &lt;a href=&quot;https://peps.python.org/pep-0770/#build-tools-environment-and-reproducibility&quot;&gt;SBOMs can be used to record the build tools used&lt;/a&gt; to create a distribution. And if you record all the software used to build a distribution, you can hopefully reproduce the exact same bits and show nothing was tampered with.&lt;/p&gt;&lt;p&gt;Unfortunately, sdists don&amp;amp;apost have a similar mechanism to record SBOMs. Since sdists are usually just a tarball with a PKG-INFO file that contains some precalculated metadata, there isn&amp;amp;apost a place to put any other metadata file. So we either have to shrug and say, &amp;quot;don&amp;amp;apost use sdists if you want reproducible builds,&amp;quot; or we will have to come up with some sdist v2 format that allows for more structured data.&lt;/p&gt;&lt;h2 id=&quot;who-records-what-software-was-used&quot;&gt;Who records what software was used?&lt;/h2&gt;&lt;p&gt;Now, you might be wondering how you would even go about reproducing a build even if you do have all of this information. Luckily, since we have the &lt;code&gt;[build-system]&lt;/code&gt; table in pyproject.toml, we have a defined entry point into the build back-end that produced the distribution. That means once we have all the software required to run the build backend recorded, we can replay the build process by installing the same things and calling the build backend as defined by &lt;code&gt;[build-system]&lt;/code&gt;. And if build backends took care of recording what&amp;amp;aposs installed in the environment they are running in, theoretically we could record all the software used for the build back-end and store it in SBOMs today without distribution producers having to do extra work (but it does mean work for the pip maintainers).&lt;/p&gt;&lt;h1 id=&quot;surfacing-reproducibility-on-pypi&quot;&gt;Surfacing reproducibility on PyPI&lt;/h1&gt;&lt;p&gt;Assuming all of this comes to pass and we record the where the source code is that went into a distribution and the software used to make the distribution, how do we make it useful to people? Does every person who cares about having a secure supply chain have to rebuild everything they use themselves? Is there some way for even people who don&amp;amp;apost care about this stuff to benefit?&lt;/p&gt;&lt;p&gt;One possible way is if there were trusted verifiers who could tell PyPI when they successfully reproduced a distribution. Since various enterprises are going to be doing this anyway, they could feed that information back to PyPI so they can visibly say for a distribution file, &amp;quot;this file was independently reproduced by &amp;lt;name of trusted party&amp;gt;&amp;quot;. That means users get to know a distribution is what the creator expected, and the verifier gets a bit of recognition for helping the community out. This could even be surfaced in the &lt;a href=&quot;https://packaging.python.org/en/latest/specifications/simple-repository-api/&quot;&gt;index API&lt;/a&gt; so you could have installers prefer reproduced distributions.&lt;/p&gt;&lt;p&gt;This should be done in a way not to shame anyone who happens not to use a build backend that can create a distribution that can be reproduced. This should always be viewed as a perk and not a requirement. It&amp;amp;aposs like getting to say your project meets &lt;a href=&quot;https://slsa.dev/spec/v1.2/build-requirements#build-levels&quot;&gt;build level 1 of SLSA&lt;/a&gt; (which all of this would meet); some people like getting to say that, but it isn&amp;amp;apost a knock against anyone who chooses not to care.&lt;/p&gt;&lt;h1 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h1&gt;&lt;p&gt;Thanks to Seth Larson for listening to my idea and also checking over this blog post.&lt;/p&gt;</description>
	<pubDate>Sun, 16 Aug 2026 03:36:12 +0000</pubDate>
</item>
<item>
	<title>Juri Pakaste: TIL: Typed do in Swift</title>
	<guid>https://juripakaste.fi/swift-do-typed/</guid>
	<link>https://juripakaste.fi/swift-do-typed/</link>
	<description>&lt;p&gt;TL;DR: Swift has &lt;code&gt;do throws(MyError)&lt;/code&gt;. It's helpful.&lt;/p&gt;
&lt;p&gt;This is one of those &quot;I can't believe I had missed that&quot; things.&lt;/p&gt;
&lt;p&gt;I've been pretty enthusiastic about adopting typed throws in Swift. If you
need to process certain kinds of errors, it just makes sense to me. However, it
was always a bit painful. You have this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot;&gt;&lt;code&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    // throwing code here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; catch&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    // error is precisely typed here, assuming&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    // the block above throws just one type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;… and all is fine and good, except that the &quot;throwing code&quot; doesn't need to
grow particularly complex before Swift decides to widen the type to &lt;code&gt;any Error&lt;/code&gt;
and your catch block starts producing compilation errors.&lt;/p&gt;
&lt;p&gt;When I ran into this, I'd use &lt;code&gt;catch let error as MyError&lt;/code&gt;. Fine. Except it
isn't, because now your error-handling code is incomplete: you have to add
an unreachable catch-all block, and you're unhappy with the language and
your life choices.&lt;/p&gt;
&lt;p&gt;I did page through the enhancement proposal when it passed through Swift
Evolution, but I just never noticed that it doesn't end there. What you do in
this situation is this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot;&gt;&lt;code&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt; throws&lt;/span&gt;&lt;span&gt;(MyError) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    // throwing code here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; catch&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    // now the compiler doesn't get confused and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    // all is well-typed unicorns and sunshine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you know too.&lt;/p&gt;</description>
	<pubDate>Sat, 15 Aug 2026 11:30:00 +0000</pubDate>
</item>
<item>
	<title>PyCharm</title>
	<guid></guid>
	<link></link>
	<description>&lt;p&gt;Open weight models are having a moment, driven by control, choice, and cost. Hybrid and local AI are now getting serious looks, so JetBrains teamed up with &lt;a href=&quot;https://www.deeplearning.ai&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DeepLearning.AI&lt;/a&gt; on a free &lt;a href=&quot;https://learn.deeplearning.ai/courses/ai-coding-workflows-from-cloud-to-local/lesson/napfi1/introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AI Coding Workflows: Hybrid to Local&lt;/a&gt; course that covers the ideas and options.&lt;/p&gt;



&lt;p&gt;The course is now available and uses &lt;a href=&quot;https://www.jetbrains.com/pycharm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm&lt;/a&gt; and its AI Chat. Here’s a peek into the course.&lt;/p&gt;



&lt;div class=&quot;wp-block-embed__wrapper&quot;&gt;

&lt;/div&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Claude Code: Subagents and cheaper models&lt;/h2&gt;



&lt;p&gt;We start the course with, well, not-local. Instead, we use what you already know – Claude Code and its Anthropic models – to introduce some of the techniques and “levers” that help bring choice, control, and even cost reduction. (Yes, I wrote emdashes.)&lt;/p&gt;



&lt;p&gt;We did a previous course on &lt;a href=&quot;https://www.deeplearning.ai/courses/spec-driven-development-with-coding-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spec-Driven Development&lt;/a&gt; (SDD) so of course, we wanted to start there. Smaller models struggle with big, open-ended “vibe coding.” Dividing and bounding the work keeps smaller models on track. Important note: this course’s example app is &lt;em&gt;really&lt;/em&gt; basic. You might say “that’s too easy.” But that’s part of the takeaway: big brain models can do the upfront work, forming right-sized steps for smaller models.&lt;/p&gt;



&lt;p&gt;We then illustrate this division with a Claude Code &lt;em&gt;subagent&lt;/em&gt;. The main chat prompt implements each roadmap phase in a fresh subagent, to better manage context. This then gives the payoff: a cheaper model for the implementer. Use a “big brain” (Opus) for main conversation thinking and a “little brain” (Haiku) for implementation.&lt;/p&gt;



&lt;p&gt;Each lesson finishes with metrics about the change in tokens, turns, cost, and estimated wall time. Which brings us to the main course goal: learning the &lt;em&gt;ideas&lt;/em&gt; instead of the specifics, which change weekly.&lt;/p&gt;



&lt;img src=&quot;https://blog.jetbrains.com/wp-content/uploads/2026/08/metrics.png&quot; alt=&quot;&quot; class=&quot;wp-image-730947&quot; /&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;New agent, inference, and model&lt;/h2&gt;



&lt;p&gt;That covers the four levers:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Specs shaped for the model size&lt;/li&gt;



&lt;li&gt;Specialist subagents to divide work&lt;/li&gt;



&lt;li&gt;Cheaper models for the routine work&lt;/li&gt;



&lt;li&gt;Collect metrics as evidence to guide thinking&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;br /&gt;The course then introduces choice and control:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;New agent: OpenCode&lt;/li&gt;



&lt;li&gt;New inference router: OpenRouter&lt;/li&gt;



&lt;li&gt;New model and inference host: DeepSeek (via OpenRouter) by moving to a new agent (OpenCode) using inference routing (OpenRouter) to inference hosting and models (DeepSeek)&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;br /&gt;We first move to OpenCode, running in PyCharm. JetBrains wants our IDEs to be &lt;em&gt;open platforms&lt;/em&gt; for agents and models. This makes the move from Claude Code to OpenCode straightforward: it’s the same UI. We add OpenRouter (a paid step), connect it to OpenCode, and choose DeepSeek as a model.&lt;/p&gt;



&lt;p&gt;Next we repeat our sequence: all in one chat, then context isolation using a subagent. But this time, with a different agent and model.&lt;/p&gt;



&lt;p&gt;We finish by making a dedicated implementer subagent in Markdown. This gives quite a number of levers of control: in the frontmatter for mandatory controls, and in the subagent body for “persuasion” guidance. Most importantly, we have the implementer use the smaller DeepSeek v4 Flash model as the “little brain.”&lt;/p&gt;



&lt;p&gt;Compared to the Claude Code version, the metrics were, unsurprisingly, a lot cheaper.&lt;/p&gt;



&lt;img src=&quot;https://blog.jetbrains.com/wp-content/uploads/2026/08/openrouter.png&quot; alt=&quot;&quot; class=&quot;wp-image-730958&quot; /&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Hybrid and Local&lt;/h2&gt;



&lt;p&gt;Now for the main attraction: for routine development, can we do some – or even all – of the work locally?&lt;/p&gt;



&lt;p&gt;We start with a lesson on setting up local AI: LM Studio as the inference server and Gemma 4 12B as the local model, targeting a 32 GB laptop.&lt;/p&gt;



&lt;p&gt;We then configure the implementer subagent to use this local Gemma 4 model, promoting DeepSeek v4 Flash from last lesson’s “little brain” up to “big brain.” The results? Quite good, as it turns out.&lt;/p&gt;



&lt;p&gt;Then the big test: fully local, with Qwen 3.5 27B as the “big brain.” The results: better than expected, showing that guardrails help.&lt;/p&gt;



&lt;p&gt;How did hybrid and local do? Both of these lessons finish with a review of the metrics. That’s one of the big course takeaways: look at the evidence. You can see how small models struggle, and see the effect of helping them succeed.&lt;/p&gt;



&lt;img src=&quot;https://blog.jetbrains.com/wp-content/uploads/2026/08/lmstudio.png&quot; alt=&quot;&quot; class=&quot;wp-image-730969&quot; /&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Hybrid and Local AI Are Heating Up&lt;/h2&gt;



&lt;p&gt;Much thanks to &lt;a href=&quot;http://deeplearning.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DeepLearning.AI&lt;/a&gt; both for working with us again and for pushing to get this out fast. This topic is now red-hot in the news: Sovereign AI, privacy and security, and of course cost. The innovations are coming really fast and it is important to have a gentle introduction to the fundamentals.&lt;/p&gt;



&lt;p&gt;We’ll do more updates here on Local AI for control, choice, and cost. Most of all, we at PyCharm believe in the human-in-the-loop. Stay tuned for more on this.&lt;/p&gt;


    &lt;div class=&quot;buttons&quot;&gt;
        &lt;div class=&quot;buttons__row&quot;&gt;
                                                &lt;a href=&quot;https://learn.deeplearning.ai/courses/ai-coding-workflows-from-cloud-to-local/lesson/napfi1/introduction&quot; class=&quot;btn&quot; target=&quot;&quot; rel=&quot;noopener&quot;&gt;Enroll for free&lt;/a&gt;
                                                    &lt;/div&gt;
    &lt;/div&gt;</description>
	<pubDate>Thu, 13 Aug 2026 13:41:43 +0000</pubDate>
</item>
<item>
	<title>Python Software Foundation: Announcing the Packaging Council Election Candidates for 2026!</title>
	<guid>https://pyfound.blogspot.com/2026/08/announcing-packaging-council-election.html</guid>
	<link>https://pyfound.blogspot.com/2026/08/announcing-packaging-council-election.html</link>
	<description>&lt;p&gt;What an exciting list! Please take a look at who is running for the inaugural Python Packaging Council (PPC) &lt;a href=&quot;https://www.python.org/nominations/elections/2026-python-packaging-council/nominees/&quot; rel=&quot;nofollow&quot;&gt;on the Nominees page&lt;/a&gt;. This election has 17 nominees for 5 open seats on the council.&lt;/p&gt;
&lt;div class=&quot;markdown-heading&quot;&gt;&lt;h2 class=&quot;heading-element&quot;&gt;Election Overview&lt;/h2&gt;&lt;a class=&quot;anchor&quot; href=&quot;https://gist.github.com/pradyunsg/c83aa751276711bfcaa916595ac927e7/edit#election-overview&quot; id=&quot;user-content-election-overview&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This inaugural election fills all five seats on the PPC. The two 
candidates receiving the highest number of votes shall be designated 
Cohort A with a two year term, and the three candidates receiving the 
next highest number of votes shall be designated Cohort B with a one 
year term.&lt;/p&gt;
&lt;p&gt;In future elections, each cohort will be elected for a full two-year 
term in alternating years, so that roughly half of the PPC turns over 
each cycle.&lt;/p&gt;
&lt;div class=&quot;markdown-heading&quot;&gt;&lt;h3 class=&quot;heading-element&quot;&gt;Election Timeline&lt;/h3&gt;&lt;a class=&quot;anchor&quot; href=&quot;https://gist.github.com/pradyunsg/c83aa751276711bfcaa916595ac927e7/edit#election-timeline&quot; id=&quot;user-content-election-timeline&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;&lt;li&gt;Nominations open: Tuesday, July 28th, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Nomination cut-off: Tuesday, August 11th, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;&lt;b&gt;Announce candidates: Thursday, August 13th&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Voter affirmation cut-off: Tuesday, August 25th, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Voting start date: Tuesday, September 1st, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Voting end date: Tuesday, September 15th, 2:00 pm UTC&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Not sure what UTC is for you locally? Check this &lt;a href=&quot;https://savvytime.com/converter/utc&quot; rel=&quot;nofollow&quot;&gt;UTC time converter&lt;/a&gt;!&lt;/p&gt;
&lt;div class=&quot;markdown-heading&quot;&gt;&lt;h2 class=&quot;heading-element&quot;&gt;Reminder: Affirm your intention to vote&lt;/h2&gt;&lt;a class=&quot;anchor&quot; href=&quot;https://gist.github.com/pradyunsg/c83aa751276711bfcaa916595ac927e7/edit#reminder-affirm-your-intention-to-vote&quot; id=&quot;user-content-reminder-affirm-your-intention-to-vote&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;b&gt;If you wish to vote in this election, you must affirm your 
intention to vote no later than Tuesday, August 25th, 2:00 pm UTC, to 
participate in this election&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Every PSF Voting Member (Supporting, Contributing, and Fellow) needs 
to affirm their membership to vote in this election. Find more 
information, including step-by-step instructions on voting affirmation, 
in our &lt;a href=&quot;https://pyfound.blogspot.com/2026/07/affirm-PSF-voting-status-2026.html&quot; rel=&quot;nofollow&quot;&gt;&quot;Affirm Your PSF Membership Voting Status&quot; blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you run into any issues, or have questions about your membership, please contact &lt;a href=&quot;mailto:pc-elections@python.org&quot;&gt;pc-elections@python.org&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;markdown-heading&quot;&gt;&lt;h2 class=&quot;heading-element&quot;&gt;Voting: What to expect&lt;/h2&gt;&lt;a class=&quot;anchor&quot; href=&quot;https://gist.github.com/pradyunsg/c83aa751276711bfcaa916595ac927e7/edit#voting-what-to-expect&quot; id=&quot;user-content-voting-what-to-expect&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;If you are a voting member of the PSF that affirmed your intention to
 participate in this election, you will receive an email from &quot;OpaVote 
Voting Link &amp;lt;&lt;a href=&quot;mailto:noreply@opavote.com&quot;&gt;noreply@opavote.com&lt;/a&gt;&amp;gt;&quot;
 with your ballot -- the subject line will read &quot;Python Packaging 
Council Election 2026&quot; on September 1st. If you don't receive a ballot 
as expected, please first check your spam folder for a message from &quot;&lt;a href=&quot;mailto:noreply@opavote.com&quot;&gt;noreply@opavote.com&lt;/a&gt;&quot;.&lt;/p&gt;
&lt;p&gt;If you don't see anything, please get in touch by emailing &lt;a href=&quot;mailto:pc-elections@python.org&quot;&gt;pc-elections@python.org&lt;/a&gt; so we can look into your account and make sure we have the most up-to-date email for you.&lt;/p&gt;&lt;br /&gt;</description>
	<pubDate>Thu, 13 Aug 2026 10:13:35 +0000</pubDate>
</item>
<item>
	<title>PyCharm: Hybrid and Local AI course at DeepLearning.AI</title>
	<guid>https://blog.jetbrains.com/pycharm/2026/08/hybrid-and-local-ai-course-at-deeplearning-ai/</guid>
	<link>https://blog.jetbrains.com/pycharm/2026/08/hybrid-and-local-ai-course-at-deeplearning-ai/</link>
	<pubDate>Thu, 13 Aug 2026 10:01:32 +0000</pubDate>
</item>
<item>
	<title>Python Software Foundation: Announcing the PSF Board Candidates for 2026!</title>
	<guid>https://pyfound.blogspot.com/2026/08/announcing-psf-board-candidates-for-2026.html</guid>
	<link>https://pyfound.blogspot.com/2026/08/announcing-psf-board-candidates-for-2026.html</link>
	<description>&lt;p&gt;What an exciting list! Please take a look at &lt;a href=&quot;https://www.python.org/nominations/elections/2026-python-software-foundation-board/nominees/&quot; target=&quot;_blank&quot;&gt;the 18 candidates running for the PSF Board this year on the Nominees page&lt;/a&gt;. This year there are 4 seats open on the PSF Board. You can see who is currently on the board on the &lt;a href=&quot;https://www.python.org/psf/board/&quot; target=&quot;_blank&quot;&gt;PSF Officers &amp;amp; Directors page&lt;/a&gt;. (Cheuk Ting Ho, Christopher Neugebauer, Denny Perez, and Georgi Ker are at the end of their current terms.)&lt;/p&gt;&lt;p&gt;Nomination and supporting statements are the clearest way to see how each candidate actually thinks: their priorities, experience, and vision for the PSF. Rather than just voting on name recognition, we encourage you to read each candidate's nomination and supporting statements. PSF Board members shape real decisions about budget, programs, and the direction of the PSF. Reading these statements helps ensure your vote reflects what the candidates would actually do in the role.&amp;nbsp;&lt;/p&gt;&lt;h2&gt;Board Election Timeline:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Nominations open: Tuesday, July 28th, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Nomination cut-off: Tuesday, August 11th, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Announce candidates: Thursday, August 13th&lt;/li&gt;&lt;li&gt;Voter affirmation cut-off: Tuesday, August 25th, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Voting start date: Tuesday, September 1st, 2:00 pm UTC&lt;/li&gt;&lt;li&gt;Voting end date: Tuesday, September 15th, 2:00 pm UTC&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Not sure what UTC is for you locally? Check this &lt;a href=&quot;https://savvytime.com/converter/utc&quot; target=&quot;_blank&quot;&gt;UTC time converter&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Reminder to affirm your intention to vote!&lt;/h2&gt;&lt;p&gt;&lt;b&gt;If you wish to vote in this year’s election, you must affirm your intention to vote no later than Tuesday, August 25th, 2:00 pm UTC, to participate in this year’s election.&lt;/b&gt; This year’s Board Election vote begins Tuesday, September 1st, 2:00 pm UTC, and closes on Tuesday, September 15th, 2:00 pm UTC.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Every PSF Voting Member (Supporting, Contributing, and Fellow) needs to affirm their membership to vote in this year’s election. You should have received an email from &quot;psf@psfmember.org &amp;lt;Python Software Foundation&amp;gt;&quot; with the subject &quot;[Action Required] Affirm your PSF Membership voting intention for 2026 PSF Board Election&quot; that contains information on how to affirm your voting status.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Per a recent Bylaw change that allows for &lt;a href=&quot;https://github.com/python/psf-bylaws/compare/a35a6071de181adbb7a160d5d1447e7b0272359c...6bac449&quot; target=&quot;_blank&quot;&gt;simplifying the voter affirmation process by treating past voting activity as intent to continue voting&lt;/a&gt;, if you voted last year, you will automatically be added to the 2026 voter roll. &lt;i&gt;Please note: If you removed or changed your email on psfmember.org, you may not automatically be added to this year's voter roll.&amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Find more information, including step-by-step instructions on voting affirmation, in our&amp;nbsp; ‘&lt;a href=&quot;https://pyfound.blogspot.com/2026/07/affirm-PSF-voting-status-2026.html&quot; target=&quot;_blank&quot;&gt;Affirm Your PSF Membership Voting Status&lt;/a&gt;” blog post. If you run into any issues, or have questions about your membership, please contact psf-elections@pyfound.org.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Voting: what to expect&lt;/h2&gt;&lt;p&gt;If you are a voting member of the PSF that affirmed your intention to participate in this year’s election, you will receive an email from “OpaVote Voting Link &amp;lt;noreply@opavote.com&amp;gt;” with your ballot, the subject line will read “Python Software Foundation Board of Directors Election 2026” on September 1st. If you don’t receive a ballot as expected, please first check your spam folder for a message from “noreply@opavote.com”. If you don’t see anything get in touch by emailing psf-elections@pyfound.org so we can look into your account and make sure we have the most up-to-date email for you.&lt;/p&gt;&lt;p&gt;If you have questions about your membership status or the election, please email psf-elections@pyfound.org. You are welcome to join &lt;a href=&quot;https://discuss.python.org/t/2026-psf-board-election/107797&quot; target=&quot;_blank&quot;&gt;the discussion about the PSF Board election on the Python Discuss forum&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Thu, 13 Aug 2026 09:59:40 +0000</pubDate>
</item>
<item>
	<title>Wingware: Wing Python IDE Version 12.0.2 - August 13, 2026</title>
	<guid>https://wingware.com/news/2026-08-13</guid>
	<link>https://wingware.com/news/2026-08-13</link>
	<description>&lt;p&gt;Wing Python IDE version 12.0.2 has been released. This release adds a native
ARM64 Windows version of Wing, improves remote development on Windows,
streamlines Claude Code setup, and improves performance and responsiveness,
particularly when working with very large projects and on Windows. It also
reduces the size of the analysis cache database by about 20% and fixes a
number of bugs. See the &lt;a class=&quot;reference&quot; href=&quot;https://wingware.com/pub/wingpro/12.0.2.0/CHANGELOG.txt&quot;&gt;change log&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;Wing 12 integrates the Claude Code AI coding agent directly into the IDE, with a
new &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Claude&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Code&lt;/span&gt;&lt;/tt&gt; tool, a &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool for planning and reviewing AI agent
work, and a set of MCP servers that give the agent access to Wing's source code
analysis, unit testing, debugger, and code review features.  See the list of
Wing 12 features below for details.&lt;/p&gt;
&lt;img src=&quot;https://wingware.com/images/screenshots/wing12-screenshot.png&quot; alt=&quot;Wing 12 Screen Shot&quot; class=&quot;eye-candy-image unfloat-at-900&quot; width=&quot;650px&quot; /&gt;&lt;h3&gt;Downloads&lt;/h3&gt;&lt;div class=&quot;note&quot;&gt;
After installing Wing 12, be sure to &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Check&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Updates&lt;/span&gt;&lt;/tt&gt; in Wing's &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Help&lt;/span&gt;&lt;/tt&gt; menu
so that you have the latest hot fixes.&lt;/div&gt;
&lt;p&gt;&lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/downloads&quot;&gt;Wing 12&lt;/a&gt; -- the full Python IDE, available as Wing Pro (for
agentic development) or Wing Classic (for manual development) depending on
your license, with a free 30-day trial of Wing Pro.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/downloads/wing-101&quot;&gt;Wing 101 v. 12&lt;/a&gt; -- a simplified free Python IDE for
teaching beginning programmers.&lt;/p&gt;
&lt;p&gt;Wing 11 and earlier versions are not affected by installation of Wing 12 and may be
installed and used independently.  However, project files for Wing 11 and earlier are
converted when opened by Wing 12 and should be saved under a new name, since Wing 12
projects cannot be opened by older versions of Wing.&lt;/p&gt;
&lt;h2&gt;New in Wing 12&lt;/h2&gt;&lt;h3&gt;AI Coding Agent Integration with Claude Code&lt;/h3&gt;&lt;p&gt;Wing 12 adds a &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Claude&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Code&lt;/span&gt;&lt;/tt&gt; tool that integrates the Claude Code AI coding agent
with the IDE.  &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Up&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Claude&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Code&lt;/span&gt;&lt;/tt&gt; in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Project&lt;/span&gt;&lt;/tt&gt; menu configures
the active project for AI agent development.&lt;/p&gt;
&lt;p&gt;A set of MCP (Model Context Protocol) servers gives Claude Code access to Wing's source
code analysis, testing, and debugger functionality, so the agent can more efficiently
navigate and understand your code, write, run, and fix unit tests, and use the
debugger to diagnose difficult runtime errors.  In our &lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/psupport/wing12/benchmarks/bench-intro.html&quot;&gt;benchmarks&lt;/a&gt;, giving Claude Code access to Wing's
MCP servers made agent-driven coding tasks both faster and cheaper.&lt;/p&gt;
&lt;h3&gt;Tasks Tool&lt;/h3&gt;&lt;p&gt;The new &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool lets you plan, queue, execute, review, and audit the
history of AI agent development tasks, making it easier to supervise and inspect
the agent's work before committing it to revision control.&lt;/p&gt;
&lt;h3&gt;FIX Features and Write Tests&lt;/h3&gt;&lt;p&gt;Wing 12 adds AI agent driven &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;FIX&lt;/span&gt;&lt;/tt&gt; features that hand the current debugger
bug, failing unit tests, or code warnings to Claude Code for resolution. New
&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Write&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Tests&lt;/span&gt;&lt;/tt&gt; items in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Testing&lt;/span&gt;&lt;/tt&gt; and editor context menus prompt the
agent to write unit tests for selected code.&lt;/p&gt;
&lt;h3&gt;Code Actions&lt;/h3&gt;&lt;p&gt;Wing 12 also adds AI &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Code&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Actions&lt;/span&gt;&lt;/tt&gt;, accessed from the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;FIX&lt;/span&gt;&lt;/tt&gt; icon in the
editor toolbar, that operate on selected code or the enclosing scope.
Built-in actions include explaining code, reviewing it for quality or
security risks, fixing code warnings, optimizing for performance, and
updating comments and docstrings. The action list is user-extensible, so you
can add your own prompts for tasks you run often.&lt;/p&gt;
&lt;h3&gt;Pseudo-Terminal for OS Commands and Debug I/O&lt;/h3&gt;&lt;p&gt;The &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;OS&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Commands&lt;/span&gt;&lt;/tt&gt; and &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Debug&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;I/O&lt;/span&gt;&lt;/tt&gt; tools now default to using a pseudo-terminal
that implements full ANSI terminal emulation, so you can run and debug programs that
use color output, cursor positioning, or full-screen TUIs.&lt;/p&gt;
&lt;h3&gt;Redesigned OS Commands Capability&lt;/h3&gt;&lt;p&gt;The &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;OS&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Commands&lt;/span&gt;&lt;/tt&gt; tool has been replaced with configurable OS Commands in
the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tools&lt;/span&gt;&lt;/tt&gt; menu. Each OS Command acts like its own tool, for use in any
tool or editor split.&lt;/p&gt;
&lt;h3&gt;Tools in Editor Splits and Reorganized Tools Menu&lt;/h3&gt;&lt;p&gt;Tools can now also be added or dragged to editor splits, allowing for much
more flexible workspace layout. The &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tools&lt;/span&gt;&lt;/tt&gt; menu has been reorganized into
related groups, with less-used and legacy tools in an &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Other&lt;/span&gt;&lt;/tt&gt; sub-menu, so
more commonly used tools are easier to find.&lt;/p&gt;
&lt;h3&gt;Test Discovery and Preferences Search&lt;/h3&gt;&lt;p&gt;Wing 12 adds automatic test file discovery and discovery of individual unit tests
within files, so you usually don't need to specify test file patterns or add test
files individually.  The &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Preferences&lt;/span&gt;&lt;/tt&gt; dialog now supports text search and
back/forward navigation.&lt;/p&gt;
&lt;h3&gt;Other Minor Features and Improvements&lt;/h3&gt;&lt;p&gt;Wing 12 also includes many other improvements, including:&lt;/p&gt;
&lt;div class=&quot;bullet-list&quot;&gt;&lt;ul&gt;&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;IDE build for ARM64 Windows&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Improved performance and responsiveness&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Improved remote agent installation and remote development&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Significantly faster source code analysis&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Prompts for SSH passphrases and HTTPS credentials when needed during VCS operations&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Faster detection of externally modified files, with reduced CPU load&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Saving and restoring of tool console scrollback across project close and reopen&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;Clickable OSC 8 hyperlinks in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;OS&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Commands&lt;/span&gt;&lt;/tt&gt; and &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Debug&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;I/O&lt;/span&gt;&lt;/tt&gt; tools&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;A preference to select the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;ssh&lt;/span&gt;&lt;/tt&gt; or &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;plink.exe&lt;/span&gt;&lt;/tt&gt; SSH implementation&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;A notice on the next startup when Wing's previous session ended in an unexpected crash&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;Wing 12 also makes a number of other bug fixes and usability improvements.&lt;/p&gt;
&lt;h3&gt;Product Line Changes&lt;/h3&gt;&lt;p&gt;Wing 12 simplifies the product line.  The Commercial / Non-Commercial use distinction
has been replaced by two feature-based product tiers:&lt;/p&gt;
&lt;div class=&quot;bullet-list&quot;&gt;&lt;ul&gt;&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Wing&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Pro&lt;/span&gt;&lt;/tt&gt; -- the full-featured Python IDE including AI agent development tools&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;bullet&quot;&gt;&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Wing&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Classic&lt;/span&gt;&lt;/tt&gt; -- the complete traditional Python IDE for hands-on development,
with no AI agent features&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;Anyone may purchase either tier for any purpose. Existing Commercial and
Non-Commercial Use licenses both become &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Wing&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Pro&lt;/span&gt;&lt;/tt&gt;. Customers who don't
need the AI agent features may move to &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Wing&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Classic&lt;/span&gt;&lt;/tt&gt; at renewal time, or
any time sooner by contacting &lt;a class=&quot;reference&quot; href=&quot;mailto:support@wingware.com&quot;&gt;support&amp;#64;wingware.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Wing&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Personal&lt;/span&gt;&lt;/tt&gt; has been discontinued.  Existing Wing Personal users may continue
to use Personal 11.x indefinitely, switch to free Wing 101, or purchase a Wing Classic
license.  See &lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/store&quot;&gt;Pricing&lt;/a&gt; for details.&lt;/p&gt;
&lt;h3&gt;Changes and Incompatibilities&lt;/h3&gt;&lt;p&gt;The single-LLM-query AI features originally introduced in Wing 11 (the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt;
&lt;span class=&quot;pre&quot;&gt;Coder&lt;/span&gt;&lt;/tt&gt; and &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Chat&lt;/span&gt;&lt;/tt&gt; tools) are considered legacy in Wing 12 and hidden
from the user interface by default. They remain available in projects that
already use them and can be re-enabled with &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Properties&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt;&lt;/tt&gt; in
Project Properties or in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Projects&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt;&lt;/tt&gt; preferences.&lt;/p&gt;
&lt;p&gt;See &lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/wingide/agent&quot;&gt;Wing's Claude Code Agent Integration&lt;/a&gt; for Wing 12's
AI agent approach.&lt;/p&gt;
&lt;p&gt;If you have questions, please don't hesitate to contact us at
&lt;a class=&quot;reference&quot; href=&quot;mailto:support@wingware.com&quot;&gt;support&amp;#64;wingware.com&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Thu, 13 Aug 2026 01:00:00 +0000</pubDate>
</item>
<item>
	<title>Trey Hunner: Reorganizing Python's sys module</title>
	<guid>https://treyhunner.com/2026/08/reorganizing-pythons-sys-module/</guid>
	<link>https://treyhunner.com/2026/08/reorganizing-pythons-sys-module/</link>
	<description>&lt;p&gt;The &lt;code&gt;sys&lt;/code&gt; module is &lt;strong&gt;the primary junk drawer&lt;/strong&gt; of the Python standard library.&lt;/p&gt;

&lt;p&gt;A good junk drawer holds miscellaneous items that don&amp;rsquo;t have another sensible home.&lt;/p&gt;

&lt;p&gt;I often think of &lt;code&gt;utils&lt;/code&gt; modules as &amp;ldquo;junk drawer&amp;rdquo; modules.
I believe that both &lt;code&gt;utils&lt;/code&gt; modules and junk drawers have their purpose, but junk drawers can get out of hand.&lt;/p&gt;

&lt;p&gt;As I recently noted in &lt;a href=&quot;https://treyhunner.com/pathlib-talk/&quot;&gt;my talk about pathlib&lt;/a&gt;, I see both the &lt;code&gt;sys&lt;/code&gt; module and &lt;a href=&quot;https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/&quot;&gt;the &lt;code&gt;os&lt;/code&gt; module&lt;/a&gt; as &lt;strong&gt;junk drawer modules&lt;/strong&gt;.
They serve a similar purpose to &lt;code&gt;utils&lt;/code&gt; modules, but they have a different name.&lt;/p&gt;

&lt;p&gt;In this post, I wonder: what would Python&amp;rsquo;s &lt;code&gt;sys&lt;/code&gt; be like if it was designed today, from scratch?&lt;/p&gt;

&lt;h2&gt;The overview: 9 new &lt;code&gt;sys&lt;/code&gt; submodules&lt;/h2&gt;

&lt;p&gt;As of Python 3.15, the &lt;code&gt;sys&lt;/code&gt; module has 115-121 attributes (depending on whether you&amp;rsquo;re in the REPL and whether an exception has occurred), and 63 of those are functions.&lt;/p&gt;

&lt;p&gt;All of those names need permanent homes.&lt;/p&gt;

&lt;p&gt;How can we reorganize a &lt;code&gt;utils&lt;/code&gt;-style module that&amp;rsquo;s grown &lt;em&gt;quite&lt;/em&gt; large?&lt;/p&gt;

&lt;p&gt;Give it submodules!&lt;/p&gt;

&lt;p&gt;No, really&amp;hellip; this isn&amp;rsquo;t the &lt;em&gt;worst&lt;/em&gt; solution.
&lt;a href=&quot;https://docs.djangoproject.com/en/stable/ref/utils/&quot;&gt;Django&amp;rsquo;s &lt;code&gt;utils&lt;/code&gt; package&lt;/a&gt; isn&amp;rsquo;t so bad.&lt;/p&gt;

&lt;p&gt;So we could split &lt;code&gt;sys&lt;/code&gt; into these 9 submodules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sys.cli&lt;/code&gt;: for command-line argument handling and program control&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.imports&lt;/code&gt;: related to imports and modules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.io&lt;/code&gt;: handles standard I/O streams&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.repl&lt;/code&gt;: handles REPL display control&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.interpreter&lt;/code&gt;: system information and installation details&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.memory&lt;/code&gt;: memory management tools used for profiling, optimization, and debugging&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.exceptions&lt;/code&gt;: exception handling&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.profile&lt;/code&gt;: profiling and introspection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys.runtime&lt;/code&gt;: interpreter runtime behavior&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;You may notice some similarities to other modules in the Python standard library.
That&amp;rsquo;s a hint that it &lt;em&gt;might&lt;/em&gt; be worth moving some of these utilities into &lt;em&gt;other parts&lt;/em&gt; of the standard library.
But moving functionality between top-level modules is a much bigger change, so let&amp;rsquo;s set that idea aside.&lt;/p&gt;

&lt;p&gt;For now, let&amp;rsquo;s take a closer look at our tentatively re-organized &lt;code&gt;sys&lt;/code&gt; package.&lt;/p&gt;

&lt;h2&gt;The &lt;code&gt;sys&lt;/code&gt; package and its submodules&lt;/h2&gt;

&lt;p&gt;A couple of these 9 submodules have only a handful of attributes, a couple have over 20, and the rest fall somewhere in the middle.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;sys.cli&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This submodule would handle command-line arguments and program control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;argv&lt;/code&gt;: Command-line arguments list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;orig_argv&lt;/code&gt;: Original unmodified arguments&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exit()&lt;/code&gt;: Function to terminate Python&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flags&lt;/code&gt;: Named tuple of interpreter flags&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_xoptions&lt;/code&gt;: Dictionary of &lt;code&gt;-X&lt;/code&gt; command options&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.imports&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Everything related to imports and modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt;: Module search path list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modules&lt;/code&gt;: Dictionary of loaded modules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;builtin_module_names&lt;/code&gt;: Tuple of built-in modules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stdlib_module_names&lt;/code&gt;: Frozen set of standard library modules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path_hooks&lt;/code&gt;: List of path-to-finder callables&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path_importer_cache&lt;/code&gt;: Finder object cache&lt;/li&gt;
&lt;li&gt;&lt;code&gt;meta_path&lt;/code&gt;: Meta path finder objects&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pycache_prefix&lt;/code&gt;: Bytecode cache directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set_lazy_imports()&lt;/code&gt;, &lt;code&gt;get_lazy_imports()&lt;/code&gt;, &lt;code&gt;set_lazy_imports_filter()&lt;/code&gt;, &lt;code&gt;get_lazy_imports_filter()&lt;/code&gt;, &lt;code&gt;lazy_modules&lt;/code&gt;: Lazy import controls (Python 3.15+)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.io&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The standard I/O streams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stdin&lt;/code&gt;: Standard input stream&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stdout&lt;/code&gt;: Standard output stream&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stderr&lt;/code&gt;: Standard error stream&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__stdin__&lt;/code&gt;, &lt;code&gt;__stdout__&lt;/code&gt;, &lt;code&gt;__stderr__&lt;/code&gt;: The original values of those three streams (useful for restoring them after replacing them)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.repl&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Hooks and settings for Python&amp;rsquo;s interactive prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;displayhook()&lt;/code&gt;: Called to show the result of each REPL expression&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__displayhook__&lt;/code&gt;: The original value of &lt;code&gt;displayhook&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps1&lt;/code&gt;: The primary prompt string (&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps2&lt;/code&gt;: The continuation prompt string (&lt;code&gt;...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__interactivehook__&lt;/code&gt;: Called when an interactive session starts up&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_baserepl()&lt;/code&gt;: Starts the basic fallback REPL&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.interpreter&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Information about the Python build, the Python installation, and the operating system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;platform&lt;/code&gt;: Platform identifier string (&lt;code&gt;linux&lt;/code&gt;, &lt;code&gt;darwin&lt;/code&gt;, &lt;code&gt;win32&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;version&lt;/code&gt;: Python version string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;version_info&lt;/code&gt;: Python version as a named tuple&lt;/li&gt;
&lt;li&gt;&lt;code&gt;implementation&lt;/code&gt;: Python implementation details (CPython, PyPy, etc.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;executable&lt;/code&gt;: Path to the Python interpreter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;/code&gt;, &lt;code&gt;exec_prefix&lt;/code&gt;: Installation prefixes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;base_prefix&lt;/code&gt;, &lt;code&gt;base_exec_prefix&lt;/code&gt;: Installation prefixes, ignoring virtual environments&lt;/li&gt;
&lt;li&gt;&lt;code&gt;platlibdir&lt;/code&gt;: Platform-specific library directory name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxunicode&lt;/code&gt;: Maximum Unicode code point (1114111)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxsize&lt;/code&gt;: Maximum size of containers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;byteorder&lt;/code&gt;: Native byte order (&lt;code&gt;'little'&lt;/code&gt; or &lt;code&gt;'big'&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hexversion&lt;/code&gt;: Version encoded as single integer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;api_version&lt;/code&gt;: C API version&lt;/li&gt;
&lt;li&gt;&lt;code&gt;copyright&lt;/code&gt;: Python copyright notice&lt;/li&gt;
&lt;li&gt;&lt;code&gt;abiflags&lt;/code&gt;: ABI flags from PEP 3149&lt;/li&gt;
&lt;li&gt;&lt;code&gt;abi_info&lt;/code&gt;: ABI details namespace (Python 3.15+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;float_info&lt;/code&gt;: Floating point implementation details&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int_info&lt;/code&gt;: Integer implementation details&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hash_info&lt;/code&gt;: Hash algorithm parameters&lt;/li&gt;
&lt;li&gt;&lt;code&gt;float_repr_style&lt;/code&gt;: float &lt;code&gt;repr&lt;/code&gt; style (&lt;code&gt;'short'&lt;/code&gt; or &lt;code&gt;'legacy'&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;winver&lt;/code&gt;, &lt;code&gt;dllhandle&lt;/code&gt;, &lt;code&gt;getwindowsversion()&lt;/code&gt;: Windows-specific details&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getandroidapilevel()&lt;/code&gt;: Android-specific detail&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_base_executable&lt;/code&gt;, &lt;code&gt;_framework&lt;/code&gt;, &lt;code&gt;_git&lt;/code&gt;, &lt;code&gt;_home&lt;/code&gt;, &lt;code&gt;_stdlib_dir&lt;/code&gt;: Assorted build and installation details&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.memory&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Memory management tools used for profiling, optimization, and debugging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getsizeof()&lt;/code&gt;: Size of an object in bytes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getrefcount()&lt;/code&gt;: Number of references to an object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getallocatedblocks()&lt;/code&gt;: Number of allocated memory blocks&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getunicodeinternedsize()&lt;/code&gt;: Number of interned strings&lt;/li&gt;
&lt;li&gt;&lt;code&gt;intern()&lt;/code&gt;: Intern a string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_is_interned()&lt;/code&gt;: Check whether a string is interned&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_is_immortal()&lt;/code&gt;: Check whether an object is immortal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_debugmallocstats()&lt;/code&gt;: Print memory allocator statistics&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_clear_type_cache()&lt;/code&gt;, &lt;code&gt;_clear_internal_caches()&lt;/code&gt;: Clear interpreter caches&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.exceptions&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Tools for accessing and handling exceptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exc_info()&lt;/code&gt;: Currently handled exception, as a 3-tuple&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exception()&lt;/code&gt;: Currently handled exception (Python 3.11+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;last_exc&lt;/code&gt;, &lt;code&gt;last_type&lt;/code&gt;, &lt;code&gt;last_value&lt;/code&gt;, &lt;code&gt;last_traceback&lt;/code&gt;: The most recent unhandled exception, mostly for REPL use&lt;/li&gt;
&lt;li&gt;&lt;code&gt;excepthook()&lt;/code&gt;: Called to display unhandled exceptions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__excepthook__&lt;/code&gt;: The original value of &lt;code&gt;excepthook&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unraisablehook()&lt;/code&gt;: Called for exceptions that can&amp;rsquo;t be raised&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__unraisablehook__&lt;/code&gt;: The original value of &lt;code&gt;unraisablehook&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tracebacklimit&lt;/code&gt;: Maximum number of traceback levels to display&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.profile&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Profiling, tracing, auditing, and other runtime introspection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setprofile()&lt;/code&gt;, &lt;code&gt;getprofile()&lt;/code&gt;: Profiling hooks&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_setprofileallthreads()&lt;/code&gt;: Set profile function for all threads (Python 3.12+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settrace()&lt;/code&gt;, &lt;code&gt;gettrace()&lt;/code&gt;: Tracing hooks&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_settraceallthreads()&lt;/code&gt;: Set trace function for all threads (Python 3.12+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;call_tracing()&lt;/code&gt;: Call a function with tracing enabled&lt;/li&gt;
&lt;li&gt;&lt;code&gt;monitoring&lt;/code&gt;: Low-overhead monitoring events namespace (Python 3.12+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_getframe()&lt;/code&gt;, &lt;code&gt;_getframemodulename()&lt;/code&gt;: Frame inspection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_current_frames()&lt;/code&gt;, &lt;code&gt;_current_exceptions()&lt;/code&gt;: Frames and exceptions across all threads&lt;/li&gt;
&lt;li&gt;&lt;code&gt;activate_stack_trampoline()&lt;/code&gt;, &lt;code&gt;deactivate_stack_trampoline()&lt;/code&gt;, &lt;code&gt;is_stack_trampoline_active()&lt;/code&gt;: Support for the perf profiler (Python 3.12+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audit()&lt;/code&gt;: Raise an auditing event&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addaudithook()&lt;/code&gt;: Register an audit hook&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remote_exec()&lt;/code&gt;, &lt;code&gt;is_remote_debug_enabled()&lt;/code&gt;: Remote debugging support (Python 3.14+)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;&lt;code&gt;sys.runtime&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Settings that control interpreter runtime behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setrecursionlimit()&lt;/code&gt;, &lt;code&gt;getrecursionlimit()&lt;/code&gt;: Recursion depth control&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setswitchinterval()&lt;/code&gt;, &lt;code&gt;getswitchinterval()&lt;/code&gt;: Thread switching control&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_finalizing()&lt;/code&gt;: Whether the interpreter is shutting down&lt;/li&gt;
&lt;li&gt;&lt;code&gt;breakpointhook()&lt;/code&gt;: Called by the built-in &lt;code&gt;breakpoint&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__breakpointhook__&lt;/code&gt;: The original value of &lt;code&gt;breakpointhook&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dont_write_bytecode&lt;/code&gt;: Suppress &lt;code&gt;.pyc&lt;/code&gt; file generation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;warnoptions&lt;/code&gt;: Warning filter settings&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getfilesystemencoding()&lt;/code&gt;, &lt;code&gt;getfilesystemencodeerrors()&lt;/code&gt;: Filesystem encoding details&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getdefaultencoding()&lt;/code&gt;: Default string encoding (always &lt;code&gt;utf-8&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_int_max_str_digits()&lt;/code&gt;, &lt;code&gt;set_int_max_str_digits()&lt;/code&gt;: Limit on int-to-string conversion (Python 3.11+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setdlopenflags()&lt;/code&gt;, &lt;code&gt;getdlopenflags()&lt;/code&gt;: Dynamic loading control&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thread_info&lt;/code&gt;: Thread implementation details&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_is_gil_enabled()&lt;/code&gt;: Whether the GIL is enabled (Python 3.13+)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_jit&lt;/code&gt;: JIT compiler introspection namespace&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_dump_tracelets()&lt;/code&gt;: Dump the JIT&amp;rsquo;s internal tracelets&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_get_cpu_count_config()&lt;/code&gt;: Configured CPU count override&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_asyncgen_hooks()&lt;/code&gt;, &lt;code&gt;set_asyncgen_hooks()&lt;/code&gt;: Async generator lifecycle hooks&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_coroutine_origin_tracking_depth()&lt;/code&gt;, &lt;code&gt;set_coroutine_origin_tracking_depth()&lt;/code&gt;: Coroutine debugging depth&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_enablelegacywindowsfsencoding()&lt;/code&gt;: Windows mbcs encoding compatibility&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Could this actually be done?&lt;/h2&gt;

&lt;p&gt;When I first pondered this experiment last year, this was a very hypothetical thought experiment that I assumed could never be done.
I still &lt;em&gt;mostly&lt;/em&gt; feel the same way.&lt;/p&gt;

&lt;p&gt;There are a few big problems with such a refactoring:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What would the transition period look like for the &lt;em&gt;huge&lt;/em&gt; amount of code that currently uses existing &lt;code&gt;sys&lt;/code&gt; features?&lt;/li&gt;
&lt;li&gt;Would backwards compatibility be maintained forever? If so, would this cause more confusion than it&amp;rsquo;s worth?&lt;/li&gt;
&lt;li&gt;How would code that monkey patches attributes like &lt;code&gt;sys.stdout&lt;/code&gt; work?&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;I thought the third question was the biggest roadblock, but I now think it&amp;rsquo;s the first 2 questions.&lt;/p&gt;

&lt;p&gt;Those first 2 questions are big questions and I haven&amp;rsquo;t thoroughly thought through the upsides and downsides of such a refactoring.&lt;/p&gt;

&lt;p&gt;That third question is a technical one, but I &lt;em&gt;think&lt;/em&gt; I can answer it&amp;hellip; but the answer is messy.&lt;/p&gt;

&lt;h2&gt;The magic of module-level &lt;code&gt;__setattr__&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;When Python users want to capture all output from their program to a file, they reassign &lt;code&gt;sys.stdout&lt;/code&gt; to an in-memory file-like object.
That&amp;rsquo;s how the &lt;a href=&quot;https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout&quot;&gt;&lt;code&gt;contextlib.redirect_stdout&lt;/code&gt;&lt;/a&gt; helper works, and many testing tools use the same technique.&lt;/p&gt;

&lt;p&gt;This monkey patching of &lt;code&gt;sys.stdout&lt;/code&gt; is &lt;strong&gt;somewhat common&lt;/strong&gt;, which poses a bit of a problem for us.&lt;/p&gt;

&lt;p&gt;Imagine that &lt;code&gt;stdout&lt;/code&gt; &lt;em&gt;actually&lt;/em&gt; lived in a &lt;code&gt;sys.io&lt;/code&gt; submodule.
If &lt;code&gt;sys.stdout&lt;/code&gt; and &lt;code&gt;sys.io.stdout&lt;/code&gt; were two separate attributes, code that assigned to one would be invisible to code that read from the other.&lt;/p&gt;

&lt;p&gt;We need a way to synchronize reads and writes of the old flat &lt;code&gt;sys&lt;/code&gt; namespace to &lt;strong&gt;forward them&lt;/strong&gt; to the newly nested namespace within the right submodule.&lt;/p&gt;

&lt;p&gt;Python has supported customizing module-level attribute &lt;em&gt;reads&lt;/em&gt; since Python 3.7, thanks to module-level &lt;code&gt;__getattr__&lt;/code&gt; functions (&lt;a href=&quot;https://peps.python.org/pep-0562/&quot;&gt;PEP 562&lt;/a&gt;).
But Python doesn&amp;rsquo;t support module-level &lt;code&gt;__setattr__&lt;/code&gt; functions (that idea was proposed in &lt;a href=&quot;https://peps.python.org/pep-0726/&quot;&gt;PEP 726&lt;/a&gt; and rejected).&lt;/p&gt;

&lt;p&gt;Although&amp;hellip; every Python module is an instance of &lt;code&gt;ModuleType&lt;/code&gt;, and &lt;strong&gt;Python allows changing the class of a module object&lt;/strong&gt;.
If we swap in a &lt;code&gt;ModuleType&lt;/code&gt; subclass, we can define whatever &lt;code&gt;__getattr__&lt;/code&gt; and &lt;code&gt;__setattr__&lt;/code&gt; behavior we&amp;rsquo;d like.&lt;/p&gt;

&lt;p&gt;This trick is demonstrated in a proof-of-concept &lt;a href=&quot;https://github.com/treyhunner/newsys&quot;&gt;&lt;code&gt;newsys&lt;/code&gt; package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;newsys&lt;/code&gt; package reimplements &lt;code&gt;sys&lt;/code&gt; as a package with 9 submodules.
As a proof of concept, this module simply proxies to the &lt;code&gt;sys&lt;/code&gt; module.
All reads and writes of &lt;code&gt;newsys.io.stdout&lt;/code&gt; &lt;em&gt;or&lt;/em&gt; &lt;code&gt;newsys.stdout&lt;/code&gt; proxy to the original &lt;code&gt;sys.stdout&lt;/code&gt; (since that&amp;rsquo;s what everything else still uses under the hood in the existing Python interpreter).&lt;/p&gt;

&lt;h2&gt;What would the transition look like?&lt;/h2&gt;

&lt;p&gt;If this transition was ever &lt;em&gt;actually&lt;/em&gt; done, I imagine it might look something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the submodules, with every old flat name still working via forwarding&lt;/li&gt;
&lt;li&gt;Update the documentation to nudge folks toward the new names&lt;/li&gt;
&lt;li&gt;Soft deprecate the flat names someday (or maybe never)&lt;/li&gt;
&lt;li&gt;(Likely never) hard deprecate the flat names&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;There&amp;rsquo;s a &lt;em&gt;tiny bit&lt;/em&gt; of precedent for &lt;code&gt;sys&lt;/code&gt; submodules: &lt;code&gt;sys.monitoring&lt;/code&gt; (added in Python 3.12) is an actual module that lives under &lt;code&gt;sys&lt;/code&gt;.
But since &lt;code&gt;sys&lt;/code&gt; isn&amp;rsquo;t a package, &lt;code&gt;import sys.monitoring&lt;/code&gt; doesn&amp;rsquo;t work, as noted at the top of the &lt;a href=&quot;https://docs.python.org/3/library/sys.monitoring.html&quot;&gt;&lt;code&gt;sys.monitoring&lt;/code&gt; documentation page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But, I doubt this will ever be done.
Python isn&amp;rsquo;t known for reorganizing modules just to clean things up (outside of the big Python 2/3 split).&lt;/p&gt;

&lt;p&gt;Removing names like &lt;code&gt;sys.path&lt;/code&gt; and &lt;code&gt;sys.argv&lt;/code&gt; would break a &lt;em&gt;huge&lt;/em&gt; amount of code&amp;hellip; and I can imagine Python tutorials and long-time Python users dragging their feet on re-learning &amp;ldquo;the new way&amp;rdquo;.
After all&amp;hellip; why re-learn something when the old version already works and isn&amp;rsquo;t going anywhere?&lt;/p&gt;

&lt;p&gt;If this was ever done, the flat names might need to keep working &lt;em&gt;forever&lt;/em&gt;, and permanent aliases might cause more confusion than such a reorganization is worth.&lt;/p&gt;

&lt;h2&gt;A thought experiment, not a proposal&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m not seriously proposing that we actually reorganize &lt;code&gt;sys&lt;/code&gt;&amp;hellip; at least not seriously enough to draft a PEP.&lt;/p&gt;

&lt;p&gt;But I do think there&amp;rsquo;s a practical takeaway here for our own code.
When a &lt;code&gt;utils&lt;/code&gt; module grows out of hand, submodules can help.
And if other code relies on the old flat names, a module-level &lt;code&gt;__getattr__&lt;/code&gt; function (or that hacky &lt;code&gt;__class__&lt;/code&gt; trick) can keep the old names working while you reorganize.&lt;/p&gt;

&lt;p&gt;I doubt &lt;code&gt;sys&lt;/code&gt; will ever change, but I had fun imagining a version of Python where it did.&lt;/p&gt;</description>
	<pubDate>Thu, 13 Aug 2026 00:30:00 +0000</pubDate>
</item>
<item>
	<title>Python Insider: Announcing the Packaging Council Election Candidates for 2026!</title>
	<guid>https://blog.python.org/2026/08/2026-packaging-council-nominees/</guid>
	<link>https://blog.python.org/2026/08/2026-packaging-council-nominees/</link>
	<description>Announcing the 17 nominees for the inaugural Python Packaging Council election, and how to vote in the election.</description>
	<pubDate>Thu, 13 Aug 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Django Weblog: DSF Office Hours</title>
	<guid>https://www.djangoproject.com/weblog/2026/aug/12/dsf-office-hours/</guid>
	<link>https://www.djangoproject.com/weblog/2026/aug/12/dsf-office-hours/</link>
	<description>&lt;p&gt;The DSF Board hosts open office hours every Wednesday at 6:00 PM UTC (&lt;a href=&quot;https://time.is/compare/6pm_12_Aug_2026_in_UTC&quot;&gt;check your local time&lt;/a&gt;). Anyone in the Django community is welcome to drop in. You do not need an agenda or an invitation. Video call details are on the &lt;a href=&quot;https://tools.jacobian.org/dsf-office-hours/&quot;&gt;DSF Office Hours page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We have been running these &lt;a href=&quot;https://www.djangoproject.com/weblog/2024/oct/16/announcing-weekly-dsf-office-hours/&quot;&gt;since October 2024&lt;/a&gt;, and right now we have two things we would especially like to talk with you about.&lt;/p&gt;
&lt;h2 id=&quot;s-who-shows-up&quot;&gt;Who shows up&lt;/h2&gt;
&lt;p&gt;On any given Wednesday, you might find DSF Board members, Steering Council members, Django Fellows, working group members, and community members who are curious about joining a working group. There is no membership requirement. Anybody from the community can join, and often does.&lt;/p&gt;
&lt;h2 id=&quot;s-the-executive-director-search&quot;&gt;The Executive Director search&lt;/h2&gt;
&lt;p&gt;We recently published a &lt;a href=&quot;https://www.djangoproject.com/weblog/2026/aug/06/call-for-applicants-for-a-django-executive-directo/&quot;&gt;call for applicants for a Django Executive Director&lt;/a&gt;. If you are considering applying, or you are still deciding whether it is the right fit, come to office hours and ask us anything: what the job actually looks like, what we expect in the first year, how the search works. We would rather answer your questions directly than have you guess from a job posting.&lt;/p&gt;
&lt;p&gt;If this is the first you are hearing about the search, please help us spread the word. The best candidate may be someone who has not thought to look.&lt;/p&gt;
&lt;h2 id=&quot;s-fundraising-to-support-it&quot;&gt;Fundraising to support it&lt;/h2&gt;
&lt;p&gt;Hiring an Executive Director is why we &lt;a href=&quot;https://www.djangoproject.com/weblog/2026/jun/10/dsf-2026-fundraising-goals/&quot;&gt;raised our 2026 fundraising goal&lt;/a&gt; from $300,000 to $500,000, which needs about $16,000 per month in additional recurring support. We have made real progress and are working to close the rest.&lt;/p&gt;
&lt;p&gt;If your company uses Django, you can help through &lt;a href=&quot;https://www.djangoproject.com/sponsor/&quot;&gt;corporate sponsorship&lt;/a&gt;, a direct donation, or &lt;a href=&quot;https://github.com/sponsors/django&quot;&gt;GitHub Sponsors&lt;/a&gt;. Most of these are a small lift for a company that already depends on Django. If you want fundraising materials to bring to your leadership team, or help picking the option that fits, come to office hours, and we will get you what you need.&lt;/p&gt;
&lt;h2 id=&quot;s-everything-else&quot;&gt;Everything else&lt;/h2&gt;
&lt;p&gt;Office hours cover plenty beyond that: what our working groups are up to and how to join one, projects the Foundation is working on, and whatever you have been wondering about how the DSF operates. In the weeks before a board meeting, we use the time to gather feedback on what we are about to discuss. If you want the board to hear something, this is a direct line.&lt;/p&gt;
&lt;p&gt;One thing office hours are not: a general Django support channel. It is not the place to debug your code or market a product. For coding help, the &lt;a href=&quot;https://forum.djangoproject.com/&quot;&gt;Django Forum&lt;/a&gt; will get you faster answers.&lt;/p&gt;
&lt;p&gt;Office hours are the most direct way to keep up with the Foundation, but they are not the only one. We wrote up &lt;a href=&quot;https://www.djangoproject.com/weblog/2026/jun/30/keeping-up-with-the-django-community/&quot;&gt;all the other places we post and where the conversation happens&lt;/a&gt; if Wednesdays do not work for you.&lt;/p&gt;
&lt;p&gt;Otherwise, put a Wednesday on your calendar and say hello.&lt;/p&gt;</description>
	<pubDate>Wed, 12 Aug 2026 17:25:24 +0000</pubDate>
</item>
<item>
	<title>PyCharm: What’s New in PyCharm 2026.2.1</title>
	<guid>https://blog.jetbrains.com/pycharm/2026/08/what-s-new-in-pycharm-2026-2-1/</guid>
	<link>https://blog.jetbrains.com/pycharm/2026/08/what-s-new-in-pycharm-2026-2-1/</link>
	<description>&lt;p&gt;This &lt;a href=&quot;https://www.jetbrains.com/pycharm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm&lt;/a&gt; release is a big one for anyone building with AI. Your agents can now roll up their sleeves inside your Jupyter notebooks – working against a live kernel instead of firing off disconnected scripts. And they finally know which Python to use, so packages land in the right environment every time.&lt;/p&gt;



&lt;p&gt;We&amp;#8217;re also welcoming marimo notebooks into the IDE and introducing changes to bundled plugins to keep PyCharm fast and focused.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Release highlights&lt;/h2&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Jupyter notebook skill for AI agents&lt;/h3&gt;



&lt;p&gt;Let AI agents such as Claude Code and Codex create, edit, and run &lt;code&gt;.ipynb&lt;/code&gt; notebooks via PyCharm&amp;#8217;s notebook model and a live kernel, so variables, models, and data persist across cells instead of disappearing when the agent shells out. For you, this means more reliable notebook and ML work – with fewer tokens used. To start, just open the AI chat and ask the agent to work in your notebook.&lt;/p&gt;


    &lt;div class=&quot;buttons&quot;&gt;
        &lt;div class=&quot;buttons__row&quot;&gt;
                                                &lt;a href=&quot;https://blog.jetbrains.com/pycharm/2026/08/we-gave-ai-agents-a-live-jupyter-kernel-in-pycharm/&quot; class=&quot;btn&quot; target=&quot;&quot;&gt;Learn more&lt;/a&gt;
                                                    &lt;/div&gt;
    &lt;/div&gt;







&lt;h3 class=&quot;wp-block-heading&quot;&gt;Agent environment coordinator&lt;/h3&gt;



&lt;p&gt;Tired of AI agents installing packages into the wrong Python environment? This new skill gives the agent your project&amp;#8217;s configured interpreter and tool – &lt;code&gt;uv&lt;/code&gt;, Poetry, &lt;code&gt;pip&lt;/code&gt; in a &lt;code&gt;venv&lt;/code&gt;, or &lt;code&gt;conda&lt;/code&gt; – so commands target the right environment, not a system one. If none exists, it can set one up via PyCharm, and the agent decides how to use the information. To start, ask the agent to run or install something in your project.&lt;/p&gt;


    &lt;div class=&quot;buttons&quot;&gt;
        &lt;div class=&quot;buttons__row&quot;&gt;
                                                &lt;a href=&quot;https://blog.jetbrains.com/pycharm/2026/08/we-stopped-ai-agents-from-installing-into-the-wrong-python-task-success-rates-jumped-to-95/&quot; class=&quot;btn&quot; target=&quot;&quot;&gt;Learn more&lt;/a&gt;
                                                    &lt;/div&gt;
    &lt;/div&gt;







&lt;h3 class=&quot;wp-block-heading&quot;&gt;marimo notebooks in PyCharm [third-party plugin]&lt;/h3&gt;



&lt;p&gt;You can now open, edit, and run marimo notebooks directly in PyCharm with the new plugin developed by the marimo team.&amp;nbsp;&lt;/p&gt;



&lt;p&gt;Work with reactive cells and interactive UI elements in a dedicated notebook without leaving your IDE. Because marimo notebooks are stored as Python files, they are Git-friendly, executable as scripts, and easy to integrate into your existing Python projects.&lt;/p&gt;



&lt;img src=&quot;https://blog.jetbrains.com/wp-content/uploads/2026/07/image-51.png&quot; alt=&quot;&quot; class=&quot;wp-image-727410&quot; /&gt;


    &lt;div class=&quot;buttons&quot;&gt;
        &lt;div class=&quot;buttons__row&quot;&gt;
                                                &lt;a href=&quot;https://plugins.jetbrains.com/plugin/32416-marimo&quot; class=&quot;btn&quot; target=&quot;&quot; rel=&quot;noopener&quot;&gt;Install the plugin&lt;/a&gt;
                                                    &lt;/div&gt;
    &lt;/div&gt;







&lt;h3 class=&quot;wp-block-heading&quot;&gt;Changes to bundled plugins in 2026.2&lt;/h3&gt;



&lt;p&gt;As part of ongoing maintenance, we are unbundling and deprecating low-usage plugins, including Data Wrangler, Hugging Face, and Google Colab support. You can continue to install compatible versions from JetBrains Marketplace, but these plugins are no longer bundled or actively maintained by the PyCharm team. A more focused set of bundled plugins means a leaner codebase, helping us keep PyCharm fast and responsive and invest our effort where it has the most impact.&lt;/p&gt;


    &lt;div class=&quot;buttons&quot;&gt;
        &lt;div class=&quot;buttons__row&quot;&gt;
                                                &lt;a href=&quot;https://blog.jetbrains.com/pycharm/2026/08/unbundling-and-deprecating-low-usage-plugins-in-pycharm/&quot; class=&quot;btn&quot; target=&quot;&quot;&gt;Learn more&lt;/a&gt;
                                                    &lt;/div&gt;
    &lt;/div&gt;







&lt;h2 class=&quot;wp-block-heading&quot;&gt;Redesigned Python Packages tool window&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Packages now appear in a collapsible tree alongside their dependencies so you can see what&amp;#8217;s installed and why – with new icons, right-aligned versions, and inline Install/Update links.&lt;/li&gt;



&lt;li&gt;A new floating search popup (think “Search Everywhere” but for packages) makes finding and installing fast. It also shows you which environment will be used and lets you pick a module and dependency group.&lt;/li&gt;



&lt;li&gt;You can install a package into specific &lt;code&gt;uv&lt;/code&gt;/Poetry dependency groups like dev or test per workspace member, change versions inline or through the new Change Version dialog, and install from VCS via Custom Installation.&lt;/li&gt;



&lt;li&gt;Package repositories can be enabled or disabled, with state remembered across sessions. In addition, unreachable URLs show a clear error, and Remote Development support is substantially improved.&lt;/li&gt;
&lt;/ul&gt;



&lt;img src=&quot;https://blog.jetbrains.com/wp-content/uploads/2026/08/PY-89838-Python-Packages-Tool-Window-redesign.png&quot; alt=&quot;Redesigned Python Packages tool window in PyCharm&quot; class=&quot;wp-image-730282&quot; /&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Clearer type checking&lt;/h2&gt;



&lt;p&gt;Get clearer, more actionable type messages:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Richer type-mismatch errors, now with a breakdown of why the types don&amp;#8217;t match. &lt;/li&gt;



&lt;li&gt;A type diff for callables and other composite types, so both sides read the same way. &lt;/li&gt;



&lt;li&gt;Fully rendered names and types in inspection tooltips, with clickable links. &lt;/li&gt;
&lt;/ul&gt;



&lt;img src=&quot;https://blog.jetbrains.com/wp-content/uploads/2026/08/PY-80221-explain_Show-a-breakdown-when-type-mismatch-is-reported.png&quot; alt=&quot;Clearer type checking in PyCharm&quot; class=&quot;wp-image-730293&quot; /&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Bug fixes&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Virtual environments for end-of-life Python&lt;/strong&gt;: PyCharm no longer creates venvs for Python 2.7, 3.6, and 3.7. You can still create a new env from a command line and add it to the IDE manually.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;SQLAlchemy 2.0 Session.get() inference&lt;/strong&gt;: &lt;code&gt;Session.get(Entity, id)&lt;/code&gt; (and SQLModel) is now inferred as a model instance rather than the class.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Download PyCharm&lt;/h2&gt;



&lt;p&gt;All of these updates are available in PyCharm 2026.2.1. Update right from the IDE or the Toolbox App, or &lt;a href=&quot;https://www.jetbrains.com/pycharm/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;download the latest version&lt;/a&gt; to try everything out on your own projects. As always, we’d love to hear your feedback.&lt;/p&gt;


    &lt;div class=&quot;buttons&quot;&gt;
        &lt;div class=&quot;buttons__row&quot;&gt;
                                                &lt;a href=&quot;https://www.jetbrains.com/pycharm/download/&quot; class=&quot;btn&quot; target=&quot;&quot; rel=&quot;noopener&quot;&gt;Download PyCharm&lt;/a&gt;
                                                    &lt;/div&gt;
    &lt;/div&gt;







&lt;p&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 12 Aug 2026 12:05:32 +0000</pubDate>
</item>
<item>
	<title>PyCharm: We Stopped AI Agents From Installing Into the Wrong Python: Task Success Rates Jumped to 95%+</title>
	<guid>https://blog.jetbrains.com/pycharm/2026/08/we-stopped-ai-agents-from-installing-into-the-wrong-python-task-success-rates-jumped-to-95/</guid>
	<link>https://blog.jetbrains.com/pycharm/2026/08/we-stopped-ai-agents-from-installing-into-the-wrong-python-task-success-rates-jumped-to-95/</link>
	<description>&lt;p&gt;AI agents are supposed to save you time. Ask one to install a dependency or run your project, though, and it often does the opposite: It installs into the wrong Python, ignores the uv or virtual environment your project uses, and hands back a broken setup for you to fix yourself.&lt;/p&gt;



&lt;p&gt;&lt;a href=&quot;https://www.jetbrains.com/pycharm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm&lt;/a&gt;’s new Agent Environment Coordinator skill fixes this, and this blog post shows just how helpful it proves to be.&lt;/p&gt;




  
    
    

    AGENT ENVIRONMENT COORDINATOR
    The agent stopped guessing Python.

    Average task success
    68%
    -&amp;gt;
    98%
    Baseline
    With skill

    
    28
    Python tasks

    
    6
    AI models

    
    
    
    No system Python pollution
  




&lt;p&gt;We tested six AI models using 28 different Python programming tasks. Without access to the project&amp;#8217;s real environment, they solved 68% of the tasks on average. After we gave them access, their average success rate shot up to 98% – and they didn’t even modify the system Python.&lt;/p&gt;



&lt;p&gt;If you’re currently using AI agents in your Python projects, read on to see how the Agent Environment Coordinator can improve their performance.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;When the agent could see the project&amp;#8217;s environment, it stopped failing&lt;/h2&gt;



&lt;p&gt;When using the Agent Environment Coordinator skill, each agent, regardless of the model, was able to complete far more of the 28 tasks. (See the Methodology section below for details on what the tasks entailed.) Here is the share of successfully completed tasks for each model, comparing the baseline to running with the skill in PyCharm:&lt;/p&gt;




  
    
    MODEL
    BASELINE
    WITH SKILL
    
    
    
    
    
    
    
    Claude Sonnet 4.6
    
    
    36%
    
    
    96%
    Claude Sonnet 5
    
    
    73%
    
    
    100%
    Claude Opus 4.8
    
    
    67%
    
    
    100%
    Claude Opus 5.0
    
    
    94%
    
    
    98%
    Codex / GPT-5.5
    
    
    62%
    
    
    95%
    Codex / GPT-5.6
    
    
    80%
    
    
    100%
  




&lt;p&gt;Every model improved, with the weakest baseline improving the most.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Why we built this&lt;/h2&gt;



&lt;p&gt;LLMs almost never use a project&amp;#8217;s dedicated virtual environment. They fall back to a system interpreter, ignoring the fact that there may be several system interpreters and real projects often have more complex, multi-interpreter setups already configured in PyCharm that the agent has no way to see.&lt;/p&gt;



&lt;p&gt;For example, &lt;code&gt;pip install httpx&lt;/code&gt; runs against the wrong Python, the package installs globally, the script fails, and the environment is polluted.&lt;/p&gt;



&lt;p&gt;PyCharm already knows which interpreter belongs to your project and which tool manages it. The agent just couldn’t ask – so we gave it a way.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;How it works&lt;/h2&gt;



&lt;p&gt;The Agent Environment Coordinator lets the agent ask PyCharm two things. &lt;code&gt;get_python_environment&lt;/code&gt; returns the correct interpreter for the file or module in question – the path plus the tool behind it (&lt;code&gt;uv&lt;/code&gt;, Poetry, &lt;code&gt;pip&lt;/code&gt; + venv, conda). If no environment exists yet, &lt;code&gt;configure_python_interpreter&lt;/code&gt; sets one up by reusing PyCharm&amp;#8217;s existing configuration mechanism – the same one that offers to create a &lt;code&gt;.venv&lt;/code&gt; – so the new interpreter also becomes visible in the IDE.&lt;/p&gt;



&lt;p&gt;The important part is what the skill &lt;em&gt;doesn&amp;#8217;t &lt;/em&gt;do. It returns information; it never intercepts or rewrites the command. The agent asks which Python to use, gets an accurate answer, and decides whether and how to use it to write the command itself. We hand it the missing context using existing mechanisms in PyCharm – we don&amp;#8217;t let it take the wheel.&lt;/p&gt;



&lt;p&gt;The payoff is practical: The agent works with your project setup out of the box. You don’t need to coach it through prompts about which environment to use, or clean up wrong installs afterward.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Methodology&lt;/h2&gt;



&lt;p&gt;We built a dataset of 28 tasks covering everyday Python-environment work, like running tests, installing a library, listing dependencies, resolving a version conflict, and so forth.&lt;/p&gt;



&lt;p&gt;Each task ultimately required the agent to pick the correct interpreter to execute a command. The eval also reduced the reward when the agent polluted the system environment, so a high score reflects a clean run, not just a passing one.&lt;/p&gt;



&lt;p&gt;We ran the full set three times per model, with and without the skill, using &lt;a href=&quot;https://www.harborframework.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Harbor&lt;/a&gt;, and averaged the results.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Results&lt;/h2&gt;



&lt;p&gt;Success rates climbed across the board – Sonnet 5 improved from 73% to 100%, Opus 5 from 94% to 100%, and Codex/GPT-5.6 from 80% to 100%.&amp;nbsp;&lt;/p&gt;



&lt;p&gt;Two things stand out in addition to this numerical jump:&amp;nbsp;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;The improved success rates demonstrate that the models lacked context, rather than being incapable of completing the tasks. The models didn&amp;#8217;t get better – they just stopped guessing the interpreter, which is why the weakest baseline improved the most.&lt;/li&gt;



&lt;li&gt;Because the eval docks points for polluting the system environment, these higher scores also imply cleaner runs. The agents didn&amp;#8217;t just pass more often; they stopped leaving a mess behind.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Want to try it?&lt;/h2&gt;



&lt;p&gt;Open the AI chat in &lt;a href=&quot;https://www.jetbrains.com/pycharm/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm 2026.2.1&lt;/a&gt; and ask your agent to install a package or run something in your project – it&amp;#8217;ll reach for the right interpreter on its own.&lt;/p&gt;



&lt;p&gt;The Agent Environment Coordinator is one of PyCharm&amp;#8217;s bundled skills. You can browse and manage all of them right in the IDE, expand the built-in library with external registries like public GitHub repositories, or import skills you&amp;#8217;ve already set up for Claude Code or Codex.&lt;/p&gt;</description>
	<pubDate>Wed, 12 Aug 2026 12:01:07 +0000</pubDate>
</item>
<item>
	<title>PyCharm: We Gave AI Agents a Live Jupyter Kernel in PyCharm</title>
	<guid>https://blog.jetbrains.com/pycharm/2026/08/we-gave-ai-agents-a-live-jupyter-kernel-in-pycharm/</guid>
	<link>https://blog.jetbrains.com/pycharm/2026/08/we-gave-ai-agents-a-live-jupyter-kernel-in-pycharm/</link>
	<description>&lt;p&gt;If you&amp;#8217;ve handed notebook work to an AI agent, you know how it tends to go: More often than not, it corrupts your &lt;code&gt;.ipynb&lt;/code&gt;, loses your trained model the moment the run finishes, or burns budget sitting idle through a long job while you watch.&lt;/p&gt;



&lt;p&gt;To solve this, we’re introducing a brand-new Jupyter skill. Built directly into &lt;a href=&quot;https://www.jetbrains.com/pycharm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm,&lt;/a&gt; it lets your AI agent work inside a live Jupyter kernel instead of handing the job to a subprocess and losing your progress. This one change means state persists across cells, the &lt;code&gt;.ipynb&lt;/code&gt; isn&amp;#8217;t corrupted, and long jobs wait until execution is completed instead of constantly checking and wasting precious tokens.&lt;/p&gt;




  
    
    

    JUPYTER SKILL FOR PYCHARM
    A live kernel made Opus
    cheaper than the shell.

    12%
    cheaper
    Claude Opus 5 across 12 ML tasks

    
    
    Kernel
    USD 59.09

    
    
    Shell
    USD 67.06

    
    12
    ML tasks

    
    98%
    cache reads

    
    
    
    State persists across cells
  




&lt;h2 class=&quot;wp-block-heading&quot;&gt;For Opus, the kernel ran cheaper than the shell&lt;/h2&gt;



&lt;p&gt;We tested the efficiency of the Jupyter skill by comparing the performance of agents when solving twelve different machine learning problems. We compared three different modes: strictly using bash, strictly using the kernel via the Jupyter skill, and a mixture of both.&lt;/p&gt;



&lt;p&gt;While the agent was able to solve all twelve tasks in every mode, there was a difference in how much each mode spent. For Claude Opus 5, working through the kernel cost 59.09 USD versus 67.06 USD through the shell – about 12% cheaper.&lt;/p&gt;




  
    
    MODE
    COST
    INPUT TOKENS
    CACHE READS
    
    
    
    Kernel (skill)
    Shell (baseline)
    
    
    USD 59.09
    
    
    USD 67.06
    
    
    72.7M
    
    
    36.3M
    
    
    98%
    
    
    82%
  




&lt;p&gt;Here’s the counterintuitive part: The kernel used more tokens, yet cost less. That&amp;#8217;s because it keeps the prompt cache warm. 98% of its input was cache reads, versus 82% for the shell – and cache reads incur only 1/12 of the cost of creating a fresh cache.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Why we built this&lt;/h2&gt;



&lt;p&gt;Notebooks are where coding agents tend to fall apart. Most AI tools treat an &lt;code&gt;.ipynb&lt;/code&gt; like a plain text file: They hand-edit the JSON (and corrupt it), and then run code by running a subprocess. The moment an agent starts the subprocess, the kernel state – the trained model, the loaded dataframe, and every import – lives in the child process, and vanishes when that process exits. The agent can&amp;#8217;t inspect it, checkpoint it, or reuse it. Output is buffered until the run ends, so progress is invisible, and long training jobs get babysat – blind until the connection times out.&lt;/p&gt;



&lt;p&gt;We asked the obvious question: What if the agent operated a live Jupyter kernel through the IDE?&lt;/p&gt;



&lt;p&gt;So we built our new Jupyter skill, which exposes PyCharm&amp;#8217;s own notebook intelligence – its notebook model and live-kernel control – to the agent. It does this through a single MCP wrapper, &lt;code&gt;execute_tool&lt;/code&gt;, which covers the core notebook operations, including creating, editing, and reading notebooks; running cells; waiting on long runs; probing a running kernel; and controlling its lifecycle. The skill tells the agent when and how to use them.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;How it works&lt;/h2&gt;



&lt;p&gt;The agent:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Runs directly in the kernel.&lt;/strong&gt; The agent writes real Python into a cell and runs it, so variables, models, and data persist across cells – exactly like a human working in a notebook.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Waits instead of polling.&lt;/strong&gt; Rather than polling on a fixed timer and re-billing context on every idle call, &lt;code&gt;wait_cell_execution&lt;/code&gt; is blocked until the cell finishes (or a safe cap), and then hands control back. This helps reduce idle round-trips.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Reads only what&amp;#8217;s new.&lt;/strong&gt; As a long run streams output, the agent reads the &lt;em&gt;delta&lt;/em&gt; – just the lines since its last check – instead of re-sending the whole, ever-growing cell output every time.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Methodology&lt;/h2&gt;



&lt;p&gt;We used twelve tasks from the MLGym machine-learning benchmark – classification, regression, and reinforcement-learning problems, each of which requires the agent to load data, train, evaluate, and save a result. We ran them across Claude Opus 5 and OpenAI&amp;#8217;s GPT-5.6 models, Sol and Terra, through Codex. We compared three modes: through the kernel only, through the kernel plus the shell, and through the shell alone. As these benchmark tasks expose test labels to the agent, we treat cost – not accuracy – as the reliable signal.&lt;/p&gt;



&lt;p&gt;One caveat, for transparency: An audit found that one of the twelve tasks, Titanic, was contaminated – the agent could peek at the test set, and each agent used this to select the best model to present as the final solution. Titanic is a well-known, easy task for LLMs, and the issue appeared consistently across all three modes, so it doesn&amp;#8217;t skew the comparison. The pattern holds even with Titanic removed – the kernel still ran 10% cheaper than the shell for Opus (56.34 USD versus 62.65 USD).&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Results&lt;/h2&gt;



&lt;p&gt;The cost win is model- and task-dependent. It was clearest for Claude Opus on long, stateful jobs, while the shell came out cheaper on short tasks and for the Codex models – which already use the cache efficiently, so there the skill earns its place on workflow, not cost.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Where it still falls short&lt;/h2&gt;



&lt;p&gt;Two things are worth keeping in mind:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Tell the agent to save its artifacts.&lt;/strong&gt; In one run, the agent trained a solid model but never saved the submission file before finishing. This is easy to prevent from your side: Just add a clear instruction in your context file (e.g. &lt;code&gt;CLAUDE.md&lt;/code&gt;) or a skill so the agent saves any model the moment it clears your target metric.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Some tasks are still beyond agents.&lt;/strong&gt; On a hard task, the agent&amp;#8217;s approach simply wasn&amp;#8217;t strong enough to clear the bar. That&amp;#8217;s genuine ML difficulty, not a tooling gap – some complex problems still need a human in the loop.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;The skill removes the &lt;em&gt;mechanical&lt;/em&gt; waste, but doesn&amp;#8217;t turn a weak approach into a strong one.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Want to try it?&lt;/h2&gt;



&lt;p&gt;Open the AI chat in &lt;a href=&quot;https://www.jetbrains.com/pycharm/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm 2026.2.1&lt;/a&gt; and ask your agent to work in a notebook – create one, load a dataset, or kick off a training run. The agent will operate the kernel directly instead of running commands in the shell.&lt;/p&gt;



&lt;p&gt;You can also browse and manage skills directly from the IDE, expand the built-in library with external registries like public GitHub repositories, or let PyCharm import skills you’ve already set up for Claude Code or Codex.&lt;/p&gt;</description>
	<pubDate>Wed, 12 Aug 2026 12:00:34 +0000</pubDate>
</item>
<item>
	<title>PyCharm: Unbundling and Deprecating Low-Usage Plugins in PyCharm</title>
	<guid>https://blog.jetbrains.com/pycharm/2026/08/unbundling-and-deprecating-low-usage-plugins-in-pycharm/</guid>
	<link>https://blog.jetbrains.com/pycharm/2026/08/unbundling-and-deprecating-low-usage-plugins-in-pycharm/</link>
	<description>&lt;p&gt;As part of ongoing maintenance, we are unbundling and deprecating low-usage plugins starting with &lt;a href=&quot;https://www.jetbrains.com/pycharm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyCharm&lt;/a&gt; 2026.2. This includes support for Data Wrangler, Hugging Face, and Google Colab, among others.&amp;nbsp;&lt;/p&gt;



&lt;p&gt;A more focused set of bundled plugins means a leaner codebase, enabling us to keep PyCharm fast and responsive and invest our effort where it has the most impact.&lt;/p&gt;



&lt;p&gt;You can continue installing compatible versions from the &lt;a href=&quot;https://plugins.jetbrains.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JetBrains Marketplace&lt;/a&gt;, but these plugins will no longer be bundled or actively maintained by the PyCharm team. Read this blog post for the full list, deprecation timeline, and next steps.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Why we’re making this change&lt;/h2&gt;



&lt;p&gt;The tools and workflows developers rely on keep evolving, and several of these plugins never reached the level of adoption we hoped for. After reviewing usage trends, we’ve decided to move a set of low-usage plugins out of active development, so our team can focus on features with broader impact for Python developers.&lt;/p&gt;



&lt;p&gt;A smaller set of bundled plugins also means a leaner, more maintainable codebase. As PyCharm continues to grow, we want to invest our engineering effort where it has the most impact and keep the IDE fast and responsive over time.&lt;/p&gt;



&lt;p&gt;Unbundling and deprecating a plugin doesn’t necessarily mean deleting it. If a certain plugin’s functionality is still used, we’ll move that plugin’s code to a separate &lt;a href=&quot;https://github.com/JetBrains/intellij-obsolete-plugins&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Obsolete Plugins repository&lt;/a&gt;. The plugin will remain searchable and installable on JetBrains Marketplace with a fixed compatibility range, but will no longer be rebuilt with every new release or maintained by the PyCharm team.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Which plugins are affected&lt;/h2&gt;



&lt;p&gt;The following plugins are being deprecated; those currently bundled will be unbundled first:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Data Wrangler&lt;/li&gt;



&lt;li&gt;Hugging Face&lt;/li&gt;



&lt;li&gt;Google Colab (Jupyter Notebook Colab)&lt;/li&gt;



&lt;li&gt;Spark, including PySpark support&lt;/li&gt;



&lt;li&gt;AI Playground&lt;/li&gt;



&lt;li&gt;AI Agents Debugger&lt;/li&gt;



&lt;li&gt;dbt&lt;/li&gt;



&lt;li&gt;Databricks&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Other low-usage plugins may be deprecated in the same way in future releases.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Timeline and what to expect&lt;/h2&gt;



&lt;p&gt;&lt;strong&gt;v2026.2&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;The bundled plugins listed above will be unbundled from PyCharm.&lt;/li&gt;



&lt;li&gt;The PyCharm team will no longer develop new features for these plugins or maintain them.&lt;/li&gt;



&lt;li&gt;Compatible versions will remain available for installation from JetBrains Marketplace and stay compatible with v2026.2.&lt;/li&gt;



&lt;li&gt;The plugin source will be published in the Obsolete Plugins repository, where you can continue to build and install it manually.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;v2026.3 and beyond&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;The PyCharm team will no longer publish compatible versions of these plugins starting from v2026.3.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;What this means for you&lt;/h2&gt;



&lt;p&gt;If you rely on any of these plugins, you can continue to install a compatible version from &lt;a href=&quot;https://plugins.jetbrains.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JetBrains Marketplace&lt;/a&gt; for PyCharm 2026.2. Because the source moves to the &lt;a href=&quot;https://github.com/JetBrains/intellij-obsolete-plugins&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Obsolete Plugins repository&lt;/a&gt; under an open model, the community can keep building and installing the plugins manually. If you’re interested in maintaining one of them, we’d love to hear from you.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Thank you&lt;/h2&gt;



&lt;p&gt;We’re grateful to everyone who used these plugins, filed issues, and shared feedback over the years. Thank you!&lt;/p&gt;



&lt;p&gt;The PyCharm team&lt;/p&gt;</description>
	<pubDate>Wed, 12 Aug 2026 11:59:50 +0000</pubDate>
</item>
<item>
	<title>Python GUIs: Adding QTabWidget to a Layout Alongside Other Widgets in PyQt6 — How to combine QTabWidget with other layouts without it taking over your entire window</title>
	<guid>https://www.pythonguis.com/faq/cant-integrate-qtabwidget-into-a-layout/</guid>
	<link>https://www.pythonguis.com/faq/cant-integrate-qtabwidget-into-a-layout/</link>
	<description>&lt;blockquote&gt;
&lt;p&gt;I'm trying to create a layout in PyQt and implement different layouts into one QHBoxLayout. Everything works fine, but when I add a QTabWidget alongside other layouts, it becomes the only visible widget &amp;mdash; as if everything else disappears. Isn't it possible to have a QTabWidget in a layout beside other layouts?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Good news: you absolutely &lt;em&gt;can&lt;/em&gt; place a &lt;code&gt;QTabWidget&lt;/code&gt; inside a layout alongside other widgets and sub-layouts. You don't need to wrap it in a &lt;code&gt;QGroupBox&lt;/code&gt; or use any special workaround. The issue usually comes down to how the tabs themselves are set up &amp;mdash; specifically, whether the tab pages have any content and layout of their own.&lt;/p&gt;
&lt;p&gt;Let's walk through what's happening and how to fix it.&lt;/p&gt;
&lt;h2 id=&quot;why-the-qtabwidget-seems-to-take-over&quot;&gt;Why the QTabWidget seems to &quot;take over&quot;&lt;/h2&gt;
&lt;p&gt;When you create a &lt;code&gt;QTabWidget&lt;/code&gt; and add empty &lt;code&gt;QWidget&lt;/code&gt; pages to it, those pages have no layout and no content. Depending on how the widget calculates its size, this can cause unexpected sizing behavior in the parent layout. The tab widget may request more space than you expect, or the other widgets may collapse because the layout gives the tab widget priority.&lt;/p&gt;
&lt;p&gt;The fix is straightforward: make sure each tab page has a layout, and give the tab widget a reasonable size policy or stretch factor so it shares space with its neighbors.&lt;/p&gt;
&lt;h2 id=&quot;a-minimal-example-that-works&quot;&gt;A minimal example that works&lt;/h2&gt;
&lt;p&gt;Let's start with a small, complete example. We'll create a horizontal layout with a vertical stack of colored widgets on the left and a &lt;code&gt;QTabWidget&lt;/code&gt; on the right &amp;mdash; sitting happily side by side.&lt;/p&gt;
&lt;p&gt;First, here's a simple &lt;code&gt;Color&lt;/code&gt; helper widget that fills itself with a solid color, useful for visualizing layouts:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;from PyQt6.QtWidgets import QWidget
from PyQt6.QtGui import QColor, QPalette


class Color(QWidget):
    &quot;&quot;&quot;A simple widget that displays a solid color.&quot;&quot;&quot;

    def __init__(self, color):
        super().__init__()
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.ColorRole.Window, QColor(color))
        self.setPalette(palette)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now let's build the full window:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget,
    QHBoxLayout, QVBoxLayout, QTabWidget, QLabel,
)


class Color(QWidget):
    def __init__(self, color):
        super().__init__()
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(palette.ColorRole.Window, QColor(color))
        self.setPalette(palette)


from PyQt6.QtGui import QColor, QPalette


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;QTabWidget in a Layout&quot;)

        # Main horizontal layout
        main_layout = QHBoxLayout()

        # Left side: a vertical stack of colored widgets
        left_layout = QVBoxLayout()
        left_layout.addWidget(Color(&quot;black&quot;))
        left_layout.addWidget(Color(&quot;red&quot;))
        left_layout.addWidget(Color(&quot;yellow&quot;))
        main_layout.addLayout(left_layout)

        # Middle: a single green widget
        main_layout.addWidget(Color(&quot;green&quot;))

        # Right side: a QTabWidget
        tab_widget = QTabWidget()
        tab_widget.setMovable(True)

        # Create tab pages WITH layouts and content
        tab1 = QWidget()
        tab1_layout = QVBoxLayout()
        tab1_layout.addWidget(QLabel(&quot;This is Tab 1&quot;))
        tab1_layout.addWidget(Color(&quot;lightblue&quot;))
        tab1.setLayout(tab1_layout)

        tab2 = QWidget()
        tab2_layout = QVBoxLayout()
        tab2_layout.addWidget(QLabel(&quot;This is Tab 2&quot;))
        tab2_layout.addWidget(Color(&quot;lightyellow&quot;))
        tab2.setLayout(tab2_layout)

        tab_widget.addTab(tab1, &quot;Tab 1&quot;)
        tab_widget.addTab(tab2, &quot;Tab 2&quot;)

        main_layout.addWidget(tab_widget)

        # Set the central widget
        container = QWidget()
        container.setLayout(main_layout)
        self.setCentralWidget(container)


app = QApplication(sys.argv)
window = MainWindow()
window.resize(800, 400)
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Run this and you'll see the colored widgets on the left, the green widget in the middle, and the tab widget on the right &amp;mdash; all sharing the horizontal space.&lt;/p&gt;
&lt;h2 id=&quot;controlling-how-much-space-each-section-gets&quot;&gt;Controlling how much space each section gets&lt;/h2&gt;
&lt;p&gt;If you want finer control over how the horizontal space is divided, you can use &lt;strong&gt;stretch factors&lt;/strong&gt;. These tell the layout how to distribute extra space among its children. For a deeper dive into how &lt;code&gt;QHBoxLayout&lt;/code&gt;, &lt;code&gt;QVBoxLayout&lt;/code&gt;, and &lt;code&gt;QGridLayout&lt;/code&gt; work in PyQt6, see our &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyqt6-layouts/&quot;&gt;guide to PyQt6 layouts&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;main_layout.addLayout(left_layout, 1)    # stretch factor 1
main_layout.addWidget(Color(&quot;green&quot;), 1)  # stretch factor 1
main_layout.addWidget(tab_widget, 2)      # stretch factor 2 (gets twice as much space)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The numbers are relative. Here the tab widget gets twice the space of the left section and the green widget. Adjust these to taste.&lt;/p&gt;
&lt;h2 id=&quot;complete-working-example&quot;&gt;Complete working example&lt;/h2&gt;
&lt;p&gt;Here's the full example with stretch factors and a grid layout section included, similar to the original code:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget,
    QHBoxLayout, QVBoxLayout, QGridLayout,
    QTabWidget, QLabel,
)
from PyQt6.QtGui import QColor, QPalette


class Color(QWidget):
    &quot;&quot;&quot;A simple widget that displays a solid color.&quot;&quot;&quot;

    def __init__(self, color):
        super().__init__()
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.ColorRole.Window, QColor(color))
        self.setPalette(palette)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;QTabWidget Alongside Other Layouts&quot;)

        main_layout = QHBoxLayout()

        # Section 1: Vertical stack
        v_layout1 = QVBoxLayout()
        v_layout1.addWidget(Color(&quot;black&quot;))
        v_layout1.addWidget(Color(&quot;red&quot;))
        v_layout1.addWidget(Color(&quot;yellow&quot;))
        v_layout1.setContentsMargins(0, 0, 20, 0)
        v_layout1.setSpacing(20)
        main_layout.addLayout(v_layout1, 1)

        # Section 2: Single widget
        main_layout.addWidget(Color(&quot;green&quot;), 1)

        # Section 3: Another vertical stack
        v_layout2 = QVBoxLayout()
        v_layout2.addWidget(Color(&quot;blue&quot;))
        v_layout2.addWidget(Color(&quot;purple&quot;))
        main_layout.addLayout(v_layout2, 1)

        # Section 4: Grid layout
        grid_layout = QGridLayout()
        grid_layout.addWidget(Color(&quot;grey&quot;), 0, 0)
        grid_layout.addWidget(Color(&quot;black&quot;), 1, 0)
        grid_layout.addWidget(Color(&quot;darkgrey&quot;), 1, 1)
        grid_layout.addWidget(Color(&quot;orange&quot;), 2, 1)
        main_layout.addLayout(grid_layout, 1)

        # Section 5: Tab widget
        tab_widget = QTabWidget()
        tab_widget.setMovable(True)
        tab_widget.setTabPosition(QTabWidget.TabPosition.North)

        # Tab 1 with content
        tab1 = QWidget()
        tab1_layout = QVBoxLayout()
        tab1_layout.addWidget(QLabel(&quot;Content for Tab 1&quot;))
        tab1_layout.addWidget(Color(&quot;lightblue&quot;))
        tab1_layout.addWidget(Color(&quot;lightyellow&quot;))
        tab1.setLayout(tab1_layout)

        # Tab 2 with content
        tab2 = QWidget()
        tab2_layout = QVBoxLayout()
        tab2_layout.addWidget(QLabel(&quot;Content for Tab 2&quot;))
        tab2_layout.addWidget(Color(&quot;lightgreen&quot;))
        tab2.setLayout(tab2_layout)

        tab_widget.addTab(tab1, &quot;Tab 1&quot;)
        tab_widget.addTab(tab2, &quot;Tab 2&quot;)

        main_layout.addWidget(tab_widget, 2)

        # Set up the central widget
        container = QWidget()
        container.setLayout(main_layout)
        self.setCentralWidget(container)


app = QApplication(sys.argv)
window = MainWindow()
window.resize(900, 400)
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When you run this, you'll see all five sections displayed side by side in a single horizontal layout &amp;mdash; colored blocks, a grid, and a tab widget, all coexisting without any one section dominating the window.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QTabWidget&lt;/code&gt; works perfectly in any layout alongside other widgets. Just make sure the tab pages have their own layouts and content, and use stretch factors to control how space is distributed. If you'd prefer to design these complex layouts visually rather than in code, you can use &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyqt6-qt-designer-gui-layout/&quot;&gt;Qt Designer to build your GUI layout&lt;/a&gt;. For a broader overview of the widgets you can place inside your tabs and layouts, take a look at our &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyqt6-widgets/&quot;&gt;PyQt6 widgets tutorial&lt;/a&gt;.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PyQt6 see my book, &lt;a href=&quot;https://www.pythonguis.com/pyqt6-book/&quot;&gt;Create GUI Applications with Python &amp;amp; Qt6.&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 12 Aug 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>Python Bytes: #491 Feeling Judged</title>
	<guid>https://pythonbytes.fm/episodes/show/491/feeling-judged</guid>
	<link>https://pythonbytes.fm/episodes/show/491/feeling-judged</link>
	<description>&amp;lt;strong&amp;gt;Topics covered in this episode:&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;

&amp;lt;ul&amp;gt;
	&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Claude Code /insights&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://blog.trailofbits.com/2026/06/30/shipping-post-quantum-cryptography-to-python/?featured_on=pythonbytes&quot;&amp;gt;Post-quantum crypto lands in Python&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://realpython.com/python-news-august-2026/?featured_on=pythonbytes&quot;&amp;gt;MCP goes stateless — and FastMCP gets renamed&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://github.com/microsoft/inshellisense?featured_on=pythonbytes&quot;&amp;gt;inshellisense - IDE style command line auto complete&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Extras&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Joke&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;

&amp;lt;/ul&amp;gt;&amp;lt;a href='https://www.youtube.com/watch?v=5iaT_bO3INA' style='font-weight: bold;'data-umami-event=&quot;Livestream-Past&quot; data-umami-event-episode=&quot;491&quot;&amp;gt;Watch on YouTube&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;About the show&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Sponsored by&amp;lt;/strong&amp;gt; &amp;lt;a href=&quot;https://pythonbytes.fm/xweather&quot;&amp;gt;Xweather&amp;lt;/a&amp;gt;
Xweather combines enterprise-grade weather intelligence with agent-ready APIs, natural language capabilities, and an MCP server so your agents can adapt workflows, automate responses, and make better decisions based on real-world conditions.
 Michael will tell you more about them later in the show. Get started for free at &amp;lt;a href=&quot;http://pythonbytes.fm/xweather&quot;&amp;gt;pythonbytes.fm/xweather&amp;lt;/a&amp;gt;
&amp;lt;strong&amp;gt;Connect with the hosts&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Michael: &amp;lt;a href=&quot;https://fosstodon.org/@mkennedy&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/mkennedy.codes?featured_on=pythonbytes&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/mkennedy?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://www.linkedin.com/in/mkennedy/?featured_on=pythonbytes&quot;&amp;gt;LinkedIn&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Calvin: &amp;lt;a href=&quot;https://sixfeetup.social/@calvin?featured_on=pythonbytes&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/calvinhp.com?featured_on=pythonbytes&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/calvinhp?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://www.linkedin.com/in/calvinhp/?featured_on=pythonbytes&quot;&amp;gt;LinkedIn&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Show: &amp;lt;a href=&quot;https://fosstodon.org/@pythonbytes&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/pythonbytes.fm&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/PythonBytes?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt;
Join us on YouTube at &amp;lt;a href=&quot;https://pythonbytes.fm/stream/live&quot;&amp;gt;&amp;lt;strong&amp;gt;pythonbytes.fm/live&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt; to be part of the audience. Usually &amp;lt;strong&amp;gt;Tuesday at 7am PT&amp;lt;/strong&amp;gt;. Older video versions available there too.
Finally, if you want an artisanal digest of every week of the show notes in email form? Add your name and email to &amp;lt;a href=&quot;https://pythonbytes.fm/friends-of-the-show&quot;&amp;gt;our friends of the show list&amp;lt;/a&amp;gt;, we'll never share it.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Michael #1: Claude Code /insights&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Michael’s Insights: &amp;lt;a href=&quot;https://blobs.pythonbytes.fm/michael-kennedy-claude-code-insights-2026-08-09.html?cache_id=6c6ef5&quot;&amp;gt;michael-kennedy-claude-code-insights-2026-08-09.html&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Be careful sharing these outputs, they include details references to your projects, errors, security findings, etc. ;)&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;/insights&amp;lt;/code&amp;gt; reads your last 30 days of local session transcripts and hands back an interactive HTML report on how you actually work.
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;One command, zero setup&amp;lt;/strong&amp;gt;: type &amp;lt;code&amp;gt;/insights&amp;lt;/code&amp;gt; in a session, or run &amp;lt;code&amp;gt;claude -p &quot;/insights&quot;&amp;lt;/code&amp;gt; from the shell for a non-interactive version that just prints the path&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Reads what's already on disk&amp;lt;/strong&amp;gt;: pulls session logs from &amp;lt;code&amp;gt;~/.claude/projects/&amp;lt;/code&amp;gt;, skipping agent sub-sessions and anything under 2 messages or 1 minute&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Project areas&amp;lt;/strong&amp;gt;: clusters your sessions into themes like &quot;CLI Tooling&quot; or &quot;Documentation&quot; with session counts&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Friction analysis&amp;lt;/strong&amp;gt;: categorizes where things went wrong by root cause - and quotes your own prompts back at you&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Interaction style&amp;lt;/strong&amp;gt;: tells you whether you're a delegator or a micromanager, plus which workflows are worth doubling down on&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Actually actionable&amp;lt;/strong&amp;gt;: suggests concrete &amp;lt;a href=&quot;http://CLAUDE.md?featured_on=pythonbytes&quot;&amp;gt;CLAUDE.md&amp;lt;/a&amp;gt; additions and Claude Code features you're not using&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;The catch&amp;lt;/strong&amp;gt;: Haiku does the per-session classification, so the first run takes several minutes; results cache to &amp;lt;code&amp;gt;~/.claude/usage-data/facets/&amp;lt;/code&amp;gt; and the report lands at &amp;lt;code&amp;gt;~/.claude/usage-data/report.html&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Calvin #2: &amp;lt;a href=&quot;https://blog.trailofbits.com/2026/06/30/shipping-post-quantum-cryptography-to-python/?featured_on=pythonbytes&quot;&amp;gt;Post-quantum crypto lands in Python&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;pyca/cryptography&amp;lt;/code&amp;gt; 48 ships ML-KEM (key establishment) and ML-DSA (signatures) — NIST's post-quantum standards, now one &amp;lt;code&amp;gt;pip install&amp;lt;/code&amp;gt; away.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Big deal because it's the 11th most-downloaded package on PyPI (~1.2B downloads/month) and sits under Ansible, Certbot, Airflow, and paramiko. No PQ there, no PQ anywhere in Python.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Trail of Bits did the work (Rust bindings, cross-backend API, tests, AWS-LC backend support), funded by the Sovereign Tech Agency.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Timing tracks a June 22 White House order setting federal deadlines: PQ key establishment by end of 2030, PQ signatures by end of 2031.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Not a drop-in swap — the wire sizes explode. ML-DSA-65 signatures are 3,309 bytes vs Ed25519's 64; ML-KEM-768 public keys are 1,184 bytes vs X25519's 32. Hardcoded field sizes and length prefixes will bite.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;API looks like the existing asymmetric primitives, except ML-KEM is encapsulate/decapsulate rather than a Diffie-Hellman exchange. SLH-DSA (the hash-based conservative backstop) is still in progress.
The primitives are here, but protocols haven't caught up — so you won't be running post-quantum Certbot this week.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Sponsor: Xweather&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;You're using agents that can write code, summarize documents, and automate workflows. But they're missing one thing: awareness of the world around them. This is where today's sponsor, Xweather comes in.
Xweather combines enterprise-grade weather intelligence with agent-ready APIs, natural language capabilities, and an MCP server built for tools like Claude, Codex, Copilot, and modern IDEs – so your agents can adapt workflows, automate responses, and make better decisions based on real-world conditions.
Backed by Vaisala, whose instruments fly on NASA missions to Mars, Xweather delivers trusted data and unique insights that go beyond conditions to actual impact – from real-time lightning strikes to road surface forecasts.
Start with 15,000 free API calls each month and pay only for what you use as you grow.
 Xweather is your full weather stack, for developers by developers. Start building for free today at &amp;lt;a href=&quot;http://pythonbytes.fm/xweather&quot;&amp;gt;pythonbytes.fm/xweather&amp;lt;/a&amp;gt;. The link is in your podcast player's show notes and on the episode page.
Thanks so much to Xweather for supporting Python Bytes.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Calvin #3: &amp;lt;a href=&quot;https://realpython.com/python-news-august-2026/?featured_on=pythonbytes&quot;&amp;gt;MCP goes stateless — and FastMCP gets renamed&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;From &amp;lt;strong&amp;gt;Philipp Acsany&amp;lt;/strong&amp;gt; over at Real Python&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The &amp;lt;code&amp;gt;2026-07-28&amp;lt;/code&amp;gt; spec landed July 28 and the Python SDK shipped 2.0.0 the same day. Biggest rewrite since MCP launched, and it's breaking on purpose. Context for scale: the Tier 1 SDKs are pulling close to half a billion downloads a month, with TypeScript and Python each past a billion total.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The headline is the stateless core. The &amp;lt;code&amp;gt;initialize&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;initialized&amp;lt;/code&amp;gt; handshake and the &amp;lt;code&amp;gt;Mcp-Session-Id&amp;lt;/code&amp;gt; header are both retired — protocol version, client identity, and capabilities now ride in &amp;lt;code&amp;gt;_meta&amp;lt;/code&amp;gt; on every request, with an optional &amp;lt;code&amp;gt;server/discover&amp;lt;/code&amp;gt; RPC if a client wants capabilities up front. Any request can land on any instance behind plain round-robin, no shared storage.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Server-initiated calls are the hard part of the migration. Sampling, elicitation, and &amp;lt;code&amp;gt;roots/list&amp;lt;/code&amp;gt; no longer call back to the client; instead the server returns &amp;lt;code&amp;gt;resultType: &quot;input_required&quot;&amp;lt;/code&amp;gt; and the client retries with &amp;lt;code&amp;gt;inputResponses&amp;lt;/code&amp;gt; attached. Multi Round-Trip Requests, MRTR. Also: &amp;lt;code&amp;gt;Mcp-Method&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Mcp-Name&amp;lt;/code&amp;gt; are now required headers so gateways route on headers instead of cracking JSON bodies, and missing-resource errors move to standard &amp;lt;code&amp;gt;32602&amp;lt;/code&amp;gt;.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Deprecation sweep with an actual policy behind it — Roots, Sampling, Logging, and the legacy HTTP+SSE transport all deprecated with a twelve-month minimum offramp. Tasks graduated out of the experimental core into a real extension, which is what the formalized extensions framework was for. MCP Apps is now an official extension too, so a tool call can return sandboxed interactive HTML. Auth picked up RFC 9207 issuer validation, issuer-bound credentials, and a shift from DCR toward CIMD.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Python SDK 2.0 is where it gets personal: &amp;lt;code&amp;gt;FastMCP&amp;lt;/code&amp;gt; is now &amp;lt;code&amp;gt;MCPServer&amp;lt;/code&amp;gt;, no alias, no shim. &amp;lt;code&amp;gt;McpError&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;MCPError&amp;lt;/code&amp;gt;. Wire types went snake_case (&amp;lt;code&amp;gt;is_error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;input_schema&amp;lt;/code&amp;gt;) and moved to a standalone &amp;lt;code&amp;gt;mcp_types&amp;lt;/code&amp;gt; package, with &amp;lt;code&amp;gt;mcp.types&amp;lt;/code&amp;gt; kept as a permanent alias. One &amp;lt;code&amp;gt;Client&amp;lt;/code&amp;gt; object replaces the old transport + &amp;lt;code&amp;gt;ClientSession&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;initialize()&amp;lt;/code&amp;gt; stack. &amp;lt;code&amp;gt;httpx&amp;lt;/code&amp;gt; became &amp;lt;code&amp;gt;httpx2&amp;lt;/code&amp;gt;. Sync handlers run on worker threads now, so &amp;lt;code&amp;gt;asyncio.get_running_loop()&amp;lt;/code&amp;gt; raises inside them.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The good news: one &amp;lt;code&amp;gt;MCPServer&amp;lt;/code&amp;gt; serves both protocol eras, so 2025-era clients keep working with nothing to configure, and a &amp;lt;code&amp;gt;Resolve(fn)&amp;lt;/code&amp;gt; parameter lets one tool body cover MRTR and the old path. 1.x is maintenance-and-security-fixes only — pin &amp;lt;code&amp;gt;mcp&amp;amp;gt;=1.28,&amp;amp;lt;2&amp;lt;/code&amp;gt; if this week is already full. The Tasks extension isn't in 2.0.0 yet, so Tasks has left the core spec but hasn't landed in the SDK.
If you only &amp;lt;em&amp;gt;call&amp;lt;/em&amp;gt; MCP servers, you mostly just get the benefits for free. If you &amp;lt;em&amp;gt;ship&amp;lt;/em&amp;gt; one, you already know what your week looks like. And if you use the standalone &amp;lt;code&amp;gt;fastmcp&amp;lt;/code&amp;gt; package instead of the official SDK — different project, 3.x line, none of this touches you. The rename is partly to stop the two from being confused.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Michael #4: &amp;lt;a href=&quot;https://github.com/microsoft/inshellisense?featured_on=pythonbytes&quot;&amp;gt;inshellisense - IDE style command line auto complete&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;via Doug Nichols&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;inshellisense&amp;lt;/code&amp;gt; provides IDE style autocomplete for shells.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;It's a terminal native runtime for &amp;lt;a href=&quot;https://github.com/withfig/autocomplete?featured_on=pythonbytes&quot;&amp;gt;autocomplete&amp;lt;/a&amp;gt; which has support for 600+ command line tools.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;inshellisense&amp;lt;/code&amp;gt; supports Windows, Linux, &amp;amp;amp; macOS.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;If you are using a &amp;lt;a href=&quot;https://www.nerdfonts.com/?featured_on=pythonbytes&quot;&amp;gt;NerdFont&amp;lt;/a&amp;gt; patched font, you can enable the NerdFonts support in your config file&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Extras&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Calvin:&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Django 6.1 Released — https://www.djangoproject.com/weblog/2026/aug/05/django-61-released/&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;DjangoCon US is quickly arriving, grab your tickets now! — https://2026.djangocon.us/
Michael:&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&quot;https://pythonbytes.fm/ai-integration&quot;&amp;gt;AI integration: Python Bytes for AI&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&quot;https://training.talkpython.fm/courses/up-and-running-with-rust?featured_on=pythonbytes&quot;&amp;gt;Up and Running with Rust Course is out!&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Joke: &amp;lt;a href=&quot;https://programmerhumor.io/security-memes/google-p5hl?featured_on=pythonbytes&quot;&amp;gt;But they already know&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;</description>
	<pubDate>Wed, 12 Aug 2026 01:00:10 +0000</pubDate>
</item>

</channel>
</rss>
