uv: быстрый менеджер пакетов и проектов для Python на практике — PROG-TIME

uv: быстрый менеджер пакетов и проектов для Python на практике

24.06.2026

Если вы пришли в Python из мира PHP и Composer, привычная история с зависимостями выглядит странно: отдельно pyenv для версий интерпретатора, отдельно venv для окружений, pip для установки пакетов, pip-tools для лок-файлов и pipx для CLI-утилит. Пять инструментов там, где в других экосистемах хватает одного. Инструмент uv от команды Astral (авторов линтера Ruff) закрывает все эти задачи одним бинарником, написанным на Rust, и делает это в десятки раз быстрее. В этой статье разберём uv на практике: установка, создание проекта, управление зависимостями, версии Python, запуск кода и сборка Docker-образов.

Что такое uv и зачем он нужен

uv — это менеджер пакетов и проектов для Python «всё в одном». Он заменяет сразу несколько привычных инструментов:

  • pip и pip-tools — установка пакетов и формирование лок-файлов;
  • virtualenv и venv — создание виртуальных окружений;
  • pyenv — установка и переключение версий Python;
  • pipx — установка изолированных CLI-утилит.

Ключевое преимущество — скорость: за счёт параллельного резолвинга зависимостей, глобального кеша и реализации на Rust uv работает значительно быстрее связки pip + virtualenv. Бинарник не требует предустановленного Python или Rust, поддерживает Linux, macOS и Windows, а лок-файл uv.lock кроссплатформенный и обеспечивает воспроизводимые сборки.

Установка

Самый простой способ — официальный установочный скрипт. Он не требует ни Python, ни прав root:

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

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

uv также доступен через Homebrew (brew install uv), pipx и даже через обычный pip install uv. После установки проверьте версию и при необходимости обновите сам uv:

uv --version
uv self update

Создание нового проекта

Команда uv init разворачивает скелет проекта. Это аналог composer init, только сразу с настройкой окружения:

uv init hello-world
cd hello-world

uv создаст набор файлов: pyproject.toml с метаданными проекта, .python-version с версией интерпретатора, README.md, main.py и инициализирует git-репозиторий. Сам pyproject.toml выглядит лаконично:

[project]
name = "hello-world"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
dependencies = []

Виртуальное окружение .venv и лок-файл uv.lock создаются автоматически при первом вызове проектной команды — uv run, uv sync или uv lock. Запустим стартовый скрипт:

uv run main.py
# Hello from hello-world!

Управление зависимостями

Добавление пакета через uv add сразу обновляет pyproject.toml, лок-файл и окружение — три действия одной командой:

# Добавить зависимость
uv add requests

# Зафиксировать версию
uv add 'requests==2.31.0'

# Зависимость из git
uv add git+https://github.com/psf/requests

# Удалить пакет
uv remove requests

Если вы переезжаете со старого проекта, импортировать зависимости из requirements.txt можно одной командой:

uv add -r requirements.txt

Обновление конкретного пакета выполняется через uv lock с флагом --upgrade-package: он подтянет свежую совместимую версию, не трогая остальной лок-файл:

uv lock --upgrade-package requests

Файл uv.lock — это человекочитаемый TOML, который содержит точные разрешённые версии всех зависимостей. Его обязательно нужно коммитить в репозиторий, но не редактировать руками: им управляет сам uv.

Запуск кода: uv run и uv sync

Главная рабочая команда — uv run. Перед каждым запуском uv проверяет, что лок-файл соответствует pyproject.toml, а окружение — лок-файлу, и при необходимости синхронизирует их. Вам не нужно вручную активировать venv:

uv add flask
uv run -- flask run -p 3000

# Запуск произвольного скрипта
uv run example.py

Если вы предпочитаете классический подход с активацией окружения, используйте uv sync, который приводит .venv в соответствие с лок-файлом:

uv sync
source .venv/bin/activate   # Windows: .venv\Scripts\activate
flask run -p 3000

Управление версиями Python

uv умеет скачивать и устанавливать сами интерпретаторы — отдельный pyenv больше не нужен:

# Установить конкретную версию
uv python install 3.13

# Посмотреть доступные и установленные версии
uv python list

# Закрепить версию для текущего проекта
uv python pin 3.13

Команда uv python pin запишет выбранную версию в .python-version, и все последующие команды проекта будут использовать именно её.

uv в Docker

Astral публикует официальные образы в ghcr.io/astral-sh/uv — как «distroless» с одним бинарником для копирования в свои сборки, так и production-образы на базе Debian, Alpine и официальных python-образов. Базовый приём — скопировать бинарник uv из официального образа, обязательно закрепив версию:

FROM python:3.12-slim-trixie
# Закрепляем конкретную версию uv ради воспроизводимости
COPY --from=ghcr.io/astral-sh/uv:0.11.23 /uv /uvx /bin/

Для реальных приложений выгодно разнести установку зависимостей и копирование кода по разным слоям: зависимости меняются редко, а код — постоянно. Флаг --no-install-project ставит только зависимости, а кеш-маунт ускоряет повторные сборки:

FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

# Слой только с зависимостями (кешируется отдельно)
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --locked --no-install-project

# Копируем проект и досинхронизируем
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked

CMD ["uv", "run", "my_app"]

Несколько практических деталей. Добавьте .venv в .dockerignore — окружение зависит от платформы и должно собираться внутри образа с нуля. Флаг --locked в uv sync гарантирует, что лок-файл актуален, иначе сборка упадёт. Для production включите компиляцию байт-кода переменной ENV UV_COMPILE_BYTECODE=1 — это ускорит старт приложения. А переменная ENV UV_LINK_MODE=copy уберёт предупреждения о невозможности создавать ссылки между кешем и окружением на разных файловых системах.

Совместимость с pip

Если переписывать весь pipeline под проектную модель пока некогда, у uv есть подкоманда uv pip — почти drop-in замена pip с тем же интерфейсом, но в разы быстрее:

# Внутри контейнера система изолирована — можно ставить в системный Python
uv pip install --system ruff

# Установка из requirements.txt
uv pip install -r requirements.txt

# Создать и использовать venv вручную
uv venv /opt/venv

Итоги

uv — это редкий случай, когда новый инструмент действительно упрощает экосистему, а не добавляет ещё один слой поверх существующих. Один бинарник заменяет pip, pyenv, pipx, virtualenv и pip-tools, даёт кроссплатформенный лок-файл для воспроизводимых сборок и работает заметно быстрее привычной связки. Для PHP-разработчиков, которым приходится касаться Python в скриптах, парсерах или DevOps-задачах, uv делает работу с зависимостями такой же предсказуемой, как Composer. Начать просто: установите uv, выполните uv init в новом проекте и добавьте первую зависимость через uv add. А в Docker-сборках official-образы Astral с закреплённой версией и кеш-маунтами дадут быстрый и воспроизводимый pipeline из коробки.