Slide 1

Slide 1 text

Денис Аникин, https://xfenix.ru Техлид/Комьюнити лид в Райфе Идеальный тулинг для управления зависимостями в python проектах Development {

Slide 2

Slide 2 text

Представлюсь — Меня зовут Денис Аникин — Я тех- и комьюнити- лид в Райфе — У меня 3 команды в scrum, 1 в less — Я fullstack (async python + микросервисы и typescript + react) — Я иногда выступаю на конференциях и вхожу в ПК http://xfenix.ru

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

О чём доклад — Я (вы) пишу микросервисы — Мне надо в них отслеживать все зависимости — Для этого нужны инструменты. Мы их рассмотрим, сравним и выберем лучшие

Slide 5

Slide 5 text

История

Slide 6

Slide 6 text

Это очень вольный пересказ истории, я всё таки техлид…

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

История тулинга (1) божественное ничего 1989 — 2004 easy_install + egg virtualenv (где-то) 2004 — pip 2008 — pypa & virtualenv 2011 — wheel 2013 —

Slide 10

Slide 10 text

История тулинга (2) pipenv 2017 — poetry 2018 — hatch 2019 — pdm 2020 —

Slide 11

Slide 11 text

История тулинга (3) rye 2020 — uv 2023 —

Slide 12

Slide 12 text

События явно ускоряются

Slide 13

Slide 13 text

Проблемы

Slide 14

Slide 14 text

А что не устраивает в pip + virtualenv? — Изоляция есть — Средство доставки тоже — Переносимость обеспечивается requirements.txt

Slide 15

Slide 15 text

Проблема транзитивных зависимостей

Slide 16

Slide 16 text

Или по-другому: — «Да ладно, у нас такого не было, лол :)» — «А у меня никогда не случалось!» — «Ни разу не видел» — «Какая-то надуманная проблема» — Когда столкнулись: «ой, я хотел месяц иначе потратить :(»

Slide 17

Slide 17 text

Что за проблема?

Slide 18

Slide 18 text

Представим себе гипотетический недо-проект

Slide 19

Slide 19 text

Мы сделали что-то такое (kek) ➜ pip install fastapi httpx

Slide 20

Slide 20 text

Заглянем в его requirements.txt Вроде все супер: httpx==0.27.0 fastapi==0.111.0

Slide 21

Slide 21 text

Сгоняем-ка в зависимости fastapi…

Slide 22

Slide 22 text

Но для начала маленькая справка — PEP 508 (формат зависимостей) — PEP 517 (формат для source trees) — PEP 518 (минимальные требования к системе сборки) — PEP 621 («содержимое pyproject») — https://packaging.python.org/en/latest/specifications/pyproject-toml/#pyproject-toml-spec — https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata-requires-dist — И еще немного: 725, 735, 660, 631, 633

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Открываем pyproject.toml

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Another smart move

Slide 28

Slide 28 text

Окей, мы откроем METADATA в wheel Requires-Dist: starlette<0.38.0,>=0.37.2 Requires-Dist: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 Requires-Dist: typing-extensions>=4.8.0 Requires-Dist: fastapi-cli>=0.0.2 Requires-Dist: httpx>=0.23.0 Requires-Dist: jinja2>=2.11.2 Requires-Dist: python-multipart>=0.0.7 Requires-Dist: ujson!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,>=4.0.1 Requires-Dist: orjson>=3.2.1 Requires-Dist: email_validator>=2.0.0 Requires-Dist: uvicorn[standard]>=0.12.0 Requires-Dist: httpx>=0.23.0; extra == "all" Requires-Dist: jinja2>=2.11.2; extra == "all" Requires-Dist: python-multipart>=0.0.7; extra == "all" …

Slide 29

Slide 29 text

Окей, мы откроем METADATA в wheel Requires-Dist: starlette<0.38.0,>=0.37.2 Requires-Dist: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 Requires-Dist: typing-extensions>=4.8.0 Requires-Dist: fastapi-cli>=0.0.2 Requires-Dist: httpx>=0.23.0 Requires-Dist: jinja2>=2.11.2 Requires-Dist: python-multipart>=0.0.7 Requires-Dist: ujson!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,>=4.0.1 Requires-Dist: orjson>=3.2.1 Requires-Dist: email_validator>=2.0.0 Requires-Dist: uvicorn[standard]>=0.12.0 Requires-Dist: httpx>=0.23.0; extra == "all" Requires-Dist: jinja2>=2.11.2; extra == "all" Requires-Dist: python-multipart>=0.0.7; extra == "all" …

Slide 30

Slide 30 text

Например: завтра выйдет jinja 3 (несовместимая)

Slide 31

Slide 31 text

От создателей «у нас такого не было, лол :)» «Так тесты же упадут!»

Slide 32

Slide 32 text

Завтра выйдет jinja 2.12.0, где будет небольшая несовместимость

Slide 33

Slide 33 text

От создателей «так тесты же упадут!» «Ну мы заметим, это мелочь!»

Slide 34

Slide 34 text

Не заметите — «Минорное» изменение может приводить к серьезным проблемам. История из жизни: изменился lxml совсем чуть-чуть, а это «положило» селекторы в scrapy. Дебаг съел много нервных сил и времени — Тесты могут не показать (не все тесты идеальны) — Проблема «протяжена» во времени — Сложно дебажить (и неприятно) — Вы давите на классическую проблему «у нас не воспроизводится»

Slide 35

Slide 35 text

Сборка раз Линтинг (сборка?) Тесты (сборка?) Сборка финального образа

Slide 36

Slide 36 text

Собираем вместе — Зависимость зависимости может измениться незаметно — Вам ОЧЕНЬ надо постараться, чтобы понять от чего зависит ваша зависимость — Против вас pypi.org, pyproject.toml и PEPы (вы не изучите и не запомните) — У зависимости зависимости тоже есть зависимость…

Slide 37

Slide 37 text

Прочие проблемы

Slide 38

Slide 38 text

Всё вместе — Человеческие ошибки (тулинг pip + requirements.txt предполагает ручную работу) — Нет уверенности, что пакет не подменят в одном из репозиториев (после того как вы его установили). Некоторые гарантии даёт pypi, но не все другие репозитории… — Разрешение конфликтов — Фиксирование зависимостей несет в себе ещё один букет проблем

Slide 39

Slide 39 text

Пару слов о зависимостях в reqs.txt формате

Slide 40

Slide 40 text

Фиксирование зависимостей — Вариант 1: пишем зависимости проекта в reqs.txt + фиксируем версии — Вариант 2: pip freeze > reqs.txt — Вариант 3: вариант 1 + задаём версии гибко — Вариант 4: вариант 1 + не указываем версии вообще

Slide 41

Slide 41 text

Современный тулинг

Slide 42

Slide 42 text

Для начала важное — Я очень давно не использую venv + reqs.txt + pip — И вам не советую — Почему мы уже определились, а теперь поговорим про тулинг зависимостей

Slide 43

Slide 43 text

Как подобные проблемы лечили в других экосистемах?

Slide 44

Slide 44 text

Ответ простой (относительно) — Надо использовать так называемые «lock» файлы — Кто изобрел их первым не ясно (apt, rpm? ранее?) — Популярность они получили благодаря npm

Slide 45

Slide 45 text

Что в lock файле?

Slide 46

Slide 46 text

Что-то такое { "name": "my-project", "lockfileVersion": 1, "requires": { "dependency1": "^2.3.1", }, "dependencies": { "dependency1": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/dependency1/-/dependency1-2.3.4.tgz", "integrity": "sha512-abc123def...", "requires": { "subdependency1": "^1.2.0" } } } }

Slide 47

Slide 47 text

Что-то такое { "name": "my-project", "lockfileVersion": 1, "requires": { "dependency1": "^2.3.1", }, "dependencies": { "dependency1": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/dependency1/-/dependency1-2.3.4.tgz", "integrity": "sha512-abc123def...", "requires": { "subdependency1": "^1.2.0" } } } }

Slide 48

Slide 48 text

Итак, тулинг для python

Slide 49

Slide 49 text

Где есть lock файлы? — Pipenv — Poetry — PDM — Hatch — PIP tools — Rye

Slide 50

Slide 50 text

И конечно python версия (toml) лок файла [[package]] name = "babel" version = "2.14.0" requires_python = ">=3.7" summary = "Internationalization utilities" groups = ["doc"] dependencies = [ "pytz>=2015.7; python_version < \"3.9\"", ] files = [ {file = "Babel-2.14.0-py3-none-any.whl" , hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" }, {file = "Babel-2.14.0.tar.gz" , hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363" }, ]

Slide 51

Slide 51 text

Pipenv

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

Pipenv — Первый тул, который давал комплексное управление всем процессом — Убирает фактор человека, давая 2 файла: Pipfile, Pipfile.lock — Мы получаем: создание виртуальных окружений автоматом, установку и контроль зависимостей, повторимость сборок, исключение человеческого фактора

Slide 54

Slide 54 text

Буквально в пару команд pipenv install pipenv shell

Slide 55

Slide 55 text

Но…

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Сегодня я использовать pipenv не стану — Pipfile это какая-то полу-функциональная редакция pyproject, она не входит в стандарт — У pipenv были больше пробелы в истории развития — Следующие утилиты делают pipenv не очень-то нужным (на мой взгляд)

Slide 58

Slide 58 text

Poetry

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

Poetry — Использует pyproject.toml (почти* в согласии со стандартом) — Как и pipenv он использует pip под капотом, но у него более комплексный и умный резолвер зависимостей — В добавок ко всем бонусам pipenv мы получаем ещё и возможность с помощью наличия всего-лишь одного pyproject.toml собирать и даже паблишить собственные пакеты! — Приятный CLI с подсветкой

Slide 61

Slide 61 text

Проблемы с poetry

Slide 62

Slide 62 text

Бывало такое (на практике) — С 1.1 на 1.4 было много проблем — https://github.com/python-poetry/poetry/issues/6300 — https://github.com/python-poetry/poetry/issues/7170 — https://github.com/python-poetry/poetry/issues/4242

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

Претензии к poetry — Не всегда понятный фидбек по ошибкам — Немного замученный poetry config (однажды я 4 часа ковырялся в keyring потому, что poetry никак не показывает, что доступ к закрытому репозиторию сейчас доступен через keychain) — Не полное следование pyproject: в PEP 621 определена секция [project] и dependencies ключ, poetry использует [tool.poetry] вместо них

Slide 65

Slide 65 text

PDM

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

Самый противоречивый вариант!

Slide 68

Slide 68 text

Большие плюсы PDM ✅ — в отличие от poetry следует PEP 621 (те самые секции [project] & dependencies) ✅ — имеет централизованый кеш похожий на pnpm (причем, с хард и софт линкингом!) ✅ — имеет свой resolver & downloader, не полагаясь на pip (вроде это даже быстрее работает, чем у конкурентов) ✅❌ — поддерживает __pypackages__, он же PEP 582

Slide 69

Slide 69 text

PEP 582 в двух словах

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

Если честно, мне очень нравится __pypackages__

Slide 72

Slide 72 text

Недостатки ❌ — не умеет собирать и паблишить пакеты ❌ — PEP 582 отклонили :(

Slide 73

Slide 73 text

И эта вещь — это управление версиями самого python Есть ещё кое-что, чего нам не хватало

Slide 74

Slide 74 text

На самом деле…

Slide 75

Slide 75 text

Неожиданный поворот — PEP 582 опционален. По-умолчанию PDM использует virtualenv — PDM теперь позволяет использовать сборку и паблишинг пакетов! — Вы можете управлять версиями python через него…

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

Создатели недавно приняли много правильных решений

Slide 80

Slide 80 text

Огрмный респект авторам — Вся причина существования PDM — это __pypackages__ — Они не стали цепляться за прошлое и убрали эту функциональность под опцию — Они поняли, что нужна сборка пакетов — Они поняли, что нужен контроль питон версий — Они сделали совместимость с rye

Slide 81

Slide 81 text

Slide 82

Slide 82 text

Pip tools

Slide 83

Slide 83 text

Зачем?

Slide 84

Slide 84 text

Зачем?

Slide 85

Slide 85 text

С какой целью???

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

Как я объясняю себе — Для тех, кто ненавидит всё остальное — Для тех, кто по какой-то причине влюблен в pip

Slide 88

Slide 88 text

Других объяснений я не нашел

Slide 89

Slide 89 text

А почему я упоминаю pip sync станет понятнее в конце

Slide 90

Slide 90 text

Next-gen тулинг

Slide 91

Slide 91 text

Next gen значит?

Slide 92

Slide 92 text

UV

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

No content

Slide 95

Slide 95 text

Погнали препарировать!

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

UV — Разработка создателей ruff — Быстрее pip, poetry, pdm, pip sync в 10-100х раз (а вы сомневались?) — Имеет свой глобальный кеш — Умеет переопределять стратегии определения зависимостей — Можно переопределить зависимости пакета (<< вот это крутая фишка!)

Slide 98

Slide 98 text

Скорость — по их заявлениям

Slide 99

Slide 99 text

Я бы не сравнивал uv и poetry & pdm

Slide 100

Slide 100 text

uv — конкурент pip (для меня)

Slide 101

Slide 101 text

Точно плюсы uv ✅✅✅ — глобальный кеш ✅✅✅ — переопределение зависимостей (это может быть очень полезным) ✅✅✅ — скорость (https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md вот тут бенчмарки не особо врут; личный опыт использования — крайне позитивен)

Slide 102

Slide 102 text

Но вот функциональность pip compile и pip sync?

Slide 103

Slide 103 text

Шутки в сторону! UV — «наш слон»

Slide 104

Slide 104 text

Hatch?

Slide 105

Slide 105 text

No content

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

Вроде бы — Амбиции как у pdm & rye — Умеет похожее (версии питона, сборка пакетов, зависимости) — Есть интересные особенности: fmt, генерация шаблонов — Но, например, нет нормального CLI управления зависимостями (они ставятся on-demand)

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

На мой взгляд, hatch больше про сборку пакетов, чем про управление зависимостями в сервисах

Slide 110

Slide 110 text

А, и сущая мелочь

Slide 111

Slide 111 text

С сожалением констатируем — lock файлов ✨✨НЕТ✨✨

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

Авторы отвечают — hatch pip compile

Slide 114

Slide 114 text

Rye

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

Отправил свой проект в астрал…

Slide 117

Slide 117 text

Прошу прощения, я не мог обойтись без каламбура

Slide 118

Slide 118 text

Так что же в rye такого, что я припас его для конца доклада?

Slide 119

Slide 119 text

Плюсы rye — Под капотом у него uv (и pip sync) — Он умеет паблишить и билдить пакеты (через build & twine) — Он умеет отслеживать зависимости и делать лок файлы — Следует PEP 621 — Он управляет версиями python и умеет их ставить — Можно ставить глобально утилиты и управлять ими (например, ruff) — У него есть fmt (!!!)

Slide 120

Slide 120 text

Armin Ronacher «a one-stop-shop for all Python users, Rye»

Slide 121

Slide 121 text

Так почему мы не используем rye? — Сы-ро-ва-то — Документация не слишком дружелюбна. Чтобы понять как управлять версиями python вам понадобится отправиться в toolchain и на ютуб

Slide 122

Slide 122 text

На что я полагался в выборе утилит

Slide 123

Slide 123 text

Это просто важно проговорить 1) Опыт эксплуатации 2) Прямое сравнение 3) Рекомендации PYPA (они немного не поспевают за трендами, но всё таки)

Slide 124

Slide 124 text

No content

Slide 125

Slide 125 text

Ура, всего три слайда

Slide 126

Slide 126 text

Я не фанат итогов, но — Текущий вариант всё-в-одном: pdm — Базовый pip можно заменять на uv — А ещё стоит следить за «приемником» pdm & poetry: rye

Slide 127

Slide 127 text

Экосистема python в 2024 году… Pypy, mypy, mypyc, gopy, pypa, pypi, pip, pip-tools, pip-compile, pip-sync, micropipenv, pep, pipx, pipenv, pipfile, pyproject, numpy, scipy, cpython, lpython, cython, brython, cythonize, pyston, peachpy, safepy, pytype, pyodide

Slide 128

Slide 128 text

Стоп, мы забыли!

Slide 129

Slide 129 text

No content

Slide 130

Slide 130 text

Я не буду это произносить

Slide 131

Slide 131 text

Нет, ну сложности в названиях меня не пугают…

Slide 132

Slide 132 text

No content

Slide 133

Slide 133 text

No content

Slide 134

Slide 134 text

Прошу прощения… (да и слайдов не 3)

Slide 135

Slide 135 text

Спасибо за внимание! Денис Аникин, https://xfenix.ru Техлид/Комьюнити лид в Райфе