Python Tooling Explained
Background and context articles that explain the why behind Python tools, packaging standards, and ecosystem decisions.
Explanation pages give the context behind Python’s tooling: what concepts mean, why standards exist, how tools compare, and what trade-offs they make. They are for reading, not doing.
To set up a tool, start with a Tutorial. To solve a specific problem, see the How-To guides.
The groups below organize concepts, tool comparisons, PEPs and standards, coming-from-another-language guides, and opinionated philosophy pieces.
Complete Guides
Long-form walkthroughs of uv, Ruff, ty, Claude Code, and Codex
Complete Guide to Claude Code
How to use Claude Code for Python development: setup, testing, debugging, and effective prompting.
Essential pytest Plugins
pytest plugins for reliable test suites: detect test-order bugs, kill hangs, retry flakes, and track performance regressions.
Complete Guide to Codex
How to use OpenAI's Codex CLI for Python development: sandbox modes, autonomy levels, project setup, testing, and scripted automation.
Complete Guide to Ruff
Guide to Ruff, the fast Python linter and formatter replacing flake8, Black, and isort. Covers installation, configuration, and migration.
Complete Guide to ty
A comprehensive guide to ty, the fast Python type checker from OpenAI. Learn installation, configuration, editor setup, and migration from mypy or pyright.
Complete Guide to uv
Guide to uv, the fast Python package manager that replaces pip, pyenv, pipx, and virtualenv. Covers installation, workflows, and migration.
Core Concepts
Definitions of virtual environments, lock files, build backends, and packaging vocabulary
Sampling vs deterministic profilers: which should I use?
Sampling uses timer snapshots; deterministic hooks every call. Each suits different performance questions.
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.
Understanding the Conda/Anaconda Ecosystem
How conda, Miniconda, Anaconda, and conda-forge fit together as a language-agnostic package management ecosystem for scientific computing.
uv init: project types, flags, and examples
uv init creates a new Python project with pyproject.toml, a venv, and a lockfile. Covers --app, --lib, --package, --bare, and --python flags.
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 is a .python-version file?
A .python-version file specifies which Python version to use for a project, recognized by uv and pyenv.
What is a build backend?
Libraries that turn source code into wheels and sdists. PEP 517 split building into frontends and backends with a standard hook API.
What is a build frontend?
A build frontend orchestrates the package build process by invoking build backends and managing build environments.
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 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 Interpreter?
A Python interpreter executes code. Understanding which one is active solves most tooling confusion.
What is a Python language server?
A long-running process providing editors with autocomplete, hover docs, go-to-definition, and diagnostics. How they relate to type checkers.
What is a Python module?
Any importable Python file: .py source files, .so/.pyd compiled extensions, or objects implementing the import protocol. Packages are different.
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 Virtual Environment?
A virtual environment is an isolated Python runtime that lets each project maintain its own dependencies and Python version.
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 CPython's JIT Compiler?
CPython's JIT: translates hot bytecode to native code via copy-and-patch at runtime. Targets 5-10% speedups without code changes.
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 is Python?
Python is a high-level, general-purpose programming language with a rich ecosystem of tools, organizations, and governance.
What is the GIL?
The GIL allows one thread to execute bytecode at a time, preventing parallelism but simplifying internals.
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.
When to Use `uv run` vs `uvx`
Use uv run for project code that needs your dependencies; use uvx for standalone tools that run independently.
Tool Comparisons
How uv, Poetry, pip, pixi, and other tools differ in features and workflow
Do you still need tox or nox if you use uv?
uv runs tests across Python versions, but tox and nox add dependency matrices, parallel execution, and session orchestration for complex test workflows.
Does Ruff support type checking?
No. Ruff is a linter and formatter; it does not perform type inference. Use ty, mypy, Pyright, or Pyrefly alongside Ruff for type checking.
How do pyenv and uv compare for Python interpreter management?
pyenv focuses on Python version switching via shell shims, while uv integrates version management into a unified development toolkit.
How do Python type checkers compare?
Compare Python type checkers: mypy, pyright, ty, Pyrefly, Basedpyright, and Zuban. Speed benchmarks, conformance, and recommendations.
How do Ruff and Pylint compare?
Ruff offers dramatically faster performance and automatic fixes via Rust, while Pylint provides deeper semantic analysis from Python.
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 do uv tool and pipx compare?
uv tool and pipx install Python CLI tools in isolated environments. uv is faster with better caching; pipx has more features. Compare for your use case.
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.
ty vs Pyrefly: which Python type checker should you pick?
The handbook recommends Pyrefly for most Python projects. Pick ty only for Pydantic-heavy codebases where you don't want to set `ConfigDict(strict=True)` per model.
uv vs pixi vs conda for Scientific Python
Choosing between uv, pixi, and conda for scientific computing and GPU workloads depends on whether your dependencies live on PyPI, conda-forge, or both.
What's the difference between pip and uv?
pip and uv both install Python packages, but uv offers 10-100x faster performance and integrated environment management.
When should I choose pixi over uv?
Use pixi when projects need conda packages for native libraries. For pure Python, uv is simpler.
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.
Standards & PEPs
PEP 8, 517, 621, 723, 735, and the standards that shape modern Python tooling
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 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 PEP?
Python Enhancement Proposals (PEPs) are formal documents that propose new features, collect community input, and record design decisions.
What is a version specifier?
Version specifiers like >=2.0, ~=1.4 tell pip, uv, and PEP 440 resolvers which package versions to install.
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 484?
PEP 484 defines Python type hints: annotation syntax, typing module, gradual typing model.
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 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 604?
PEP 604 lets Python 3.10+ write union types with the pipe operator: int | str replaces Union[int, str], and int | None replaces Optional[int].
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 612?
PEP 612 adds ParamSpec and Concatenate to Python's typing system so decorators can preserve the signatures of the functions they wrap.
What is PEP 621?
PEP 621 defines [project] in pyproject.toml for package metadata any build tool can read.
What is PEP 649?
PEP 649 defers type annotation evaluation in Python 3.14; PEP 749 adds runtime annotation inspection.
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 681?
PEP 681's dataclass_transform marker tells type checkers a library's classes behave like dataclasses, eliminating the need for per-library checker plugins.
What is PEP 688?
PEP 688 types the buffer protocol, removing the promotion that let bytearray pass as bytes.
What is PEP 695?
PEP 695 adds Python 3.12 syntax for generics: class Box[T], def first[T], and type aliases without TypeVar or Generic base classes.
What is PEP 703?
PEP 703 adds a build configuration that lets CPython run without the Global Interpreter Lock, producing the free-threaded Python interpreter.
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 standardizes development dependencies in pyproject.toml's [dependency-groups] table.
What is PEP 740?
PEP 740 lets package indexes like PyPI accept and serve cryptographically signed attestations, giving installers verifiable proof of who published each file.
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, an elected body governing packaging standards.
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 779?
PEP 779 sets the criteria the free-threaded Python build had to meet before Python 3.14 could mark it officially supported.
What is PEP 8?
PEP 8 is Python's official style guide covering naming conventions, whitespace, line length, and code formatting standards.
What is PEP 810?
PEP 810: lazy imports speed short-running CLIs by deferring module loads until first use. Long-running services see no startup benefit.
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.
Why pylock.toml Includes Digital Attestations
Lockfiles record publisher identities with hashes, making supply chain changes visible in review.
Coming From Another Language
Python tooling for engineers experienced with Go, Rust, TypeScript, Java, or C#
Python Tooling for C# Developers
A guide to Python's development tooling for developers coming from the C# and .NET ecosystem.
Python Tooling for Go Developers
A guide to Python's development tooling for developers coming from the Go ecosystem.
Python Tooling for Java Developers
A guide to Python's development tooling for developers coming from the Java ecosystem.
Python Tooling for Node.js Developers
A guide to Python's development tooling for developers coming from the Node.js ecosystem.
Python Tooling for PHP Developers
A guide to Python's development tooling for developers coming from the PHP ecosystem.
Python Tooling for Ruby Developers
A guide to Python's development tooling for developers coming from the Ruby ecosystem.
Python Tooling for Rust Developers
A guide to Python's development tooling for developers coming from the Rust ecosystem.
Python Tooling for TypeScript Developers
Python equivalents of npm, ESLint, Prettier, and tsc for TypeScript developers. Maps JS concepts to uv, Ruff, pytest, and pyproject.toml.
uv for Non-Python Teams
Non-Python teams use Python for scripts and CLI tools. uv is the unified package manager, environment tool, and Python version tool for polyglot projects.
Why Python Tooling Looks Like This
Opinionated takes on packaging history, defaults, and recommended choices
Can you trust uv long-term?
uv is VC-funded and Astral was acquired by OpenAI. The dual MIT / Apache license and a forkable codebase make uv a defensible long-term bet anyway.
Do I need a project to use uv?
uv works without a project directory. Here are options for using uv with single-file scripts, script collections, and when each approach makes sense.
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.
Is Conda actually free?
conda and conda-forge are free and open source. Anaconda's commercial repository requires a license for organizations with over 200 employees.
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.
Should I use Homebrew to install Python?
Homebrew's Python exists to support other Homebrew tools and can break unexpectedly on upgrade. Use uv to manage Python instead.
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 used Hatchling for its modern, standards-compliant design. Since July 2025, uv_build is default.
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, import, and twice at startup via .pth files.
Why should I avoid using the system Python?
System Python risks breaking OS tools, forces one version per machine, lacks project isolation.
Why should I choose Conda?
Conda manages non-Python dependencies that pip cannot, making it the right choice when your project depends on compiled libraries across languages.
Why Should I Choose pyproject.toml over requirements.txt for managing dependencies?
pyproject.toml provides standardized metadata, build configuration, and tool settings in one file versus requirements.txt's flat dependency list.
Why should I use a virtual environment?
Virtual environments prevent dependency conflicts, protect system Python, and make projects reproducible across machines.
Why use native uv commands instead of uv pip
uv's native project interface (uv add, uv sync, uv run) provides lockfiles, declarative dependencies, and automatic environments that uv pip cannot.
Why Use Trusted Publishing for PyPI?
Trusted publishing replaces long-lived PyPI tokens with short-lived OIDC credentials.
Why You Should Try uv if You Use Python
Why uv replaces pip, virtualenv, pyenv, and pip-tools with one tool that installs packages 10-100x faster and follows Python standards.
Topic Deep Dives
Longer explorations of how Python tools work under the hood
Enough Git to Supervise Your AI Coding Agent
The mental model of Git and GitHub you need to understand what your AI coding agent is doing with version control.
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 Does Hot Reloading Work in Python?
Python has no universal hot-reload convention. Instead, different tools and frameworks implement their own approaches to reloading code during development.
How mypy, ty, and Pyrefly handle untyped code
mypy skips unannotated function bodies by default; ty and Pyrefly infer types and check them. This is why a mypy-clean codebase surfaces new errors under ty or Pyrefly, and which config flags control it.
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.
How Python tools adopt uv under the hood
Hatch, PDM, pixi, tox, and other tools embed uv's resolver and installer as shared infrastructure, giving their users uv's speed without switching tools.
Modern Python Project Setup Guide for AI Assistants
Standardized instructions for AI assistants to scaffold modern Python projects using uv and pyproject.toml.
What Happens When You Run `uv run`
What happens when you run `uv run`: project discovery, Python resolution, environment creation, locking, syncing, and command execution in six stages.
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 is Python Slow?
Python is slow because the language requires runtime work that compiled languages skip. Type lookups, attribute resolution, boxed numbers, and pointer chasing add up; implementations can optimize common cases, but full compatibility keeps the dynamic checks in play.