Python notes

pip_interface

uv pip interface

  • Purpose: uv pip provides fast, pip-compatible CLI commands for managing virtual environments and packages directly, without relying on a project structure (pyproject.toml).

  • Compatibility:

    • Mimics pip, pip-tools, and virtualenv
    • Behaviors may differ in edge cases
    • Refer to the pip-compatibility guide for differences
  • Scope:

    • Creating environments: Replacement for virtualenv
    • Installing/managing packages: Replacement for pip
    • Inspecting environments: Show and analyze installed packages
    • Declaring dependencies: Supports requirements.in/.txt
    • Locking/syncing: Replacement for pip-tools' compile/sync
  • Interface model:

    • Operates directly on environments
    • No automatic project detection or environment management
  • Use case:

    • Useful for:
      • Power users
      • Legacy projects
      • Manual environment control
    • Not tied to pyproject.toml-based workflows
  • Examples:

    • uv venv: Create environment
    • uv pip install flask: Install package
    • uv pip compile requirements.in: Lock dependencies
    • uv pip sync: Apply lockfile to environment
  • Warning:

    • Not a byte-for-byte substitute for pip; behavioral differences can exist outside standard workflows.

Using Python environments

  • Environment usage:

    • Each Python interpreter uses an environment where packages can be installed.
    • Modifying system Python environments is discouraged; use virtual environments instead.
    • uv requires virtual environments for package operations by default.
  • Creating virtual environments:

    • Default:
      uv venv  # creates `.venv`
    • Custom path:
      uv venv my-env
    • With Python version:
      uv venv --python 3.11
  • Using virtual environments:

    • After creation, uv auto-detects .venv during subsequent commands.
    • Example:
      uv pip install ruff
  • Activating environments:

    • Unix/macOS:
      source .venv/bin/activate
    • Windows:
      .venv\Scripts\activate.bat
  • Deactivating environments:

    • To exit:
      deactivate
  • Using arbitrary environments:

    • Via VIRTUAL_ENV:
      VIRTUAL_ENV=/some/path uv pip install ...
    • Via --python:
      uv pip install --python /path/to/python
  • Installing into system environment:

    • Use:
      uv pip install --system
    • Allows direct modification of system Python
    • Needed when uv finds a system interpreter for a --python request
    • Not recommended for general use; valid for CI or Docker
  • Behavior with python -m uv:

    • Defaults to modifying the parent interpreter’s environment
    • Adds startup overhead; avoid for general usage
  • Environment discovery (mutation commands like uv pip install):

    1. Activated via VIRTUAL_ENV
    2. Activated Conda via CONDA_PREFIX
    3. .venv in current/parent directories
    4. If none found, prompts to create one with uv venv
  • Discovery with --system:

    • Skips virtual env search
    • Searches for installed system Pythons
  • Interpreter still required:

    • Even when not mutating, e.g., for uv pip compile
    • See Python discovery docs for interpreter search behavior.

Managing packages

  • Installing a package:

    • Single package:

      uv pip install flask
    • With extras:

      uv pip install "flask[dotenv]"
    • Multiple packages:

      uv pip install flask ruff
    • With version constraint:

      uv pip install 'ruff>=0.2.0'
    • Specific version:

      uv pip install 'ruff==0.3.0'
    • From local directory:

      uv pip install "ruff @ ./projects/ruff"
    • From GitHub:

      uv pip install "git+https://github.com/astral-sh/ruff"
    • From GitHub with specific reference:

      # Tag
      uv pip install "git+https://github.com/astral-sh/ruff@v0.2.0"
      
      # Commit
      uv pip install "git+https://github.com/astral-sh/ruff@<commit-hash>"
      
      # Branch
      uv pip install "git+https://github.com/astral-sh/ruff@main"
  • Editable installs:

    • Current project:
      uv pip install -e .
    • Other directory:
      uv pip install -e "ruff @ ./project/ruff"
  • Installing from files:

    • From requirements.txt:
      uv pip install -r requirements.txt
    • From pyproject.toml:
      uv pip install -r pyproject.toml
    • With extras:
      uv pip install -r pyproject.toml --extra foo
      uv pip install -r pyproject.toml --all-extras
  • Installing from dependency groups:

    • In current pyproject.toml:
      uv pip install --group foo
    • From specific project directory:
      uv pip install --project some/path/ --group foo --group bar
    • From specific pyproject.toml files:
      uv pip install --group some/path/pyproject.toml:foo --group other/pyproject.toml:bar

    Note: --group only applies to the current directory or explicitly set --project, not to files passed via -r or -e.

  • Uninstalling packages:

    • Single package:
      uv pip uninstall flask
    • Multiple packages:
      uv pip uninstall flask ruff

Inspecting environments

  • List installed packages:

    • Human-readable:
      uv pip list
    • JSON format:
      uv pip list --format json
    • requirements.txt format:
      uv pip freeze
  • Inspect installed package(s):

    • Single package (e.g., numpy):
      uv pip show numpy
    • Multiple packages:
      uv pip show numpy flask
  • Verify environment integrity:

    • Check for dependency conflicts or missing packages:
      uv pip check

Declaring dependencies

  • Declare dependencies in pyproject.toml:

    [project]
    dependencies = [
      "httpx",
      "ruff>=0.3.0"
    ]
  • Declare optional dependencies (extras):

    [project.optional-dependencies]
    cli = [
      "rich",
      "click",
    ]
    • Installable via:
      • uv pip install "project[cli]"
      • uv pip install -r pyproject.toml --extra cli
  • Declare dependencies in requirements.in:

    httpx
    ruff>=0.3.0
    
    • Simpler format; commonly used with uv pip compile to generate a lockfile.
    • Does not support optional dependency groups.

Locking environments

  • Locking dependencies from pyproject.toml:

    uv pip compile pyproject.toml -o requirements.txt
  • Locking dependencies from requirements.in:

    uv pip compile requirements.in -o requirements.txt
  • Locking multiple sources:

    uv pip compile pyproject.toml requirements-dev.in -o requirements-dev.txt
  • Locking optional dependencies (extras):

    uv pip compile pyproject.toml --extra foo
    uv pip compile pyproject.toml --all-extras
  • Locking specific groups:

    uv pip compile --group foo
    uv pip compile --project some/path/ --group foo --group bar
    uv pip compile --group some/path/pyproject.toml:foo
  • Upgrade specific package(s):

    uv pip compile - -o requirements.txt --upgrade-package ruff
  • Upgrade all packages:

    uv pip compile - -o requirements.txt --upgrade
  • Sync environment exactly to lockfile:

    uv pip sync requirements.txt
    uv pip sync pyproject.toml
  • Using constraints:

    • constraints.txt:
      pydantic<2.0
      
    • Command:
      uv pip compile requirements.in --constraint constraints.txt
  • Using build constraints:

    • build-constraints.txt:
      setuptools==75.0.0
      
  • Using overrides to bypass incompatible metadata:

    • overrides.txt:
      c>=2.0
      
    • Command:
      uv pip compile requirements.in --override overrides.txt

Compatibility with pip and pip-tools

  • Compatibility intent:

    • uv aims to be a drop-in replacement for pip and pip-tools.
    • Full 1:1 behavior is not guaranteed, especially in edge cases or non-standard workflows.
  • Configuration differences:

    • uv does not support pip.conf or PIP_INDEX_URL.
    • Instead, uses its own config: UV_INDEX_URL, uv.toml, and [tool.uv.pip].
  • Pre-release handling:

    • uv only installs pre-releases if:
      • The pre-release is explicitly specified (e.g., flask>=2.0.0rc1), or
      • All available versions are pre-releases.
    • Otherwise, use --prerelease allow.
  • Index handling:

    • uv stops at the first index that contains a package.
    • pip aggregates versions across all indexes.
    • To use pip-like behavior, use --index-strategy unsafe-best-match.
  • Build isolation:

    • uv uses PEP 517 build isolation by default (like pip install --use-pep517).
    • To disable: preinstall build deps and use --no-build-isolation.
  • Transitive URL dependencies:

    • uv rejects indirect URL dependencies unless declared directly.
    • To resolve, explicitly include them in pyproject.toml or requirements.in.
  • Virtual environments:

    • uv requires virtual environments by default.
    • Use --system or --python to install outside of venvs.
    • Differs from pip, which defaults to system environment if no venv is active.
  • Resolution strategy:

    • uv and pip may resolve different but valid sets of packages.
    • Example: conflicts between fastapi and starlette based on version constraints.
    • Suggestion: tighten constraints to control resolution.
  • uv pip check:

    • More strict than pip’s pip check.
    • Reports missing METADATA, incompatible Python, missing/incompatible deps, duplicate versions.
  • User scheme:

    • uv does not support --user.
    • uv does not fallback to user installs when lacking permissions.
  • --only-binary and --no-binary:

    • uv enforces both flags strictly, including for direct URLs.
    • uv compiles from source only if explicitly allowed.
  • PEP 600 (manylinux):

    • uv respects manylinux_compatible() but only evaluates for current glibc.
  • Bytecode compilation:

    • uv skips .pyc generation unless --compile-bytecode or UV_COMPILE_BYTECODE=1 is set.
  • Strict spec enforcement:

    • uv is stricter than pip, e.g., with invalid URLs.
    • Will reject non-PEP-compliant formats unless patched.
  • Partial pip CLI support:

    • Missing: --trusted-host, --user, some subcommands.
    • Missing features tracked in issues based on demand.
  • Registry authentication:

    • uv supports only --keyring-provider subprocess.
    • Credentials always sent if present (no HTTP 401 waiting).
  • Egg support:

    • uv does not install .egg packages.
    • Will recognize and uninstall existing .egg-info or .egg-link packages.
  • Build constraints:

    • uv requires --build-constraint for build deps.
    • pip allows constraints via PIP_CONSTRAINT.
  • pip compile differences:

    • uv requires -o/--output-file to write files.
    • uv defaults to --strip-extras; pip-tools defaults to --no-strip-extras.
    • Use --emit-index-url in uv to include all index URLs in output.
  • requires-python:

    • uv ignores upper bounds (e.g., treats >=3.8,<4 as >=3.8).
    • Pre-releases like 3.13.0b1 treated as 3.13.0 for matching.
  • Package priority:

    • uv is more sensitive to input order than pip.
    • Changing order in install or compile inputs may change resolution.