<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Python Developer Tooling Handbook – Python Tooling Blog</title>
    <link>https://pydevtools.com/blog/</link>
    <description>Articles on Python developer tools including uv, ruff, ty, pytest, and the evolving packaging ecosystem.</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Tue, 06 Feb 2024 16:32:39 +0000</lastBuildDate>
    
	  <atom:link href="https://pydevtools.com/blog/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>If you&#39;re on mypy in 2026, Pyrefly is the obvious upgrade</title>
      <link>https://pydevtools.com/blog/pyrefly-1-0-is-the-obvious-mypy-upgrade/</link>
      <pubDate>Wed, 13 May 2026 11:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/pyrefly-1-0-is-the-obvious-mypy-upgrade/</guid>
      <description>&lt;p&gt;The case for staying on &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; has often been migration cost. &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyrefly/&#34;&gt;Pyrefly&lt;/a&gt; 1.0, released May 12, 2026, makes the mechanical half close to free:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv add --dev pyrefly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run pyrefly init
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run pyrefly check --baseline&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;pyrefly-baseline.json --update-baseline
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run pyrefly check&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;pyrefly init&lt;/code&gt; reads an existing &lt;code&gt;mypy.ini&lt;/code&gt; or &lt;code&gt;[tool.mypy]&lt;/code&gt; section, writes the equivalent Pyrefly configuration, and turns on a preset called &lt;code&gt;legacy&lt;/code&gt; that disables the checks mypy does not have. Pyrefly&amp;rsquo;s inference is more aggressive than mypy&amp;rsquo;s on the checks both tools run, so a real codebase will surface new diagnostics on the first check pass. The count depends on the codebase and how much was typed before. The baseline-snapshot step writes those errors to JSON so the final &lt;code&gt;check&lt;/code&gt; returns clean and CI stays green while the team triages on its own schedule.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Python 3.14.5 rolls back the incremental garbage collector</title>
      <link>https://pydevtools.com/blog/python-3145-rolls-back-the-incremental-garbage-collector/</link>
      <pubDate>Mon, 11 May 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/python-3145-rolls-back-the-incremental-garbage-collector/</guid>
      <description>&lt;p&gt;Python 3.14.5 &lt;a href=&#34;https://blog.python.org/2026/05/python-3145-is-out/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;landed on 10 May 2026&lt;/a&gt;, pulled the incremental garbage collector that shipped in 3.14.0 through 3.14.4, and put the 3.13 generational collector back. Patch releases almost never reverse a major implementation change. The &lt;a href=&#34;https://docs.python.org/3.14/whatsnew/3.14.html#garbage-collection&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;What&amp;rsquo;s New page&lt;/a&gt; names the cause: &amp;ldquo;due to a number of reports of significant memory pressure in production environments, it has been reverted back to the generational GC from 3.13.&amp;rdquo;&lt;/p&gt;
&lt;h2&gt;Recap what the incremental collector promised&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;recap-what-the-incremental-collector-promised&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#recap-what-the-incremental-collector-promised&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-python/&#34;&gt;CPython&lt;/a&gt; collects cyclic garbage with a tracing collector that runs alongside refcounting. Up through 3.13, that collector was generational with three generations. Objects that survived a collection moved up a generation, and the collector visited older generations less often. A full collection of the oldest generation traced every object the program kept alive, which on long-running processes produced multi-hundred-millisecond pauses.&lt;/p&gt;</description>
    </item>
    <item>
      <title>mypy 2.0 picks parallelism over a rewrite</title>
      <link>https://pydevtools.com/blog/mypy-2-0-parallel-type-checking/</link>
      <pubDate>Sat, 09 May 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/mypy-2-0-parallel-type-checking/</guid>
      <description>&lt;p&gt;For most of the past year, the speed conversation around Python type checkers has had one shape: &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; is the slow incumbent, and the fast alternatives (&lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyrefly/&#34;&gt;Pyrefly&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/zuban/&#34;&gt;Zuban&lt;/a&gt;) earn their speed by being written in Rust. &lt;a href=&#34;https://mypy-lang.blogspot.com/2026/05/mypy-20-relased.html&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;mypy 2.0&lt;/a&gt;, released May 6, 2026, takes a different route. It runs across multiple cores.&lt;/p&gt;
&lt;h2&gt;Run mypy across cores&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;run-mypy-across-cores&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#run-mypy-across-cores&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The headline feature is &lt;code&gt;--num-workers N&lt;/code&gt; (or &lt;code&gt;-nN&lt;/code&gt;). Pass a worker count and mypy splits type checking across processes:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Locking dependencies for PEP 723 single-file scripts in May 2026</title>
      <link>https://pydevtools.com/blog/locking-dependencies-for-pep-723-scripts/</link>
      <pubDate>Fri, 08 May 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/locking-dependencies-for-pep-723-scripts/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-723/&#34;&gt;PEP 723&lt;/a&gt; plus &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; made single-file Python scripts easy to share. Declare dependencies in a commented TOML block, drop the file in a gist, and &lt;code&gt;uv run script.py&lt;/code&gt; builds an ephemeral environment and runs it without a project directory or activation step. Locking those dependencies so the script behaves the same six months from now is still awkward. The inline &lt;code&gt;dependencies&lt;/code&gt; list pins the top-level requirements you specify and nothing else; the transitive graph gets re-resolved every time the script runs on a new machine.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ruff Already Rewrites Your Python to Be More Idiomatic</title>
      <link>https://pydevtools.com/blog/ruff-already-rewrites-your-python-to-be-more-idiomatic/</link>
      <pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/ruff-already-rewrites-your-python-to-be-more-idiomatic/</guid>
      <description>&lt;p&gt;Open any Python codebase that&amp;rsquo;s been through a few hands and you&amp;rsquo;ll find the same fossils: a &lt;code&gt;for&lt;/code&gt; loop adding items to a set one at a time, a conditional slice that could be &lt;code&gt;removesuffix()&lt;/code&gt;, a two-line &lt;code&gt;open()&lt;/code&gt;/&lt;code&gt;read()&lt;/code&gt; that &lt;code&gt;pathlib&lt;/code&gt; handles in one call. The code works. It passes every linter you&amp;rsquo;ve enabled. And a reviewer who knows Python well would rewrite all of it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt; can already do that rewriting. It ported 36 rules from &lt;a href=&#34;https://github.com/dosisod/refurb&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;refurb&lt;/a&gt; into a category called &lt;code&gt;FURB&lt;/code&gt;, and every one of them ships with an auto-fix. Most projects haven&amp;rsquo;t turned them on because Ruff&amp;rsquo;s defaults only enable Pyflakes (&lt;code&gt;F&lt;/code&gt;) and a subset of pycodestyle (&lt;code&gt;E&lt;/code&gt;). The rules that catch non-idiomatic patterns sit behind an opt-in flag, invisible to the people who&amp;rsquo;d benefit most.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lightning Got Owned: When `import lightning` Steals Your Credentials</title>
      <link>https://pydevtools.com/blog/lightning-pypi-compromise-import-time-supply-chain-attack/</link>
      <pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/lightning-pypi-compromise-import-time-supply-chain-attack/</guid>
      <description>&lt;p&gt;&lt;code&gt;import lightning&lt;/code&gt; shows up at the top of millions of PyTorch training scripts. On April 30, 2026, that line was enough to ship a developer&amp;rsquo;s credentials to an attacker.&lt;/p&gt;
&lt;p&gt;Two malicious versions of the &lt;a href=&#34;https://pypi.org/project/lightning/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;lightning&lt;/a&gt; PyPI package, &lt;code&gt;2.6.2&lt;/code&gt; and &lt;code&gt;2.6.3&lt;/code&gt;, were uploaded today. Lightning averages 311 thousand downloads a day, and any CI that ran &lt;code&gt;uv sync --upgrade&lt;/code&gt; between the upload and the takedown pulled the bad wheel. Neither version corresponds to a GitHub release on &lt;code&gt;Lightning-AI/pytorch-lightning&lt;/code&gt;; the latest tagged release there is still &lt;code&gt;2.6.1&lt;/code&gt; from January 30. The bad code was uploaded directly to PyPI, which is the same pattern as the &lt;a href=&#34;https://pydevtools.com/blog/litellm-supply-chain-attack-and-securing-python-dependencies/&#34;&gt;litellm compromise&lt;/a&gt; six weeks ago. &lt;a href=&#34;https://socket.dev/blog/lightning-pypi-package-compromised&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Socket&lt;/a&gt; flagged both releases 18 minutes after upload, and PyPI has since quarantined the entire project.&lt;/p&gt;</description>
    </item>
    <item>
      <title>What Reddit taught me about why people switch to uv</title>
      <link>https://pydevtools.com/blog/what-reddit-taught-me-about-why-people-switch-to-uv/</link>
      <pubDate>Mon, 27 Apr 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/what-reddit-taught-me-about-why-people-switch-to-uv/</guid>
      <description>&lt;p&gt;A thread titled &lt;a href=&#34;https://www.reddit.com/r/Python/comments/1mfd3ww/but_really_why_use_uv/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;But really, why use uv?&amp;rdquo;&lt;/a&gt; landed on r/Python and pulled 476 upvotes. The original poster wasn&amp;rsquo;t antagonistic. They used Python casually, installed packages two or three times a month, and couldn&amp;rsquo;t see why &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; was worth adding to a setup that already worked.&lt;/p&gt;
&lt;p&gt;The comments convinced them. Reading through the top responses surfaces something the standard uv pitch misses: the compelling case for casual users is not the same as the compelling case for power users.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ty and pyrefly find different bugs</title>
      <link>https://pydevtools.com/blog/ty-and-pyrefly-find-different-bugs/</link>
      <pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/ty-and-pyrefly-find-different-bugs/</guid>
      <description>&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:flex-col hx:rounded-lg hx:border hx:py-4 hx:px-4 hx:border-gray-200 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-blue-200 hx:bg-blue-100 hx:text-blue-900 hx:dark:border-blue-200/30 hx:dark:bg-blue-900/30 hx:dark:text-blue-200&#34;&gt;
  &lt;p class=&#34;hx:flex hx:items-center hx:font-medium&#34;&gt;&lt;svg height=16px class=&#34;hx:inline-block hx:align-middle hx:mr-2&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; fill=&#34;none&#34; viewBox=&#34;0 0 24 24&#34; stroke-width=&#34;2&#34; stroke=&#34;currentColor&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; d=&#34;M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z&#34;/&gt;&lt;/svg&gt;Note&lt;/p&gt;

  &lt;div class=&#34;hx:w-full hx:min-w-0 hx:leading-7&#34;&gt;
    &lt;div class=&#34;hx:mt-6 hx:leading-7 hx:first:mt-0&#34;&gt;&lt;p&gt;&lt;strong&gt;Update 2026-04-29&lt;/strong&gt;: An earlier version of this post used a multi-line Liskov-violation panel from &lt;code&gt;rich/_null_file.py&lt;/code&gt; as an example of ty catching a real protocol bug. That diagnostic turned out to be a &lt;a href=&#34;https://github.com/astral-sh/ty/issues/2237&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ty false positive&lt;/a&gt;: ty reports the base parameter type as &lt;code&gt;Buffer&lt;/code&gt; when checking overrides on subclasses of &lt;code&gt;IO[str]&lt;/code&gt;, even though the parameterization should resolve &lt;code&gt;AnyStr&lt;/code&gt; to &lt;code&gt;str&lt;/code&gt;. mypy and pyright are both silent on the same code. The &amp;ldquo;Where ty pulls ahead&amp;rdquo; section has been rewritten with a tuple-arity finding instead, and the conclusion&amp;rsquo;s reference to &amp;ldquo;Liskov panels&amp;rdquo; has been dropped. Thanks to a reader for the catch.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Did pip 26 close the gap with uv?</title>
      <link>https://pydevtools.com/blog/did-pip-26-close-the-gap-with-uv/</link>
      <pubDate>Fri, 24 Apr 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/did-pip-26-close-the-gap-with-uv/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; 26.0 closed two of &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;&amp;rsquo;s clearest feature gaps in January: &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-723/&#34;&gt;PEP 723&lt;/a&gt; script installs and a datetime-based package filter that mirrors uv&amp;rsquo;s &lt;code&gt;--exclude-newer&lt;/code&gt;. The &lt;a href=&#34;https://news.ycombinator.com/item?id=45751400&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;October 2025 Hacker News thread&lt;/a&gt; that kept circling back to &amp;ldquo;pip has quietly caught up&amp;rdquo; now reads less contrarian than it did at the time, and the &lt;a href=&#34;https://pydevtools.com/blog/openai-acquires-astral/&#34;&gt;OpenAI acquisition of Astral&lt;/a&gt; in March changes the &amp;ldquo;is this safe to depend on&amp;rdquo; calculus at the same time.&lt;/p&gt;
&lt;h2&gt;Review pip&amp;rsquo;s 2025 to 2026 releases&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;review-pips-2025-to-2026-releases&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#review-pips-2025-to-2026-releases&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Four pip releases have landed since April 2025, and the first three narrowed gaps uv was best known for:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How Astral Uses Its Own Tools</title>
      <link>https://pydevtools.com/blog/how-astral-uses-its-own-tools/</link>
      <pubDate>Thu, 23 Apr 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/how-astral-uses-its-own-tools/</guid>
      <description>&lt;p&gt;Astral runs &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; inside the repos that build them. Their &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project/&#34;&gt;&lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;&lt;/a&gt;, and CI files are public, and a walk through the three shows how the people making ruff, ty, and uv wire their own toolchain into the projects that produce it.&lt;/p&gt;
&lt;h2&gt;Build ty from source and type-check Python with it&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;build-ty-from-source-and-type-check-python-with-it&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#build-ty-from-source-and-type-check-python-with-it&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ruff repository ships ty as part of its crate tree. Three CI steps build ty from source and run it against the repo&amp;rsquo;s own Python:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Astral told you how they secure uv. Here&#39;s what to keep.</title>
      <link>https://pydevtools.com/blog/astral-security-post-what-to-keep/</link>
      <pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/astral-security-post-what-to-keep/</guid>
      <description>&lt;p&gt;Astral published &lt;a href=&#34;https://astral.sh/blog/open-source-security-at-astral&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;a detailed writeup&lt;/a&gt; of how they secure the org that ships uv, Ruff, and ty. It&amp;rsquo;s a good post. It&amp;rsquo;s also, for most readers, the wrong post.&lt;/p&gt;
&lt;p&gt;Most of what Astral describes is team-scale GitHub hygiene: org-wide branch protection rulesets, workflow audits with &lt;code&gt;zizmor&lt;/code&gt;, action pinning with &lt;code&gt;pinact&lt;/code&gt;, isolated GitHub Apps for privileged operations. If you run a project with outside contributors, read the whole thing. If you&amp;rsquo;re one person shipping a Python package, a lot of it is overkill for the threat model you actually face.&lt;/p&gt;</description>
    </item>
    <item>
      <title>PyPI&#39;s Second Audit Found 14 Bugs. Two Remain.</title>
      <link>https://pydevtools.com/blog/pypi-second-security-audit/</link>
      <pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/pypi-second-security-audit/</guid>
      <description>&lt;p&gt;PyPI completed its &lt;a href=&#34;https://blog.pypi.org/posts/2026-04-16-pypi-completes-second-audit/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;second external security audit&lt;/a&gt; today. Trail of Bits found 14 issues in the Warehouse codebase: 2 High, 1 Medium, 7 Low, 3 Informational, 0 Critical. Twelve were patched. Two were accepted as known gaps. The work was funded by the &lt;a href=&#34;https://www.sovereign.tech/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Sovereign Tech Agency&lt;/a&gt;, with remediation by PSF&amp;rsquo;s Mike Fiedler through &lt;a href=&#34;https://alpha-omega.dev/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Alpha-Omega&lt;/a&gt; support.&lt;/p&gt;
&lt;p&gt;An audit of &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt; is an audit of the index infrastructure, not of the packages hosted on it. None of the findings describe malware in the wild. The patched bugs are the predictable part; the accepted ones are where the signal lives.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Your Python Wheels Still Target 2009 CPUs</title>
      <link>https://pydevtools.com/blog/your-python-wheels-still-target-2009-cpus/</link>
      <pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/your-python-wheels-still-target-2009-cpus/</guid>
      <description>&lt;p&gt;Intel shipped AVX2 in 2013. AMD reached it with Excavator-era parts around 2015. Eleven years later, the default NumPy wheel &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; downloads on an &lt;code&gt;x86_64&lt;/code&gt; Linux box is still compiled to run on processors from roughly 2003, the year AMD launched the Opteron and defined the AMD64 baseline. Every SIMD instruction that has shipped since is off-limits to the compiler that produced that wheel.&lt;/p&gt;
&lt;p&gt;The reason is structural. A &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheel&lt;/a&gt; filename encodes three pieces of compatibility metadata: Python version, ABI, and platform. &amp;ldquo;Platform&amp;rdquo; for mainstream Linux wheels is typically &lt;code&gt;manylinux_2_17_x86_64&lt;/code&gt;, which says &amp;ldquo;works on any glibc 2.17+ x86-64 distro&amp;rdquo; and nothing about which CPU instruction sets the machine supports. When a project publishes one binary for all of those users, it has to target the lowest common denominator.&lt;/p&gt;</description>
    </item>
    <item>
      <title>uv won developer hearts. Now it has to win READMEs.</title>
      <link>https://pydevtools.com/blog/uv-admired-but-not-adopted/</link>
      <pubDate>Tue, 14 Apr 2026 09:00:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/uv-admired-but-not-adopted/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; ranked as the &lt;a href=&#34;https://survey.stackoverflow.co/2025/technology#admired-and-desired&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;most admired technology&lt;/a&gt; in Stack Overflow&amp;rsquo;s 2025 Developer Survey at 74%. A recent &lt;a href=&#34;https://aleyan.com/blog/2026-why-arent-we-uv-yet/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;analysis by Andrey Aleyan&lt;/a&gt; of the top 100,000 Python repositories on GitHub put uv adoption (measured by the presence of &lt;code&gt;uv.lock&lt;/code&gt;) at roughly 10%. The gap between &amp;ldquo;developers love this&amp;rdquo; and &amp;ldquo;developers ship this&amp;rdquo; is wider than any tooling story in recent memory.&lt;/p&gt;
&lt;p&gt;Aleyan&amp;rsquo;s diagnosis is that AI coding agents are the bottleneck: their training data is overwhelmingly &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;, so they emit &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;. That diagnosis is correct but incomplete. Adoption is bottlenecked by three reinforcing forces, and the AI-agent story is only one of them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Python Packaging Summit Returns to PyCon US</title>
      <link>https://pydevtools.com/blog/python-packaging-summit-2026/</link>
      <pubDate>Thu, 09 Apr 2026 12:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/python-packaging-summit-2026/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://us.pycon.org/2026/events/packaging-summit/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Packaging Summit&lt;/a&gt; returns Friday, May 15, 2026 in Room 201A of the Long Beach Convention Center, running 1:45 to 5:45 PM on the Friday of PyCon US. Pradyun Gedam, C.A.M. Gerlach, and Jannis Leidel co-chair again. Attendance is capped and invite-only: submit the &lt;a href=&#34;https://forms.gle/tu4zHaFYDCFFYMqx6&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;attendance form&lt;/a&gt; and &lt;a href=&#34;https://forms.gle/3ht7mTZ5N6FktnfH8&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;topic-pitch form&lt;/a&gt; by April 30 (AoE). The schedule drops around May 4.&lt;/p&gt;
&lt;p&gt;The summit puts the people who build &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/poetry/&#34;&gt;Poetry&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;Hatch&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/conda/&#34;&gt;conda&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt;, and the major &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheel&lt;/a&gt;-producing libraries in one room to argue through the year&amp;rsquo;s thorniest packaging questions. The notes from &lt;a href=&#34;https://hackmd.io/@pradyunsg/pycon2024-pack-summit&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2024&lt;/a&gt; and &lt;a href=&#34;https://hackmd.io/@pradyunsg/pycon2025-packaging-summit&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2025&lt;/a&gt; are the best public window into where &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;, wheel tags, and &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-lock-file/&#34;&gt;lock files&lt;/a&gt; are headed.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How uv Solves Dependencies So Fast</title>
      <link>https://pydevtools.com/blog/how-uv-solves-dependencies-so-fast/</link>
      <pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/how-uv-solves-dependencies-so-fast/</guid>
      <description>&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:flex-col hx:rounded-lg hx:border hx:py-4 hx:px-4 hx:border-gray-200 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-green-200 hx:bg-green-100 hx:text-green-900 hx:dark:border-green-200/30 hx:dark:bg-green-900/30 hx:dark:text-green-200&#34;&gt;
  &lt;p class=&#34;hx:flex hx:items-center hx:font-medium&#34;&gt;&lt;svg height=16px class=&#34;hx:inline-block hx:align-middle hx:mr-2&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; fill=&#34;none&#34; viewBox=&#34;0 0 24 24&#34; stroke-width=&#34;2&#34; stroke=&#34;currentColor&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; d=&#34;M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z&#34;/&gt;&lt;/svg&gt;Tip&lt;/p&gt;

  &lt;div class=&#34;hx:w-full hx:min-w-0 hx:leading-7&#34;&gt;
    &lt;div class=&#34;hx:mt-6 hx:leading-7 hx:first:mt-0&#34;&gt;&lt;p&gt;Want more on uv? Browse every uv tutorial, how-to, reference, and explanation on the &lt;a href=&#34;https://pydevtools.com/handbook/topics/uv/&#34;&gt;uv topic page&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Python dependency resolution is NP-hard in the formal sense: it reduces to &lt;a href=&#34;https://en.wikipedia.org/wiki/Boolean_satisfiability_problem&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Boolean satisfiability&lt;/a&gt;. In a &lt;a href=&#34;https://www.janestreet.com/tech-talks/uv-an-extremely-fast-python-package-manager/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Jane Street tech talk&lt;/a&gt; (&lt;a href=&#34;https://youtu.be/gSKTfG1GXYQ&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;YouTube&lt;/a&gt;), Charlie Marsh walked through why &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;&amp;rsquo;s resolver has to solve this problem and the architectural decisions that let it do so 10-100x faster than &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>LLM-Powered Copycats Are Flooding PyPI</title>
      <link>https://pydevtools.com/blog/llm-powered-copycats-are-flooding-pypi/</link>
      <pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/llm-powered-copycats-are-flooding-pypi/</guid>
      <description>&lt;p&gt;A developer named Roman Dubrovin &lt;a href=&#34;https://pypi.org/project/repowise/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;published repowise&lt;/a&gt;, a tool for generating structured wikis from codebases, as his first PyPI package. The next morning, he searched for it on PyPI and found three new packages he didn&amp;rsquo;t recognize: &lt;code&gt;repowise-pro&lt;/code&gt;, &lt;code&gt;repowise-enhanced&lt;/code&gt;, and &lt;code&gt;repowise-next&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All three had been uploaded within a 90-minute window. All three carried the same description: &amp;ldquo;Codebase intelligence that thinks ahead — outperforms repowise on every dimension.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;They weren&amp;rsquo;t empty shells. Someone had forked Dubrovin&amp;rsquo;s AGPL-3.0 licensed source code, run it through an LLM to patch a couple of minor issues, and republished under new names without attribution or license compliance. A community member &lt;a href=&#34;https://www.reddit.com/r/Python/comments/1sek3gq/i_published_my_first_pypi_package_few_ago_copycat/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;confirmed&lt;/a&gt; that all three packages traced back to the same person and the same GitHub repository.&lt;/p&gt;</description>
    </item>
    <item>
      <title>In 2012, Guido Had No Idea NumPy Had Its Own Packaging System</title>
      <link>https://pydevtools.com/blog/guido-had-no-idea-about-numpy-distutils/</link>
      <pubDate>Tue, 07 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/guido-had-no-idea-about-numpy-distutils/</guid>
      <description>&lt;p&gt;In a &lt;a href=&#34;https://youtu.be/QjXJLVINsSA&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;recently resurfaced 2012 PyData panel discussion&lt;/a&gt;, Fernando Perez, Travis Oliphant, and David Cournapeau sat down with Guido van Rossum to discuss the scientific Python community&amp;rsquo;s needs. The conversation wandered through operator overloading (which eventually produced the &lt;code&gt;@&lt;/code&gt; matrix multiplication operator in Python 3.5) and import performance on supercomputers. The packaging segment is the one worth revisiting.&lt;/p&gt;
&lt;p&gt;David Cournapeau, who maintained NumPy&amp;rsquo;s build infrastructure, explained that NumPy had written its own packaging layer on top of &lt;a href=&#34;https://pydevtools.com/handbook/reference/distutils/&#34;&gt;distutils&lt;/a&gt; that was &amp;ldquo;as much code as distutils itself.&amp;rdquo; NumPy had to override nearly every piece of distutils to handle Fortran compilers, C++ extensions, &lt;a href=&#34;https://cython.org/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Cython&lt;/a&gt;, cross-platform compiler flags, and builds on exotic hardware like IBM Blue Gene supercomputers.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Migrating from mypy to ty: Lessons from FastAPI</title>
      <link>https://pydevtools.com/blog/migrating-from-mypy-to-ty-lessons-from-fastapi/</link>
      <pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/migrating-from-mypy-to-ty-lessons-from-fastapi/</guid>
      <description>&lt;p&gt;Sebastián Ramírez, creator of &lt;a href=&#34;https://github.com/tiangolo/fastapi&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;FastAPI&lt;/a&gt;, &lt;a href=&#34;https://x.com/tiangolo/status/1907849737048363046&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;recently announced&lt;/a&gt; that all his Python projects now use &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; for type checking. That includes FastAPI, &lt;a href=&#34;https://github.com/fastapi/typer&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Typer&lt;/a&gt;, &lt;a href=&#34;https://github.com/fastapi/sqlmodel&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SQLModel&lt;/a&gt;, &lt;a href=&#34;https://github.com/fastapi/asyncer&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Asyncer&lt;/a&gt;, and &lt;a href=&#34;https://github.com/fastapi/fastapi-cli&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;FastAPI CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Migrating the projects wasn&amp;rsquo;t a hard switch. It was incremental, messy in the middle, and completed at different speeds across different projects. That pattern offers a useful template for anyone considering the same move.&lt;/p&gt;
&lt;p&gt;Ramírez didn&amp;rsquo;t rip out &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; and replace it with ty in a single PR. Instead, he added ty alongside mypy and ran both checkers in parallel. Four of his five major repos still operate this way. Only SQLModel has fully dropped mypy.&lt;/p&gt;</description>
    </item>
    <item>
      <title>LiteLLM Got Owned, and Your Dependencies Might Be Next</title>
      <link>https://pydevtools.com/blog/litellm-supply-chain-attack-and-securing-python-dependencies/</link>
      <pubDate>Tue, 24 Mar 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/litellm-supply-chain-attack-and-securing-python-dependencies/</guid>
      <description>&lt;p&gt;Earlier today, someone published malicious versions of &lt;a href=&#34;https://pypi.org/project/litellm/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;litellm&lt;/a&gt; (versions 1.82.7 and 1.82.8) to PyPI. No corresponding release appeared on GitHub. The package was uploaded directly to PyPI, bypassing the normal release process, which points to a compromised maintainer account or token.&lt;/p&gt;
&lt;h2&gt;What the malware did&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-the-malware-did&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-the-malware-did&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The payload was a &lt;code&gt;.pth&lt;/code&gt; file named &lt;code&gt;litellm_init.pth&lt;/code&gt;. Python executes &lt;code&gt;.pth&lt;/code&gt; files automatically on interpreter startup, so the malware ran without any user interaction once the package was installed.&lt;/p&gt;</description>
    </item>
    <item>
      <title>OpenAI to Acquire Astral</title>
      <link>https://pydevtools.com/blog/openai-acquires-astral/</link>
      <pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/openai-acquires-astral/</guid>
      <description>&lt;p&gt;OpenAI &lt;a href=&#34;https://openai.com/index/openai-to-acquire-astral/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;announced today&lt;/a&gt; that it will acquire &lt;a href=&#34;https://astral.sh/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Astral&lt;/a&gt;, the company behind &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;. The Astral team will join OpenAI&amp;rsquo;s Codex group after the deal closes, subject to regulatory approval.&lt;/p&gt;
&lt;h2&gt;What this means for Codex&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-this-means-for-codex&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-this-means-for-codex&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://openai.com/index/codex/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Codex&lt;/a&gt;, OpenAI&amp;rsquo;s coding agent, has grown to over 2 million weekly active users, with 3x user growth and 5x usage increase since the start of 2026. Acquiring Astral gives OpenAI direct ownership of tools that millions of Python developers already depend on. OpenAI plans to integrate Astral&amp;rsquo;s tools more deeply into Codex so the agent can interact with the toolchain developers already use.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Charlie Marsh on uv, Coding Agents, and the Changing Open Source Contract</title>
      <link>https://pydevtools.com/blog/charlie-marsh-test-set-interview/</link>
      <pubDate>Tue, 24 Feb 2026 12:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/charlie-marsh-test-set-interview/</guid>
      <description>&lt;p&gt;Charlie Marsh (founder of &lt;a href=&#34;https://astral.sh/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Astral&lt;/a&gt;, creator of &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;) joined Michael Chow and Wes McKinney on &lt;a href=&#34;https://posit.co/thetestset/episode/charlie-marsh-more-productive-but-a-lot-less-fun/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Test Set&lt;/a&gt;. They covered uv&amp;rsquo;s adoption strategy, how coding agents are changing Astral&amp;rsquo;s development process, and what&amp;rsquo;s happening to open source when writing code becomes cheap.&lt;/p&gt;
&lt;h2&gt;uv&amp;rsquo;s compatibility layer was the point&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;uvs-compatibility-layer-was-the-point&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#uvs-compatibility-layer-was-the-point&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When uv first shipped, it only had &lt;code&gt;uv pip install&lt;/code&gt; and &lt;code&gt;uv venv&lt;/code&gt;. Some people found this odd. Charlie says it was deliberate:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Seven Claude Code Skills for Python from the Creator of spaCy</title>
      <link>https://pydevtools.com/blog/matthew-honnibal-claude-skills-for-python/</link>
      <pubDate>Mon, 16 Feb 2026 08:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/matthew-honnibal-claude-skills-for-python/</guid>
      <description>&lt;p&gt;atthew Honnibal, co-founder of &lt;a href=&#34;https://explosion.ai/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Explosion&lt;/a&gt; and creator of &lt;a href=&#34;https://spacy.io/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;spaCy&lt;/a&gt;, has published &lt;a href=&#34;https://github.com/honnibal/claude-skills&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;a collection of Claude Code skills&lt;/a&gt; for Python development. It&amp;rsquo;s one of the more thoughtful skill collections I&amp;rsquo;ve seen.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://code.claude.com/docs/en/skills&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code skills&lt;/a&gt; are markdown files you place in &lt;code&gt;~/.claude/commands/&lt;/code&gt;. When you type &lt;code&gt;/&amp;lt;skill-name&amp;gt;&lt;/code&gt; in Claude Code, the file&amp;rsquo;s contents are injected as instructions. Think of them as reusable prompts that give Claude a specific methodology for a task, rather than leaving it to improvise.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Pydantic Monty: A Secure Python Interpreter for AI Agents</title>
      <link>https://pydevtools.com/blog/pydantic-monty-secure-python-interpreter-for-ai-agents/</link>
      <pubDate>Fri, 06 Feb 2026 10:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/pydantic-monty-secure-python-interpreter-for-ai-agents/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydantic.dev/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pydantic&lt;/a&gt; has released &lt;a href=&#34;https://github.com/pydantic/monty&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Monty&lt;/a&gt;, a minimal Python interpreter written in Rust for safely executing LLM-generated code.&lt;/p&gt;
&lt;p&gt;AI agents that generate code face a tradeoff: trust the generated code completely, or spin up containers for isolation. Containers are slow and resource-intensive. Trusting arbitrary code is risky. Monty sidesteps both by sandboxing execution at the interpreter level, blocking dangerous operations while running Python in microseconds.&lt;/p&gt;
&lt;h2&gt;How It Works&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;how-it-works&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#how-it-works&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Monty provides a straightforward API:&lt;/p&gt;</description>
    </item>
    <item>
      <title>FOSDEM Talk: Modern Python Monorepo with uv, Workspaces, and prek</title>
      <link>https://pydevtools.com/blog/fosdem-talk-modern-python-monorepo/</link>
      <pubDate>Thu, 05 Feb 2026 08:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/fosdem-talk-modern-python-monorepo/</guid>
      <description>&lt;p&gt;Jarek Potiuk, Apache Airflow PMC member and the project&amp;rsquo;s top committer, gave a talk at FOSDEM 2026 on how Airflow manages its massive Python monorepo. The &lt;a href=&#34;https://ftp.belnet.be/mirror/FOSDEM/video/2026/ua2220/WE7NHM-modern-python-monorepo-apache-airflow.av1.webm&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;recording is now available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Airflow ships over 120 separate Python distributions from a single repository, with 700+ dependencies and 3,600+ contributors. That scale forced the team to modernize their tooling. The talk walks through how they did it.&lt;/p&gt;
&lt;h2&gt;uv Workspaces for Monorepo Management&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;uv-workspaces-for-monorepo-management&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#uv-workspaces-for-monorepo-management&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The new setup centers on &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; workspaces. Rather than splitting 120 distributions across separate repositories or bundling everything into an unmanageable monolith, Airflow uses uv&amp;rsquo;s workspace feature to let distributions depend on each other via local sources instead of pulling from PyPI.&lt;/p&gt;</description>
    </item>
    <item>
      <title>uvx.sh: Install Python tools without uv or Python</title>
      <link>https://pydevtools.com/blog/uvx-sh-install-python-tools-without-uv-or-python/</link>
      <pubDate>Thu, 22 Jan 2026 12:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/uvx-sh-install-python-tools-without-uv-or-python/</guid>
      <description>&lt;p&gt;Astral has released &lt;a href=&#34;https://uvx.sh&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uvx.sh&lt;/a&gt;, a service that generates installation scripts for any Python tool on PyPI. With a single curl or PowerShell command, users can install tools like &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt; or &lt;a href=&#34;https://pydevtools.com/handbook/reference/pytest/&#34;&gt;pytest&lt;/a&gt; without having &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; or Python already installed on their system.&lt;/p&gt;
&lt;h2&gt;How It Works&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;how-it-works&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#how-it-works&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;uvx.sh dynamically generates installation scripts for any PyPI package. The URL pattern is simple:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;pre&gt;&lt;code&gt;uvx.sh/{package}/install.sh     # macOS/Linux
uvx.sh/{package}/install.ps1    # Windows&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For example, to install ruff:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Teaching Claude Code Quality Patterns with a Custom Skill</title>
      <link>https://pydevtools.com/blog/dignified-python-313-claude-skill/</link>
      <pubDate>Fri, 09 Jan 2026 09:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/dignified-python-313-claude-skill/</guid>
      <description>&lt;p&gt;Dagster&amp;rsquo;s &lt;a href=&#34;https://github.com/dagster-io/erk/tree/d0e3c177edc5f5013d149794f5cbee459c7b9ccd/.claude/skills/dignified-python-313&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;dignified-python-313 skill&lt;/a&gt; guides Claude Code to write Python 3.13 code that matches their project conventions.&lt;/p&gt;
&lt;h2&gt;What It Covers&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-it-covers&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-it-covers&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modern Python 3.13 Patterns: Use native type syntax (&lt;code&gt;list[str]&lt;/code&gt;, &lt;code&gt;str | None&lt;/code&gt;) instead of older alternatives. Skip &lt;code&gt;from __future__ import annotations&lt;/code&gt; since Python 3.13 doesn&amp;rsquo;t need it.&lt;/p&gt;
&lt;p&gt;CLI Development: Build Click interfaces with proper error handling. Use &lt;code&gt;click.echo()&lt;/code&gt; for output, direct errors to stderr, and treat CLI commands as error boundaries that catch exceptions and exit with &lt;code&gt;SystemExit(1)&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ty is Built with AI</title>
      <link>https://pydevtools.com/blog/ai-driven-software-development/</link>
      <pubDate>Fri, 02 Jan 2026 08:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/ai-driven-software-development/</guid>
      <description>&lt;p&gt;Tool creators are building their tools with AI coding assistants.&lt;/p&gt;
&lt;p&gt;Boris Cherny, creator of &lt;a href=&#34;https://code.claude.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt;, &lt;a href=&#34;https://x.com/bcherny/status/2004626064187031831&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;didn&amp;rsquo;t open an IDE in December but wrote 200 PRs with Claude Code&lt;/a&gt;. Charlie Marsh, creator of &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;, &lt;a href=&#34;https://x.com/charliermarsh/status/2006792788369965393&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;noted&lt;/a&gt; that all &lt;a href=&#34;https://github.com/astral-sh/ruff/pulls?q=is%3Apr&amp;#43;author%3Acharliermarsh&amp;#43;label%3Aty&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;his PRs&lt;/a&gt; to ty were created with Claude Code. The tools building themselves.&lt;/p&gt;
&lt;h2&gt;Integration with Python Tooling&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;integration-with-python-tooling&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#integration-with-python-tooling&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The handbook&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/explanation/modern-python-project-setup-guide-for-ai-assistants/&#34;&gt;Modern Python Project Setup Guide for AI Assistants&lt;/a&gt; provides structured guidance so AI tools default to &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; and modern patterns rather than falling back to &lt;code&gt;pip&lt;/code&gt; commands.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How uv Achieved Its Performance</title>
      <link>https://pydevtools.com/blog/how-uv-achieved-its-performance/</link>
      <pubDate>Fri, 26 Dec 2025 18:00:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/how-uv-achieved-its-performance/</guid>
      <description>&lt;p&gt;Andrew Nesbitt&amp;rsquo;s &lt;a href=&#34;https://nesbitt.io/2025/12/26/how-uv-got-so-fast.html&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;How uv got so fast&amp;rdquo;&lt;/a&gt; explains that &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;&amp;rsquo;s speed comes less from Rust and more from eliminating work entirely.&lt;/p&gt;
&lt;h2&gt;Speed Through Elimination&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;speed-through-elimination&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#speed-through-elimination&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rather than optimizing slow code paths, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; just removes them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;.egg&lt;/code&gt; support&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;pip.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;No bytecode compilation by default&lt;/li&gt;
&lt;li&gt;Ignoring &lt;code&gt;requires-python&lt;/code&gt; upper bounds reduces resolver backtracking&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Rust-Independent Optimizations&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;rust-independent-optimizations&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#rust-independent-optimizations&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many of &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;&amp;rsquo;s performance gains could work in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parallel downloads instead of sequential&lt;/li&gt;
&lt;li&gt;Smart HTTP range requests for metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; got fast by launching when PEP 658 infrastructure was ready and by skipping backward compatibility requirements that slow down &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ty: Astral&#39;s New Python Type Checker Released</title>
      <link>https://pydevtools.com/blog/ty-beta/</link>
      <pubDate>Tue, 16 Dec 2025 22:43:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/ty-beta/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://astral.sh&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Astral&lt;/a&gt; released &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;, a Python type checker written in Rust, today. The company behind uv and Ruff designed ty as an alternative to &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; and &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt;, with performance as a primary focus.&lt;/p&gt;
&lt;h2&gt;Speed Benchmarks&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;speed-benchmarks&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#speed-benchmarks&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;According to Astral&amp;rsquo;s benchmarks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ty checks the home-assistant project in 2.19 seconds (20x faster than mypy&amp;rsquo;s 45.66 seconds)&lt;/li&gt;
&lt;li&gt;After editing a file in PyTorch, ty recomputes diagnostics in 4.7ms (80x faster than pyright&amp;rsquo;s 386ms)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Key Features&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;key-features&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#key-features&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ty includes several design choices that distinguish it from existing type checkers:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Teaching LLMs Python Best Practices</title>
      <link>https://pydevtools.com/blog/teaching-llms-python-best-practices/</link>
      <pubDate>Fri, 21 Nov 2025 09:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/teaching-llms-python-best-practices/</guid>
      <description>&lt;p&gt;Large language models possess extensive Python knowledge from training data, yet they consistently struggle with modern tooling practices. Despite being trained on massive amounts of Python code, frontier models often default to outdated patterns like direct &lt;code&gt;python&lt;/code&gt; or &lt;code&gt;pip&lt;/code&gt; commands instead of using virtual environments and modern tools like &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;how is it, that despite every frontier LLM being insanely python maxxed they rarely use virtural envs, and even adding rules like &amp;quot;we are using uv, do everything with uv&amp;quot; they ignore it and think the system python is broken. like, every time. that&amp;#39;s actually an accomplishment&lt;/p&gt;</description>
    </item>
    <item>
      <title>Claude Code Hooks for uv Projects</title>
      <link>https://pydevtools.com/blog/claude-code-hooks-for-uv/</link>
      <pubDate>Tue, 11 Nov 2025 06:00:00 -0500</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/claude-code-hooks-for-uv/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://code.claude.com/docs/en/overview&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; supports &lt;a href=&#34;https://code.claude.com/docs/en/hooks-guide&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;custom hooks&lt;/a&gt; that guide the AI agent toward project-specific workflows. For Python projects using &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, hooks can prevent Claude from falling back to &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;python&lt;/code&gt; commands.&lt;/p&gt;
&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:flex-col hx:rounded-lg hx:border hx:py-4 hx:px-4 hx:border-gray-200 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-blue-200 hx:bg-blue-100 hx:text-blue-900 hx:dark:border-blue-200/30 hx:dark:bg-blue-900/30 hx:dark:text-blue-200&#34;&gt;
  &lt;p class=&#34;hx:flex hx:items-center hx:font-medium&#34;&gt;&lt;svg height=16px class=&#34;hx:inline-block hx:align-middle hx:mr-2&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; fill=&#34;none&#34; viewBox=&#34;0 0 24 24&#34; stroke-width=&#34;2&#34; stroke=&#34;currentColor&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; d=&#34;M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z&#34;/&gt;&lt;/svg&gt;Note&lt;/p&gt;

  &lt;div class=&#34;hx:w-full hx:min-w-0 hx:leading-7&#34;&gt;
    &lt;div class=&#34;hx:mt-6 hx:leading-7 hx:first:mt-0&#34;&gt;&lt;p&gt;This post builds on the &lt;a href=&#34;https://pydevtools.com/blog/interceptors/&#34;&gt;interceptor approach&lt;/a&gt; for teaching AI agents about uv. Interceptors provide runtime feedback; hooks prevent problematic commands before execution.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sync with uv: Eliminate Pre-commit Version Drift</title>
      <link>https://pydevtools.com/blog/sync-with-uv-eliminate-pre-commit-version-drift/</link>
      <pubDate>Fri, 26 Sep 2025 15:01:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/sync-with-uv-eliminate-pre-commit-version-drift/</guid>
      <description>&lt;p&gt;anaging tool versions across multiple configuration files creates persistent headaches in Python development. When you upgrade &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt; in your &lt;code&gt;pyproject.toml&lt;/code&gt;, you must remember to manually update the &lt;a href=&#34;https://pre-commit.com&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pre-commit&lt;/a&gt; hook version in &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;. This version drift causes inconsistent behavior between local development and &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project/&#34;&gt;pre-commit checks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/tsvikas/sync-with-uv&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;sync-with-uv&lt;/a&gt; library solves this by automatically synchronizing tool versions between &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/a&gt;&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-lock-file/&#34;&gt;lockfile&lt;/a&gt; and &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;the-problem&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#the-problem&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consider this common scenario:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# pyproject.toml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dependency-groups&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;lint&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ruff&amp;gt;=0.1.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mypy&amp;gt;=1.0.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# .pre-commit-config.yaml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;repos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;https://github.com/astral-sh/ruff-pre-commit&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v0.1.5 &lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Must manually sync with pyproject.toml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hooks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ruff&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When &lt;code&gt;uv lock --upgrade&lt;/code&gt; updates ruff to 0.1.8, the pre-commit hook stays pinned to 0.1.5. This creates confusing behavior where local checks differ from pre-commit results. The same gap applies to &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; and any other tool pinned in both files.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Analysis of the New Wave of Python Type Checkers</title>
      <link>https://pydevtools.com/blog/analysis-of-the-new-wave-of-python-type-checkers/</link>
      <pubDate>Wed, 17 Sep 2025 20:31:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/analysis-of-the-new-wave-of-python-type-checkers/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sinon.github.io/future-python-type-checkers/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Rob Hand&amp;rsquo;s comparison of emerging type checkers&lt;/a&gt; is the first comprehensive look at three new Rust-based tools: &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; (Astral), &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyrefly/&#34;&gt;pyrefly&lt;/a&gt; (Meta), and &lt;a href=&#34;https://pydevtools.com/handbook/reference/zuban/&#34;&gt;zuban&lt;/a&gt; (David Halter).&lt;/p&gt;
&lt;h2&gt;Key Findings&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;key-findings&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#key-findings&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Performance drives the rewrite. All three abandon Python implementations for Rust, targeting the bottlenecks that slow existing checkers on large codebases.&lt;/p&gt;
&lt;p&gt;Conformance scores don&amp;rsquo;t predict usefulness. ty passes only 15% of the &lt;a href=&#34;https://github.com/python/typing/tree/main/conformance&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;typing conformance suite&lt;/a&gt;&amp;rsquo;s tests but works well for everyday Python. The suite apparently focuses on edge cases most developers never hit.&lt;/p&gt;</description>
    </item>
    <item>
      <title>prek: pre-commit, but fast</title>
      <link>https://pydevtools.com/blog/prek-pre-commit-but-fast/</link>
      <pubDate>Tue, 16 Sep 2025 10:40:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/prek-pre-commit-but-fast/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pre-commit.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pre-commit&lt;/a&gt; is an essential tool in my development workflow for running &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt; and other tools. However, nobody wants to wait for their commits to be saved, and pre-commit isn&amp;rsquo;t always the fastest.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/prek/&#34;&gt;prek&lt;/a&gt; is a Rust-based drop-in replacement that runs 10x faster while using half the disk space.&lt;/p&gt;
&lt;p&gt;Replacing pre-commit with prek is painless:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install with &lt;code&gt;uv tool install prek&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pre-commit uninstall &amp;amp;&amp;amp; prek install&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it. No configuration changes, no compatibility issues.&lt;/p&gt;</description>
    </item>
    <item>
      <title>uv format: Code Formatting Comes to uv (experimentally!)</title>
      <link>https://pydevtools.com/blog/uv-format-code-formatting-comes-to-uv-experimentally/</link>
      <pubDate>Thu, 21 Aug 2025 16:08:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/uv-format-code-formatting-comes-to-uv-experimentally/</guid>
      <description>&lt;p&gt;The latest &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; release (&lt;a href=&#34;https://github.com/astral-sh/uv/blob/main/CHANGELOG.md#0813&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;0.8.13&lt;/a&gt;) quietly introduced an experimental new command that Python developers have been waiting for: &lt;code&gt;uv format&lt;/code&gt;. This addition brings code formatting directly into uv&amp;rsquo;s toolkit, eliminating the need to juggle multiple tools for basic Python development workflows.&lt;/p&gt;
&lt;h2&gt;What is uv format?&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-is-uv-format&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-is-uv-format&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;uv format&lt;/code&gt; command provides Python code formatting through uv&amp;rsquo;s interface. Under the hood, it calls &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt;&amp;rsquo;s formatter to automatically style your code according to consistent standards.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Google Sunsets Pytype: The End of an Era for Python Type Checking</title>
      <link>https://pydevtools.com/blog/google-sunsets-pytype-the-end-of-an-era-for-python-type-checking/</link>
      <pubDate>Thu, 21 Aug 2025 10:48:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/google-sunsets-pytype-the-end-of-an-era-for-python-type-checking/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/google/pytype/blob/main/README.md&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google announced that Pytype&lt;/a&gt;, their Python static type checker, will end support with Python 3.12. After 13 years of development, Google is shifting resources toward &amp;ldquo;new typing approaches&amp;rdquo; rather than continuing to maintain their bytecode-based analyzer.&lt;/p&gt;
&lt;p&gt;Pytype&amp;rsquo;s fundamental architecture became its limitation. Built on bytecode analysis, the tool struggled with Python&amp;rsquo;s evolving type system. As Google noted, &amp;ldquo;bytecode&amp;rsquo;s inherent instability and propensity to change&amp;rdquo; made implementing new typing PEPs increasingly difficult.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ty&#39;s Breakthrough: Why Incremental Analysis Matters for Python</title>
      <link>https://pydevtools.com/blog/tys-breakthrough-why-incremental-analysis-matters-for-python/</link>
      <pubDate>Mon, 11 Aug 2025 09:22:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/tys-breakthrough-why-incremental-analysis-matters-for-python/</guid>
      <description>&lt;p&gt;In a recent &lt;a href=&#34;https://www.pybitespodcast.com/1501156/episodes/17587007-199-charlie-marsh-on-ty-uv-and-the-python-tooling-renaissance&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PyBytes podcast interview&lt;/a&gt;, Astral&amp;rsquo;s Charlie Marsh shared insights into what makes their new type checker &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; unique and how it aims to address longstanding challenges in Python type checking.&lt;/p&gt;
&lt;h2&gt;What is ty?&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-is-ty&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-is-ty&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ty serves dual purposes: it functions as a standalone command-line type checker (similar to &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt;) and as a language server that powers IDE features like go-to-definition, code completion, and real-time diagnostics.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;We wanted to build a great type checker and a great language server, and they have things that are in common but they also have very different requirements,&amp;rdquo; Marsh explained. &amp;ldquo;If you don&amp;rsquo;t think about both of those from the start, you end up in a little bit of trouble.&amp;rdquo;&lt;/p&gt;</description>
    </item>
    <item>
      <title>How Python&#39;s RFC Process Paved the Way for uv, Ruff, and Ty</title>
      <link>https://pydevtools.com/blog/peps-and-astral/</link>
      <pubDate>Fri, 01 Aug 2025 15:22:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/peps-and-astral/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://astral.sh/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Astral&lt;/a&gt;, an independent startup, has taken the Python world by storm over the last few years with three fast, robust Python developer tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;ruff&lt;/a&gt; (linter and formatter)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; (packaging and project management)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; (static type checker, still under development)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These tools came from the mind of Charlie Marsh, who is neither a Python core developer nor directed by the Python Steering Council. While being independently developed, these tools work seamlessly within the established Python ecosystem. This success stems partly from Astral&amp;rsquo;s attention to guidelines established by the Python Enhancement Proposal (&lt;a href=&#34;https://pydevtools.com/handbook/explanation/pep/&#34;&gt;PEP&lt;/a&gt;) process over the last twenty-five years.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Interview with the Pybites podcast</title>
      <link>https://pydevtools.com/blog/interview-with-the-pybites-podcast/</link>
      <pubDate>Wed, 30 Jul 2025 09:20:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/interview-with-the-pybites-podcast/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/in/bbelderbos/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bob Belderbos&lt;/a&gt; invited me on the &lt;a href=&#34;https://tdhopper.com/blog/interview-with-the-pybites-podcast/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pybites podcast where I talked about the handbook, uv, and more&lt;/a&gt;. I hope you enjoy it.&lt;/p&gt;
&lt;iframe data-testid=&#34;embed-iframe&#34; style=&#34;border-radius:12px&#34; src=&#34;https://open.spotify.com/embed/episode/7xyb2HUcqPEpvLYo8qjQrV?utm_source=generator&amp;theme=0&amp;t=0&#34; width=&#34;100%&#34; height=&#34;352&#34; frameBorder=&#34;0&#34; allowfullscreen=&#34;&#34; allow=&#34;autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture&#34; loading=&#34;lazy&#34;&gt;&lt;/iframe&gt;</description>
    </item>
    <item>
      <title>Use Interceptors to teach Claude Code to use uv</title>
      <link>https://pydevtools.com/blog/interceptors/</link>
      <pubDate>Mon, 28 Jul 2025 09:34:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/interceptors/</guid>
      <description>&lt;p&gt;AI coding agents like Claude Code, Cursor, or GitHub Copilot often default to using system Python interpreters instead of using &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://x.com/mitsuhiko/status/1949093355373142400&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Armin Ronacher, creator of Flask and Jinja, shared an elegant solution to this problem&lt;/a&gt;: creating dummy Python interpreter that actively redirect AI agents toward better tooling choices.&lt;/p&gt;
&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:flex-col hx:rounded-lg hx:border hx:py-4 hx:px-4 hx:border-gray-200 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-green-200 hx:bg-green-100 hx:text-green-900 hx:dark:border-green-200/30 hx:dark:bg-green-900/30 hx:dark:text-green-200&#34;&gt;
  &lt;p class=&#34;hx:flex hx:items-center hx:font-medium&#34;&gt;&lt;svg height=16px class=&#34;hx:inline-block hx:align-middle hx:mr-2&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; fill=&#34;none&#34; viewBox=&#34;0 0 24 24&#34; stroke-width=&#34;2&#34; stroke=&#34;currentColor&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; d=&#34;M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z&#34;/&gt;&lt;/svg&gt;Tip&lt;/p&gt;</description>
    </item>
    <item>
      <title>uvhow: Get uv upgrade instructions for your uv install</title>
      <link>https://pydevtools.com/blog/uvhow-get-uv-upgrade-instructions-for-your-uv-install/</link>
      <pubDate>Tue, 22 Jul 2025 20:18:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/uvhow-get-uv-upgrade-instructions-for-your-uv-install/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve released &lt;a href=&#34;https://github.com/python-developer-tooling-handbook/uvhow&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uvhow&lt;/a&gt;, a simple command-line tool that detects how &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; was installed on your system and provides the correct upgrade instructions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; can be &lt;a href=&#34;https://docs.astral.sh/uv/getting-started/installation/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;installed through multiple methods&lt;/a&gt;. When it&amp;rsquo;s time to upgrade, users often struggle to remember which installation method they used, leading to confusion about the correct upgrade command.&lt;/p&gt;
&lt;p&gt;uvhow automatically detects your uv installation method and tells you exactly how to upgrade:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uvx uvhow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The tool works across Windows, macOS, and Linux and supports all major installation methods including:&lt;/p&gt;</description>
    </item>
    <item>
      <title>uv 0.8 Release: Automatic Python Installation to PATH</title>
      <link>https://pydevtools.com/blog/uv-0-8-release-automatic-python-installation-to-path/</link>
      <pubDate>Sat, 19 Jul 2025 09:27:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/uv-0-8-release-automatic-python-installation-to-path/</guid>
      <description>&lt;p&gt;[!TIP]&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-upgrade-uv/&#34;&gt;Check out our guide to upgrading uv&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; 0.8 stabilizes one of the most significant workflow improvements in Python tooling: automatic installation of Python executables to your PATH. This means you can finally install Python versions with &lt;code&gt;uv python install&lt;/code&gt; and use them system-wide without wrestling with environment activation.&lt;/p&gt;
&lt;h2&gt;Global Python Access Without the Hassle&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;global-python-access-without-the-hassle&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#global-python-access-without-the-hassle&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The headline feature addresses a long-standing frustration in Python development. When you run:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Python is good now!</title>
      <link>https://pydevtools.com/blog/python-is-good-now/</link>
      <pubDate>Wed, 16 Jul 2025 13:43:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/python-is-good-now/</guid>
      <description>&lt;p&gt;love &lt;a href=&#34;https://www.linkedin.com/in/cesarsotovalero/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;César Soto Valero&lt;/a&gt;&amp;rsquo;s recent post &lt;a href=&#34;https://www.cesarsotovalero.net/blog/i-am-switching-to-python-and-actually-liking-it.html&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;I&amp;rsquo;m Switching to Python and Actually Liking It&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;To my great surprise, I’ve found that Python, and everything around it, has really improved a lot over the last decades.&lt;/p&gt;
&lt;p&gt;Here are just three examples:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Python has created a very complete ecosystem of libraries and tools for processing and analyzing data.&lt;/li&gt;
&lt;li&gt;Python has gotten faster with optimized static compilers like Cython.&lt;/li&gt;
&lt;li&gt;Python has done a good job of hiding its legacy ugliness (such as &lt;code&gt;__init__&lt;/code&gt;, &lt;code&gt;__new__&lt;/code&gt;, and similar aberrations), sweetening its syntax to accommodate developers with good taste.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cesarsotovalero.net/blog/i-am-switching-to-python-and-actually-liking-it.html&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Read the whole post&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Why isn&#39;t Python packaging part of core development?</title>
      <link>https://pydevtools.com/blog/why-isnt-python-packaging-part-of-core-development/</link>
      <pubDate>Wed, 16 Jul 2025 10:51:00 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/why-isnt-python-packaging-part-of-core-development/</guid>
      <description>&lt;p&gt;In a &lt;a href=&#34;https://www.bitecode.dev/p/brett-cannon-on-python-humans-and&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;video interview with bitecode.dev&lt;/a&gt;, Python core developer Brett Cannon explains why packaging was never part of core development. The answer is disarmingly simple: the people in charge weren&amp;rsquo;t interested.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Basically, they&amp;rsquo;re separate because Guido doesn&amp;rsquo;t care about packaging. That&amp;rsquo;s really what it comes down to. When packaging started to become a thing, we just didn&amp;rsquo;t have any interest in it, and so it never became a core dev concern. It just never came up—it was just not our thing. So the community in various ways stepped up to fill that void.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hynek Schlawack&#39;s uv Workflow Guide</title>
      <link>https://pydevtools.com/blog/fast-and-boring-uv/</link>
      <pubDate>Mon, 07 Jul 2025 10:21:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/fast-and-boring-uv/</guid>
      <description>&lt;p&gt;{&amp;lt; youtube TiBIjouDGuI &amp;gt;}}&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hynek.me/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hynek Schlawack&lt;/a&gt;&amp;rsquo;s new video &lt;a href=&#34;https://youtu.be/TiBIjouDGuI&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;uv: Making Python Local Workflows FAST and BORING in 2025&amp;rdquo;&lt;/a&gt; demonstrates practical &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; workflows using real  examples.&lt;/p&gt;
&lt;p&gt;He covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replacing &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt;/&lt;a href=&#34;https://pydevtools.com/handbook/reference/virtualenv/&#34;&gt;virtualenv&lt;/a&gt;/&lt;a href=&#34;https://pydevtools.com/handbook/reference/pyenv/&#34;&gt;pyenv&lt;/a&gt; with a single tool&lt;/li&gt;
&lt;li&gt;Dependency management and lock files&lt;/li&gt;
&lt;li&gt;Testing and linting integration&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://just.systems/man/en/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;just&lt;/code&gt;&lt;/a&gt; integration for cross-platform commands&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you missed Part 1 of Hynek&amp;rsquo;s series, &lt;a href=&#34;https://www.youtube.com/watch?v=mFyE9xgeKcA&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;it&amp;rsquo;s available here&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The uv build backend is now stable</title>
      <link>https://pydevtools.com/blog/uv-build-backend/</link>
      <pubDate>Thu, 03 Jul 2025 01:29:29 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/uv-build-backend/</guid>
      <description>&lt;p&gt;For about a year, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; has had a &lt;code&gt;uv build&lt;/code&gt; command for generating distributable &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheels&lt;/a&gt; and &lt;a href=&#34;https://pydevtools.com/handbook/reference/sdist/&#34;&gt;source distributions&lt;/a&gt; on &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;pypi&lt;/a&gt; and elsewhere.&lt;/p&gt;
&lt;p&gt;However, uv has relied on other tools for the &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-build-backend/&#34;&gt;build backend&lt;/a&gt;, i.e. the actual piece constructing the wheel or sdist as defined by &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-517/&#34;&gt;PEP 517&lt;/a&gt;. By default, uv uses &lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;hatchling&lt;/a&gt; as the build backend.&lt;/p&gt;
&lt;p&gt;As of this week, the uv team has now declared the uv build backend as stable and, most notably, really, really fast. &lt;a href=&#34;https://x.com/charliermarsh/status/1940583972607873226&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Charlie Marsh&amp;rsquo;s benchmarks&lt;/a&gt; suggest that it&amp;rsquo;s 10 to 35 times faster than &lt;a href=&#34;https://pydevtools.com/handbook/reference/flit/&#34;&gt;flit&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;hatchling&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/setuptools/&#34;&gt;setuptools&lt;/a&gt;. While I&amp;rsquo;ve never really needed my package builds to be faster, I&amp;rsquo;ve learned that &lt;a href=&#34;https://x.com/tdhopper/status/1850885052894196149&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;faster tools often enable new things I didn&amp;rsquo;t imagine possible&lt;/a&gt;; I&amp;rsquo;m interested to see what those might be here.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Managing Python Versions In Your uv Projects</title>
      <link>https://pydevtools.com/blog/managing-python-versions-in-your-uv-projects/</link>
      <pubDate>Wed, 25 Jun 2025 10:09:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/managing-python-versions-in-your-uv-projects/</guid>
      <description>&lt;p&gt;One of the many ways the package manager &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; has changed Python is by making it painless to install and run different versions of the Python interpreter.&lt;/p&gt;
&lt;p&gt;That said, I&amp;rsquo;ve occasionally gotten tripped up configuring this correctly in my development environments. I&amp;rsquo;ve written a few articles to try to clarify things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-install-python-with-uv/&#34;&gt;How to install Python with uv&lt;/a&gt;. Before you can pin a Python version, you need to have it installed.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-python-version-file/&#34;&gt;What is a .python-version file?&lt;/a&gt; Not unique to uv, a .python-version file specifies which Python version should be used for a particular project or directory.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-python-version-file/#python-version-vs-requires-python-in-pyprojecttoml&#34;&gt;.python-version vs requires-python in pyproject.toml&lt;/a&gt;. The former is for development environments, while the latter is for package metadata.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-change-the-python-version-of-a-uv-project/&#34;&gt;How to change the python version of a uv project&lt;/a&gt;. If &lt;code&gt;uv run&lt;/code&gt; isn&amp;rsquo;t using the version of Python you expected or wanted, here is what you can do.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The goal of the handbook is to help you understand the ecosystem of tools used to make Python development easier and more productive. What are some missing topics you&amp;rsquo;d like to see included?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Comparison of the Two New Typecheckers</title>
      <link>https://pydevtools.com/blog/comparison-of-the-two-new-typecheckers/</link>
      <pubDate>Wed, 28 May 2025 07:29:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/comparison-of-the-two-new-typecheckers/</guid>
      <description>&lt;p&gt;At PyCon 2025&amp;rsquo;s Typing Summit, participants saw the first demonstrations of Meta&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/blog/pyrefly-metas-new-type-checker-for-python/&#34;&gt;Pyrefly&lt;/a&gt; and Astral&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;, two new Python type checkers with significant speed and analysis improvements.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.edward-li.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Edward Li&lt;/a&gt; helpfully took notes and provided a right-up.&lt;/p&gt;
&lt;p&gt;Here are some takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Both tools show substantial speed gains&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pyrefly claims up to 1.8 million lines/sec (35× faster than Pyre, 14× faster than MyPy/pyright), while ty benchmarks show it running 2–3× faster than Pyrefly on real-world codebases.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The tools differ in their approach to type inference&lt;/p&gt;</description>
    </item>
    <item>
      <title>Pyrefly: Meta&#39;s New Type Checker for Python</title>
      <link>https://pydevtools.com/blog/pyrefly-metas-new-type-checker-for-python/</link>
      <pubDate>Wed, 30 Apr 2025 14:45:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/blog/pyrefly-metas-new-type-checker-for-python/</guid>
      <description>&lt;p&gt;Meta has announced &lt;a href=&#34;https://pyrefly.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pyrefly&lt;/a&gt;, a new static type checker built in Rust to deliver fast performance and scalability for large Python codebases.&lt;/p&gt;
&lt;p&gt;While inspired by Meta’s earlier tool &lt;a href=&#34;https://pyre-check.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pyre&lt;/a&gt;, Pyrefly is not a rewrite: it’s a clean-slate implementation with a new type inference engine, a custom incremental computation model, and cross-platform support.&lt;/p&gt;
&lt;p&gt;Despite the maturity of tools like &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt;, and Pyre, Meta found that scaling static analysis across massive codebases required a faster, more flexible foundation. Pyrefly is designed to deliver instant IDE feedback with strong type inference.&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
