•9 min read

Modern Python Development Environment with pyenv, Poetry, uv, and pyproject.toml

Modern Python Development Environment with pyenv, Poetry, uv, and pyproject.toml
Python Environment

pyenv

Click to reveal
Python Environment
Manages and switches between Python versions (3.10, 3.12, 3.14...) per project. Prevents conflicts with system Python.

pyenv

Python Environment

Poetry

Click to reveal
Python Environment
Modern package manager for Python. Handles dependencies, virtual environments, and lock files (poetry.lock) in one tool.

Poetry

Python Environment

uv

Click to reveal
Python Environment
Ultra-fast Python package installer, resolver, and project manager written in Rust. Replaces pip/pip-tools/venv/pyenv in a single binary. 10-100x faster.

uv

Python Environment

pyproject.toml

Click to reveal
Python Environment
Standardized configuration file for Python projects (PEP 621). Replaces setup.py, setup.cfg, requirements.txt for metadata and dependencies.

pyproject.toml

Python Environment

Virtual Environment

Click to reveal
Python Environment
Isolated Python environment per project. Prevents dependency conflicts between projects. Created with `uv venv` or `python -m venv .venv`.

Virtual Environment

Modern Python Development Environment Setup

Using just pip install leads to version conflicts, "works on my machine" problems, and no reproducible builds. Modern Python development requires environment isolation, version locking, and consistent tooling — ideally from a single, fast tool.

Audio Briefing
0:00 / 0:00
Standard Modern Toolkit
  • pyenv (or uv): Manage and switch between Python versions (3.10, 3.12, 3.14...).
  • uv: The fastest package manager — replaces pip, pip-tools, venv, and pyenv in one binary.
  • pyproject.toml: Standard config for all Python projects (PEP 621).
  • Ruff: Linter and formatter — replaces flake8, black, isort in one tool.
  • ty: Pyright-based type checker from Astral, the creators of uv and Ruff.

Complete Setup Steps

Step 1: Install uv (The Modern Way)

uv is now the recommended single tool for managing Python versions, virtual environments, and packages. Install it once, globally:

# Linux / macOS
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

After installation, uv handles everything — you don't need pyenv, pip, or venv separately.

Step 2: Pin and Install the Right Python Version

Use uv to install and pin a Python version per project. This creates a .python-version file that is committed to git — every developer on the team uses the same version automatically:

# Install a specific Python version
uv python install 3.14.0

# Pin it for this project (creates .python-version)
uv python pin 3.14.0

# Verify
uv python list

If you still prefer pyenv for version management, uv respects .python-version files from pyenv seamlessly.

Step 3: Initialize the Project and Virtual Environment

uv init creates a pyproject.toml and uv.lock file. uv sync creates the virtual environment and installs all dependencies from the lockfile in one command:

# New project
uv init myapp
cd myapp

# Or sync an existing repo after cloning
uv sync

The virtualenv is created at .venv/ automatically. You never need to activate it manually when using uv run.

Step 4: Add Dependencies (Never pip install directly)

Always add dependencies through uv add — this updates both pyproject.toml and uv.lock atomically, ensuring the lockfile stays consistent:

# Add a runtime dependency
uv add fastapi uvicorn[standard]

# Add a dev-only dependency
uv add --dev pytest ruff ty

# Remove a package
uv remove httpx

Never run pip install directly in a uv-managed project — it bypasses the lock file.

Step 5: Run Code with uv run

uv run executes commands in the project's virtualenv without activating it. This is the standard way to run scripts, tests, and tools:

# Run your app
uv run python main.py

# Run tests
uv run pytest -v

# Run the linter
uv run ruff check .

# Run the type checker
uv run ty check

# Run a one-off script (auto-installs dependencies from inline script metadata)
uv run scripts/migrate.py

This pattern works identically in CI/CD without any activation step.

Step 6: Set Up Pre-commit Hooks with Ruff

Enforce formatting and linting on every commit with pre-commit. Ruff handles both formatting (replacing Black) and linting (replacing flake8 + isort) in a single fast pass:

uv add --dev pre-commit

Create .pre-commit-config.yaml:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

Install the hooks:

uv run pre-commit install

Now every git commit automatically runs Ruff format + lint with auto-fix.


Advertisement

Complete pyproject.toml Reference

This is what a well-structured pyproject.toml looks like for a real project — covers metadata, dependencies, dev dependencies, tool configuration for Ruff and ty, and test settings:

[project]
name = "myapp"
version = "1.0.0"
description = "Your project description"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115",
    "uvicorn[standard]>=0.32",
    "httpx>=0.28",
    "pydantic>=2.10",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "pytest-asyncio>=0.24",
    "ruff>=0.9",
    "ty>=0.0.1a14",
    "pre-commit>=4.0",
]

[project.scripts]
myapp = "myapp.main:app"

[tool.uv]
required-version = ">=0.6"
dev-dependencies = [
    "pytest>=8.0",
    "ruff>=0.9",
    "ty>=0.0.1a14",
]

[tool.ruff]
target-version = "py312"
line-length = 100

[tool.ruff.lint]
select = ["E", "F", "UP", "B", "I"]
ignore = ["E501"]

[tool.ruff.format]
quote-style = "double"

[tool.ty]
# ty is the Astral type checker — fast, Pyright-based
python-version = "3.12"

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]

Which Tool Should You Choose?

ToolBest ForVerdict
venv
Python built-in, simple, reliable
Great for simple scripts and learning
Pipenv
Was popular but now slower, abandoned by many
Avoid for new projects
Poetry
Mature, excellent dependency resolution, good DX
Solid choice, especially for libraries
uv
Rust-based, 10-100x faster, replaces pip+venv+pyenv
Recommended for 2026+ projects
Warning for Beginners

Absolutely avoid sudo pip install or installing packages directly into system Python. Always, always use virtual environments — whether via uv venv, python -m venv, or Poetry.


Quick Comparison: Poetry vs uv

FeaturePoetryuv
Speed
Good
Blazing fast (Rust, 10-100x)
Lock file
poetry.lock
uv.lock (cross-platform, exact)
Virtual env
Auto-managed
Auto-managed (.venv)
Python version mgmt
Delegates to pyenv
Built-in (uv python install)
Script runner
poetry run
uv run (+ inline script deps)
Build/package
poetry build / publish
uv build / publish
Maturity
Mature, stable (5+ years)
Rapidly evolving, Astral-backed

Advertisement

Lock File Discipline

The uv.lock file (or poetry.lock) is as important as your code. It pins every transitive dependency to exact versions, ensuring that uv sync on a CI server, a colleague's machine, or a production container installs the exact same packages.

Rules:

  1. Always commit the lockfile to git — it is not a generated artifact to .gitignore
  2. Never edit it manually — use uv add, uv remove, or uv lock --upgrade-package <name>
  3. Update dependencies intentionally: uv lock --upgrade upgrades all packages to their latest compatible versions, then review the diff
# Upgrade a single package
uv lock --upgrade-package fastapi

# Upgrade all packages (then run tests!)
uv lock --upgrade

# Check what changed
git diff uv.lock
Continue Learning

Next: Learn Python Fundamentals if you're new to Python, or explore Python Tricks & Patterns for practical patterns that save time.

Python Environment pyenv Poetry uv

You Might Also Like

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement