uv — инструмент компании Astral, написанный на Rust. Он объединяет то, что раньше приходилось собирать из pip, virtualenv, pip-tools и poetry: создание окружения, установку пакетов, фиксацию зависимостей, загрузку интерпретаторов и запуск кода. Главное практическое отличие — скорость: разрешение зависимостей идёт параллельно, а скачанные колёса остаются в общем кэше. В Linux Mint 22 и Ubuntu 24.04 установка занимает минуту, root нужен только для системных пакетов.
Какие задачи закрывает uv
Инструмент работает в двух режимах. В проекте он читает pyproject.toml, строит граф зависимостей и пишет uv.lock. Вне проекта умеет ставить пакеты в отдельное окружение или запускать одноразовые команды. Разделение важное: для эксперимента не нужно создавать каталог, а для рабочего репозитория не нужно помнить десяток флагов.
- Окружения: uv venv создаёт .venv с нужной версией Python.
- Зависимости: uv add и uv remove правят pyproject.toml и lock-файл одновременно.
- Запуск: uv run выполняет команду внутри окружения проекта без активации.
- Инструменты: uvx запускает утилиту во временном окружении, не засоряя систему.
- Python: uv python install скачивает сборки python-build-standalone в домашний каталог.
Установка в Linux Mint и Ubuntu
Официальный установщик кладёт бинарник в ~/.local/bin и не трогает системный Python. Это предпочтительный способ для рабочей машины. Если политика запрещает запуск скриптов из сети, используйте pipx — он изолирует uv в собственном окружении. В свежих выпусках дистрибутивов uv появляется и в репозитории, но там он может отставать.
curl -LsSf https://astral.sh/uv/install.sh | sh
pipx install uv
uv --version
uv self update
После установки проверьте, что ~/.local/bin есть в PATH. Команда uv self update обновляет только установку из скрипта; версию из pipx обновляют через pipx upgrade uv, а версию из apt — обычным обновлением пакетов.
Проект с нуля
Команда uv init создаёт минимальный каркас: pyproject.toml, README, .python-version и каталог src, если указан флаг —package. Файл .python-version фиксирует интерпретатор, а uv.lock — точные версии прямых и транзитивных зависимостей. Lock-файл нужно коммитить: тогда коллеги и CI получат одинаковый набор пакетов.
[project]
name = "report-bot"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["httpx>=0.27", "rich>=13.7"]
[dependency-groups]
dev = ["pytest>=8.2", "ruff>=0.6"]
Группа dev появилась вместе с поддержкой PEP 735. uv понимает и старый раздел [tool.poetry.dependencies], но для нового проекта лучше сразу использовать [project] и [dependency-groups]: такой файл читают и другие инструменты.
Ежедневные команды
Активировать venv вручную не нужно. uv run сам проверяет, совпадает ли окружение с lock-файлом, и при расхождении сообщает об этом. uv sync приводит .venv к состоянию lock-файла: удаляет лишние пакеты и доставляет недостающие. Флаг —frozen запрещает обновлять lock, а —locked требует, чтобы файл уже был актуален.
uv add httpx rich
uv add --dev pytest ruff
uv sync
uv run python -m report_bot
uv tree
Обновление зависимостей — отдельное действие: uv lock —upgrade поднимает все пакеты в рамках ограничений, uv lock —upgrade-package httpx — только один. После обновления прогоняйте тесты: мажорные версии библиотек меняют поведение чаще, чем кажется.
Несколько версий Python
uv держит рядом 3.11, 3.12 и 3.13, не конфликтуя с системным интерпретатором. Сборки лежат в ~/.local/share/uv/python и не требуют прав root. Команда uv python pin записывает выбранную версию в .python-version, после чего uv run и uv sync используют именно её.
uv python install 3.12 3.13
uv python list
uv python pin 3.12
uv run python -V
Если нужна конкретная сборка, укажите её в requires-python. Для старых проектов держите отдельное окружение: современные библиотеки всё чаще требуют Python 3.10 и выше.
Скрипты и разовые инструменты
Для небольших утилит проект не нужен. uv поддерживает встроенные метаданные PEP 723: зависимости объявляются комментариями в начале файла, а uv run создаёт под них временное окружение. Это удобно для парсеров, миграций и скриптов дежурного инженера.
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx"]
# ///
import httpx
print(httpx.get("https://example.com").status_code)
Команда uvx ruff check . запускает линтер без установки в проект. Аналог — uv tool install ruff, если инструмент нужен постоянно. Оба варианта держат утилиты в отдельных окружениях, поэтому конфликты версий между проектами исчезают.
CI и воспроизводимость
В конвейере достаточно двух шагов: установить uv и синхронизировать окружение по lock-файлу. Кэш uv между запусками заметно ускоряет сборку. Не используйте в CI команду uv add: она меняет lock-файл и маскирует забытое обновление зависимостей.
uv sync --frozen
uv run pytest -q
uv export --format requirements-txt > requirements.txt
Экспорт в requirements.txt нужен, если часть инфраструктуры пока работает со старым pip. Это совместимость, а не замена lock-файлу: uv.lock хранит больше информации о разрешении графа. Для приватного индекса добавьте [[tool.uv.index]] в pyproject.toml и укажите url; логин и пароль храните в переменных окружения, а не в файле.
Диагностика
Когда пакет не находится или версия не та, смотрите uv tree и uv pip list. Конфликт ограничений uv печатает с указанием, кто именно требует несовместимую версию. Если сборка идёт без сети, помогает —offline при заполненном кэше. Проблемы с жёсткими ссылками в контейнерах решает переменная UV_LINK_MODE=copy.
uv tree --depth 2
uv pip list
uv cache dir
uv cache prune
UV_LINK_MODE=copy uv sync
- uv —version показывает версию; после обновления проверьте её повторно.
- uv cache clean удаляет весь кэш, prune — только устаревшие записи.
- UV_NO_CACHE=1 отключает кэш для отладки, но замедляет установку.
- uv run -v печатает команды и пути, помогает понять, какое окружение выбрано.
Чек-лист внедрения
- Закоммитьте uv.lock и .python-version, добавьте .venv в .gitignore.
- Зафиксируйте requires-python и не позволяйте ему расходиться с CI.
- Разделите основные и dev-зависимости через dependency-groups.
- В CI используйте uv sync —frozen, а не установку по одному пакету.
- Обновляйте зависимости отдельным коммитом и прогоняйте тесты.
Итог
uv сокращает рутину вокруг Python-окружений: один бинарник заменяет venv, pip и pip-tools, а lock-файл делает сборки предсказуемыми. Начните с установки через официальный скрипт, создайте проект командой uv init и перенесите зависимости в pyproject.toml. Дальше достаточно uv sync и uv run — остальные команды нужны для обновлений и диагностики.