Files
gh-tenequm-claude-plugins-u…/skills/skill/references/migration.md
2025-11-30 09:01:33 +08:00

14 KiB

Migration Guide: Moving to UV and Ruff

Complete guide for migrating from pip, conda, poetry, or pipx to UV, and from Flake8, Black, isort to Ruff.

Table of Contents

  1. Why Migrate?
  2. From pip + virtualenv
  3. From conda
  4. From poetry
  5. From pipx
  6. From Flake8/Black/isort to Ruff
  7. Complete Workflow Migration

Why Migrate?

UV Benefits

  • 10-100x faster than pip for package installation
  • Single tool replacing pip, pip-tools, pipx, poetry, pyenv, virtualenv
  • Automatic environment management - no manual activation needed
  • Universal lockfiles for cross-platform reproducibility
  • Python version management built-in
  • Zero dependencies - standalone binary

Ruff Benefits

  • 10-100x faster than existing linters
  • Single tool replacing Flake8, Black, isort, pyupgrade, autoflake
  • 800+ lint rules with auto-fix capabilities
  • Formatting compatible with Black
  • Editor integration with first-class support
  • Zero configuration needed to get started

From pip + virtualenv

Current Workflow

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # or .venv\Scripts\activate on Windows

# Install dependencies
pip install -r requirements.txt

# Install dev dependencies
pip install -r requirements-dev.txt

# Run application
python main.py

New Workflow with UV

# Initialize project (one-time)
uv init my-project
cd my-project

# Add dependencies
uv add requests pandas numpy

# Add dev dependencies
uv add --dev pytest black ruff

# Run application (no activation needed!)
uv run python main.py

# Run tests
uv run pytest

Migration Steps

Step 1: Install UV

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

Step 2: Convert requirements.txt to pyproject.toml

If you have requirements.txt:

# Create new project
uv init .

# Install from requirements.txt
uv pip install -r requirements.txt

# Generate pyproject.toml dependencies
uv add $(cat requirements.txt | grep -v '^#' | grep -v '^$')

Or manually create pyproject.toml:

[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "requests>=2.31.0",
    "pandas>=2.0.0",
]

[tool.uv]
dev-dependencies = [
    "pytest>=7.0.0",
    "ruff>=0.1.0",
]

Step 3: Create lockfile

uv lock

Step 4: Update CI/CD

Before:

- name: Setup Python
  uses: actions/setup-python@v4
  with:
    python-version: '3.11'

- name: Install dependencies
  run: |
    python -m pip install --upgrade pip
    pip install -r requirements.txt

After:

- name: Install uv
  run: curl -LsSf https://astral.sh/uv/install.sh | sh

- name: Install dependencies
  run: uv sync

Step 5: Update Development Scripts

Before:

#!/bin/bash
source .venv/bin/activate
python manage.py runserver

After:

#!/bin/bash
uv run python manage.py runserver

Maintaining requirements.txt (Optional)

If you need to maintain requirements.txt for compatibility:

# Generate requirements.txt from lockfile
uv export -o requirements.txt

# Generate dev requirements
uv export --group dev -o requirements-dev.txt

From conda

Current Workflow

# Create environment
conda create -n myenv python=3.11
conda activate myenv

# Install dependencies
conda install numpy pandas scipy
pip install requests  # Some packages not in conda

# Export environment
conda env export > environment.yml

New Workflow with UV

# Initialize project
uv init my-project
cd my-project

# Pin Python version
uv python pin 3.11

# Add dependencies (all from PyPI)
uv add numpy pandas scipy requests

# All dependencies in one place
uv lock

Migration Steps

Step 1: Export conda dependencies

# Get list of installed packages
conda list --export > conda-packages.txt

# Or just the package names
conda env export --from-history > environment.yml

Step 2: Convert to pyproject.toml

From environment.yml:

name: myenv
dependencies:
  - python=3.11
  - numpy=1.24.0
  - pandas=2.0.0
  - pip:
    - requests==2.31.0

To pyproject.toml:

[project]
name = "myproject"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "numpy>=1.24.0",
    "pandas>=2.0.0",
    "requests>=2.31.0",
]

Step 3: Handle Conda-Only Packages

Some packages are only available through conda. Options:

  1. Use PyPI alternatives: Many packages are now on PyPI
  2. Keep conda for specific packages: Use conda + uv hybrid
  3. Build from source: UV can build packages if needed

Step 4: Remove Conda Environment

# Deactivate conda environment
conda deactivate

# Remove environment
conda env remove -n myenv

Conda vs UV Comparison

Feature conda UV
Speed Slow (10-30min) Fast (10-30sec)
Python Versions
Non-Python Packages
PyPI Packages Limited Full
Lockfiles
Cross-platform
Memory Usage High (1-2GB) Low (<100MB)

When to Keep Conda

Keep conda if you need:

  • Non-Python packages (R, Julia, C libraries)
  • Specific binary distributions
  • Legacy scientific computing workflows

You can use both:

# Use conda for system-level dependencies
conda install gcc openblas

# Use uv for Python packages
uv sync

From poetry

Current Workflow

# Create project
poetry new my-project
cd my-project

# Add dependencies
poetry add requests

# Install dependencies
poetry install

# Run scripts
poetry run python main.py

New Workflow with UV

# Create project
uv init my-project
cd my-project

# Add dependencies
uv add requests

# Install dependencies (automatic with add)
# No separate install step needed!

# Run scripts
uv run python main.py

Migration Steps

Step 1: Convert pyproject.toml

Poetry pyproject.toml:

[tool.poetry]
name = "my-project"
version = "0.1.0"
description = ""
authors = ["Your Name <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31.0"

[tool.poetry.dev-dependencies]
pytest = "^7.0.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

UV pyproject.toml:

[project]
name = "my-project"
version = "0.1.0"
description = ""
authors = [{name = "Your Name", email = "[email protected]"}]
requires-python = ">=3.11"
dependencies = [
    "requests>=2.31.0",
]

[tool.uv]
dev-dependencies = [
    "pytest>=7.0.0",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Step 2: Convert Version Constraints

Poetry uses caret (^) for version constraints:

  • ^2.31.0 means >=2.31.0, <3.0.0

UV uses standard pip syntax:

  • >=2.31.0,<3.0.0 or >=2.31.0

Step 3: Remove Poetry Files

rm poetry.lock
rm -rf .venv
poetry env remove --all

Step 4: Initialize UV

uv lock
uv sync

Step 5: Update Scripts

Before:

[tool.poetry.scripts]
start = "my_project.main:main"

After:

[project.scripts]
start = "my_project.main:main"

Or just use uv run:

uv run python -m my_project.main

Poetry vs UV Comparison

Feature Poetry UV
Speed Medium Very Fast
Lockfiles
Python Management
Tool Running (uvx)
Build Backend poetry-core Any (hatchling, setuptools)
Configuration Opinionated Flexible

From pipx

Current Workflow

# Install tools globally
pipx install black
pipx install ruff
pipx install pytest

# Run tools
black .
ruff check .

New Workflow with UV

# Install tools globally
uv tool install black
uv tool install ruff
uv tool install pytest

# Or run tools ephemerally
uvx black .
uvx ruff check .
uvx pytest

Migration Steps

Step 1: List pipx installations

pipx list

Step 2: Install with UV

# For each tool in pipx list
uv tool install tool-name

Step 3: Remove pipx tools

pipx uninstall-all

Step 4: Update PATH (if needed)

Tools are installed in:

  • pipx: ~/.local/bin/
  • uv: ~/.local/bin/ (same location!)

No PATH changes needed!

pipx vs UV Tool Comparison

Feature pipx UV Tool
Speed Medium Fast
Ephemeral runs (uvx)
Python Management
Isolated Environments
Upgrade Command

From Flake8/Black/isort to Ruff

Current Workflow

# Multiple tools
isort .
black .
flake8 .

# With configuration in multiple files
# .flake8
# pyproject.toml [tool.black]
# pyproject.toml [tool.isort]

New Workflow with Ruff

# Single command
ruff check --fix . && ruff format .

# All configuration in pyproject.toml
# [tool.ruff]

Migration Steps

Step 1: Install Ruff

uv add --dev ruff

Step 2: Convert Configuration

From .flake8:

[flake8]
max-line-length = 88
extend-ignore = E203, W503
exclude = .git,__pycache__,build
per-file-ignores =
    __init__.py:F401

From pyproject.toml:

[tool.black]
line-length = 88
target-version = ['py311']

[tool.isort]
profile = "black"
known_first_party = ["myproject"]

To unified Ruff config:

[tool.ruff]
line-length = 88
target-version = "py311"

[tool.ruff.lint]
ignore = ["E203", "W503"]
exclude = [".git", "__pycache__", "build"]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]

[tool.ruff.lint.isort]
known-first-party = ["myproject"]

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

Step 3: Test Ruff

# Check for issues
ruff check .

# Auto-fix
ruff check --fix .

# Format
ruff format .

Step 4: Remove Old Tools

uv remove --dev black isort flake8

Step 5: Update Pre-commit

Before:

repos:
  - repo: https://github.com/PyCQA/isort
    rev: 5.12.0
    hooks:
      - id: isort

  - repo: https://github.com/psf/black
    rev: 23.0.0
    hooks:
      - id: black

  - repo: https://github.com/PyCQA/flake8
    rev: 6.0.0
    hooks:
      - id: flake8

After:

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

Step 6: Update CI/CD

Before:

- name: Lint
  run: |
    pip install black isort flake8
    isort --check .
    black --check .
    flake8 .

After:

- name: Lint
  run: |
    uv tool install ruff
    ruff check .
    ruff format --check .

Complete Workflow Migration

Before: Traditional Setup

Project Structure:

my-project/
├── .flake8
├── requirements.txt
├── requirements-dev.txt
├── setup.py
└── src/

Development Workflow:

# Setup
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -r requirements-dev.txt

# Development
isort .
black .
flake8 .
pytest

# Every day
source .venv/bin/activate  # Easy to forget!

After: Modern Setup with UV + Ruff

Project Structure:

my-project/
├── pyproject.toml  # All configuration
├── uv.lock         # Reproducible dependencies
└── src/

Development Workflow:

# Setup (one-time)
uv sync

# Development (no activation needed!)
uv run ruff check --fix .
uv run ruff format .
uv run pytest

# That's it!

Migration Checklist

  • Install UV
  • Convert requirements to pyproject.toml
  • Generate lockfile (uv lock)
  • Install dependencies (uv sync)
  • Install Ruff (uv add --dev ruff)
  • Convert linter/formatter config
  • Test Ruff (ruff check . && ruff format .)
  • Update CI/CD pipelines
  • Update pre-commit hooks
  • Update documentation
  • Remove old tools
  • Update team workflows
  • Celebrate faster builds! 🎉

Rollback Plan

If you need to rollback:

Save Old Configuration:

# Before migration
cp requirements.txt requirements.txt.backup
cp .flake8 .flake8.backup
# etc.

Keep Old Files: Don't delete old files until you're confident in the migration.

Gradual Migration: You can run UV and pip side-by-side:

# Use both during transition
uv sync              # For new workflow
pip install -r requirements.txt  # For old workflow

Common Issues

UV Can't Find Python

# Install Python with UV
uv python install 3.12

# Or point to existing Python
uv python pin $(which python3.12)

Ruff Too Strict

# Start with minimal rules
ruff check --select F .  # Only Pyflakes

# Gradually add more
ruff check --select E,F .  # Add pycodestyle

Performance Issues

# Clear caches
uv cache clean
ruff clean

# Exclude large directories
# In pyproject.toml
[tool.ruff]
exclude = ["node_modules", "vendor"]

Success Stories

Typical Results After Migration:

  • Installation time: 5 minutes → 30 seconds (10x faster)
  • Linting time: 15 seconds → 0.5 seconds (30x faster)
  • CI/CD time: 10 minutes → 2 minutes (5x faster)
  • Tools to manage: 7 → 2 (3.5x fewer)
  • Config files: 4 → 1 (4x simpler)
  • Memory usage: 2GB → 200MB (10x less)

Next Steps

After migration:

  1. Configure Ruff rules to your needs
  2. Set up pre-commit hooks
  3. Update team documentation
  4. Train team on new workflow
  5. Monitor CI/CD improvements
  6. Consider adopting more modern Python features

Resources