Skip to content

Packaging

Packaging Python is a discipline of its own, with build backends, frontends, lock files, and a long history of tools that solve overlapping problems. The handbook explains the modern workflow — pyproject.toml, locked dependencies, signed wheels — and how to publish a package safely.

Build and publish

Lock and reproduce

More Packaging pages

Everything else tagged packaging, grouped by section. Pages featured above are not repeated here.

How To

How to Add a Dependency to a uv Project

Add a package to a uv project with uv add: it records the dependency in pyproject.toml and the lockfile so anyone who runs uv sync gets the same versions.

How to Build Multi-Platform Wheels with cibuildwheel

Build Python wheels for Linux, macOS, and Windows in GitHub Actions using cibuildwheel, then publish to PyPI.

How to convert a script with requirements.txt to PEP 723 inline metadata

Move a one-off Python script's dependencies out of a sidecar requirements.txt and into a PEP 723 inline metadata block uv can read.

How to create a pylock.toml lockfile

Generate PEP 751 pylock.toml with uv export, pip lock, or pdm export. Compare producers, pick the right one.

How to Create and Distribute a Python CLI Tool

Define a console_scripts entry point in pyproject.toml, publish to PyPI, and let users run your tool with uvx or uv tool install.

How to Debug uv Dependency Resolution Failures

Fix uv resolution errors by reading the conflict chain, inspecting the dependency tree, and applying overrides or constraint narrowing.

How to Fix "ImportError: attempted relative import with no known parent package"

Run your code with python -m or a project entry point to fix Python's attempted relative import error for good.

How to fix the "externally-managed-environment" error

Fix the externally-managed-environment error on Linux. Use virtual environments or uv tool install instead.

How to format pyproject.toml with taplo

Use taplo to automatically format and validate pyproject.toml files in Python projects managed with uv.

How to Host Your Own Python Package Index

Host private or mirrored Python packages. Choose between devpi, pypiserver, or bandersnatch for your network.

How to Ignore a Dependency in Dependabot Without Blocking Its Security Updates

Scope a Dependabot ignore rule to version updates so a pinned package stops routine PRs but still gets security fixes.

How to Inspect a Virtual Environment You Did Not Create

Read the dependency tree of an existing virtualenv with uv pip tree to learn what is installed and which package pulled it in.

How to install from a pylock.toml lockfile with pip

Install locked dependencies with pip 26.1+: `pip install -r pylock.toml --no-deps` for exact lockfile match.

How to install uv on 32-bit Raspberry Pi OS

Install uv on 32-bit Raspberry Pi OS, work around the libc detection and 32-bit-userland bugs, and configure piwheels for armv7l wheels.

How to Keep a Capped Dependency from Blocking Dependabot Security Updates

Drop or raise a version ceiling in pyproject.toml so Dependabot can open security PRs instead of failing silently.

How to migrate from Pipenv to uv

Convert a Pipenv project to uv by translating Pipfile to pyproject.toml and replacing Pipenv commands.

How to migrate from Poetry to uv

Migrate from Poetry to uv: convert pyproject.toml, regenerate lockfiles, and update scripts and indexes.

How to migrate from requirements.txt to pyproject.toml with uv

Convert requirements.txt to pyproject.toml with uv. Import pins, generate lockfiles, and keep reproducibility.

How to migrate from setup.py to pyproject.toml

Migrate from setup.py to pyproject.toml. Move to the modern standard, drop setuptools complexity, and unlock uv builds.

How to migrate from uv to pip

Move a uv-managed project to pip and pyenv (or python.org on Windows) by leaning on PEP 621, PEP 735, and PEP 751 in pyproject.toml.

How to Package Python Projects with Native Extensions

Build and check sdists and platform wheels for Python projects that ship C, C++, or Rust extension modules.

How to Publish a Python Package to conda-forge

Generate a conda recipe with grayskull, submit it to conda-forge staged-recipes, and inherit a bot-maintained feedstock for your PyPI package.

How to Publish Python Packages with Digital Attestations

Add PEP 740 digital attestations to your PyPI releases so consumers can verify package provenance through pylock.toml.

How to Publish to TestPyPI with uv

Upload a Python package to TestPyPI with uv to rehearse a PyPI release, then install it back to verify before pushing to the real index.

How to require a virtualenv when installing packages with pip?

Configure pip to refuse package installation outside a virtual environment using PIP_REQUIRE_VIRTUALENV.

How to run Python scripts on a Raspberry Pi with uv

Install uv on Raspberry Pi OS, then run Python scripts on a Pi without tripping the externally-managed-environment error.

How to Set Up Documentation for a Python Package with Sphinx or MkDocs

Choose Sphinx or MkDocs, scaffold docs, pull docstrings via autodoc/mkdocstrings, preview locally, deploy to Read the Docs.

How to ship type annotations with a Python library

Add a py.typed marker and verify it ships in your wheel so your users' type checkers can read your annotations.

How to Upgrade a Dependency Past Its Version Ceiling

Raise the version ceiling in pyproject.toml and force uv to re-lock so a capped dependency can move to its new major.

How to Upgrade Python Developer Tools

Stay current on Python developer tools: the right upgrade command depends on how each tool was installed.

How to use picamera2 and GPIO with uv on Raspberry Pi

Build a uv-managed environment on a Raspberry Pi that can import picamera2, libcamera, and gpiozero alongside pip-installed dependencies.

How to use uv to speed up Hatch

Configure Hatch to use uv as its installer. Speed up environment creation 5-10x without changing Hatch workflows.

How to use uv to speed up PDM

Configure PDM to use uv as its resolver. Speed up dependency resolution 5-10x without changing your PDM workflow.

How to Vet a Python Package Before Installing It

Vet Python packages with a checklist: download trends, source verification, and reputation tools. Catch supply chain risks before they happen.

How to write install instructions for a Python library

Show readers (and their AI agents) how to install your library with uv, not just pip. The install snippet in your README is the first thing both will copy.

Explanation

Does Poetry Support Python Standards for Dependency Management?

Poetry 2.0 adopted PEP 621 standard project metadata in pyproject.toml while retaining its own tool.poetry section for advanced features.

How do I ship a Python application to end users?

A practical guide to the 2026 options for distributing Python applications: from uvx one-liners to freezer bundles to ONNX for ML.

How do uv and Poetry compare?

uv and Poetry both manage Python projects and dependencies through pyproject.toml, but they differ in scope, speed, and standards alignment.

How Python Package Formats Evolved: From tar.gz to .whl

The 25-year journey from distutils tarballs through eggs to wheels, and how each format solved one problem while creating the next.

Should I run `python setup.py`?

Commands like python setup.py install and python setup.py sdist are deprecated. Use uv build or python -m build instead.

src layout vs flat layout: which to use and why

Src layout for libraries (tests installed package), flat for apps. Src catches packaging bugs flat hides.

Understanding dependency groups in uv

Dependency groups in uv organize project and dev dependencies. Learn how dependency groups, optional dependencies, and extras differ and when to use each.

Versioning Python packages: SemVer, CalVer, and PEP 440

PEP 440 is the version grammar for Python packages. SemVer and CalVer are naming policies. Learn how they interact and pick a versioning scheme.

What are Optional Dependencies and Dependency Groups?

Optional dependencies provide installable feature extras for end users, while dependency groups organize dev and test requirements.

What Are uv Overrides and Constraints?

Control uv dependency resolution with overrides, constraints, and sources. Bypass version limits, enforce policies, or redirect package sources.

What Are Wheel Variants?

Wheel variants (PEP 817/825): ship hardware-specific builds under one wheel name. Let installers detect CPU, GPU, and pick the best.

What is a build frontend?

A build frontend runs build backends to produce wheels and sdists, isolating build-time dependencies from your project by default.

What is a Dependency Cooldown?

A dependency cooldown ignores package versions published in the last few days, so malicious releases get caught before they reach your environment.

What is a lockfile?

A lockfile records exact dependency versions and hashes to guarantee reproducible Python environments across systems, teams, and time periods.

What is a PEP?

Python Enhancement Proposals (PEPs) are formal documents that propose new features, collect community input, and record design decisions.

What is a Python application?

A Python application is a program users run directly, not code imported by other programs. This affects dependency management and distribution strategy.

What is a Python package?

A Python package is reusable code bundled with metadata and distributed as a wheel or sdist so others can install it with pip or uv.

What Is a Python Supply Chain Attack?

Python supply chain attacks reach through packages, maintainer accounts, builds, or PyPI. Map attack categories to defenses.

What is a version specifier?

Version specifiers (>=2.0, ~=1.4) declare package version constraints. Control which versions pip and uv install to avoid breaking changes.

What Is an Editable Install?

An editable install links a package's source code to the Python environment so code changes take effect without reinstalling.

What is core metadata?

Standardized metadata describing a Python distribution: name, version, dependencies, classifiers. Stored in METADATA (wheel) or PKG-INFO (sdist).

What is PEP 503?

PEP 503 defines the Simple Repository API that package indexes like PyPI implement for compatibility with pip and uv.

What is PEP 508?

PEP 508 defines the syntax for specifying Python package dependencies, with support for version constraints, extras, and environment markers.

What is PEP 517/518 compatibility?

PEP 517/518 replaced setup.py-only builds. PEP 518 introduced pyproject.toml; PEP 517 defined a standard build backend hook API.

What is PEP 541 (Package Index Name Retention)?

PEP 541 defines how PyPI reassigns an abandoned project name to a new owner, and the protections that stop a name being taken from a reachable maintainer.

What is PEP 561?

PEP 561 defines how packages ship type info: py.typed markers for inline annotations, -stubs packages for separate types.

What is PEP 609?

PEP 609 establishes the governance model for the Python Packaging Authority, formalizing membership, decision making, and project lifecycle.

What is PEP 621?

PEP 621 defines the [project] table in pyproject.toml, standardizing package metadata across all build tools.

What is PEP 660?

PEP 660 standardizes how build backends implement editable installs, replacing the setuptools-only setup.py develop approach.

What is PEP 668?

PEP 668 marks system Python installations as externally managed, causing pip to refuse package installation outside a virtual environment.

What is PEP 723?

Inline script metadata in Python files. PEP 723 lets uv, pipx, and other runners execute scripts with dependencies declared at the top.

What is PEP 735?

PEP 735: Dependency groups in pyproject.toml. Declare test, lint, docs deps separately from production.

What is PEP 740?

PEP 740 defines modern Python package version schemes. How to use post-releases, dev versions, and local identifiers.

What is PEP 751?

PEP 751 introduces pylock.toml, a standardized lockfile format for reproducible Python dependency installation.

What is PEP 772?

PEP 772 creates the Python Packaging Council. Understand new governance for packaging standards and the PyPA.

What is PEP 773?

PEP 773 introduces PyManager, a unified tool for installing and managing Python versions on Windows, replacing the traditional installer and py launcher.

What is PEP 829?

PEP 829 closes the .pth import-line surface by splitting into two files: .pth for sys.path, .start for package startup entry points.

What is PyPA (Python Packaging Authority)?

PyPA (Python Packaging Authority) is the working group that maintains core Python packaging tools like pip, setuptools, wheel, twine, and virtualenv.

What is PyPI (Python Package Index)?

PyPI is the official Python Package Index where developers publish and discover installable packages, installable via pip, uv, and other tools.

What's the difference between a distribution package and an import package?

Distribution packages are what you install on PyPI; import packages are what you import. They can differ, so pip install Pillow gives import PIL.

Which Python package manager should I use?

A decision tree for choosing the right Python package manager based on your project type, team needs, and technical requirements.

Why are there so many Python packaging tools?

PEP 517 broke setuptools' monopoly on Python packaging, and a dozen alternatives rushed in to fill the gap.

Why did uv originally use Hatch as a build backend?

uv switched from Hatchling to uv_build backend. Why Hatchling was chosen first and why uv_build replaced it.

Why doesn't Python just fix packaging?

Python's packaging is decentralized by design: each organization has its scope, so standards replaced unified tools.

Why Doesn't the Authoritative Python Packaging Guide Mention the Best Thing that's Happened to Python Packaging?

The Python Packaging User Guide omits uv because PyPA only documents its own tools, despite uv's widespread adoption.

Why Installing a Python Package Can Run Code

Python packages run code at install time, import time, and startup via .pth files. Supply chain attack surfaces and defense strategies.

Why Installing GPU Python Packages Is So Complicated

Wheels can't express GPU requirements, so CUDA packages invent workarounds. How the ecosystem works and what wheel variants will change.

Why pylock.toml Includes Digital Attestations

pylock.toml attestations prove who published each package. Detect supply chain compromises during code review.

Why Use Trusted Publishing for PyPI?

Trusted publishing for PyPI uses short-lived OIDC credentials instead of long-lived API tokens. CI-scoped security for package uploads.

Reference

Briefcase

Briefcase packages Python apps for iOS, Android, macOS, Windows, Linux, and Web from a single pyproject.toml config. Part of BeeWare.

build

build is PyPA's PEP 517-compliant frontend tool for building Python packages using any standards-compliant build backend.

cibuildwheel

cibuildwheel is a CI tool that automates building Python wheels across multiple operating systems, architectures, and Python versions for distribution.

Conda Package

A conda package is a compressed archive containing pre-built binaries, metadata, and dependency information for distribution through conda channels.

conda-pypi

conda-pypi is a conda plugin that installs PyPI packages into conda environments, tracked by conda's solver alongside native conda packages.

cx_Freeze

cx_Freeze freezes Python apps into native installers (MSI, DMG, AppImage, deb, rpm) for Windows, macOS, and Linux from one config.

distutils

distutils was Python's original standard library module for building and distributing packages, deprecated in Python 3.10 and removed in Python 3.12.

Flit

Minimal build and publish tool for pure-Python packages with zero runtime dependencies. PyPI publishing and build backend without setuptools boilerplate.

hatch

hatch is a PyPA-maintained Python project manager combining environment management, building, publishing, and version management.

Nuitka

Nuitka compiles Python source to C and links against libpython, producing standalone native executables for Windows, macOS, and Linux.

PDM

PDM is a Python package and dependency manager built on the modern PEP 517/518 build-system interface and PEP 621 project metadata in pyproject.toml.

pip-tools

pip-tools provides pip-compile for resolving and locking dependencies and pip-sync for synchronizing environments to lockfiles.

pip

pip is Python's default package installer. Key features, known limitations, and when to consider uv or conda as alternatives.

pipdeptree

pipdeptree renders installed packages as a dependency tree, revealing which package pulled in each transitive dependency.

pipenv

pipenv: Dependency manager combining pip and virtualenv. Superseded by uv and pyproject.toml for new projects.

Pipfile

Pipfile: Pipenv's TOML dependency format. Largely superseded by pyproject.toml—use modern standards for new projects instead.

pipreqs

pipreqs reads a project's import statements and writes a requirements.txt of only the packages the code actually uses.

poetry

Poetry is a Python packaging and dependency management tool handling installation, environments, building, and publishing via pyproject.toml.

PyInstaller

PyInstaller bundles a Python app and CPython into a single executable for Windows, macOS, and Linux distribution.

pyproject-fmt

Opinionated pyproject.toml formatter: sorts deps, normalizes specifiers, reorders tables, generates classifiers.

pyproject.toml

pyproject.toml is the standard config file for Python projects, holding metadata, dependencies, build-system settings, and tool config.

Python Packaging User Guide

The Python Packaging User Guide is PyPA's official documentation for packaging standards, tools like pip and build, and publishing to PyPI.

requirements.txt

requirements.txt is a plain-text format for declaring Python package dependencies, used by pip, uv, and pip-tools as deployment artifacts or lockfiles.

scikit-build-core

PEP 517 build backend for C, C++, and Fortran extensions using CMake. Configure in pyproject.toml, supports editable installs and free-threaded wheels.

sdist

An sdist (source distribution) is a Python package format containing raw source code that may need building during installation.

setup.cfg

Legacy INI-style setuptools configuration file for project metadata, dependencies, and build options. Superseded by pyproject.toml for metadata.

setuptools

setuptools is Python's original and most established build backend for building, distributing, and installing packages.

Twine

Twine uploads Python packages to PyPI and other indexes with secure authentication and TLS verification, handling credentials safely.

uv

uv is a fast Python package and project manager. One binary replaces pip, pip-tools, pyenv, pipx, virtualenv, and Poetry.

Wheel

A wheel (.whl) is Python's pre-built binary package format. Wheels install without compiling, skip setup.py, and are what pip and uv prefer from PyPI.

From the blog

Posts tagged packaging.

Last updated on