Third-Party Package Management — pip, requirements.txt, pyproject.toml, uv
One of Python's greatest strengths is its ecosystem of hundreds of thousands of third-party packages. Master the proper way to install, manage, and distribute packages.
pip Basic Commands
pip is the Python Package Installer, which installs packages from PyPI (Python Package Index).
# Install
pip install requests
pip install "requests==2.31.0" # Exact version
pip install "requests>=2.28,<3.0" # Version range
pip install requests[security] # Optional dependencies (extras)
# Upgrade
pip install --upgrade requests
pip install -U pip # Upgrade pip itself
# Remove
pip uninstall requests
pip uninstall -y requests # Remove without confirmation
# List
pip list # Installed packages
pip list --outdated # Packages with available updates
pip show requests # Detailed info for a specific package
# Export dependencies
pip freeze # Installed packages in requirements.txt format
pip freeze > requirements.txt
# Offline install
pip download requests -d ./packages # Download only
pip install --no-index -f ./packages requests # Install from downloaded files
requirements.txt Management
Basic Format
# requirements.txt
requests==2.31.0
numpy>=1.26.0,<2.0
pandas~=2.1.0 # ~= compatible version (>=2.1.0, <2.2.0)
flask>=3.0
# Comments are supported
# Install local package
-e ./my_local_package
# Include another file
-r requirements-base.txt
Environment-Specific File Separation Pattern
requirements/
base.txt # Common dependencies
dev.txt # Development environment additions
prod.txt # Production additions
test.txt # Test environment additions
# requirements/base.txt
fastapi==0.110.0
sqlalchemy==2.0.28
pydantic==2.6.3
# requirements/dev.txt
-r base.txt
pytest==8.1.1
pytest-asyncio==0.23.5
black==24.2.0
ruff==0.3.2
# requirements/prod.txt
-r base.txt
uvicorn[standard]==0.27.1
gunicorn==21.2.0
# Install per environment
pip install -r requirements/dev.txt
pip install -r requirements/prod.txt
pyproject.toml — Modern Package Configuration
The modern Python project configuration file following PEP 517/518/621. Consolidates setup.py, setup.cfg, and requirements.txt.
# pyproject.toml
[build-system]
requires = ["setuptools>=68", "setuptools-scm"]
build-backend = "setuptools.backends.legacy:build"
[project]
name = "my-awesome-package"
version = "1.0.0"
description = "A really useful package"
readme = "README.md"
license = { text = "MIT" }
authors = [
{ name = "Jane Doe", email = "jane@example.com" }
]
requires-python = ">=3.12"
keywords = ["utility", "tools"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: MIT License",
]
# Runtime dependencies
dependencies = [
"requests>=2.28",
"pydantic>=2.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"black>=24.0",
"ruff>=0.3",
"mypy>=1.8",
]
docs = [
"sphinx>=7.0",
"sphinx-rtd-theme",
]
[project.urls]
Homepage = "https://github.com/example/my-package"
Documentation = "https://my-package.readthedocs.io"
[project.scripts]
my-tool = "mypackage.cli:main" # CLI entry point
[tool.setuptools.packages.find]
where = ["src"]
Consolidate Tool Configuration in pyproject.toml
[tool.black]
line-length = 88
target-version = ["py312"]
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP"]
[tool.mypy]
python_version = "3.12"
strict = true
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
[tool.coverage.run]
source = ["src"]
uv — Ultra-Fast Python Package Manager
uv is a next-generation Python package manager written in Rust. It is 10–100x faster than pip and integrates virtual environment management, package locking, and Python version management.
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# or: pip install uv
# Start a new project
uv init my-project
cd my-project
# Add packages
uv add requests
uv add "fastapi>=0.110"
uv add --dev pytest black ruff
# Remove packages
uv remove requests
# Sync dependencies (based on uv.lock)
uv sync
uv sync --dev # Include development dependencies
# Run scripts
uv run python main.py
uv run pytest
uv run -- python -c "import requests; print(requests.__version__)"
# Python version management
uv python install 3.12
uv python list
# pyproject.toml generated by uv
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"requests>=2.31.0",
"fastapi>=0.110.0",
]
[dependency-groups]
dev = [
"pytest>=8.1.1",
"black>=24.2.0",
]
# uv.lock — complete dependency lock file (recommended to commit to git)
version = 1
requires-python = ">=3.12"
[[package]]
name = "requests"
version = "2.31.0"
source = { registry = "https://pypi.org/simple" }
...
Virtual Environments and Package Isolation
Use an independent Python environment for each project to prevent dependency conflicts.
venv (Built-in)
# Create virtual environment
python -m venv .venv
# Activate
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate.bat # Windows CMD
.venv\Scripts\Activate.ps1 # Windows PowerShell
# Verify activation
which python # .venv/bin/python
pip list # Shows only packages in this environment
# Deactivate
deactivate
Managing Virtual Environments with uv
# uv manages .venv automatically
uv venv # Create .venv
uv venv --python 3.12 # Specify version
source .venv/bin/activate # Manual activation (optional)
uv sync # Sync based on uv.lock
pyenv (Python Version Management)
# After installing pyenv
pyenv install 3.12.2
pyenv local 3.12.2 # Set version for current directory
pyenv global 3.12.2 # Set global default version
Dependency Resolution Strategies
Dependency Locking
Record the exact versions of all dependencies for reproducible builds.
# pip-tools approach
pip install pip-tools
# requirements.in — list only direct dependencies
cat > requirements.in << EOF
requests>=2.28
fastapi>=0.100
EOF
# Generate requirements.txt (lock all dependencies)
pip-compile requirements.in -o requirements.txt
pip-compile requirements-dev.in -o requirements-dev.txt
# Sync
pip-sync requirements.txt
Security Vulnerability Scanning
# pip-audit
pip install pip-audit
pip-audit
# safety
pip install safety
safety check
# uv
uv audit
Dependency Tree Visualization
pip install pipdeptree
pipdeptree
pipdeptree --reverse # Reverse: who uses this package
# Specific package
pipdeptree -p requests
Practical Example: Project Environment Automation Script
#!/usr/bin/env python3
"""Project initialization script"""
import subprocess
import sys
from pathlib import Path
def run(cmd: list[str], check: bool = True) -> subprocess.CompletedProcess:
"""Run a command"""
print(f"$ {' '.join(cmd)}")
return subprocess.run(cmd, check=check, capture_output=True, text=True)
def setup_project(project_dir: str = ".") -> None:
"""Set up project environment"""
project_path = Path(project_dir)
# Check Python version
if sys.version_info < (3, 12):
print("Python 3.12 or higher is required.")
sys.exit(1)
# Check if uv is installed
result = run(["uv", "--version"], check=False)
if result.returncode != 0:
print("Installing uv...")
run(["pip", "install", "uv"])
# Create virtual environment and sync
run(["uv", "venv", "--python", "3.12"])
run(["uv", "sync", "--dev"])
print("\nEnvironment setup complete!")
print("Get started with:")
print(" source .venv/bin/activate")
print(" uv run python main.py")
if __name__ == "__main__":
setup_project()
Expert Tips
Tip 1: Check before installing with pip install --dry-run
pip install --dry-run fastapi uvicorn
Tip 2: Suppress .pyc file generation with PYTHONDONTWRITEBYTECODE
export PYTHONDONTWRITEBYTECODE=1
# Useful for saving space in Docker images
Tip 3: Provide optional dependencies with extras_require
# pyproject.toml
[project.optional-dependencies]
postgres = ["asyncpg>=0.29", "psycopg>=3.1"]
redis = ["redis>=5.0"]
all = ["mypackage[postgres,redis]"]
pip install "mypackage[postgres]"
pip install "mypackage[all]"
Tip 4: Run scripts without venv using uv run
# Inline dependency declaration (PEP 723)
# At the top of script.py:
# /// script
# dependencies = ["requests", "rich"]
# ///
uv run script.py # Auto-creates a temporary environment and runs