<?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 – Packaging</title>
    <link>https://pydevtools.com/handbook/topics/packaging/</link>
    <description>Build wheels, lock dependencies, and publish Python packages to PyPI.</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 08 Apr 2026 13:59:07 -0400</lastBuildDate>
    
	  <atom:link href="https://pydevtools.com/handbook/topics/packaging/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Why Doesn&#39;t the Authoritative Python Packaging Guide Mention the Best Thing that&#39;s Happened to Python Packaging?</title>
      <link>https://pydevtools.com/handbook/explanation/uv-not-in-ppug/</link>
      <pubDate>Thu, 27 Feb 2025 14:56:00 +0000</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/uv-not-in-ppug/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://docs.astral.sh/uv/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uv&lt;/a&gt; is the most widely adopted new Python tool in years, yet the &lt;a href=&#34;https://packaging.python.org/en/latest/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Packaging User Guide&lt;/a&gt; (PPUG) at &lt;a href=&#34;https://packaging.python.org/en/latest/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;packaging.python.org&lt;/a&gt; makes no mention of it. The reason has less to do with uv and more to do with how Python packaging governance works.&lt;/p&gt;
&lt;h2&gt;What uv Does&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-uv-does&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-uv-does&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;uv delivers 10-100x faster package operations than pip while consolidating functionality previously spread across multiple utilities (pip, pip-tools, virtualenv, pyenv, and more) into a single tool. Since its introduction in early 2024, it has become the default recommendation in many Python teams and communities.&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>build: Python Package Build Frontend</title>
      <link>https://pydevtools.com/handbook/reference/build/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/build/</guid>
      <description>&lt;p&gt;build is a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-517/&#34;&gt;PEP 517-compliant&lt;/a&gt; Python package builder developed by the &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypa/&#34;&gt;Python Packaging Authority (PyPA)&lt;/a&gt;. It provides a standardized interface for building Python packages using any compliant &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-build-backend/&#34;&gt;build backend&lt;/a&gt;, serving as a simple frontend tool that executes the build process defined by backends like &lt;a href=&#34;https://pydevtools.com/handbook/reference/setuptools/&#34;&gt;setuptools&lt;/a&gt;, &lt;a href=&#34;https://pydevtools.com/handbook/reference/flit/&#34;&gt;flit&lt;/a&gt;, or &lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;hatchling&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Core Functionality&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;core-functionality&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#core-functionality&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Build Operations&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;build-operations&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#build-operations&#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;Source Distributions: Creates &lt;a href=&#34;https://pydevtools.com/handbook/reference/sdist/&#34;&gt;sdist&lt;/a&gt; packages containing source code&lt;/li&gt;
&lt;li&gt;Binary Distributions: Builds &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheel packages&lt;/a&gt; for direct installation&lt;/li&gt;
&lt;li&gt;Backend Compatibility: Works with any &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-517/&#34;&gt;PEP 517-compatible&lt;/a&gt; build backend&lt;/li&gt;
&lt;li&gt;Isolated Builds: Manages build dependencies in separate environments&lt;/li&gt;
&lt;li&gt;Cross-Platform Support: Functions consistently across operating systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Command Interface&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;command-interface&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#command-interface&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Build both wheel and sdist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&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;c1&#34;&gt;# Build only a wheel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m build --wheel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&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;c1&#34;&gt;# Build only a source distribution&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m build --sdist
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&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;c1&#34;&gt;# Build in a specified directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m build /path/to/project
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&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;c1&#34;&gt;# Build with specific Python interpreter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m build --python-executable /path/to/python&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;h2&gt;Technical Design&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;technical-design&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#technical-design&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;build operates using a straightforward process flow:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Build a Python library with a C extension</title>
      <link>https://pydevtools.com/handbook/tutorial/build-a-python-library-with-a-c-extension/</link>
      <pubDate>Wed, 29 Apr 2026 07:06:23 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/build-a-python-library-with-a-c-extension/</guid>
      <description>&lt;p&gt;Python handles strings well. C handles them faster. In this tutorial, you&amp;rsquo;ll write three string functions in C, compile them into a shared library, and call them from Python using &lt;a href=&#34;https://cffi.readthedocs.io/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cffi&lt;/a&gt;. The result is a normal Python package that anyone can import.&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;You need two things installed:&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; (&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&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-01-0&#34; role=&#34;tab&#34; type=&#34;button&#34; aria-controls=&#34;tabs-panel-tabs-01-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-01-1&#34; role=&#34;tab&#34; type=&#34;button&#34; aria-controls=&#34;tabs-panel-tabs-01-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-01-0&#34; role=&#34;tabpanel&#34; aria-labelledby=&#34;tabs-tab-tabs-01-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 already have a C compiler. Check by running:&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>Build a Python library with a Rust extension</title>
      <link>https://pydevtools.com/handbook/tutorial/build-a-python-library-with-a-rust-extension/</link>
      <pubDate>Fri, 15 May 2026 11:45:25 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/build-a-python-library-with-a-rust-extension/</guid>
      <description>&lt;p&gt;Python is flexible and productive, but sometimes a function needs to run faster than Python allows. Rust gives you that speed with memory safety and no garbage collector. This tutorial walks you through creating a Python package where the performance-critical code lives in Rust, 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://www.maturin.rs/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;maturin&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 compiles Rust code into a Python extension module&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pyo3.rs/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PyO3&lt;/a&gt; is the Rust library that bridges Rust and Python, letting you write Rust 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;Rust installed via &lt;a href=&#34;https://rustup.rs/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;rustup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Verify both are working:&lt;/p&gt;</description>
    </item>
    <item>
      <title>cibuildwheel: Cross-Platform Python Wheel Builder</title>
      <link>https://pydevtools.com/handbook/reference/cibuildwheel/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/cibuildwheel/</guid>
      <description>&lt;p&gt;cibuildwheel is a CI tool that builds Python &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheels&lt;/a&gt; for multiple platforms, architectures, and Python versions from a single configuration. It runs on CI servers (GitHub Actions, GitLab CI, Azure Pipelines, CircleCI, and Cirrus CI), automating the work of compiling C/C++/Rust/Cython extensions and producing &lt;a href=&#34;https://peps.python.org/pep-0600/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;manylinux&lt;/a&gt;/musllinux-compliant wheels.&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>Conda Package</title>
      <link>https://pydevtools.com/handbook/reference/conda-package/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/conda-package/</guid>
      <description>&lt;p&gt;A conda package is a compressed archive containing pre-built binaries, library code, metadata, and dependency information for installation through &lt;a href=&#34;https://pydevtools.com/handbook/reference/conda/&#34;&gt;conda&lt;/a&gt; channels. It serves the same role in the conda ecosystem that a &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheel&lt;/a&gt; serves on &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt;, with one critical difference: conda packages can bundle software from any language (Python, R, C++, Fortran, Julia), not just Python.&lt;/p&gt;
&lt;h2&gt;Package Formats&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;package-formats&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#package-formats&#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 conda ecosystem recognizes two archive formats, referred to as v1 and v2.&lt;/p&gt;</description>
    </item>
    <item>
      <title>cx_Freeze</title>
      <link>https://pydevtools.com/handbook/reference/cx-freeze/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/cx-freeze/</guid>
      <description>&lt;p&gt;cx_Freeze is a Python application freezer that packages a Python program and its dependencies into a self-contained directory or executable. It targets Windows, macOS, and Linux from the same configuration and ships native commands for producing each platform&amp;rsquo;s preferred installer format. Recent releases add experimental support for freezing free-threaded CPython builds. Install it with &lt;code&gt;uv tool install cx_Freeze&lt;/code&gt; or &lt;code&gt;pipx install cx_Freeze&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;When to Use cx_Freeze&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-cx_freeze&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-cx_freeze&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;cx_Freeze fits projects whose deliverable is an installer rather than a raw binary. Its &lt;code&gt;bdist_msi&lt;/code&gt;, &lt;code&gt;bdist_dmg&lt;/code&gt;, &lt;code&gt;bdist_appimage&lt;/code&gt;, and &lt;code&gt;bdist_deb&lt;/code&gt; commands produce platform-native installers in one step, without a second packaging tool like WiX, dmgbuild, or &lt;code&gt;dpkg-deb&lt;/code&gt;. Most other freezers stop at a folder or single executable and leave installer generation to the user.&lt;/p&gt;</description>
    </item>
    <item>
      <title>distutils: Python&#39;s Original Build System</title>
      <link>https://pydevtools.com/handbook/reference/distutils/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/distutils/</guid>
      <description>&lt;p&gt;distutils was a standard library module that provided the original mechanism for building and distributing Python packages. It defined the &lt;code&gt;setup.py&lt;/code&gt;-based workflow that became the foundation of Python packaging for over two decades.&lt;/p&gt;
&lt;h2&gt;What It Did&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;what-it-did&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#what-it-did&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;distutils handled package building, installation, and distribution through a &lt;code&gt;setup.py&lt;/code&gt; script:&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;distutils.core&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&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&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;example&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;py_modules&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;example&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Running &lt;code&gt;python setup.py install&lt;/code&gt; would copy modules into the correct location on the target system. Running &lt;code&gt;python setup.py sdist&lt;/code&gt; would produce a source distribution archive.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Does Poetry Support Python Standards for Dependency Management?</title>
      <link>https://pydevtools.com/handbook/explanation/poetry-python-dependency-management/</link>
      <pubDate>Tue, 07 Apr 2026 14:40:41 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/poetry-python-dependency-management/</guid>
      <description>&lt;p&gt;Poetry 2.0 supports standard &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; project metadata in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;. Before version 2.0, Poetry used only its own &lt;code&gt;tool.poetry&lt;/code&gt; configuration format, but &lt;a href=&#34;https://python-poetry.org/blog/announcing-poetry-2.0.0&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the 2.0 release&lt;/a&gt; adopted the standard &lt;code&gt;project&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;Poetry now offers two configuration approaches. You can use &lt;code&gt;project.dependencies&lt;/code&gt; for standard dependency declarations or &lt;code&gt;tool.poetry.dependencies&lt;/code&gt; for Poetry-specific features, and you can combine both when needed.&lt;/p&gt;
&lt;p&gt;Standard metadata makes projects more portable between build tools and aligns with emerging packaging standards.&lt;/p&gt;
&lt;h2&gt;Related Handbook Pages&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;related-handbook-pages&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#related-handbook-pages&#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/poetry/&#34;&gt;Poetry reference page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-migrate-from-poetry-to-uv/&#34;&gt;How to migrate from Poetry to uv&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&#34;pdt-learn-more&#34;&gt;Learn More&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;learn-more&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#learn-more&#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://python-poetry.org/blog/announcing-poetry-2.0.0&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Poetry 2.0 Release Blog Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://peps.python.org/pep-0621/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PEP 621 Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://packaging.python.org/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Packaging User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://python-poetry.org/docs/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Poetry Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Flit: Python Package Build and Publish Tool</title>
      <link>https://pydevtools.com/handbook/reference/flit/</link>
      <pubDate>Tue, 07 Apr 2026 14:40:41 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/flit/</guid>
      <description>&lt;p&gt;Flit is a Python packaging tool designed to be simple to use. Flit provides &lt;code&gt;flit init&lt;/code&gt; to create a new package, &lt;code&gt;flit publish&lt;/code&gt; for publishing to PyPI, automatically includes data files in the package, and fetches the package version number from the &lt;code&gt;__init__.py&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Flit does not support advanced packaging functionality like building C extensions. It also doesn&amp;rsquo;t provide a CLI for managing virtual environments or dependencies; the user creates their own &lt;a href=&#34;https://pydevtools.com/handbook/reference/virtualenv/&#34;&gt;virtualenv&lt;/a&gt; and adds dependencies to the &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt; file manually.&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 do I ship a Python application to end users?</title>
      <link>https://pydevtools.com/handbook/explanation/how-do-i-ship-a-python-application-to-end-users/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/how-do-i-ship-a-python-application-to-end-users/</guid>
      <description>&lt;p&gt;Python usually ships an environment rather than a native executable. It ships as code plus an interpreter plus dependencies, which is why distribution gets harder the moment the users are not Python developers themselves. The real question is not whether Python can be shipped well. It can. The question is which delivery shape fits the audience: an install command, a bundled app, a container image, or something that stops being Python at all.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How do uv and Poetry compare?</title>
      <link>https://pydevtools.com/handbook/explanation/how-do-uv-and-poetry-compare/</link>
      <pubDate>Fri, 10 Apr 2026 13:36:01 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/how-do-uv-and-poetry-compare/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/poetry/&#34;&gt;Poetry&lt;/a&gt; and &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; both manage Python projects through &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;, create lockfiles, and handle virtual environments. Poetry has been the default recommendation for years; uv, built by Astral, arrived in 2024 with broader scope and faster dependency resolution. They differ in how.&lt;/p&gt;
&lt;h2&gt;Scope&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;scope&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#scope&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Poetry handles dependency management, virtual environments, building, and publishing. Everything else it delegates. A different Python version requires &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyenv/&#34;&gt;pyenv&lt;/a&gt;. Running a CLI tool without installing it globally requires &lt;a href=&#34;https://pydevtools.com/handbook/reference/pipx/&#34;&gt;pipx&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How Python Package Formats Evolved: From tar.gz to .whl</title>
      <link>https://pydevtools.com/handbook/explanation/how-python-package-formats-evolved/</link>
      <pubDate>Sat, 11 Apr 2026 17:25:27 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/explanation/how-python-package-formats-evolved/</guid>
      <description>&lt;p&gt;In 2000, installing a third-party Python package meant downloading a tarball, extracting it, and running &lt;code&gt;python setup.py install&lt;/code&gt;. There was no dependency resolution, no uninstall command, no record of what got installed where. Removing a package meant deleting files by hand and hoping none were missed.&lt;/p&gt;
&lt;p&gt;Twenty-five years later, &lt;code&gt;uv pip install numpy&lt;/code&gt; fetches a pre-built binary wheel and drops it into place in under a second. The journey between those two moments is a story of each generation solving one problem while inadvertently creating the next.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to add dynamic versioning to uv projects</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-add-dynamic-versioning-to-uv-projects/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-add-dynamic-versioning-to-uv-projects/</guid>
      <description>&lt;p&gt;Dynamic versioning generates version numbers from Git tags instead of requiring manual updates to a static version string in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;. The release workflow becomes a single &lt;code&gt;git tag&lt;/code&gt; command: the build backend reads the tag, and the wheel and source distribution filenames pick up the matching version automatically.&lt;/p&gt;
&lt;p&gt;This guide uses &lt;a href=&#34;https://github.com/ninoseki/uv-dynamic-versioning/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uv-dynamic-versioning&lt;/a&gt;, a &lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;hatchling&lt;/a&gt; plugin that ships a sensible default configuration for &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; projects.&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;A Git repository for your Python project with at least one commit&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; installed on your system&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;src/your_package/&lt;/code&gt; layout (the default for &lt;code&gt;uv init --package&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Configure the build system&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;configure-the-build-system&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#configure-the-build-system&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Update &lt;code&gt;pyproject.toml&lt;/code&gt; to use uv-dynamic-versioning as a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-build-backend/&#34;&gt;build backend&lt;/a&gt; dependency:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Build Multi-Platform Wheels with cibuildwheel</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-build-multi-platform-wheels-with-cibuildwheel/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-build-multi-platform-wheels-with-cibuildwheel/</guid>
      <description>&lt;p&gt;Python packages with compiled extensions (C, C++, Rust, Cython) need platform-specific &lt;a href=&#34;https://pydevtools.com/handbook/reference/wheel/&#34;&gt;wheels&lt;/a&gt; so users can install them without a compiler. &lt;a href=&#34;https://pydevtools.com/handbook/reference/cibuildwheel/&#34;&gt;cibuildwheel&lt;/a&gt; automates building these wheels across operating systems, architectures, and Python versions in CI.&lt;/p&gt;
&lt;p&gt;This guide sets up a GitHub Actions workflow that builds wheels for Linux, macOS, and Windows, then publishes them to &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&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;ul&gt;
&lt;li&gt;A Python project with a compiled extension and a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-517/&#34;&gt;PEP 517&lt;/a&gt;-compliant &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-build-backend/&#34;&gt;build backend&lt;/a&gt; (setuptools, scikit-build-core, maturin, etc.)&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;[build-system]&lt;/code&gt; table in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A GitHub repository&lt;/li&gt;
&lt;li&gt;A PyPI account with &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing/&#34;&gt;trusted publishing&lt;/a&gt; configured for the repository&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Configure cibuildwheel&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;configure-cibuildwheel&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#configure-cibuildwheel&#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 a &lt;code&gt;[tool.cibuildwheel]&lt;/code&gt; section to &lt;code&gt;pyproject.toml&lt;/code&gt;. This example targets CPython 3.11 through 3.13, skips 32-bit builds, and runs pytest after each wheel build:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to convert a script with requirements.txt to PEP 723 inline metadata</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-convert-a-script-with-requirements-txt-to-pep-723-inline-metadata/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-convert-a-script-with-requirements-txt-to-pep-723-inline-metadata/</guid>
      <description>&lt;p&gt;A standalone Python script paired with a &lt;code&gt;requirements.txt&lt;/code&gt; is the old way of saying &amp;ldquo;this script needs these libraries.&amp;rdquo; &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-723/&#34;&gt;PEP 723&lt;/a&gt; replaces the sidecar file with a TOML block embedded in the script itself, and &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; reads that block to install dependencies into a temporary &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt; on every run.&lt;/p&gt;
&lt;h2&gt;Translate the requirements.txt into inline metadata&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;translate-the-requirementstxt-into-inline-metadata&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#translate-the-requirementstxt-into-inline-metadata&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Point &lt;code&gt;uv add --script&lt;/code&gt; at the existing requirements file. uv reads it and prepends a PEP 723 block to the script:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Create and Distribute a Python CLI Tool</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-create-and-distribute-a-python-cli-tool/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-create-and-distribute-a-python-cli-tool/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt; lets you attach any Python function to an executable command name via &lt;code&gt;[project.scripts]&lt;/code&gt;. When someone installs the package, their package manager creates a wrapper script that calls that function. With &lt;a href=&#34;https://pydevtools.com/handbook/reference/uvx/&#34;&gt;uvx&lt;/a&gt;, users can run the tool without even installing it first.&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>How to fix the &#34;externally-managed-environment&#34; error</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-fix-the-externally-managed-environment-error/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-fix-the-externally-managed-environment-error/</guid>
      <description>&lt;p&gt;Running &lt;code&gt;pip install&lt;/code&gt; on a system Python protected by &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-668/&#34;&gt;PEP 668&lt;/a&gt; produces this error:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;pre&gt;&lt;code&gt;error: externally-managed-environment

× This environment is externally managed&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The fix depends on what was being installed.&lt;/p&gt;
&lt;h2&gt;Installing project dependencies&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;installing-project-dependencies&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#installing-project-dependencies&#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 &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; to create a project with its own &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt;:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to format pyproject.toml with taplo</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-format-pyproject-toml-with-taplo/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-format-pyproject-toml-with-taplo/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; does not include a built-in formatter for &lt;code&gt;pyproject.toml&lt;/code&gt;. &lt;a href=&#34;https://taplo.tamasfe.dev/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Taplo&lt;/a&gt; is a TOML formatter and validator that keeps &lt;code&gt;pyproject.toml&lt;/code&gt; files consistently styled across a project.&lt;/p&gt;
&lt;h2&gt;Format with uvx&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;format-with-uvx&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#format-with-uvx&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run taplo as a one-off command without installing it:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uvx taplo fmt pyproject.toml&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 check formatting without modifying files (useful in CI):&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Host Your Own Python Package Index</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-host-your-own-python-package-index/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-host-your-own-python-package-index/</guid>
      <description>&lt;p&gt;A self-hosted Python package index can save a team from PyPI outages, vendor lock-in, or restricted networks, but it also gives that team another service to run. Three tools cover almost every use case: &lt;a href=&#34;https://github.com/devpi/devpi&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;devpi&lt;/a&gt; for production multi-team setups, &lt;a href=&#34;https://github.com/pypiserver/pypiserver&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pypiserver&lt;/a&gt; for a small team that needs somewhere to put &lt;code&gt;internal-greeter-0.1.0.whl&lt;/code&gt;, and &lt;a href=&#34;https://github.com/pypa/bandersnatch&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;bandersnatch&lt;/a&gt; for full PyPI mirrors on networks that cannot reach &lt;code&gt;pypi.org&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Hosting an index is the server-side counterpart to &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-use-private-package-indexes-with-uv/&#34;&gt;How to use private package indexes with uv&lt;/a&gt;, which covers the client configuration for managed services like AWS CodeArtifact and JFrog Artifactory.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to install from a pylock.toml lockfile with pip</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-install-from-a-pylock-toml-lockfile-with-pip/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-install-from-a-pylock-toml-lockfile-with-pip/</guid>
      <description>&lt;p&gt;A teammate hands you a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-751/&#34;&gt;&lt;code&gt;pylock.toml&lt;/code&gt;&lt;/a&gt;. Or &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;&amp;rsquo;s &lt;code&gt;uv export --format pylock.toml&lt;/code&gt; produces one. Now you need &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; to install from it. As of pip 26.1 (April 2026), &lt;code&gt;pip install -r pylock.toml&lt;/code&gt; works, with a few caveats worth knowing before you put it in CI.&lt;/p&gt;
&lt;h2&gt;Confirm pip 26.1 or newer&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;confirm-pip-261-or-newer&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#confirm-pip-261-or-newer&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-r pylock.toml&lt;/code&gt; form was added in pip 26.1. Older pips will treat the file as a regular requirements file and choke on the first TOML line.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to install uv on 32-bit Raspberry Pi OS</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-install-uv-on-32-bit-raspberry-pi-os/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-install-uv-on-32-bit-raspberry-pi-os/</guid>
      <description>&lt;p&gt;uv&amp;rsquo;s standalone installer works on 32-bit Raspberry Pi OS (armv7l), but three quirks bite first-time users: &lt;code&gt;uv python install&lt;/code&gt; can fail to detect glibc on some Pi setups, PyPI rarely ships armv7l wheels, and a 32-bit userland running on a 64-bit kernel reports the wrong architecture. This guide walks through each so a 32-bit Pi install ends up in a working state.&lt;/p&gt;
&lt;p&gt;For 64-bit Pi OS, the standard path applies; see &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-run-python-scripts-on-a-raspberry-pi-with-uv/&#34;&gt;How to run Python scripts on a Raspberry Pi with uv&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to migrate from Pipenv to uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-migrate-from-pipenv-to-uv/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-migrate-from-pipenv-to-uv/</guid>
      <description>&lt;p&gt;Pipenv combines &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; and &lt;a href=&#34;https://pydevtools.com/handbook/reference/virtualenv/&#34;&gt;virtualenv&lt;/a&gt; into a single tool. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; covers the same ground and adds Python version management, a standards-compliant &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;-based workflow, and significantly faster dependency resolution.&lt;/p&gt;
&lt;p&gt;Migrating replaces the &lt;a href=&#34;https://pydevtools.com/handbook/reference/pipfile/&#34;&gt;Pipfile&lt;/a&gt; and &lt;code&gt;Pipfile.lock&lt;/code&gt; with &lt;code&gt;pyproject.toml&lt;/code&gt; and &lt;code&gt;uv.lock&lt;/code&gt;, and swaps &lt;code&gt;pipenv&lt;/code&gt; commands for their &lt;code&gt;uv&lt;/code&gt; equivalents.&lt;/p&gt;
&lt;h2&gt;Automated migration&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;automated-migration&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#automated-migration&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&#34;https://osprey-oss.github.io/migrate-to-uv/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;migrate-to-uv&lt;/a&gt; tool automates the conversion.&lt;/p&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. Run the migration tool&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;1-run-the-migration-tool&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#1-run-the-migration-tool&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&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; uvx migrate-to-uv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The tool reads your &lt;code&gt;Pipfile&lt;/code&gt; and:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to migrate from Poetry to uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-migrate-from-poetry-to-uv/</link>
      <pubDate>Thu, 14 May 2026 14:35:17 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-migrate-from-poetry-to-uv/</guid>
      <description>&lt;p&gt;This guide walks through the process of migrating a &lt;a href=&#34;https://pydevtools.com/handbook/reference/poetry/&#34;&gt;Poetry&lt;/a&gt;-managed Python project to &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; using the &lt;a href=&#34;https://osprey-oss.github.io/migrate-to-uv/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;migrate-to-uv&lt;/a&gt; tool.&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/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;uv&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;A &lt;a href=&#34;https://pydevtools.com/handbook/reference/poetry/&#34;&gt;Poetry&lt;/a&gt;-managed Python project&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Basic Migration&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;basic-migration&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#basic-migration&#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. Navigate to your Poetry project directory&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;1-navigate-to-your-poetry-project-directory&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#1-navigate-to-your-poetry-project-directory&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; your-poetry-project&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;h3&gt;2. Run the migration tool&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;2-run-the-migration-tool&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#2-run-the-migration-tool&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uvx migrate-to-uv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The tool will:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to migrate from requirements.txt to pyproject.toml with uv</title>
      <link>https://pydevtools.com/handbook/how-to/migrate-requirements.txt/</link>
      <pubDate>Mon, 04 May 2026 08:09:53 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/migrate-requirements.txt/</guid>
      <description>&lt;p&gt;To migrate a &lt;a href=&#34;https://pydevtools.com/handbook/reference/requirements/&#34;&gt;requirements.txt&lt;/a&gt; project to &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;, run &lt;code&gt;uv init --bare&lt;/code&gt; to create a minimal pyproject.toml, then &lt;code&gt;uv add -r requirements.txt&lt;/code&gt; to import every dependency. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; reads the file, writes the packages into &lt;code&gt;[project.dependencies]&lt;/code&gt;, and generates a &lt;code&gt;uv.lock&lt;/code&gt; file that pins exact resolved versions.&lt;/p&gt;
&lt;p&gt;For a detailed explanation of why pyproject.toml replaces requirements.txt, see &lt;a href=&#34;https://pydevtools.com/handbook/explanation/pyproject-vs-requirements/&#34;&gt;why choose pyproject.toml over requirements.txt&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; if it isn&amp;rsquo;t already on your system.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to migrate from setup.py to pyproject.toml</title>
      <link>https://pydevtools.com/handbook/how-to/migrate-setup-py/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/migrate-setup-py/</guid>
      <description>&lt;p&gt;The &lt;code&gt;setup.py&lt;/code&gt; file was long the dominant way to configure a Python package. &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; changed that by standardizing project metadata in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;, and every major build backend now supports it. Migrating removes the need for executable configuration files, makes metadata readable by any tool, and aligns a project with current packaging standards.&lt;/p&gt;
&lt;p&gt;This guide covers projects that use &lt;a href=&#34;https://pydevtools.com/handbook/reference/setuptools/&#34;&gt;setuptools&lt;/a&gt; as their build backend. If a project uses Poetry, see &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-migrate-from-poetry-to-uv/&#34;&gt;How to migrate from Poetry to uv&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to migrate from uv to pip</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-migrate-from-uv-to-pip/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-migrate-from-uv-to-pip/</guid>
      <description>&lt;p&gt;Moving a uv-managed project to &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; is mostly an audit of &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;, not a rebuild of the project. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; consolidates Python interpreter installs, virtual environments, resolution, package installation, and lockfile generation into one tool, but if a project&amp;rsquo;s metadata sticks to packaging standards, most of the substitutes are short. This how-to walks through the audit and the runtime equivalents: &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyenv/&#34;&gt;pyenv&lt;/a&gt; on macOS and Linux, the official python.org installer on Windows.&lt;/p&gt;
&lt;h2&gt;Audit your pyproject.toml for uv-specific tables&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;audit-your-pyprojecttoml-for-uv-specific-tables&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#audit-your-pyprojecttoml-for-uv-specific-tables&#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 exporting a lockfile, scan your &lt;code&gt;pyproject.toml&lt;/code&gt; for settings under &lt;code&gt;[tool.uv]&lt;/code&gt; and tables under &lt;code&gt;[tool.uv.*]&lt;/code&gt;. Anything outside that namespace is already standardized and pip can read it. The settings that matter:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Publish Python Packages with Digital Attestations</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-publish-python-packages-with-digital-attestations/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-publish-python-packages-with-digital-attestations/</guid>
      <description>&lt;p&gt;Digital attestations let PyPI record &lt;em&gt;who published&lt;/em&gt; each file, not just what the file contains. When consumers generate a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-751/&#34;&gt;pylock.toml&lt;/a&gt; lockfile, their tools can write your package&amp;rsquo;s publisher identity into the lockfile. Any change to that identity in a future update becomes visible in code review.&lt;/p&gt;
&lt;p&gt;This guide shows how to configure a GitHub Actions workflow that publishes to PyPI with attestations enabled. The setup requires &lt;a href=&#34;https://pydevtools.com/handbook/explanation/why-use-trusted-publishing-for-pypi/&#34;&gt;trusted publishing&lt;/a&gt;; attestations are cryptographically tied to the same OIDC identity that trusted publishing uses.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Publish to PyPI with Trusted Publishing</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing/</guid>
      <description>&lt;p&gt;Trusted publishing lets GitHub Actions upload packages to &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt; without storing any secrets. Instead of creating an API token and pasting it into your CI settings, you tell PyPI which GitHub repository and workflow are allowed to publish. GitHub Actions then proves its identity to PyPI using an OIDC token that lives only for the duration of the workflow run.&lt;/p&gt;
&lt;p&gt;This guide covers GitHub Actions, the most common CI provider for Python projects. PyPI also supports trusted publishing from GitLab CI/CD, Google Cloud, and ActiveState.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Publish to TestPyPI with uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-publish-to-testpypi-with-uv/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-publish-to-testpypi-with-uv/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt; versions are write-once. Upload &lt;code&gt;0.1.0&lt;/code&gt; with a broken README or a missing dependency, and the only fix is a new version number. &lt;a href=&#34;https://test.pypi.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TestPyPI&lt;/a&gt; is a parallel index wired to the same tooling where the cost of a bad upload is zero. Upload there first and promote to PyPI only after the rehearsal works end to end.&lt;/p&gt;
&lt;p&gt;This guide uses &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; for the build, upload, and verification steps. The workflow slots into the &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing/&#34;&gt;trusted-publishing setup&lt;/a&gt; for CI or runs entirely from a local shell with an API token.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to require a virtualenv when installing packages with pip?</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-require-a-virtual-for-installing-packages/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-require-a-virtual-for-installing-packages/</guid>
      <description>&lt;p&gt;By default, &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; allows installing packages into the global Python environment. This can lead to dependency conflicts and break system tools. Configuring pip to require a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment/&#34;&gt;virtual environment&lt;/a&gt; prevents accidental global installs.&lt;/p&gt;
&lt;h2&gt;Using an environment variable&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;using-an-environment-variable&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#using-an-environment-variable&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Set the &lt;code&gt;PIP_REQUIRE_VIRTUALENV&lt;/code&gt; environment variable to &lt;code&gt;true&lt;/code&gt; in your shell profile (e.g. &lt;code&gt;~/.bashrc&lt;/code&gt;, &lt;code&gt;~/.zshrc&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PIP_REQUIRE_VIRTUALENV&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;true&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;With this set, running &lt;code&gt;pip install&lt;/code&gt; outside a virtual environment produces an error:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to run Python scripts on a Raspberry Pi with uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-run-python-scripts-on-a-raspberry-pi-with-uv/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-run-python-scripts-on-a-raspberry-pi-with-uv/</guid>
      <description>&lt;p&gt;Running &lt;code&gt;pip install requests&lt;/code&gt; on a fresh Raspberry Pi OS Bookworm install prints &lt;code&gt;error: externally-managed-environment&lt;/code&gt; and refuses to install anything into the system Python. &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; is the cleanest fix on a Pi: install the prebuilt binary, then run scripts inline with inline metadata or inside a project venv that uv manages for you. This guide covers both paths.&lt;/p&gt;
&lt;p&gt;It assumes a Pi running 64-bit Raspberry Pi OS. The 32-bit edition has its own quirks; see &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-install-uv-on-32-bit-raspberry-pi-os/&#34;&gt;How to install uv on 32-bit Raspberry Pi OS&lt;/a&gt;. If your project needs &lt;code&gt;picamera2&lt;/code&gt;, &lt;code&gt;gpiozero&lt;/code&gt;, or another apt-installed library, see &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-use-picamera2-and-gpio-with-uv-on-raspberry-pi/&#34;&gt;How to use picamera2 and GPIO with uv on Raspberry Pi&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Set Up Documentation for a Python Package with Sphinx or MkDocs</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-set-up-documentation-for-a-python-package/</link>
      <pubDate>Fri, 15 May 2026 21:28:17 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-set-up-documentation-for-a-python-package/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/sphinx/&#34;&gt;Sphinx&lt;/a&gt; and &lt;a href=&#34;https://pydevtools.com/handbook/reference/mkdocs/&#34;&gt;MkDocs&lt;/a&gt; are the two documentation generators most Python packages reach for. They cover the same job (turn Markdown or reStructuredText plus your docstrings into a static HTML site) but optimize for different writers. This guide picks one, scaffolds a docs site inside an existing &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; project, and gets a build running locally.&lt;/p&gt;
&lt;h2&gt;Pick Sphinx or MkDocs&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;pick-sphinx-or-mkdocs&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#pick-sphinx-or-mkdocs&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Two questions decide it for most projects.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s the dominant content type? API reference dominates in libraries like NumPy and Django, where most pages are autogenerated from docstrings. Sphinx was built for that workload and has the older and broader extension ecosystem around API reference work (&lt;code&gt;intersphinx&lt;/code&gt; for cross-project links, &lt;code&gt;sphinx-autodoc-typehints&lt;/code&gt; for signature rendering). MkDocs with &lt;a href=&#34;https://pydevtools.com/handbook/reference/mkdocstrings/&#34;&gt;mkdocstrings&lt;/a&gt; covers the API case competently, especially for Python-only projects. MkDocs is friendlier when the docs are prose-first and the API reference is one section among many tutorials and how-tos.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to use picamera2 and GPIO with uv on Raspberry Pi</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-picamera2-and-gpio-with-uv-on-raspberry-pi/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-picamera2-and-gpio-with-uv-on-raspberry-pi/</guid>
      <description>&lt;p&gt;&lt;code&gt;picamera2&lt;/code&gt;, &lt;code&gt;libcamera&lt;/code&gt;, and &lt;code&gt;gpiozero&lt;/code&gt; ship through &lt;code&gt;apt&lt;/code&gt; on Raspberry Pi OS, not through PyPI. A clean uv venv cannot import them, and &lt;code&gt;pip install picamera2&lt;/code&gt; inside that venv fails on the missing &lt;code&gt;libcamera&lt;/code&gt; module. The workaround is to install the system packages with apt, then build a uv venv against &lt;code&gt;/usr/bin/python3&lt;/code&gt; that inherits the system site-packages. This guide walks through that setup and the constraints it brings.&lt;/p&gt;
&lt;p&gt;It assumes uv is already installed on the Pi. If not, start with &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-run-python-scripts-on-a-raspberry-pi-with-uv/&#34;&gt;How to run Python scripts on a Raspberry Pi with uv&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to use uv to speed up Hatch</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-uv-to-speed-up-hatch/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-uv-to-speed-up-hatch/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/hatch/&#34;&gt;Hatch&lt;/a&gt; can use &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; as its installer backend instead of pip and virtualenv. This makes environment creation and dependency installation significantly faster without changing the rest of your Hatch workflow.&lt;/p&gt;
&lt;div class=&#34;hx:overflow-x-auto hx:mt-6 hx:flex hx:flex-col hx:rounded-lg hx:border hx:py-4 hx:px-4 hx:border-gray-200 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-blue-200 hx:bg-blue-100 hx:text-blue-900 hx:dark:border-blue-200/30 hx:dark:bg-blue-900/30 hx:dark:text-blue-200&#34;&gt;
  &lt;p class=&#34;hx:flex hx:items-center hx:font-medium&#34;&gt;&lt;svg height=16px class=&#34;hx:inline-block hx:align-middle hx:mr-2&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; fill=&#34;none&#34; viewBox=&#34;0 0 24 24&#34; stroke-width=&#34;2&#34; stroke=&#34;currentColor&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; d=&#34;M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z&#34;/&gt;&lt;/svg&gt;Note&lt;/p&gt;

  &lt;div class=&#34;hx:w-full hx:min-w-0 hx:leading-7&#34;&gt;
    &lt;div class=&#34;hx:mt-6 hx:leading-7 hx:first:mt-0&#34;&gt;&lt;p&gt;This guide assumes you already have a Hatch project and &lt;a href=&#34;https://pydevtools.com/handbook/how-to/how-to-install-uv/&#34;&gt;uv installed&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to use uv to speed up PDM</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-use-uv-to-speed-up-pdm/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-use-uv-to-speed-up-pdm/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/handbook/reference/pdm/&#34;&gt;PDM&lt;/a&gt; has experimental support for using &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; as its resolver and installer (available since PDM 2.19.0). This makes dependency resolution and installation significantly faster without changing the rest of your PDM workflow.&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>How to Verify Dependencies with Hashes in uv</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-pin-dependencies-with-hashes-in-uv/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-pin-dependencies-with-hashes-in-uv/</guid>
      <description>&lt;p&gt;Dependency hashes let &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; verify that every downloaded artifact matches what was resolved, catching tampering before anything gets installed.&lt;/p&gt;
&lt;h2&gt;Hashes in uv.lock&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;hashes-in-uvlock&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#hashes-in-uvlock&#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;code&gt;uv.lock&lt;/code&gt; includes SHA-256 hashes for every distribution by default. After running &lt;code&gt;uv lock&lt;/code&gt; or &lt;code&gt;uv add&lt;/code&gt;, each entry in the lockfile contains hashes for both sdists and wheels:&lt;/p&gt;
&lt;div class=&#34;hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code&#34;&gt;

&lt;div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;certifi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2026.2.25&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;registry&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://pypi.org/simple&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;sdist&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;wheels&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;hextra-code-copy-btn-container  hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0&#34;&gt;
  &lt;button
    class=&#34;hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50&#34;
    title=&#34;Copy code&#34;
    aria-label=&#34;Copy code&#34;
    data-copied-label=&#34;Copied!&#34;
  &gt;
    &lt;div class=&#34;hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4&#34;&gt;&lt;/div&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When &lt;code&gt;uv sync&lt;/code&gt; or &lt;code&gt;uv run&lt;/code&gt; installs packages, it checks each downloaded artifact against these hashes. If a hash does not match, installation fails.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Vet a Python Package Before Installing It</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-vet-a-python-package-before-installing-it/</link>
      <pubDate>Fri, 15 May 2026 21:28:17 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-vet-a-python-package-before-installing-it/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://pydevtools.com/blog/litellm-supply-chain-attack-and-securing-python-dependencies/&#34;&gt;litellm 1.82.7 and 1.82.8&lt;/a&gt;, and &lt;a href=&#34;https://pydevtools.com/blog/lightning-pypi-compromise-import-time-supply-chain-attack/&#34;&gt;Lightning AI 2.6.2 and 2.6.3&lt;/a&gt;, hit PyPI before matching source releases appeared on GitHub. A 30-second tag check would have caught either one. Use this five-minute pre-install routine to catch that kind of &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-python-supply-chain-attack/&#34;&gt;Python supply chain attack&lt;/a&gt; before adding a package to &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Read the PyPI signals&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;read-the-pypi-signals&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#read-the-pypi-signals&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open the package page on &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt; and check four things.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Download trend.&lt;/strong&gt; Run &lt;a href=&#34;https://pydevtools.com/handbook/reference/uvx/&#34;&gt;&lt;code&gt;uvx&lt;/code&gt;&lt;/a&gt; with &lt;a href=&#34;https://github.com/hugovk/pypistats&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;pypistats&lt;/code&gt;&lt;/a&gt; to see recent download counts:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to write install instructions for a Python library</title>
      <link>https://pydevtools.com/handbook/how-to/how-to-write-install-instructions-for-a-python-library/</link>
      <pubDate>Wed, 13 May 2026 06:43:22 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/how-to/how-to-write-install-instructions-for-a-python-library/</guid>
      <description>&lt;p&gt;A library&amp;rsquo;s README is the first place a new user lands, and the install command in that README is the first thing they copy. AI coding agents copy it too. If the only command shown is &lt;code&gt;pip install mylib&lt;/code&gt;, every uv user has to translate, and every agent learns one more reason to default to pip. Lead with &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;, keep &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; as the fallback, and the snippet works for everyone.&lt;/p&gt;
&lt;h2&gt;Lead with &lt;code&gt;uv add&lt;/code&gt;&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;lead-with-uv-add&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#lead-with-uv-add&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Put the uv command first in the install section. Keep pip as a clearly labeled fallback.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Nuitka</title>
      <link>https://pydevtools.com/handbook/reference/nuitka/</link>
      <pubDate>Tue, 28 Apr 2026 21:54:51 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/nuitka/</guid>
      <description>&lt;p&gt;Nuitka is a Python-to-C compiler that translates CPython bytecode into C source, then compiles and links the result against &lt;code&gt;libpython&lt;/code&gt;. The output runs without a separate Python installation and can ship as a standalone folder, a self-extracting single-file executable, or an importable extension module. Nuitka runs on Linux, macOS, and Windows; the build machine needs a C toolchain (&lt;code&gt;gcc&lt;/code&gt;, &lt;code&gt;clang&lt;/code&gt;, or MSVC). Install it with &lt;code&gt;uv tool install nuitka&lt;/code&gt; or &lt;code&gt;pipx install nuitka&lt;/code&gt;. Nuitka is AGPL-3.0+ with a runtime exception for compiled output, so the license does not carry over to the applications it produces.&lt;/p&gt;</description>
    </item>
    <item>
      <title>PDM: Python Package and Dependency Manager</title>
      <link>https://pydevtools.com/handbook/reference/pdm/</link>
      <pubDate>Mon, 27 Apr 2026 09:16:18 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pdm/</guid>
      <description>&lt;p&gt;PDM is a Python package and dependency manager that implements the modern &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-517/&#34;&gt;PEP 517/518 build-system interface&lt;/a&gt; and reads &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility/&#34;&gt;PEP 621 project metadata&lt;/a&gt; from &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;When to use PDM&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pdm&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pdm&#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 PDM when you have an existing project built around its workflow and want a standards-compliant package manager with lockfile support and dependency groups. PDM&amp;rsquo;s strict adherence to the &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-517/&#34;&gt;PEP 517/518&lt;/a&gt; build-system interface and &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility/&#34;&gt;PEP 621&lt;/a&gt; project metadata makes it a good fit for teams that prioritize alignment with official Python packaging standards. For new projects, &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt; provides &lt;a href=&#34;https://pydevtools.com/handbook/explanation/which-python-package-manager-should-i-use/&#34;&gt;faster performance and broader functionality&lt;/a&gt;; PDM&amp;rsquo;s standalone build backend, pdm-backend, can still be used in uv projects without adopting the full PDM CLI.&lt;/p&gt;</description>
    </item>
    <item>
      <title>pip: Python Package Installer</title>
      <link>https://pydevtools.com/handbook/reference/pip/</link>
      <pubDate>Thu, 14 May 2026 14:35:17 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pip/</guid>
      <description>&lt;p&gt;pip is the Python Package Authority&amp;rsquo;s (PyPA) standard package installer. It enables installing and managing Python packages from the Python Package Index (PyPI) and other package indexes. pip comes with modern Python installations and serves as the default tool for package operations in the Python ecosystem.&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;While pip remains Python&amp;rsquo;s default package installer, many workflows benefit from newer tools like uv that provide better performance and more integrated functionality.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;Core Functionality&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;core-functionality&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#core-functionality&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;pip provides essential package management capabilities:&lt;/p&gt;</description>
    </item>
    <item>
      <title>pip-tools: Python Dependency Pinning Tools</title>
      <link>https://pydevtools.com/handbook/reference/pip-tools/</link>
      <pubDate>Mon, 04 May 2026 08:09:53 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pip-tools/</guid>
      <description>&lt;p&gt;pip-tools is a set of command-line utilities for managing Python dependency pinning. It consists of two commands: &lt;code&gt;pip-compile&lt;/code&gt; for resolving and locking dependencies, and &lt;code&gt;pip-sync&lt;/code&gt; for synchronizing a virtual environment to match a &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-lock-file/&#34;&gt;lockfile&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-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>pipenv: Python Dependency Manager</title>
      <link>https://pydevtools.com/handbook/reference/pipenv/</link>
      <pubDate>Sat, 18 Apr 2026 11:22:55 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pipenv/</guid>
      <description>&lt;p&gt;pipenv is a tool for managing &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-python-application/&#34;&gt;application&lt;/a&gt; dependencies analogous to npm for Node.js or
bundler for Ruby.&lt;/p&gt;
&lt;p&gt;Per the &lt;a href=&#34;https://pipenv.pypa.io&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pipenv documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Pipenv automatically creates and manages a virtualenv for your projects, as well as
adds/removes packages from your Pipfile as you install/uninstall packages. It also
generates a project Pipfile.lock, which is used to produce deterministic builds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;When to Use Pipenv&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-pipenv&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-pipenv&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pipenv fits teams already committed to a Pipfile-based workflow for an &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-a-python-application/&#34;&gt;application&lt;/a&gt; project, where the existing lockfile and automatic virtualenv still cover the team&amp;rsquo;s needs. Its release cadence has slowed relative to newer tools, and it predates the &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt; standards the rest of the packaging ecosystem has adopted.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Pipfile: Python Dependency Declaration Format</title>
      <link>https://pydevtools.com/handbook/reference/pipfile/</link>
      <pubDate>Mon, 04 May 2026 08:09:53 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/pipfile/</guid>
      <description>&lt;p&gt;A Pipfile is a TOML-formatted file that declares a project&amp;rsquo;s Python dependencies for use with &lt;a href=&#34;https://pydevtools.com/handbook/reference/pipenv/&#34;&gt;Pipenv&lt;/a&gt;. It was originally proposed as a successor to &lt;a href=&#34;https://pydevtools.com/handbook/reference/requirements/&#34;&gt;requirements.txt&lt;/a&gt;, adding structured runtime and development dependency sections alongside a paired &lt;code&gt;Pipfile.lock&lt;/code&gt; for reproducible installs.&lt;/p&gt;
&lt;p&gt;The standalone &lt;code&gt;pipfile&lt;/code&gt; specification project at &lt;a href=&#34;https://github.com/pypa/pipfile&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pypa/pipfile&lt;/a&gt; has not seen substantive activity since 2019. The format lives on inside Pipenv, which reads and writes both the &lt;code&gt;Pipfile&lt;/code&gt; and &lt;code&gt;Pipfile.lock&lt;/code&gt;. The broader Python packaging ecosystem moved toward dependency declarations in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt; under &lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility/&#34;&gt;PEP 621&lt;/a&gt;, and the two formats are no longer in active competition.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Poetry: Python Packaging and Dependency Manager</title>
      <link>https://pydevtools.com/handbook/reference/poetry/</link>
      <pubDate>Thu, 23 Apr 2026 06:56:42 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/reference/poetry/</guid>
      <description>&lt;p&gt;Poetry is a Python packaging and dependency management tool that handles dependency installation, virtual environment management, package building, and publishing. It aims to provide a unified workflow for Python project management through configuration in &lt;a href=&#34;https://pydevtools.com/handbook/reference/pyproject.toml/&#34;&gt;pyproject.toml&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;When to Use Poetry&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;when-to-use-poetry&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#when-to-use-poetry&#34; class=&#34;subheading-anchor&#34; aria-label=&#34;Permalink for this section&#34;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Poetry fits teams that already have an established Poetry workflow and need integrated dependency management, virtual environment handling, and package publishing. Its lockfile and dependency group features suit application projects that require reproducible builds.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Publishing Your First Python Package to PyPI</title>
      <link>https://pydevtools.com/handbook/tutorial/publishing-your-first-python-package-to-pypi/</link>
      <pubDate>Tue, 28 Apr 2026 08:41:30 -0400</pubDate>
      <author>Tim Hopper</author>
      <guid>https://pydevtools.com/handbook/tutorial/publishing-your-first-python-package-to-pypi/</guid>
      <description>&lt;p&gt;This tutorial guides you through publishing a Python package to the Python Package Index (&lt;a href=&#34;https://pydevtools.com/handbook/explanation/what-is-pypi/&#34;&gt;PyPI&lt;/a&gt;) using &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;. You&amp;rsquo;ll learn the essential steps of building and uploading a package that others can install with &lt;a href=&#34;https://pydevtools.com/handbook/reference/pip/&#34;&gt;pip&lt;/a&gt; or &lt;a href=&#34;https://pydevtools.com/handbook/reference/uv/&#34;&gt;uv&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since this is your first package, we&amp;rsquo;ll start by uploading to &lt;a href=&#34;https://test.pypi.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TestPyPI&lt;/a&gt;, a &amp;ldquo;separate instance of the Python Package Index that allows you to try distribution tools and processes without affecting the real index.&amp;rdquo;&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 TestPyPI account (&lt;a href=&#34;https://test.pypi.org/account/register/&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;register here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A Python project ready for distribution&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setting Up Your Project&lt;span class=&#34;hx:absolute hx:-mt-20&#34; id=&#34;setting-up-your-project&#34;&gt;&lt;/span&gt;
    &lt;a href=&#34;#setting-up-your-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;Create a new project with a name that is not currently taken on &lt;a href=&#34;https://test.pypi.org&#34;target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Test PyPI&lt;/a&gt;. You might try something like your name followed by a random number, e.g. timhopper2456543. Browse the project&amp;rsquo;s URL at &lt;code&gt;https://test.pypi.org/project/&amp;lt;PACKAGE_NAME&amp;gt;/&lt;/code&gt; first; if it returns a project page rather than a 404, the name is taken and &lt;code&gt;uv publish&lt;/code&gt; will fail later.&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
