<?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 Developer Tooling Handbook</title>
    <link>https://pydevtools.com/handbook/</link>
    <description>A practical guide to Python&#39;s packaging, linting, testing, and typing tools. Covers uv, ruff, pytest, mypy, and more.</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Fri, 08 May 2026 03:22:32 -0400</lastBuildDate>
    
	  <atom:link href="https://pydevtools.com/handbook/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>What is PEP 810?</title>
      <link>https://pydevtools.com/handbook/explanation/what-is-pep-810/</link>
      <pubDate>Fri, 08 May 2026 03:22:32 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/what-is-pep-810/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://peps.python.org/pep-0810/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 810: Explicit Lazy Imports&lt;/a&gt; adds a &lt;code&gt;lazy&lt;/code&gt; keyword in front of an &lt;code&gt;import&lt;/code&gt; or &lt;code&gt;from&lt;/code&gt; statement that defers loading the module until the imported name is first used. Authored by Pablo Galindo Salgado, Germán Méndez Bravo, Thomas Wouters, and others, the PEP was &lt;a href=&#34;https://github.com/python/steering-council/issues/314&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;accepted unanimously by the Steering Council on 3 November 2025&lt;/a&gt; for Python 3.15. Python 3.15 reached beta 1 on 7 May 2026, the first build to ship the feature. PEP 810 is the second attempt at lazy imports in CPython after the implicit-everywhere &lt;a href=&#34;https://peps.python.org/pep-0690/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 690&lt;/a&gt; was withdrawn in 2023; the explicit, opt-in design is the trade that got 810 across the line.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to use uv with VS Code devcontainers</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-uv-with-vs-code-devcontainers/</link>
      <pubDate>Fri, 08 May 2026 03:19:53 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-uv-with-vs-code-devcontainers/</guid>
      <description>&lt;p&gt;A devcontainer hands every teammate the same Python interpreter and the same locked dependencies. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; makes that hand-off cheap: a single &lt;code&gt;uv sync --locked&lt;/code&gt; reads &lt;code&gt;uv.lock&lt;/code&gt; and installs the resolved graph in seconds, on every machine.&lt;/p&gt;
&lt;p&gt;This guide configures a VS Code devcontainer that uses uv to materialize the project&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt; inside the container, points VS Code at the in-container interpreter, and uses the &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-lock-file/&#34;&gt;lockfile&lt;/a&gt; to keep team environments in sync.&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;</description>
    </item>
    
    <item>
      <title>ty: Python Type Checker by Astral</title>
      <link>https://pydevtools.com/handbook/reference/ty/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/ty/</guid>
      <description>&lt;p&gt;ty (pronounced &lt;em&gt;tee-why&lt;/em&gt;) is a static type checker and language server for Python from Astral (creators of &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/uv/&#34;&gt;uv&lt;/a&gt;). It performs static analysis on Python code to identify type-related issues before runtime.&lt;/p&gt;
&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 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;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;&lt;/div&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;ty was initially known by the code name &amp;ldquo;Red-Knot&amp;rdquo; during its early development phase. The tool is in beta, with a stable 1.0 release targeted for 2026.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;When to use ty&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-ty&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-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;Use ty when you want a fast type checker that provides near-instant feedback during development, especially in a large codebase where &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; or &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt; feel slow. Its &amp;ldquo;gradual guarantee&amp;rdquo; ensures that adding type annotations to working code never introduces new errors, which makes incremental adoption predictable. If you already use &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/uv/&#34;&gt;uv&lt;/a&gt;, ty fits naturally into the same Astral toolchain. For a comparison of all three type checkers, see &lt;a href=&#34;https://pydevtools.com/handbook/explanation/how-do-mypy-pyright-and-ty-compare/&#34;&gt;How do mypy, pyright, and ty compare?&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>pyright: Python Static Type Checker by Microsoft</title>
      <link>https://pydevtools.com/handbook/reference/pyright/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pyright/</guid>
      <description>&lt;p&gt;pyright is a static type checker and language server for Python, built and maintained by Microsoft. It analyzes type annotations to detect bugs before runtime and provides editor features like autocompletion, hover information, and go-to-definition.&lt;/p&gt;
&lt;p&gt;pyright powers the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pylance extension&lt;/a&gt; for Visual Studio Code. Pylance is closed-source and adds features on top of pyright&amp;rsquo;s open-source language server, but pyright itself can be used with any editor that supports LSP.&lt;/p&gt;
&lt;h2&gt;When to use pyright&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pyright&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pyright&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;pyright is a strong choice for teams that want real-time type feedback in their editor, especially in VS Code through the Pylance extension. Its aggressive type inference catches bugs in unannotated code that &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; would skip by default.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Pyrefly: Python Type Checker by Meta</title>
      <link>https://pydevtools.com/handbook/reference/pyrefly/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pyrefly/</guid>
      <description>&lt;p&gt;Pyrefly is a static type checker and language server for Python, developed by Meta. It performs static analysis on Python code to identify type-related issues before runtime and provides IDE features like code navigation, autocompletion, and semantic highlighting.&lt;/p&gt;
&lt;p&gt;Pyrefly is a clean-slate implementation inspired by Meta&amp;rsquo;s earlier &lt;a href=&#34;https://pyre-check.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pyre&lt;/a&gt; type checker. It uses a new type inference engine, a custom incremental computation model, and multi-threaded parallel checking.&lt;/p&gt;
&lt;h2&gt;When to use Pyrefly&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pyrefly&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pyrefly&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pyrefly is worth evaluating for large Python codebases where &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; or &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt; feel slow and where aggressive type inference that catches errors in unannotated code is desirable. Its conformance score (90% of the typing spec test suite as of April 2026, per the &lt;a href=&#34;https://htmlpreview.github.io/?https://github.com/python/typing/blob/main/conformance/results/results.html&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python typing conformance dashboard&lt;/a&gt;) is higher than &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/ty/&#34;&gt;ty&lt;/a&gt;, though lower than &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt; and Zuban (another Rust-based checker).&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>pyproject.toml: The Standard Python Project Configuration File</title>
      <link>https://pydevtools.com/handbook/reference/pyproject.toml/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pyproject.toml/</guid>
      <description>&lt;p&gt;pyproject.toml is the standard configuration file for a Python project. It is written in &lt;a href=&#34;https://toml.io/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TOML&lt;/a&gt; and lives in the project root. A single file captures three kinds of information that older Python projects scattered across &lt;code&gt;setup.py&lt;/code&gt;, &lt;code&gt;setup.cfg&lt;/code&gt;, &lt;code&gt;MANIFEST.in&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;, &lt;code&gt;.flake8&lt;/code&gt;, &lt;code&gt;mypy.ini&lt;/code&gt;, &lt;code&gt;pytest.ini&lt;/code&gt;, and &lt;code&gt;tox.ini&lt;/code&gt;: project metadata, build-system requirements, and third-party tool configuration.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://peps.python.org/pep-0518/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 518&lt;/a&gt; introduced pyproject.toml in 2016 to declare build-system requirements in a tool-agnostic way. &lt;a href=&#34;https://peps.python.org/pep-0621/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 621&lt;/a&gt; extended it in 2020 with a standardized &lt;code&gt;[project]&lt;/code&gt; table for project metadata. Together, the two PEPs make pyproject.toml the canonical home for a Python project&amp;rsquo;s configuration.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to use ty in CI</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-ty-in-ci/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-ty-in-ci/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; can run in CI with no installation step beyond &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;. Because ty is a single binary with no runtime dependencies, it adds minimal overhead to your pipeline.&lt;/p&gt;
&lt;h2&gt;GitHub Actions&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;github-actions&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#github-actions&#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 simplest approach uses &lt;code&gt;uvx&lt;/code&gt; to run ty without adding it as a project dependency:&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-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;nt&#34;&gt;uses&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;actions/checkout@v4&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;uses&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;astral-sh/setup-uv@v7&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;run&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;uvx ty check src/&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;To get inline annotations on pull requests, use the &lt;code&gt;github&lt;/code&gt; output format:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to migrate from pyright to ty</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-migrate-from-pyright-to-ty/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-migrate-from-pyright-to-ty/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; is a Python type checker developed by &lt;a href=&#34;https://astral.sh/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Astral&lt;/a&gt; (the creators of &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/ruff/&#34;&gt;Ruff&lt;/a&gt;). It ships as a single binary with no runtime dependencies, which eliminates &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt;&amp;rsquo;s Node.js requirement.&lt;/p&gt;
&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-amber-200 hx:bg-amber-100 hx:text-amber-900 hx:dark:border-amber-200/30 hx:dark:bg-amber-900/30 hx:dark:text-amber-200&#34;&gt;
  &lt;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z&#34;/&gt;&lt;/svg&gt;&lt;/div&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;ty is currently in beta. While actively developed, it&amp;rsquo;s still missing some features and may not be ready for full production adoption. This guide helps evaluate readiness and plan for migration.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;Understanding ty&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;understanding-ty&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#understanding-ty&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;When to consider migrating&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-consider-migrating&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-consider-migrating&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Projects wanting faster type checking on large codebases&lt;/li&gt;
&lt;li&gt;Teams already using other Astral tools (Ruff, uv)&lt;/li&gt;
&lt;li&gt;Projects wanting to eliminate Node.js dependency&lt;/li&gt;
&lt;li&gt;Projects without complex platform-specific dependencies lacking stubs&lt;/li&gt;
&lt;li&gt;Projects with simple pyright configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;When to wait&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-wait&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-wait&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Projects heavily dependent on pyright-specific features like &lt;code&gt;--verifytypes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Projects requiring &lt;code&gt;typeCheckingMode&lt;/code&gt; presets (until ty adds equivalents)&lt;/li&gt;
&lt;li&gt;Projects with complex platform-specific dependencies lacking stubs&lt;/li&gt;
&lt;li&gt;Projects where pyright&amp;rsquo;s specific type inference is depended upon&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installation and basic usage&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;installation-and-basic-usage&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#installation-and-basic-usage&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Installing ty&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;installing-ty&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#installing-ty&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ty is distributed as a standalone binary. The easiest way to use it is via &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uvx&lt;/a&gt;:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to install the Astral plugins for Claude Code</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-install-astral-plugins-for-claude-code/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-install-astral-plugins-for-claude-code/</guid>
      <description>&lt;p&gt;Astral publishes an &lt;a href=&#34;https://github.com/astral-sh/claude-code-plugins&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;official Claude Code plugin&lt;/a&gt; that bundles three skills (&lt;code&gt;/astral:uv&lt;/code&gt;, &lt;code&gt;/astral:ruff&lt;/code&gt;, &lt;code&gt;/astral:ty&lt;/code&gt;) and a &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt; language server. The skills give Claude up-to-date usage guidance for each tool, and the language server feeds live type-checking diagnostics into the conversation.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://claude.com/product/claude-code&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-install-uv/&#34;&gt;uv installed&lt;/a&gt; (required by the ty language server)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Install the plugin for yourself&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;install-the-plugin-for-yourself&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#install-the-plugin-for-yourself&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;hextra-steps hx:ml-4 hx:mb-12 hx:ltr:border-l hx:rtl:border-r hx:border-gray-200 hx:ltr:pl-6 hx:rtl:pr-6 hx:dark:border-neutral-800 [counter-reset:step]&#34;&gt;
&lt;h3&gt;1. Add the Astral marketplace&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;1-add-the-astral-marketplace&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#1-add-the-astral-marketplace&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run this slash command inside Claude Code:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How do Python type checkers compare?</title>
      <link>https://pydevtools.com/handbook/explanation/how-do-mypy-pyright-and-ty-compare/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/how-do-mypy-pyright-and-ty-compare/</guid>
      <description>&lt;p&gt;&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;, &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/basedpyright/&#34;&gt;Basedpyright&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/zuban/&#34;&gt;Zuban&lt;/a&gt; all analyze type annotations to catch bugs before runtime. They read the same type-hint annotations (from &lt;a href=&#34;https://peps.python.org/pep-0484/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 484&lt;/a&gt;, the standard that introduced Python&amp;rsquo;s type system in 2014) and largely agree on the parts of the spec a working program uses. They disagree on speed, default strictness, treatment of unannotated code, editor integration, and licensing, and those disagreements are what make the choice matter.&lt;/p&gt;
&lt;p&gt;Here is the shape of the field in 2026:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Basedpyright: Python Type Checker (pyright Fork)</title>
      <link>https://pydevtools.com/handbook/reference/basedpyright/</link>
      <pubDate>Fri, 08 May 2026 03:19:33 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/basedpyright/</guid>
      <description>&lt;p&gt;Basedpyright is a static type checker and language server for Python, maintained by DetachHead as a community fork of Microsoft&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt;. It tracks upstream pyright closely and adds diagnostic rules, stricter defaults, and language-server features that Microsoft keeps exclusive to its closed-source Pylance extension.&lt;/p&gt;
&lt;p&gt;The fork exists because pyright ships as an npm package and depends on Node.js, which makes it awkward to pin as a project dependency, and because the editor features most Python developers associate with &amp;ldquo;pyright&amp;rdquo; actually live in Pylance, whose license restricts it to official Microsoft VS Code builds. Basedpyright packages the language server on &lt;a href=&#34;https://pypi.org/project/basedpyright/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PyPI&lt;/a&gt; so &lt;code&gt;uv add --dev basedpyright&lt;/code&gt; works, and re-implements Pylance-style features (inlay hints, semantic highlighting, docstring completion) in the open-source server so VS Code forks like Cursor, VSCodium, and Positron can use them.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>pylint: Python Static Code Analyzer</title>
      <link>https://pydevtools.com/handbook/reference/pylint/</link>
      <pubDate>Fri, 08 May 2026 03:18:58 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pylint/</guid>
      <description>&lt;p&gt;pylint is a static code analysis tool that identifies programming errors, coding standard violations, and potential bugs in Python code. It analyzes source code without running it to find issues from basic syntax errors to complex design problems.&lt;/p&gt;
&lt;h2&gt;When to use pylint&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pylint&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pylint&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pylint fits codebases that depend on its semantic checks, such as cyclomatic complexity, duplicate-code detection, and design-rule enforcement that go beyond what style-focused linters catch. Teams with an established &lt;code&gt;.pylintrc&lt;/code&gt; and CI pipelines tuned around its output keep a familiar tool backed by a long-running plugin ecosystem.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>flake8: Python Linter</title>
      <link>https://pydevtools.com/handbook/reference/flake8/</link>
      <pubDate>Fri, 08 May 2026 03:18:58 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/flake8/</guid>
      <description>&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 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;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;&lt;/div&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;Flake8 has been largely superseded by newer tools like &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ruff&lt;/a&gt;, which offer significantly faster performance and more features. Consider using Ruff for new projects.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Flake8 is a Python linting tool that enforces style consistency and checks for programming errors. It combines multiple code quality tools into a single interface: PyFlakes for logical errors, pycodestyle for style checking, and mccabe for code complexity checking.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Black: Python Code Formatter</title>
      <link>https://pydevtools.com/handbook/reference/black/</link>
      <pubDate>Fri, 08 May 2026 03:18:58 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/black/</guid>
      <description>&lt;p&gt;Black is an opinionated Python code formatter that automatically formats Python code to conform to a strict subset of PEP 8. Black deliberately offers minimal configuration options, aiming to end arguments about code formatting by providing &amp;ldquo;one way&amp;rdquo; to format code.&lt;/p&gt;
&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 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;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;&lt;/div&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;Consider using &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ruff&lt;/a&gt; instead of Black. Ruff provides the same formatting capabilities but with significantly better performance. Ruff also includes linting, import sorting, and other code quality tools in a single high-performance package.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;When to use Black&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-black&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-black&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Black suits codebases that already run it in CI or pre-commit hooks and teams that want a zero-config formatter to end style debates. It has been the default Python formatter for years, with stable output that editor plugins, &lt;code&gt;pre-commit&lt;/code&gt; hooks, and CI configurations across the ecosystem rely on.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Build a Python library with a C&#43;&#43; extension</title>
      <link>https://pydevtools.com/handbook/tutorial/build-a-python-library-with-a-cpp-extension/</link>
      <pubDate>Fri, 08 May 2026 03:18:44 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/build-a-python-library-with-a-cpp-extension/</guid>
      <description>&lt;p&gt;Python handles most tasks well, but numerical code and tight loops can hit its performance ceiling. C++ removes that ceiling. This tutorial walks you through creating a Python package where the performance-critical code lives in C++, compiled into a native extension module that Python imports like any other module.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll use three tools together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; manages the Python project, dependencies, and virtual environment&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://scikit-build-core.readthedocs.io/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;scikit-build-core&lt;/a&gt; is the &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-build-backend/&#34;&gt;build backend&lt;/a&gt; that drives CMake to compile C++ code into a Python extension module&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pybind11.readthedocs.io/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pybind11&lt;/a&gt; is the C++ library that bridges C++ and Python, letting you write C++ functions callable from Python&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; installed (&lt;a href=&#34;https://docs.astral.sh/uv/getting-started/installation/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;installation guide&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A C++ compiler (g++ or clang++)&lt;/li&gt;
&lt;li&gt;CMake 3.15 or later&lt;/li&gt;
&lt;/ul&gt;






&lt;div class=&#34;hextra-scrollbar hx:overflow-x-auto hx:overflow-y-hidden hx:overscroll-x-contain&#34;&gt;
  &lt;div class=&#34;hx:mt-4 hx:flex hx:w-max hx:min-w-full hx:border-b hx:border-gray-200 hx:pb-px hx:dark:border-neutral-800&#34; role=&#34;tablist&#34;&gt;&lt;button class=&#34;hextra-tabs-toggle hx:cursor-pointer hx:data-[state=selected]:border-primary-500 hx:data-[state=selected]:text-primary-600 hx:data-[state=selected]:dark:border-primary-500 hx:data-[state=selected]:dark:text-primary-600 hx:mr-2 hx:rounded-t hx:p-2 hx:font-medium hx:leading-5 hx:transition-colors hx:-mb-0.5 hx:select-none hx:border-b-2 hx:border-transparent hx:text-gray-600 hx:hover:border-gray-200 hx:hover:text-black hx:dark:text-gray-200 hx:dark:hover:border-neutral-800 hx:dark:hover:text-white hx:hextra-focus-visible-inset&#34; id=&#34;tabs-tab-tabs-03-0&#34; role=&#34;tab&#34; type=&#34;button&#34; aria-controls=&#34;tabs-panel-tabs-03-0&#34; aria-selected=&#34;true&#34; tabindex=&#34;0&#34; data-state=&#34;selected&#34;&gt;&lt;span class=&#34;hx:inline-flex hx:items-center hx:gap-1.5&#34;&gt;&lt;span&gt;macOS/Linux&lt;/span&gt;&lt;/span&gt;&lt;/button&gt;&lt;button class=&#34;hextra-tabs-toggle hx:cursor-pointer hx:data-[state=selected]:border-primary-500 hx:data-[state=selected]:text-primary-600 hx:data-[state=selected]:dark:border-primary-500 hx:data-[state=selected]:dark:text-primary-600 hx:mr-2 hx:rounded-t hx:p-2 hx:font-medium hx:leading-5 hx:transition-colors hx:-mb-0.5 hx:select-none hx:border-b-2 hx:border-transparent hx:text-gray-600 hx:hover:border-gray-200 hx:hover:text-black hx:dark:text-gray-200 hx:dark:hover:border-neutral-800 hx:dark:hover:text-white hx:hextra-focus-visible-inset&#34; id=&#34;tabs-tab-tabs-03-1&#34; role=&#34;tab&#34; type=&#34;button&#34; aria-controls=&#34;tabs-panel-tabs-03-1&#34; aria-selected=&#34;false&#34; tabindex=&#34;-1&#34;&gt;&lt;span class=&#34;hx:inline-flex hx:items-center hx:gap-1.5&#34;&gt;&lt;span&gt;Windows&lt;/span&gt;&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;div class=&#34;hextra-tabs-panel hx:rounded-sm hx:pt-6 hx:hidden hx:data-[state=selected]:block&#34; id=&#34;tabs-panel-tabs-03-0&#34; role=&#34;tabpanel&#34; aria-labelledby=&#34;tabs-tab-tabs-03-0&#34; aria-hidden=&#34;false&#34; tabindex=&#34;0&#34; data-state=&#34;selected&#34;&gt;&lt;p&gt;Most macOS and Linux systems ship with a C++ compiler. On macOS, install the Xcode Command Line Tools (&lt;code&gt;xcode-select --install&lt;/code&gt;). On Ubuntu/Debian, install the &lt;code&gt;build-essential&lt;/code&gt; and &lt;code&gt;cmake&lt;/code&gt; packages.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>What is PEP 829?</title>
      <link>https://pydevtools.com/handbook/explanation/what-is-pep-829/</link>
      <pubDate>Thu, 07 May 2026 13:56:14 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/what-is-pep-829/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://peps.python.org/pep-0829/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 829: Package Startup Configuration Files&lt;/a&gt; splits the two jobs that &lt;code&gt;.pth&lt;/code&gt; files do today into two separate files. &lt;code&gt;.pth&lt;/code&gt; keeps the &lt;code&gt;sys.path&lt;/code&gt; extension job. A new &lt;code&gt;&amp;lt;name&amp;gt;.start&lt;/code&gt; file takes over package initialization, replacing the &lt;code&gt;import&lt;/code&gt; line that turns every &lt;code&gt;.pth&lt;/code&gt; file into an &lt;code&gt;exec()&lt;/code&gt; surface at interpreter startup. Authored by Barry Warsaw and accepted on 24 April 2026 for Python 3.15. Python 3.15 reached beta 1 on 7 May 2026, the first build to ship the &lt;code&gt;.start&lt;/code&gt; mechanism for package authors to test against.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>What is CPython&#39;s JIT Compiler?</title>
      <link>https://pydevtools.com/handbook/explanation/what-is-cpythons-jit-compiler/</link>
      <pubDate>Thu, 07 May 2026 13:56:14 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/what-is-cpythons-jit-compiler/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-python/&#34;&gt;CPython&lt;/a&gt;&amp;rsquo;s JIT compiler is an experimental feature, introduced in Python 3.13, that translates frequently executed Python bytecode into machine code while a program runs. It is off by default and requires no changes to Python source code. Its goal is to make CPython faster over successive releases without asking developers to switch runtimes or rewrite anything.&lt;/p&gt;
&lt;h2&gt;How CPython runs code without the JIT&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;how-cpython-runs-code-without-the-jit&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#how-cpython-runs-code-without-the-jit&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CPython compiles &lt;code&gt;.py&lt;/code&gt; files into bytecode, a compact set of instructions stored in &lt;code&gt;.pyc&lt;/code&gt; files. The interpreter then executes those instructions one at a time in a loop: fetch the next bytecode, dispatch to the C function that implements it, repeat. Every Python program pays the cost of that fetch-and-dispatch cycle on every instruction.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Sampling vs deterministic profilers: which should I use?</title>
      <link>https://pydevtools.com/handbook/explanation/sampling-vs-deterministic-profilers/</link>
      <pubDate>Thu, 07 May 2026 13:56:14 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/sampling-vs-deterministic-profilers/</guid>
      <description>&lt;p&gt;Two different designs dominate Python profiling, and they produce two different kinds of lies about your program. A &lt;strong&gt;deterministic profiler&lt;/strong&gt; intercepts every function call, records the entry and exit, and tallies the total. A &lt;strong&gt;sampling profiler&lt;/strong&gt; peeks at the call stack on a timer and counts how often each function shows up. Both give you a list of hot functions, and the list will not always agree.&lt;/p&gt;
&lt;p&gt;The difference matters because the choice changes what you can trust about the output.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>profiling.sampling: Statistical Profiler in the Standard Library</title>
      <link>https://pydevtools.com/handbook/reference/profiling-sampling/</link>
      <pubDate>Thu, 07 May 2026 13:56:14 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/profiling-sampling/</guid>
      <description>&lt;p&gt;&lt;code&gt;profiling.sampling&lt;/code&gt; is the statistical sampling profiler that ships with Python 3.15, developed under the codename Tachyon. It samples the call stacks of a Python process on a timer rather than instrumenting every call, and it can attach to a process that is already running by PID. The CLI is invoked as &lt;code&gt;python -m profiling.sampling&lt;/code&gt;, with &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;attach&lt;/code&gt; as the two profiling entry points, &lt;code&gt;dump&lt;/code&gt; for a single stack snapshot, and &lt;code&gt;replay&lt;/code&gt; for converting saved binary profiles to other output formats.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to Test Against Multiple Python Versions Using uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-test-against-multiple-python-versions-using-uv/</link>
      <pubDate>Thu, 07 May 2026 13:56:14 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-test-against-multiple-python-versions-using-uv/</guid>
      <description>&lt;p&gt;A library that works on Python 3.11 can break on 3.12 because of removed deprecations, C API changes, or subtle differences in standard library behavior. Catching these failures before your users do requires running tests against each version you support. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; makes this straightforward: it downloads Python versions on demand, so there is no need to install them yourself.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.astral.sh/uv/getting-started/installation/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uv installed&lt;/a&gt; on your system&lt;/li&gt;
&lt;li&gt;A Python project with &lt;a href=&#34;https://pydevtools.com/handbook/reference/pytest/&#34;&gt;pytest&lt;/a&gt; configured as a dependency (see &lt;a href=&#34;https://pydevtools.com/handbook/tutorial/setting-up-testing-with-pytest-and-uv/&#34;&gt;Setting up testing with pytest and uv&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Run Tests Against a Single Alternate Version&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;run-tests-against-a-single-alternate-version&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#run-tests-against-a-single-alternate-version&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pass &lt;code&gt;--python&lt;/code&gt; to select a specific Python version:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>What is PEP 517/518 compatibility?</title>
      <link>https://pydevtools.com/handbook/explanation/what-is-pep-517/</link>
      <pubDate>Thu, 07 May 2026 07:17:13 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/what-is-pep-517/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://peps.python.org/pep-0518/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 518&lt;/a&gt; introduced &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt; in 2016 and defined the &lt;code&gt;[build-system]&lt;/code&gt; table for declaring build-time dependencies in a tool-agnostic way. &lt;a href=&#34;https://peps.python.org/pep-0517/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 517&lt;/a&gt; followed in 2017 and defined the hook API that every build backend implements and every build frontend calls. Together they replaced the setup.py-only build model and made it possible to use &lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;Hatchling&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/flit/&#34;&gt;flit_core&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/poetry/&#34;&gt;poetry-core&lt;/a&gt;, uv_build, maturin, or any other backend with the same install commands.&lt;/p&gt;
&lt;h2&gt;The problem the PEPs solved&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;the-problem-the-peps-solved&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#the-problem-the-peps-solved&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before PEP 518, every Python package was built by running &lt;code&gt;setup.py&lt;/code&gt;, a Python script that imported &lt;a href=&#34;https://pydevtools.com/handbook/reference/setuptools/&#34;&gt;setuptools&lt;/a&gt; (or the older distutils) and called functions to declare metadata, list dependencies, and produce build artifacts. The installer had to execute &lt;code&gt;setup.py&lt;/code&gt; to discover anything about the package, including which build dependencies the script itself needed. That ordering created a circular requirement: setuptools had to already be present before the installer could ask the project what it required.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Briefcase</title>
      <link>https://pydevtools.com/handbook/reference/briefcase/</link>
      <pubDate>Thu, 07 May 2026 07:15:39 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/briefcase/</guid>
      <description>&lt;p&gt;Briefcase is the only mainstream Python packaging tool that ships to iOS and Android. It also packages applications for macOS, Windows, Linux, and the Web, producing platform-specific artifacts (&lt;code&gt;.app&lt;/code&gt;/DMG, MSI, &lt;code&gt;.deb&lt;/code&gt;/&lt;code&gt;.rpm&lt;/code&gt;/AppImage/Flatpak, Xcode project, Gradle project, PyScript/Pyodide site) from a single &lt;code&gt;pyproject.toml&lt;/code&gt; configuration.&lt;/p&gt;
&lt;p&gt;Briefcase is part of the &lt;a href=&#34;https://beeware.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;BeeWare&lt;/a&gt; project and is the packaging companion to &lt;a href=&#34;https://toga.readthedocs.io/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Toga&lt;/a&gt;, BeeWare&amp;rsquo;s cross-platform GUI toolkit. Briefcase does not require Toga; it packages any Python application, GUI or otherwise. Install it with &lt;code&gt;uv tool install briefcase&lt;/code&gt; or &lt;code&gt;pipx install briefcase&lt;/code&gt;; the BSD 3-Clause license imposes no restrictions on applications it packages.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Run your first Python script with uv</title>
      <link>https://pydevtools.com/handbook/tutorial/how-to-run-your-first-python-script/</link>
      <pubDate>Thu, 07 May 2026 07:15:18 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/how-to-run-your-first-python-script/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; can run &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-python/&#34;&gt;Python&lt;/a&gt; scripts without any prior Python installation. This tutorial starts with a one-line script and builds up to using a third-party package through &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-723/&#34;&gt;inline script metadata&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#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/how-to/how-to-install-uv/&#34;&gt;Install uv&lt;/a&gt; on your system.&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>Setting up GitHub Actions with uv</title>
      <link>https://pydevtools.com/handbook/tutorial/setting-up-github-actions-with-uv/</link>
      <pubDate>Wed, 06 May 2026 06:25:49 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/setting-up-github-actions-with-uv/</guid>
      <description>&lt;p&gt;Every push to &lt;code&gt;main&lt;/code&gt; and every pull request should be tested and linted automatically. This tutorial sets up that pipeline using GitHub Actions and &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, running &lt;a href=&#34;https://pydevtools.com/handbook/reference/pytest/&#34;&gt;pytest&lt;/a&gt; and &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt; across multiple Python versions.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; installed (&lt;a href=&#34;https://docs.astral.sh/uv/getting-started/installation/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;installation guide&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A GitHub account&lt;/li&gt;
&lt;li&gt;Familiarity with &lt;a href=&#34;https://pydevtools.com/handbook/tutorial/setting-up-testing-with-pytest-and-uv/&#34;&gt;setting up testing with pytest and uv&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Clone the Example Project&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;clone-the-example-project&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#clone-the-example-project&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This tutorial uses a small temperature-converter project with code and tests already written but no CI configured. Clone it and move into the directory:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>pipx: Install Python CLI Tools in Isolation</title>
      <link>https://pydevtools.com/handbook/reference/pipx/</link>
      <pubDate>Wed, 06 May 2026 06:23:54 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pipx/</guid>
      <description>&lt;p&gt;pipx is a command line tool to install and run Python command line applications in isolated environments. Each installed application gets its own virtual environment, preventing dependency conflicts between tools while making their executables available on your &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;When to use pipx&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pipx&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pipx&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reach for pipx when installing standalone Python CLI tools (ruff, csvkit, httpie, cookiecutter) that should stay isolated from any project&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt; and remain on &lt;code&gt;PATH&lt;/code&gt; across shell sessions. It fits teams that already have pipx wired into setup scripts, documentation, or CI and prefer a narrowly-scoped tool over a general-purpose one. For new installations, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; provides equivalent isolation through &lt;code&gt;uv tool install&lt;/code&gt; and &lt;code&gt;uvx&lt;/code&gt; while also handling Python version and project management in the same binary.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Hatch: Python Project Manager</title>
      <link>https://pydevtools.com/handbook/reference/hatch/</link>
      <pubDate>Wed, 06 May 2026 06:23:54 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/hatch/</guid>
      <description>&lt;p&gt;hatch is a Python project management tool maintained by the Python Packaging Authority (PyPA). It handles virtual environment management, dependency resolution, project scaffolding, and publishing through a unified interface that follows Python packaging standards. Its build backend, hatchling, is one of the most widely used on PyPI.&lt;/p&gt;
&lt;h2&gt;When to Use Hatch&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-hatch&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-hatch&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hatch suits library authors who want a single, standards-compliant tool covering scaffolding, building, publishing, and multi-version testing. Its environment matrix system runs tests across Python versions and dependency sets without a separate tool like &lt;a href=&#34;https://pydevtools.com/handbook/reference/tox/&#34;&gt;tox&lt;/a&gt; or &lt;a href=&#34;https://pydevtools.com/handbook/reference/nox/&#34;&gt;nox&lt;/a&gt;. PyPA governance backs the project.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to write Claude Code hooks for Python projects</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-write-claude-code-hooks-for-python-projects/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-write-claude-code-hooks-for-python-projects/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://code.claude.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; hooks are scripts that run at specific points during a session, letting you enforce project conventions programmatically. A &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-configure-claude-code-to-use-uv/&#34;&gt;CLAUDE.md file&lt;/a&gt; suggests how Claude should behave; hooks guarantee it by blocking disallowed commands, auto-formatting files, or injecting context before Claude sees your prompt. See the &lt;a href=&#34;https://code.claude.com/docs/en/hooks&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;official hooks documentation&lt;/a&gt; for the full reference.&lt;/p&gt;
&lt;h2&gt;How hooks work&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;how-hooks-work&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#how-hooks-work&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hooks fire on events during a Claude Code session. Claude Code supports over 25 event types (SessionStart, PreToolUse, PostToolUse, UserPromptSubmit, Stop, and more). This guide covers the four most useful for Python projects:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to use Python skills with Claude Code</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-python-skills-with-claude-code/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-python-skills-with-claude-code/</guid>
      <description>&lt;p&gt;Skills bottle up your Python workflow. Instead of re-explaining &amp;ldquo;tighten these type annotations&amp;rdquo; or &amp;ldquo;use &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; instead of pip&amp;rdquo; every session, save the procedure to a markdown file once and let &lt;a href=&#34;https://code.claude.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; reach for it when you ask, either by slash command or by describing the task in plain English. Long reference material that would crowd a &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-use-the-pydevtools-claude-md-template/&#34;&gt;CLAUDE.md&lt;/a&gt; only loads when the skill runs.&lt;/p&gt;
&lt;p&gt;This guide installs the Astral plugin, walks through writing a custom Python skill, and shows when a skill beats CLAUDE.md or a hook.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to Set Up CLAUDE.md for a Python Project</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-the-pydevtools-claude-md-template/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-the-pydevtools-claude-md-template/</guid>
      <description>&lt;p&gt;Claude Code reads a &lt;code&gt;CLAUDE.md&lt;/code&gt; file in your project root every session. Without one, it falls back to &lt;code&gt;pip install&lt;/code&gt;, bare &lt;code&gt;python&lt;/code&gt; commands, and &lt;code&gt;setup.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://pydevtools.com/&#34;&gt;Python Developer Tooling Handbook&lt;/a&gt; maintains a &lt;a href=&#34;https://pydevtools.com/configs/CLAUDE.md&#34;&gt;CLAUDE.md template&lt;/a&gt; for Python projects using &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/pytest/&#34;&gt;pytest&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What the template covers&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-the-template-covers&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-the-template-covers&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Package management with uv (&lt;code&gt;uv add&lt;/code&gt;, &lt;code&gt;uv run&lt;/code&gt;, &lt;code&gt;uv sync&lt;/code&gt; instead of pip)&lt;/li&gt;
&lt;li&gt;Project creation with &lt;code&gt;uv init&lt;/code&gt; and &lt;code&gt;pyproject.toml&lt;/code&gt; (never &lt;code&gt;setup.py&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Testing with pytest (discovery conventions, file layout, execution)&lt;/li&gt;
&lt;li&gt;Linting and formatting with ruff&lt;/li&gt;
&lt;li&gt;Type checking with ty or mypy&lt;/li&gt;
&lt;li&gt;Pre-commit hooks with &lt;a href=&#34;https://pydevtools.com/handbook/reference/prek/&#34;&gt;prek&lt;/a&gt; or pre-commit&lt;/li&gt;
&lt;li&gt;Anti-patterns Claude should avoid (manual venvs, &lt;code&gt;pip install&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At 86 lines, the template stays inside Anthropic&amp;rsquo;s &lt;a href=&#34;https://code.claude.com/docs/en/best-practices&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;recommended 200-line limit&lt;/a&gt; for CLAUDE.md files.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to configure Ruff with Claude Code</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-configure-ruff-with-claude-code/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-configure-ruff-with-claude-code/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://code.claude.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; does not run &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt; by default, so Python edits land unformatted and lint errors slip through unless you wire Ruff in yourself. Out of the box, Claude often calls bare &lt;code&gt;ruff&lt;/code&gt; (which may resolve outside the project&amp;rsquo;s virtual environment) and skips formatting after edits. Wiring Ruff in correctly takes four layers, each with a different job.&lt;/p&gt;
&lt;p&gt;This guide covers all four and how they stack together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A CLAUDE.md instruction that points Claude at Ruff&lt;/li&gt;
&lt;li&gt;The Astral plugin&amp;rsquo;s &lt;code&gt;/astral:ruff&lt;/code&gt; skill for on-demand Ruff guidance&lt;/li&gt;
&lt;li&gt;A PostToolUse hook that auto-formats every Python edit&lt;/li&gt;
&lt;li&gt;A &lt;a href=&#34;https://pre-commit.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pre-commit&lt;/a&gt; gate that catches anything Claude missed before commit time&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://code.claude.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;A Python project with Ruff added as a dev dependency (&lt;code&gt;uv add --dev ruff&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jq&lt;/code&gt; installed if you want to use the shell version of the auto-format hook&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Pick the right layer for your goal&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;pick-the-right-layer-for-your-goal&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#pick-the-right-layer-for-your-goal&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each layer answers a different question. Pick the ones that match what you actually need; nothing requires installing all four.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to configure Claude Code to use virtual environments</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-configure-claude-code-to-use-virtual-environments/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-configure-claude-code-to-use-virtual-environments/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://code.claude.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; starts a fresh shell for every Bash tool call, so &lt;code&gt;source .venv/bin/activate&lt;/code&gt; in one command has no effect on the next. Without configuration, Claude reaches for system Python and installs packages outside the project&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt;. Four configuration patterns work around the stateless-shell limitation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;uv run&lt;/code&gt; for projects on &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, which sidesteps activation entirely&lt;/li&gt;
&lt;li&gt;A CLAUDE.md instruction that tells Claude to call the venv&amp;rsquo;s interpreter directly&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;.claude/settings.json&lt;/code&gt; &lt;code&gt;env&lt;/code&gt; block that pre-sets &lt;code&gt;VIRTUAL_ENV&lt;/code&gt; and &lt;code&gt;PATH&lt;/code&gt; for every session&lt;/li&gt;
&lt;li&gt;A PreToolUse hook that blocks bare &lt;code&gt;python&lt;/code&gt; and &lt;code&gt;pip&lt;/code&gt; so the rules are enforced, not just suggested&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Trace why &lt;code&gt;source activate&lt;/code&gt; doesn&amp;rsquo;t persist&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;trace-why-source-activate-doesnt-persist&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#trace-why-source-activate-doesnt-persist&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each Bash tool call Claude Code runs spawns a separate shell process. Environment changes made by &lt;code&gt;source .venv/bin/activate&lt;/code&gt; (it sets &lt;code&gt;VIRTUAL_ENV&lt;/code&gt; and prepends &lt;code&gt;.venv/bin&lt;/code&gt; to &lt;code&gt;PATH&lt;/code&gt;) live only inside that shell. When the next tool call starts a new shell, those variables are gone.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to configure Claude Code to use uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-configure-claude-code-to-use-uv/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-configure-claude-code-to-use-uv/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://claude.com/product/claude-code&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Claude Code&lt;/a&gt; defaults to &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; when it needs to install packages or run scripts. A &lt;a href=&#34;https://code.claude.com/docs/en/memory#set-up-a-project-claude-md&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CLAUDE.md&lt;/a&gt; file in your project root overrides that default so every session uses &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; instead.&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>Claude Code for Python: A Complete Guide</title>
      <link>https://pydevtools.com/handbook/explanation/claude-code-complete-guide/</link>
      <pubDate>Wed, 06 May 2026 06:23:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/claude-code-complete-guide/</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; is a terminal-based AI assistant that reads your files, runs commands, edits code, and iterates on errors. Describe what you want in plain English, and Claude Code determines which files to read, which commands to run, and what code to write. When something breaks, it reads the error, adjusts, and tries again.&lt;/p&gt;
&lt;p&gt;This guide covers how to use Claude Code for Python development specifically. Each section is self-contained, so skip to whatever is relevant.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to set up prek hooks for a Python project</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-set-up-prek-hooks-for-a-python-project/</link>
      <pubDate>Wed, 06 May 2026 06:22:32 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-set-up-prek-hooks-for-a-python-project/</guid>
      <description>&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-amber-200 hx:bg-amber-100 hx:text-amber-900 hx:dark:border-amber-200/30 hx:dark:bg-amber-900/30 hx:dark:text-amber-200&#34;&gt;
  &lt;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z&#34;/&gt;&lt;/svg&gt;&lt;/div&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;This guide assumes you have a Python project managed with &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uv&lt;/a&gt;. If you haven&amp;rsquo;t created a project yet, see the &lt;a href=&#34;https://pydevtools.com/handbook/tutorial/create-your-first-python-project/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;project creation tutorial&lt;/a&gt;.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/prek/&#34;&gt;prek&lt;/a&gt; is a fast drop-in replacement for &lt;a href=&#34;https://pre-commit.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pre-commit&lt;/a&gt; that runs hooks faster, uses less disk space, and ships as a single binary with no Python dependency. It reads the same &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; files, so the configuration in this guide also works with pre-commit. See the &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 version of this guide&lt;/a&gt; for the original tool.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to set up pre-commit hooks for a Python project</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project/</link>
      <pubDate>Wed, 06 May 2026 06:22:32 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project/</guid>
      <description>&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-amber-200 hx:bg-amber-100 hx:text-amber-900 hx:dark:border-amber-200/30 hx:dark:bg-amber-900/30 hx:dark:text-amber-200&#34;&gt;
  &lt;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z&#34;/&gt;&lt;/svg&gt;&lt;/div&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;This guide assumes you have a Python project managed with &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uv&lt;/a&gt;. If you haven&amp;rsquo;t created a project yet, see the &lt;a href=&#34;https://pydevtools.com/handbook/tutorial/create-your-first-python-project/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;project creation tutorial&lt;/a&gt;.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&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 a framework that manages Git hooks. It runs tools like linters and formatters automatically before each commit, catching problems before they reach version control. This guide walks through installing pre-commit, configuring hooks for a Python project, and integrating it with &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/mypy/&#34;&gt;mypy&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to migrate from Black to Ruff formatter</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-migrate-from-black-to-ruff-formatter/</link>
      <pubDate>Wed, 06 May 2026 06:22:32 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-migrate-from-black-to-ruff-formatter/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt;&amp;rsquo;s &lt;code&gt;ruff format&lt;/code&gt; command is a drop-in replacement for &lt;a href=&#34;https://pydevtools.com/handbook/reference/black/&#34;&gt;Black&lt;/a&gt;. It follows the same formatting style, reads the same defaults (88-character lines, double quotes, space indentation), and formats 10-100x faster. Ruff also handles linting and import sorting, so the migration is often a chance to consolidate three tools (Black, &lt;a href=&#34;https://pydevtools.com/handbook/reference/flake8/&#34;&gt;flake8&lt;/a&gt;, isort) into one.&lt;/p&gt;
&lt;p&gt;This guide covers translating Black&amp;rsquo;s configuration, reformatting the codebase, updating &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 hooks&lt;/a&gt;, and updating CI.&lt;/p&gt;
&lt;h2&gt;Check your starting point&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;check-your-starting-point&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#check-your-starting-point&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Commit any pending changes. The migration reformats files, so starting from a clean working tree makes the diff easy to review.&lt;/li&gt;
&lt;li&gt;Note your current Black version. Ruff&amp;rsquo;s formatter tracks Black&amp;rsquo;s stable style; the reformatting diff should be empty or nearly empty if your project already runs a recent Black release.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Add Ruff to the project&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;add-ruff-to-the-project&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#add-ruff-to-the-project&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Add Ruff as a development dependency:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to configure Ruff for Django</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-configure-ruff-for-django/</link>
      <pubDate>Wed, 06 May 2026 06:22:32 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-configure-ruff-for-django/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt;&amp;rsquo;s default rule set knows nothing about Django. It will not flag &lt;code&gt;CharField(null=True)&lt;/code&gt;, but it will flag every long line in an auto-generated migration. This guide fixes that: enable the &lt;code&gt;DJ&lt;/code&gt; rule set, give Ruff the per-file ignores Django&amp;rsquo;s generated code needs, and produce a configuration block that catches Django-specific bugs without burying them under noise.&lt;/p&gt;
&lt;p&gt;This guide assumes a working Django project. Follow &lt;a href=&#34;https://pydevtools.com/handbook/tutorial/set-up-a-django-project-with-uv/&#34;&gt;Set up a Django project with uv&lt;/a&gt; first if there isn&amp;rsquo;t one yet.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Ruff: A Complete Guide to Python&#39;s Fastest Linter and Formatter</title>
      <link>https://pydevtools.com/handbook/explanation/ruff-complete-guide/</link>
      <pubDate>Wed, 06 May 2026 06:22:32 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/ruff-complete-guide/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt; replaces flake8, &lt;a href=&#34;https://pydevtools.com/handbook/reference/black/&#34;&gt;Black&lt;/a&gt;, isort, pyupgrade, pydocstyle, and dozens of other Python code quality tools with a single binary. It re-implements over 1,000 lint rules from dozens of existing tools and runs 10-100x faster than the tools it replaces.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://astral.sh&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Astral&lt;/a&gt; (the team behind &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;) builds and maintains Ruff.&lt;/p&gt;
&lt;h2&gt;Why Ruff exists&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;why-ruff-exists&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#why-ruff-exists&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ruff gives Python developers a single tool for linting, formatting, import sorting, and code modernization. One dev dependency, one configuration section in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;, one CI step. It ships as a standalone binary with no runtime dependencies, so installation is fast and there are no version conflicts to manage.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to configure recommended Ruff defaults</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-configure-recommended-ruff-defaults/</link>
      <pubDate>Tue, 05 May 2026 16:21:56 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-configure-recommended-ruff-defaults/</guid>
      <description>&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-amber-200 hx:bg-amber-100 hx:text-amber-900 hx:dark:border-amber-200/30 hx:dark:bg-amber-900/30 hx:dark:text-amber-200&#34;&gt;
  &lt;div class=&#34;hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2&#34;&gt;&lt;svg height=1.2em class=&#34;hx:inline-block hx:align-middle&#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;M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z&#34;/&gt;&lt;/svg&gt;&lt;/div&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;This guide assumes you have a Python project set up. If you haven&amp;rsquo;t created a project yet, see the &lt;a href=&#34;https://pydevtools.com/handbook/tutorial/create-your-first-python-project/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;project creation tutorial&lt;/a&gt; before proceeding.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This guide shows how to configure &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt; with a curated set of linting rules that extend beyond the defaults. When starting a new project, it&amp;rsquo;s easier to enable a comprehensive set of rules from the beginning and selectively disable any that don&amp;rsquo;t fit the project&amp;rsquo;s needs, rather than gradually adding rules later when there&amp;rsquo;s already code to fix.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Set up a data science project with uv</title>
      <link>https://pydevtools.com/handbook/tutorial/set-up-a-data-science-project-with-uv/</link>
      <pubDate>Tue, 05 May 2026 06:58:20 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/set-up-a-data-science-project-with-uv/</guid>
      <description>&lt;p&gt;This tutorial sets up a data analysis project with &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; so that every dependency is pinned, notebooks run in the right environment, and a collaborator can reproduce your setup with a single command.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Install uv following the &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-install-uv/&#34;&gt;installation guide&lt;/a&gt;. No separate Python install is required.&lt;/p&gt;
&lt;h2&gt;Create the project&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;create-the-project&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#create-the-project&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&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-console&#34; data-lang=&#34;console&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; uv init weather_analysis
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;go&#34;&gt;Initialized project `weather-analysis` at `/path/to/weather_analysis`
&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;go&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; weather_analysis
&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;This creates a project directory with a &lt;code&gt;pyproject.toml&lt;/code&gt;, a &lt;code&gt;main.py&lt;/code&gt;, and a &lt;code&gt;README.md&lt;/code&gt;. The &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt; stores all project metadata and dependencies:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Set up a Django project with uv</title>
      <link>https://pydevtools.com/handbook/tutorial/set-up-a-django-project-with-uv/</link>
      <pubDate>Tue, 05 May 2026 06:57:20 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/set-up-a-django-project-with-uv/</guid>
      <description>&lt;p&gt;Most &lt;a href=&#34;https://www.djangoproject.com/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt; setup guides still tell you to install Python and a virtual environment by hand before you reach &lt;code&gt;runserver&lt;/code&gt;. This tutorial uses &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; for the Python install and the &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt;. Every &lt;code&gt;manage.py&lt;/code&gt; command runs against a pinned interpreter.&lt;/p&gt;
&lt;h2&gt;Confirm uv is installed&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;confirm-uv-is-installed&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#confirm-uv-is-installed&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you do not already have uv, follow the &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-install-uv/&#34;&gt;installation guide&lt;/a&gt;. No separate Python install is required; uv will download an interpreter on first use.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>mypy: Python Static Type Checker</title>
      <link>https://pydevtools.com/handbook/reference/mypy/</link>
      <pubDate>Tue, 05 May 2026 06:57:20 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/mypy/</guid>
      <description>&lt;p&gt;mypy is a static type checker for Python that analyzes type annotations to detect bugs before runtime. It has been the default Python type checker since 2012 and has the broadest ecosystem support of any Python type checking tool.&lt;/p&gt;
&lt;h2&gt;When to use mypy&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-mypy&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-mypy&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use mypy when you want to catch type-related bugs before runtime by adding static type checking to a Python project. It is the most established Python type checker with broad ecosystem support, making it a reliable default for projects that are adopting type annotations incrementally. For faster checking or tighter VS Code integration, consider &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyright/&#34;&gt;pyright&lt;/a&gt;; for an emerging alternative from the creators of &lt;a href=&#34;https://pydevtools.com/handbook/reference/ruff/&#34;&gt;Ruff&lt;/a&gt;, see &lt;a href=&#34;https://pydevtools.com/handbook/reference/ty/&#34;&gt;ty&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Zuban: Mypy-Compatible Python Type Checker</title>
      <link>https://pydevtools.com/handbook/reference/zuban/</link>
      <pubDate>Tue, 05 May 2026 06:56:59 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/zuban/</guid>
      <description>&lt;p&gt;Zuban is a static type checker and language server for Python, written in Rust by David Halter, author of &lt;a href=&#34;https://github.com/davidhalter/jedi&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Jedi&lt;/a&gt; (the longstanding Python autocompletion library) and &lt;a href=&#34;https://github.com/davidhalter/parso&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;parso&lt;/a&gt;. It runs in two modes: &lt;code&gt;zuban mypy&lt;/code&gt; (aliased as &lt;code&gt;zmypy&lt;/code&gt;) behaves as a mypy-compatible drop-in, and &lt;code&gt;zuban check&lt;/code&gt; applies a pyright-style inference strategy.&lt;/p&gt;
&lt;p&gt;Zuban launched as open source under AGPL-3.0 in September 2025, with a paid commercial license available for organizations that cannot accept AGPL&amp;rsquo;s source-disclosure requirements. That licensing split is the tool&amp;rsquo;s most load-bearing distinguishing factor: it funds full-time development in a way that MIT-licensed competitors cannot, but it also rules Zuban out for many proprietary codebases unless the team buys a commercial license.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>What is a Python language server?</title>
      <link>https://pydevtools.com/handbook/explanation/what-is-a-python-language-server/</link>
      <pubDate>Tue, 05 May 2026 06:56:59 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/what-is-a-python-language-server/</guid>
      <description>&lt;p&gt;Type a dot after a variable in your editor and a list of methods appears. Hover a function and its signature shows up in a tooltip. Right-click an import and &amp;ldquo;Go to definition&amp;rdquo; jumps to the source. Most Python developers have used these features for years without knowing the name of the program behind them.&lt;/p&gt;
&lt;p&gt;That program is a &lt;strong&gt;language server&lt;/strong&gt;. It is a separate process running alongside your editor, and it is doing most of the work readers usually credit to &amp;ldquo;the editor.&amp;rdquo; Naming it explains why VS Code, Neovim, Cursor, and Zed give you the same autocomplete on the same file, and why a faster type checker makes your editor feel faster.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to configure mypy and django-stubs in a uv project</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-configure-mypy-and-django-stubs-in-a-uv-project/</link>
      <pubDate>Tue, 05 May 2026 06:56:59 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-configure-mypy-and-django-stubs-in-a-uv-project/</guid>
      <description>&lt;p&gt;Run &lt;a href=&#34;https://pydevtools.com/handbook/reference/mypy/&#34;&gt;mypy&lt;/a&gt; on a Django project without &lt;code&gt;django-stubs&lt;/code&gt; and the first error is &lt;code&gt;Need type annotation for &amp;quot;name&amp;quot;&lt;/code&gt; on every model field. mypy cannot infer that &lt;code&gt;models.CharField(max_length=200)&lt;/code&gt; resolves to &lt;code&gt;str&lt;/code&gt; or that &lt;code&gt;Question.objects.filter()&lt;/code&gt; returns a &lt;code&gt;QuerySet[Question]&lt;/code&gt;. The &lt;code&gt;django-stubs&lt;/code&gt; package and its bundled mypy plugin fill those gaps.&lt;/p&gt;
&lt;p&gt;This guide installs both with &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; and configures everything from a single &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;&lt;code&gt;pyproject.toml&lt;/code&gt;&lt;/a&gt;, with an override pattern for adopting type checking gradually on a legacy Django codebase.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>How to deploy a uv project to AWS Lambda</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-deploy-a-uv-project-to-aws-lambda/</link>
      <pubDate>Tue, 05 May 2026 06:55:50 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-deploy-a-uv-project-to-aws-lambda/</guid>
      <description>&lt;p&gt;AWS Lambda packages a Python function as either a zip archive (up to 250 MB unzipped) or a container image (up to 10 GB). Both formats need every dependency the function imports, compiled for Lambda&amp;rsquo;s Linux runtime, with no virtual environment and no &lt;code&gt;pip install&lt;/code&gt; step at runtime. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; is fast at producing exactly that shape, and its &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-lock-file/&#34;&gt;lockfile&lt;/a&gt; makes the resulting deployment reproducible.&lt;/p&gt;
&lt;h2&gt;Pick a packaging format&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;pick-a-packaging-format&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#pick-a-packaging-format&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Format&lt;/th&gt;
          &lt;th&gt;Pick when&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Container image&lt;/td&gt;
          &lt;td&gt;Production services, dependencies near or above the 250 MB zip limit, native libraries that don&amp;rsquo;t ship manylinux wheels, image-based local testing.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Zip archive&lt;/td&gt;
          &lt;td&gt;Small functions, simple dependencies, fastest cold starts on Python managed runtimes.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Lambda layer + zip&lt;/td&gt;
          &lt;td&gt;Dependencies change rarely, function code changes often.&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The zip and layer paths use the same &lt;code&gt;uv export&lt;/code&gt; + &lt;code&gt;uv pip install --target&lt;/code&gt; recipe; only the zip layout differs. The container path uses Lambda&amp;rsquo;s official Python base image and &lt;code&gt;uv pip install&lt;/code&gt; at build time.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Why should I use a virtual environment?</title>
      <link>https://pydevtools.com/handbook/explanation/why-should-i-use-a-virtual-environment/</link>
      <pubDate>Tue, 05 May 2026 06:54:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/why-should-i-use-a-virtual-environment/</guid>
      <description>&lt;p&gt;A virtual environment is an isolated Python runtime environment that allows you to work on different Python projects with different dependencies without conflicts. Virtual environments are fundamental to Python development.&lt;/p&gt;
&lt;h2&gt;The Problem Virtual Environments Solve&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;the-problem-virtual-environments-solve&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#the-problem-virtual-environments-solve&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;details class=&#34;hx:last-of-type:mb-0 hx:rounded-lg hx:bg-neutral-50 hx:dark:bg-neutral-800 hx:p-2 hx:mt-4 hx:group&#34; open&gt;
  &lt;summary class=&#34;hx:flex hx:items-center hx:cursor-pointer hx:select-none hx:list-none hx:p-1 hx:rounded-sm hx:transition-colors hx:hover:bg-gray-100 hx:dark:hover:bg-neutral-800 hx:before:mr-1 hx:before:inline-block hx:before:transition-transform hx:before:content-[&#39;&#39;] hx:dark:before:invert hx:rtl:before:rotate-180 hx:group-open:before:rotate-90&#34;&gt;
    &lt;strong class=&#34;hx:text-lg&#34;&gt;Real-world analogy&lt;/strong&gt;
  &lt;/summary&gt;
  &lt;div class=&#34;hx:p-2 hx:overflow-hidden&#34;&gt;
    Think of a virtual environment like a clean workshop for each project. Instead of having all your tools mixed together in one garage (which could lead to version conflicts or missing dependencies), each project gets its own dedicated space with exactly the tools it needs.
  &lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;When you install Python packages globally (directly into your system Python), several problems arise:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>virtualenv: Python Virtual Environment Tool</title>
      <link>https://pydevtools.com/handbook/reference/virtualenv/</link>
      <pubDate>Tue, 05 May 2026 06:54:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/virtualenv/</guid>
      <description>&lt;p&gt;virtualenv creates isolated Python virtual environments. Virtual environments are self-contained directories that contain a Python installation for a particular version of Python, plus additional packages.&lt;/p&gt;
&lt;h2&gt;When to use virtualenv&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-virtualenv&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-virtualenv&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;virtualenv fits projects that need broader Python version support than the standard library&amp;rsquo;s &lt;a href=&#34;https://pydevtools.com/handbook/reference/venv/&#34;&gt;venv&lt;/a&gt; module offers, or that benefit from its faster environment creation through cached seed packages. Most modern projects on Python 3.3 or later can use venv, which ships in the standard library and covers the same core workflow without an extra dependency. For new work, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; creates and manages &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environments&lt;/a&gt; automatically as part of its run and sync commands, removing most of the manual steps either tool requires.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>pyenv: Python Version Manager</title>
      <link>https://pydevtools.com/handbook/reference/pyenv/</link>
      <pubDate>Tue, 05 May 2026 06:54:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pyenv/</guid>
      <description>&lt;p&gt;pyenv is a command-line tool for installing, managing, and switching between multiple Python interpreter versions on macOS and Linux. It intercepts Python commands through shell shims, routing them to whichever interpreter version is active for the current directory, user, or system.&lt;/p&gt;
&lt;h2&gt;When to use pyenv&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pyenv&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pyenv&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;pyenv fits workflows where Python version management should remain separate from package management. It pairs with &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/venv/&#34;&gt;venv&lt;/a&gt;, or any other packaging tool without imposing opinions on how dependencies are managed. If you want a single tool that also handles dependencies and virtual environments, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; covers version management alongside those workflows.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Create your first Python project with uv</title>
      <link>https://pydevtools.com/handbook/tutorial/create-your-first-python-project/</link>
      <pubDate>Mon, 04 May 2026 10:58:58 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/create-your-first-python-project/</guid>
      <description>&lt;p&gt;This Python uv tutorial walks you through building a text analysis tool that counts words, measures sentence length, and reports word frequency. No prior Python experience required; &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; handles the Python install, project scaffolding, and dependency management for you.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;prerequisites&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#prerequisites&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we begin, make sure you have uv installed on your system. You can install it following &lt;a href=&#34;https://docs.astral.sh/uv/getting-started/installation/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the directions from the uv documentation&lt;/a&gt;.&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>
    
  </channel>
</rss>
