Environments Highlights Summary
Every highlight bullet from the 10 pages in this section, gathered on one page and grouped by the page it came from.
- import doesn't search your whole disk - it walks a specific, ordered list called sys.path
- A virtual environment isn't a sandbox around the interpreter - it's a different site-packages directory spliced into sys.path
- pyproject.toml declares acceptable version ranges; the lockfile records the exact graph that was actually resolved
- uv, Poetry, and PDM solve the same resolution problem - they differ in speed, lockfile format, and workflow ergonomics
- Reproducibility comes from committing the lockfile, never from range declarations alone
- Create virtual environments with venv, add .venv to gitignore
- Declare dependencies in pyproject.toml with version constraints
- Commit lockfiles to ensure identical environments across teams
- uv is the recommended default toolchain for Python 3.14 projects
- uv run executes code inside the project environment automatically
- Manage multiple Python versions with uv instead of pyenv
- uv replaces pip, venv, pip-tools, and pyenv with a single fast Rust CLI
- uv init creates pyproject.toml, src/ structure, and .venv in one command
- uv.lock must be committed to prevent teammates from getting different versions
- uv resolves dependencies in Rust, performing 10-100x faster than pip
- Always run uv sync after cloning to avoid ModuleNotFoundError
- Never mix pip and uv in the same project to prevent metadata conflicts
- Poetry and PDM pin exact versions with lockfiles to ensure reproducible installs
- Both resolve transitive dependencies and detect conflicts before installation
- Use Poetry for mature publish workflow when team already standardized on it
- Enable PDM speed by setting pdm config install.use_uv true for faster installs
- Commit lockfiles to prevent CI and local environments from diverging
- Pick one toolchain per project to avoid conflicting lockfile versions
- Use pyproject.toml as the single config file for modern Python projects
- [project] block holds metadata, dependencies, and entry point scripts
- [build-system] block is required or pip install . fails with errors
- [tool.ruff] and [tool.pytest] configure tools without separate config files
- Migrate fully to pyproject.toml and delete setup.py to prevent config conflicts
- Match requires-python range to your CI matrix to prevent installation failures
- Lockfiles freeze exact versions to ensure consistency across machines
- Declare ranges in pyproject.toml to express intent separate from resolution
- Use --frozen to prevent installation if lockfile drifts from dependencies
- Lockfile hashes verify package integrity and prevent supply chain attacks
- Commit lockfiles to avoid transitive dependency drift across CI builds
- Over-constraining versions blocks resolution, loosen bounds to unblock
- Use uv python or pyenv to manage multiple Python versions locally
- Never develop with system Python, always pin a project interpreter
- Commit .python-version to avoid teammates using different versions
- Declare supported versions with requires-python in pyproject.toml
- Test against all requires-python versions in CI to catch regressions
- Standardize on one version manager per project to avoid pin conflicts
- Editable installs make code changes visible immediately without reinstall
- src/ layout prevents accidental imports of uninstalled code
- Use uv workspaces to coordinate multiple editable packages in monorepos
- Flat layout tests pass locally but fail in CI without the actual install
- Relative paths or uv workspaces prevent dependency breakage on other machines
- Publishing requires uv build for distribution; editable-only packages fail
- Use UV_INDEX_URL env var for persistent private index configuration
- Store index credentials in env vars or .netrc, never commit tokens
- Always use HTTPS for private indexes to prevent package tampering
- Add PyPI as extra index to handle mirror lag on new releases
- Namespace internal packages to avoid collision with PyPI names
- Private indexes must serve stable URLs for lockfile verification
- Commit lockfiles to ensure CI and prod install identical packages
- Use uv sync --frozen in CI to fail if lockfile gets out of date
- One virtual environment per project prevents version conflicts
- Separate dev and prod dependencies so production excludes test tools
- Use src/ layout with editable installs so tests import the package
- Standardize on one package manager per repo, never mix pip/Poetry/uv
Reviewed by Chris St. John·Last updated Jul 31, 2026