uv для Python: установка, зависимости и переход с pip

Python Автор: Среда и версия: Python 3 + uv; точные версии среды не зафиксированы

uv объединяет управление версиями Python, виртуальными окружениями и зависимостями. Но у него есть два разных интерфейса, которые легко перепутать:

  • uv add, uv remove, uv run и uv sync управляют проектом через pyproject.toml и uv.lock;
  • uv pip работает напрямую с виртуальным окружением и нужен прежде всего для совместимости с привычными командами pip.

Для нового проекта почти всегда выбирай первый вариант. Минимальный рабочий цикл выглядит так:

uv init --no-package weather-bot
cd weather-bot
uv add requests
uv run python -c "import requests; print(requests.__version__)"

Отдельно создавать и активировать окружение не пришлось: uv подготовил .venv, записал зависимость в проект и запустил нужный интерпретатор.

Что заменяет uv

uv не меняет сам язык Python. Он берёт на себя операции, для которых раньше требовались отдельные команды или инструменты.

Задачаpip и venvПроект uv
Создать проектсоздать каталог и файлы вручнуюuv init
Создать окружениеpython -m venv .venvсоздаётся при первой проектной команде
Добавить пакетpython -m pip install requestsuv add requests
Зафиксировать версииpip freeze > requirements.txtuv обновляет uv.lock
Запустить командуактивировать .venv, затем запуститьuv run ...
Восстановить окружениеpip install -r requirements.txtuv sync
Выбрать Pythonустановить отдельноuv python install и uv python pin

Это не означает, что pip и venv стали неправильными. Для небольшого учебного скрипта достаточно обычного виртуального окружения. uv полезнее, когда проект нужно одинаково запускать на нескольких компьютерах, обновлять без случайной смены всех версий и воспроизводить в CI.

Как установить uv на Windows, macOS и Linux

Актуальные способы установки перечислены в официальной документации uv.

На macOS и Linux:

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

На Windows в PowerShell:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Если правила компании запрещают выполнять загруженный скрипт, установи uv через уже настроенный менеджер пакетов. Например, официальный вариант для PyPI:

pipx install uv

Проверь установку:

uv --version

Если терминал отвечает command not found или «имя uv не распознано», закрой его и открой снова. Установщик мог добавить каталог uv в PATH, но уже запущенная оболочка ещё не прочитала обновлённые настройки.

Как создать новый проект

Для простого приложения без сборки пакета выполни:

uv init --no-package weather-bot
cd weather-bot
uv run main.py

Флаг --no-package создаёт понятную заготовку с main.py. Начиная с uv 0.12 команда без этого флага по умолчанию готовит устанавливаемое приложение со структурой src/ и точкой входа. Для библиотеки, которую планируется импортировать или публиковать, используй отдельный шаблон:

uv init --lib weather-client

После первой команды uv run, uv add, uv sync или uv lock в проекте появятся основные служебные файлы:

  • pyproject.toml — метаданные и допустимые диапазоны версий прямых зависимостей;
  • uv.lock — точные версии всех прямых и транзитивных зависимостей;
  • .python-version — версия Python, выбранная для проекта;
  • .venv — локальное виртуальное окружение с интерпретатором и пакетами.

В Git добавляют pyproject.toml и uv.lock. Файл .python-version тоже обычно добавляют, если команда договорилась об одной версии Python. Каталог .venv не добавляют: он зависит от операционной системы и восстанавливается командой uv sync.

uv.lock можно читать, но не нужно редактировать вручную. По документации uv это кроссплатформенный lock-файл, которым управляет сам uv.

Как добавлять, удалять и обновлять зависимости

Обычную зависимость добавляют так:

uv add requests

Команда выполняет сразу три связанных действия:

  1. добавляет requests в pyproject.toml;
  2. пересчитывает uv.lock;
  3. синхронизирует .venv.

Ограничение версии можно указать явно. Кавычки защищают символы > и < от обработки оболочкой:

uv add "requests>=2.32,<3"

Инструменты разработки лучше хранить отдельно от зависимостей приложения:

uv add --dev pytest
uv run pytest

Удаление пакета тоже должно менять описание проекта, поэтому используй:

uv remove requests

Если нужно обновить только один пакет до новейшей версии, которая подходит под ограничения проекта:

uv lock --upgrade-package requests
uv sync

Обычный uv sync не обновляет всё до последних доступных версий. При существующем uv.lock он сохраняет уже выбранные версии, пока они совместимы с pyproject.toml. Это защищает проект от случайного массового обновления.

Как запускать проект через uv run

uv run запускает команду внутри окружения проекта:

uv run python main.py
uv run pytest
uv run ruff check .

Перед запуском uv проверяет соответствие pyproject.toml, uv.lock и .venv. Поэтому активировать окружение через source .venv/bin/activate не обязательно.

Если редактору нужен готовый интерпретатор или окружение требуется восстановить заранее, запусти:

uv sync

У этой команды есть важное свойство: по умолчанию она выполняет точную синхронизацию и удаляет из .venv пакеты, которых нет в lock-файле. Поэтому пакет, установленный вручную через uv pip install, может исчезнуть после uv sync. Для постоянной зависимости проекта нужен uv add.

В CI полезно запрещать незаметное изменение lock-файла:

uv sync --locked
uv run --locked pytest

Если pyproject.toml и uv.lock расходятся, команда завершится ошибкой вместо автоматического обновления файла. Значит, разработчик забыл пересчитать и закоммитить uv.lock.

Чем uv add отличается от uv pip install

Разница не в скорости, а в том, чем управляет команда.

uv add requests

работает на уровне проекта: объявляет зависимость, обновляет lock-файл и окружение. А команда:

uv pip install requests

работает только с найденным виртуальным окружением. Она не превращает пакет в зависимость проекта и не обновляет uv.lock.

Официальная документация называет uv pip низкоуровневым интерфейсом совместимости. Он пригодится, если проект пока остаётся на requirements.txt:

uv venv
uv pip install -r requirements.txt

uv найдёт .venv в текущем или родительском каталоге даже без активации. Но внутри полноценного uv-проекта не смешивай два подхода без причины:

  • нужна постоянная зависимость — uv add;
  • нужно удалить её из проекта — uv remove;
  • нужно восстановить состояние из lock-файла — uv sync;
  • нужно временно проверить пакет или сохранить старый процесс на requirements — uv pip.

Несмотря на название, uv pip не запускает установленный pip. Он повторяет распространённые команды и поведение pip, но полная совместимость не гарантируется.

Как перенести существующий проект с requirements.txt

Сначала сохрани рабочее состояние проекта и не удаляй requirements.txt: он понадобится для сравнения и отката.

Если pyproject.toml ещё нет, создай только его, не добавляя в существующий репозиторий README, исходники и новый каталог Git:

uv init --bare

Если pyproject.toml уже существует, этот шаг пропусти.

Дальше выбор зависит от того, как устроены старые файлы.

В requirements.txt перечислены только прямые зависимости

Например, файл написан вручную и содержит django, psycopg и gunicorn, а не полный вывод pip freeze. Его можно импортировать напрямую:

uv add -r requirements.txt
uv run python main.py

После проверки тестов добавь в Git pyproject.toml и uv.lock.

Есть requirements.in и зафиксированный requirements.txt

Если прямые зависимости хранятся в requirements.in, а requirements.txt содержит их точные разрешённые версии, используй старый lock как ограничения:

uv add -r requirements.in -c requirements.txt

Такой способ рекомендует официальное руководство по переходу с pip: прямые зависимости попадут в pyproject.toml, а версии при первой сборке uv.lock останутся прежними, если набор ограничений совместим.

requirements.txt получен командой pip freeze

uv add -r requirements.txt технически сработает, но объявит прямыми все строки, включая транзитивные пакеты. Тогда позже будет непонятно, какие библиотеки нужны самому приложению, а какие пришли как зависимости других библиотек.

Лучше сначала восстановить короткий список прямых зависимостей по импортам, документации и истории проекта. Добавь его через uv add, затем сравни запуск и тесты со старым окружением. Это чуть дольше миграции одной командой, зато pyproject.toml останется понятным.

Если сервер развёртывания всё ещё принимает только requirements.txt, не нужно вести версии вручную в двух местах. Сначала экспортируй их из lock-файла в отдельный файл:

uv export --format requirements.txt > requirements-export.txt

Сравни результат со старым requirements.txt и только после проверки замени входной файл сборки. Сначала переведи локальную разработку и CI, затем меняй production-сборку отдельным шагом. Так проще понять, на каком этапе возникла несовместимость.

Как установить и закрепить версию Python

uv умеет находить системный Python и при необходимости загружать управляемую версию. Явная установка выглядит так:

uv python install 3.12

Чтобы выбрать эту версию для текущего проекта:

uv python pin 3.12
uv run python --version

uv python pin записывает запрос версии в .python-version. При этом ограничение requires-python в pyproject.toml тоже должно допускать Python 3.12. Если там указано >=3.13, uv справедливо откажется создать окружение на 3.12.

Обычно фиксируют минорную версию, например 3.12, а не патч 3.12.3: тогда uv может подобрать свежий совместимый патч. Точную патч-версию стоит закреплять только тогда, когда проект действительно от неё зависит.

Частые ошибки

Пакет импортируется через uv run, но не через python

Обычная команда python запустила системный интерпретатор или другое активное окружение. Проверь оба пути:

python -c "import sys; print(sys.executable)"
uv run python -c "import sys; print(sys.executable)"

Для проекта продолжай использовать uv run. Если программа запускается из редактора, выбери интерпретатор внутри .venv.

uv sync удалил установленный пакет

Пакет установили через uv pip install, но не объявили в проекте. uv sync выполняет точную синхронизацию с lock-файлом. Верни зависимость правильно:

uv add package-name

uv сообщает, что lock-файл устарел

Кто-то изменил зависимости в pyproject.toml, но не обновил uv.lock. Локально выполни uv lock или нужный uv add, проверь изменения и закоммить оба файла. В CI не заменяй --locked на автоматическое обновление: сборка не должна молча переписывать исходники.

После смены Python окружение ведёт себя странно

Каталог .venv расходный. После изменения основной версии Python синхронизируй проект заново; при необходимости удали только .venv и выполни:

uv sync

Не удаляй uv.lock: он описывает воспроизводимое состояние зависимостей, а не конкретный локальный каталог.

Стоит ли переходить на uv

Для нового приложения разумный базовый набор — uv init, uv add, uv run и закоммиченный uv.lock. Он заменяет ручную связку venv + pip freeze и снижает вероятность запустить проект не тем интерпретатором.

Стабильный старый проект не обязательно переносить только ради модного инструмента. Если текущие pip, requirements.txt и CI воспроизводимы, можно сначала заменить лишь команды установки на uv pip, не меняя формат зависимостей. Полный переход имеет смысл, когда команда готова считать pyproject.toml и uv.lock единственным источником состояния проекта.

Источники