Привет! Это Леша Жиряков, техлид backend-команды витрины онлайн-кинотеатра KION. В прошлый раз я писал про Msgspec vs DataClasses, а сегодня поговорим о пакетных менеджерах. 

В жизни каждого разработчика наступает момент, когда нужно воспользоваться сторонней библиотекой — для работы с данными или отправки запросов в БД. А после выбора библиотеки и версии — использовать менеджер пакетов. Вот какие у него функции:

  • установка и удаление пакетов;

  • обновление пакетов;

  • безопасность, или сравнение контрольной суммы пакета;

  • разрешение конфликтов версионирования в зависимостях пакетов.

В этом посте рассмотрим Poetry и UV, которые могут упростить и ускорить разработку на Python. Покажу, как устанавливать, создавать проекты, сравню производительность. Поехали!

В левом углу ринга — Poetry

Пакетный менеджер Poetry вышел в начале 2018 года благодаря разработчику Себастьяну Юстасу. Слоган проекта: «Легкое управление пакетами и зависимостями на Python». И да, главный плюс инструмента — простота.

  • Особенности: всестороннее определение зависимостей, изоляция от системы, интуитивные команды.

  • Количество звезд на GitHub: 32,4 тыс.

  • Открытых Issues: 472.

  • Версия: 2.0.1.

  • Год релиза: 2018.

  • Merge Requests (MRs): участвует главный разработчик и сообщество.

Установка

В документации нас встречает большое и красное предупреждение, что Poetry всегда нужно устанавливать в выделенной виртуальной среде. Цель — изолировать ее от остальной части системы.

Установить менеджер пакетов можно при помощи pip, pipx, curl и командой для Powershell.

Пример команды для установки:

$ pipx install poetry

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

Проект создается при помощи команды:

$ poetry init 

При выполнении команды в терминале получаем такой вывод (до двоеточия — описание, после двоеточия — значение вводит пользователь):

Package name [testpoetry]:  ProjectWithPoetry            
Version [0.1.0]:  0.1.1
Description []:  Test project for Habr 
Author [A <@gmail.com>, n to skip]:  n
License []:  No
Compatible Python versions [>=3.13]:  >=3.9           
Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your development dependencies interactively? (yes/no) [yes] no

Каждая строка выглядит довольно просто и понятно. Можно сразу указать название, версию, описание, автора, лицензию, поддерживаемые версии Python и определить зависимости. После этого будет сгенерирован файл pyproject.toml в директории проекта.

Добавляем модули в pyproject.toml и устанавливаем при помощи poetry add:

$ poetry add fastapi

Установка из requirements.txt:

$ poetry add $(cat requirements.txt)

Еще в Poetry можно указать группу зависимостей. Например, нам нужно добавить библиотеки для разработки (black и isort) из файла requirements.dev.txt. Тогда команда получится такой:

$ poetry add --group dev $(cat requirements.dev.txt)

Теперь откроем файл pyproject.toml и изучим его содержимое:

[project]
name = "projectwithpoetry"
version = "0.1.1"
description = "Test project for Habr"
authors = [
    {name = "Your Name",email = "you@example.com"}
]
license = {text = "No"}
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
    "fastapi (>=0.115.8,<0.116.0)"
]
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.group.dev.dependencies]
black = "^25.1.0"
isort = "^6.0.0"

Сразу видны имя проекта, версия, описания и авторы. Зависимости разделяются на основные (dependencies) и для разработки (tool.poetry.group.dev.dependencies).

В правом углу ринга — UV

Лучшее слово, которое характеризует UV, — скорость. Этот инструмент быстро устанавливает пакеты, быстро набирает звезды на GitHub, и даже его название читается быстро! Как комментирует создатель проекта Чарли Марш, причина в том, что он написан на Rust и в механизме кэширования, который оптимизирован для «теплых» операций.  

Пакетный менеджер впервые предстал перед публикой в 2024 году и уже успел набрать большую популярность в среде разработки.

  • Особенности: в 10 раз быстрее pip и в 30 быстрее Poetry, переход между версиями Python, заменяет собой pip/pip-tools/pipx/pyenv и другие инструменты.

  • Количество звезд на GitHub: 37,2 тыс.

  • Открытых Issues: 1,1 тыс.

  • Версия: 0.5.24.

  • Год релиза: 2024.

  • Merge Requests (MRs): участвует главный разработчик и сообщество.

Установка

Чтобы установить UV, нужно воспользоваться командами, которые я дал выше. Но к ним добавляется еще и brew.

Самый простой способ установить UV:

$ brew install uv

В документации мы замечаем приятную вишенку на торте — образ Docker:

$ docker pull ghcr.io/astral-sh/uv:0.5.25

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

Выполняется при помощи команды:

$ uv init

При вводе получаем:

Initialized project `testuv`

В директории проекта обнаруживаем автоматически сгенерированный файл с таким содержанием:

[project]
name = "testuv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = []

Добавляем модули в pyproject.toml и устанавливаем при помощи uv add:

$ uv add fastapi

Установка из requirements.txt:

$ uv add -r requirements.txt

Дополнительно установим зависимости для разработки в группу development из файла requirements.dev.txt. В нем указаны библиотеки black и isort.

$ uv add --dev -r requirements.dev.txt

Файл pyproject.toml:

[project]
name = "testuv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "fastapi>=0.115.8",
]
[dependency-groups]
dev = [
    "black>=25.1.0",
    "isort>=6.0.0",
]

Файл pyproject.toml чуть меньше, чем аналогичный при генерации с помощью Poetry, и не содержит полей «лицензия» и «авторы». Заметно разделение зависимостей — указаны «основные» (dependencies) и «для разработки» (dev).

Чем отличаются Poetry и UV

Poetry — простой, но медленный

Как подметил в своей статье Ларри Ду, опыт использования Poetry похож на проекты  Cargo и npm. Если сравнивать с pip, то Poetry предварительно пытается разрешить полный граф зависимостей DAG (англ. Directed Acyclic Graph, ориентированный ациклический граф) и устанавливает зависимости по топологической сортировке. Эта сортировка представляет собой линейное упорядочивание вершин, так что для каждого направленного ребра (u, v) вершина u предшествует вершине v.

Как conda и venv, Poetry может управлять виртуальными средами, которые находятся внутри или за пределами директории проекта. Он генерирует файлы блокировки poetry.lock, а это огромное преимущество для воспроизводимости. К тому же файлы многоплатформенные, а значит, могут быть довольно большими.

Poetry позволяет налегке разрабатывать и публиковать Python-пакеты. Это практически идеальный инструмент, но у него все-таки есть недостатки, которые могут затруднить разработку. Основное — разрешение зависимостей может быть невероятно медленным. Причина — то, как в Python-пакетах указаны зависимости. Изучение зависимостей для каждого возможного пакета в DAG может потребовать большого количества операций через загрузку и парсинг Python wheels.

Разрешаются зависимости в Poetry при помощи алгоритма поиска в глубину, написанном на Python. Для сравнения mamba использует написанные на C++ логические SAT-решатели, которые на порядок быстрее.

Устранение зависимостей для крупных проектов в Poetry в сочетании с созданием многоплатформенных файлов блокировки может занять довольно много времени, особенно при наличии реального конфликта в DAG.

UV — быстрый, но только набирающий обороты

Это многообещающий инструмент управления пакетами в экосистеме Python. Проект призван стать заменой pip и дополнением к Python. Сейчас API нестабильно — на это указывает мажорная версия проекта, которая начинается с 0. Примечательно, что разработка ведется при поддержке компании Astral.sh, основанной Чарли Маршем и создателями линтера ruff — инструмента, который практически в одночасье вытеснил всех конкурентов, когда был выпущен в 2022 году.

UV, как и Poetry, поддерживает pyproject.toml и, как и pip, использует алгоритм обратного отслеживания для разрешения зависимостей. Но есть одно отличие — в UV алгоритм написан на Rust, чем и обосновывается его быстрая скорость работы. Когда дело доходит до разрешения зависимостей, то UV работает быстрее, чем Poetry.

Сравнение производительности

Немного о бенчмарках

Из документации UV — все тесты были рассчитаны на macOS с использованием Python 3.12.4 (для инструментов, отличных от UV) и содержат несколько важных предостережений:

  • Производительность тестов может сильно различаться в зависимости от различных операционных и файловых систем. Дело в том, что UV использует разные стратегии установки, основываясь на возможностях файловой системы.
    Так, в macOS используется рефлинкинг, а в Linux — хардлинкинг.

  • Производительность тестов может сильно различаться в зависимости от устанавливаемых пакетов. 

Дальше рассмотрим тесты на примере пакета Trio и его зависимостей, которые указаны в docs-requirements.in.

«Горячая» установка

Сравнительный анализ установки пакета (команда uv sync) с использованием «теплого» кэша. Эквивалентно удалению и повторному созданию виртуальной среды, а затем заполнению ее зависимостями, которые были раньше установлены на том же компьютере.

На графике видно, что UV в разы обгоняет своих конкурентов — PDM, Poetry и pip-sync. Poetry занимает второе место.

«Холодная» установка

Анализ установки пакетов с использованием «холодного» кэша. Равно выполнению команды uv sync на новом компьютере или в CI (предполагается, что кэш менеджера пакетов — не общий для всех запусков).

UV занимает первое место по скорости выполнения, но отставание других пакетных менеджеров намного меньше, чем в тесте выше.

«Теплое» разрешение зависимостей

Тест на разрешение зависимостей (uv lock) с помощью «теплого» кэша, но без существующего файла блокировки (uv.lock). Равнозначно удалению requirements.txt для его генерации из файла requirements.in.

Тут и нечего говорить: UV лидирует.

«Холодное» разрешение зависимостей

Сравнение разрешения зависимостей с помощью холодного кэша. Соответствует запуску uv lock на новом компьютере или в CI — при условии, что кэш менеджера пакетов не используется совместно для всех запусков.

UV справился менее чем за 0,5 секунды, когда его коллеги по цеху — за 3 и более секунд.

Что в итоге

Подытожим сравнительной таблицей:

Параметр

Poetry

Uv

Год появления

2018

2024

Версия Python

3.9-3.13

3.8-3.13

Текущий релиз

2.0.1

0.5.25

Лицензия

MIT

Apache-2.0 или MIT

ЯП проекта

Python

Rust

Кол-во контрибьюторов

581

304

Кол-во звезд

32,5 тыс.

37,6 тыс.

Первое, что бросается в глаза, — это скорость работы UV. Кто бы что ни говорил, он все равно очень быстрый. Благодарить можно как разработчиков, так и то, что проект написан на Rust. Только в одном тест-кейсе, когда проводилась «холодная» установка, Poetry приближался к UV. В остальных случаях UV — безусловный лидер.

Как и в прошлом моем посте про сравнение FastAPI и Litestar, важно подчеркнуть различие версий у Poetry и UV. Первый проект начал разрабатываться в далеком 2018 году, и текущий релиз начинается с 2.0 — это говорит о стабильности продукта. UV появился в 2024 и до сих пор движется к первому крупному релизу. Пока же его версия 0.5 — а это не гарантирует бесперебойной работы в продакшне.

UV дополнительно поддерживает версию Python 3.8. Пункт может быть важен для команд, которые сейчас разрабатывают решения на этой версии языка программирования.

Лицензия проекта Poetry — MIT. У UV ее можно выбрать — MIT или Apache-2.0.

Инициализация проекта при помощи Poetry более user-friendly и позволяет сразу указать описание проекта, его авторов, поддерживаемые версии Python и лицензию. В этом плане UV более минималистичен, но приходится вручную открывать и редактировать pyproject.toml.

Кто уже использует UV в проде, поделитесь своим полетом в комментариях. Пишите, какой менеджер пакетов используете вы — посмотрим, что на Хабре популярнее.

Что еще почитать:

Комментарии (13)


  1. CrazyOpossum
    18.02.2025 13:12

    Всегда против тулз на языках, не совпадающих с целевым. Цикл отладки размыкается и разработчик лишается мгновенной обратной связи. Скорость для пакетного менеджера имеет значение только в CI/CD, это как раз горячая установка в которой отставание незначительно, и вряд ли является решающим тормозом в пайплайне. С другой стороны, разработчики на Rust не заинтересованы кровно в надёжности тулзы для разработчиков на Python, в отличие от poetry.


    1. RH215
      18.02.2025 13:12

      Никакого разделения на "разработчиков на Rust" и "разработчиков на Python" тут нет. Есть разработчики на Python и Rust. Python вообще никогда не был замкнутой на себе экосистемой.


    1. kompilainenn2
      18.02.2025 13:12

      а что там насчет NumPy и еще кучи питоновых либ, написанных на С?


      1. CrazyOpossum
        18.02.2025 13:12

        Это не тулзы. Я говорю про проекты, которые применимы сами к себе - тестовые фреймворки, линтеры, стайлеры и, да, пакетные менеджеры.


    1. Roman_Cherkasov
      18.02.2025 13:12

      У нас довольно большой проект десктопного приложения, который разбит на микросервисы (это позволяет нам разрабатывать модули и обновлять их независимо друг от друга). Изначально это был монолит, который мы успешно попилили. В процессе перехали с `pip install -r ...` на poetry. Пока модулей было 3-4 - все было нормально. Когда модулей стало 20+ резолв зависимостей время от времени начал занимать какое-то не адекватное количество времени. У нас в чате скидывали скрины с 3000+ секунд, на выполнение poetry update.
      Мы некоторое время искали проблемы внутри (и они определенно были. Например бинарные файлы в репах). Исправили это. Но время на poetry update для проекта в который подключены все модули - 500-600 секунд запросто.
      В тестовом формате добавили uv. Первый резолв долгий, около 120-150 секунд. Но дальше все стало сильно лучше 20-30 секунд и обновления уже загружены. И о чудо. Добавление конкретной ревизии модуля (по имени ветки или хэшу коммита) не растягивает общий резолв. Короче команда радуется, а я все ещё настороженно отношусь к продуктам с нулевой мажорной версией.

      С CI\CD кстати в poetry не так больно, и разницы с uv - нет. Так как уже сформирован lock файл. Нет необходимости решать зависимости, просто берешь пакеты и устанавливаешь.


      1. CrazyOpossum
        18.02.2025 13:12

        У вас poetry update частая операция? Я тоже над немаленьким проектом работаю, но мы обновляем зависимости только по веским причинам и редко сразу несколько: poetry lock --no-update реагирует только на изменённые в pyproject.toml версии.


        1. Roman_Cherkasov
          18.02.2025 13:12

          У разработчиков не прям чтобы частая, но вот тестеровщики - очень даже, потому что им надо тестировать модули в составе продуктов.


        1. Roman_Cherkasov
          18.02.2025 13:12

          Ещё раз обращаю внимание, что это не резолв внешних зависимостей, это модули нашего приложения. Внешние зависимости у нас тоже с фиксированными версиями и обновляются только при CVE или других критичных багфиксах


    1. kalombo
      18.02.2025 13:12

      Любой инструмент либо вызывает боль на данный момент, либо нет. Если вам норм с poetry/pip, то переходить на uv нет смысла. Если у вас есть проблемы с uv, а pip/poetry их решает, то есть смысл перейти на pip/poetry. А все эти домыслы про то, что uv испортится в будущем(потому что на расте, потому делается сторонней фирмой и т.п.) точно также применимы и к poetry и к pip, pip по сути уже "испортился". Мы не знаем, что будет завтра, возможно pip переделают и он станет самым лучшим менджером в python. Свитчится придётся всё равно рано или поздно, т.к. мир меняется и появляются новые инструменты, которые вытесняют старые.


  1. r2d
    18.02.2025 13:12

    Автор, а вы можете сказать почему в кинотеатре где вы занимаетесь бэкендом нет обычных фильтров что бы можно было отфильтровать фильмы по жанру\году\стране?


  1. f1ex0
    18.02.2025 13:12

    poetry, uv всё это надстройки без которых можно обходиться. ориентироваться лучше на PEP 518 и PEP 621. у poetry есть существенный недостаток, он еще далек о стабильной версии и не стоит удивляться если после обновления у вас станут возникать ошибки.

    По UV из статьи не понять как собирается пакет.

    В целом статья с пробелами, да тема выбрана из разряда, есть плохое решение и еще одно, попробуем их сравнить по непонятным метрикам. Автору стоила заглянуть в исходники какой-либо библиотеки более или менее популярной (например fastapi, flask, numpy и т.д.), удивиться что там нет ни poetry, ни uv, изучить используемые технологии и написать хорошую статью.


    1. kivsiak
      18.02.2025 13:12

      https://github.com/fastapi/fastapi/blob/master/.github/workflows/test.yml
      И uv и ruff в наличии, uv - это не сборщик. по крайней мере пока.

      Flask уже давно не передовой с точки зрения прогресса продукт.
      Numpy слишком тяжелый и специфичный проект и uv им последнюю очередь нужен.

      И нет, без uv я уже жить не хочу. Это наверно лучше что было сделано для тулинга питона за последние несколько лет

      Сделают еще тайпчекер внутри ruff я еще и pyright выкину.