Poetry - это инструмент для управления зависимостями в Python проектах (аналог встроенного pip). Идея реализации данного инструмента пришла его создателю в связи с тем, что различные способы менеджмента пакетов (requirements.txt, setup.cfg, MANIFEST.ini и другие) показались создателю Poetry не очень-то удобными.
Предлагаю тем, кто пишет на Python, познакомиться с данным инструментом, так как это очень простой и удобный в использовании инструмент, применение которого может упростить ведение и разработку проекта.
Установка
Установить poetry на windows можно либо при помощи pip:
pip install poetry
Либо более гибким вариантом через powershell:
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -
Отличие от pip
Pip хранит данные о зависимостях в файле requirements.txt (название на самом-то деле может быть любое), poetry хранит информацию в файле pyproject.toml, однако, в случае с pip, в его файле хранится только список зависимостей с описанием версий, а в .toml хранится вся основная информация о проекте, что очень удобно, так как все данные собраны в одном месте (далее последует более подробное описание).
Чтобы установить зависимости в pip необходимо выполнить:
pip install -r requirements.txt
Что для poetry займет всего 2 слова:
# для первичной установки
poetry install
# для обновления
poetry update
Просмотр зависимостей в pip можно сделать только командой:
pip freeze
Однако будут показаны только актуальные версии библиотек, не будет возможности увидеть структуру всех пакетов с их зависимостями. В poetry в файле poetry.lock можно увидеть сведения обо всех установленных пакетах, команда:
poetry show --tree
Покажет древовидную структуру пакетов с их личными зависимостями.
Так же запуск проекта в pip (в случае с виртуальным окружением) создает неудобства, так как первым делом необходимо зайти в это самое окружение при помощи команды:
./venv/Scripts/activate.bat
И только затем можно выполнять какие-либо изменения с проектом. В poetry нет необходимости активировать виртуальное окружение, достаточно лишь зайти в папку с проектом и начинать пользоваться командами. Poetry сам найдет нужное окружение. Также в poetry можно менять версию python без необходимости менять старое виртуальное окружение.
Это лишь малая часть преимуществ. Далее рассмотрим примеры команд и структуру poetry файлов.
pyproject.toml
Главный файл для poetry - это pyproject.toml. Все данные о проекты должны быть записаны в нём. При установке пакетов poetry берёт данные из этого файла и формирует файл с зависимостями poetry.lock (если уже есть готовый файл poetry.lock, то данные будут браться из него). Toml файл состоит из нескольких блоков, каждый из которых имеет свои особенности, рассмотрим данные блоки:
[tool.poetry] - содержит основную информацию о проекте, такую как:
name - имя проекта
version - версия проекта
description - описание проекта
license - лицензия проекта
authors - список авторов проекта в формате name <email>
maintainers - список менторов проекта формате name <email>
readme - readme файл проекта в формате README.rst или README.md
homepage - URL сайта проекта
repository - URL репозитория проекта
documentation- URL документации проекта
keywords - список ключевых слов проекта (макс: 5)
classifier - список PyPI классификаторов
[tool.poetry.dependencies] - содержит описание всех зависимостей проекта. Каждая зависимость должна иметь название с указанием версии, также присутствует возможность скачать проекта с github с указанием ветки/версии/тэга, например:
requests = "^2.26.0"
requests = { git = "https://github.com/requests/requests.git" }
requests = { git = "https://github.com/kennethreitz/requests.git", branch = "next" }
numpy = { git = "https://github.com/numpy/numpy.git", tag = "v0.13.2" }
[tool.poetry.scripts] - в данном разделе можно описать различные сценарии или скрипты, которые будут выполняться при установке пакетов или при запуске приложения. Например:
poetry = 'poetry.console:run'
main-run = 'new_proj.main:run' (после чего достаточно запустить
poetry main-run
и будет выполнен запуск функции run в файле new_prof/main.py)
[tool.poetry.extras] - в данном блоке описываются группы зависимостей, которые можно устанавливать отдельно:
[tool.poetry.dependencies]
psycopg2 = { version = "^2.7", optional = true }
pymysql = { version = "1.0.2", optional = true }
[tool.poetry.extras]
mysql = ["pymysql"]
pgsql = ["psycopg2"]
Далее зависимости можно установить двумя способами:
poetry install --extras "mysql pgsql"
poetry install -E mysql -E pgsql
[tool.poetry.urls] - помимо основных URL, указанных в [tool.poetry], можно указывать свои URL:
"Bug Tracker" = "https://github.com/python-poetry/poetry/issues"
Пример данных в pyproject.toml
[tool.poetry]
name = "new_proj"
version = "0.1.0"
description = "My description"
authors = ["Daniil Gorbenko <dani.gorbenko@gmail.com>"]
[tool.poetry.dependencies]
python = "^3.10"
pygame = "^2.1.0"
icecream = "^2.1.1"
requests = "^2.26.0"
psycopg2 = { version = "^2.7", optional = true }
pymysql = { version = "1.0.2", optional = true }
[tool.poetry.dev-dependencies]
Pympler = "^0.9"
[tool.poetry.urls]
"Bug Tracker" = "https://github.com/python-poetry/poetry/issues"
[tool.poetry.scripts]
run-main = "new_proj.main:main_def"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Основные методы
new
Чтобы создать новый проект с помощью Poetry, достаточно выполнить poetry new <название папки с проектом>. После чего создастся папка с названием вашего проекта, в этой папке будет лежать файл pyproject.toml.
poetry new new_project
init
Чтобы сделать пакетным менеджером poetry в уже имеющемся проекте, достаточно выполнить:
poetry init
Далее будет предложено заполнить немного основной информации о проекте
Метод может принимать некоторые необязательные параметры:
--name: имя проекта
--description: описание проекта
--author: имя автора
--python: совместимые версии Python
--dependency: требуемый пакет с версией пакета
--dev-dependency: требования к разработке
После чего в проекте появится файл pyproject.toml, в котором вручную можно изменить любые данные.
install
Чтобы установить зависимости проекта достаточно выполнить команду:
poetry install
Poetry считывает данные из pyproject.toml, строит дерево зависимостей проекта, разрешая проблемы с версиями зависимостей, и устанавливает все пакеты. Однако, если в проекте уже есть файл poetry.lock, то будут использоваться точные версии из этого файла.
Метод может принимать параметры:
--remove-untracked: удалит старые пакеты, которые больше не используются в проекте
--no-dev: dev пакеты не будут устанавливаться
update
Чтобы обновить версии зависимостей (тем самым обновив файл poetry.lock) достаточно выполнить:
poetry update
Также есть возможность обновить лишь определенные пакеты:
poetry update icecream pygame
Метод может принимать дополнительные параметры:
--no-dev : игнорирует обновление dev пакетов
--lock : не устанавливает и не обновляет пакеты, а только обновляет файл poetry.lock
add
Чтобы добавить новую библиотеку достаточно выполнить:
poetry add pygame
Можно указывать версию пакета:
poetry add "pygame>=2"
poetry add pygame@^2
Можно передать параметры:
--dev (-D): установит пакет в качестве dev зависимости
--path: путь к пакету (если пакет лежит локально)
--lock : не устанавливает зависимости, а только обновляет файл poetry.lock
remove
Чтобы удалить зависимость достаточно выполнить:
poetry remove pygame
Дополнительно можно передать параметры:
--dev : удалит пакет из dev зависимостей
show
Чтобы посмотреть зависимости проекта достаточно выполнить:
poetry show
результат poetry show
Если необходимо посмотреть информацию о конкретном пакете:
poetry show pygame
результат poetry show pygame
Посмотреть дерево зависимостей проекта можно при помощи:
poetry show --tree
результат poetry show --tree
Также можно передать параметры:
--tree: список зависимостей в виде дерева
--latest (-l): показать последние версии проектов
--outdated (-o): показать последние версии только для устаревших пакетов
run
Чтобы запустить проект достаточно выполнить:
poetry run python <имя python файла>
poetry run python main.py
poetry run <имя скрипта, описанного в [tool.poetry.scripts]>
poetry run main-run
PyCharm & Poetry
В PyCharm 2021.3 добавили поддержку Poetry. Теперь при создании проекта можно сразу указать poetry основным пакетным менеджером. Перед использованием необходимо установить executable версию poetry (на windows через poweshell):
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -
После чего можно без проблем выбрать Poetry при создании проекта:
Далее автоматически будет создан .toml файл:
При установке пакетов через менеджер PyCharm файл pyproject.toml будет автоматически обновляться сам:
Версии зависимостей
При установке пакета можно указать точную версию проекта, например:
[tool.poetry.dependencies]
pygame = "2.1.0"
Но иногда есть необходимость указать диапазон версий пакета, чтобы получать обновления, в таком случае есть несколько способов указать диапазон:
[tool.poetry.dependencies]
pygame = "^2.1"
pygame = "~2.1"
pygame = "2.1.*"
pygame = "*"
Вот какие диапазоны принимают данные префиксы версий:
Зависимость |
Минимальная версия |
Максимальная версия |
^1.2.3 |
>=1.2.3 |
<2.0.0 |
^1.2 |
>=1.2.0 |
<2.0.0 |
^1 |
>=1.0.0 |
<2.0.0 |
^0.2.3 |
>=0.0.3 |
<0.0.4 |
~1.2.3 |
>=1.2.3 |
<1.3.0 |
~1.2 |
>=1.2.0 |
<1.3.0 |
~1 |
>=1.0.0 |
<2.0.0 |
* |
>=0.0.0 |
- |
1.* |
>=1.0.0 |
<2.0.0 |
1.2.* |
>=1.2.0 |
<1.3.0 |
Заключение
Poetry - отличная альтернатива pip. Он позволяет отказаться от requirements.txt в пользу более гибкой настройки проекта. Благодаря poetry можно в любой момент посмотреть информацию о зависимостях любого пакета, гибко настраивать версии и обмениваться poetry.lock файлами с уже заготовленным списком версий пакетов.
Комментарии (35)
kalbas
06.12.2021 11:46+4В какой-то момент добавил к использованию pip пакет pip-tools, и в принципе проблема с тем, что непонятно откуда какие зависимости приходят ушла, теперь все нужные для проекта зависимости описываю в requirements.in, а requirements.txt генерится и содержит в принципе ту же метадату о взаимосвязях зависимостей. Есть ли в poetry еще плюсы? Может установка быстрее или что-нибудь еще?
rg_software
06.12.2021 12:20+1Для меня, скажем, основной плюс в том, что это all-in-one solution. На чистой машине выкачиваю репозиторий проекта, по toml файлу автоматом создаётся virtual environment и устанавливаются зависимости. Вместо
python
набираюpoetry run python
-- запускается версия Питона в виртуальном окружении. Можно настроить так, чтобы окружение создавалось в папке проекта, тогда если проект больше не нужен, папка удаляется -- и всё с концами. Ещё у меня была проблема с тем, что какой-то из более стандартных менеджеров зависимостей на каких-то проектах зависал навечно при попытке определить скачиваемые пакеты, вот и пришлось искать альтернативы.
daniilgorbenko Автор
06.12.2021 12:39+удобно использовать несколько версий Python
poetry env use <пусть до python.exe нужной версии>
особенно, когда хотите перейти от более старой версии к более новой, но боитесь что-то сломать, самое-то
kalbas
06.12.2021 12:46+4Это неплохо конечно, но у меня для этого докер есть, любой новый сервис сразу заворачивается в контейнер типовой конфигурации, где уже и pip-tools сидит. А там я уже могу как угодно не только версиями питона вращать, но и версиями системных пакетов.
daniilgorbenko Автор
06.12.2021 13:37-3докеры - хороший вариант, когда работаете над большими/долго живущими проектами
а если, допустим, человек хочет дома создать какой-то пет-проект или надо быстро опробовать какую-то фишку (которая не факт, что пригодится), то не совсем удобно тянуть за собой докер, когда можно выполнитьpoetry new test_project
и начинать работать
но это дело привычки, если рука набита или есть заготовки, чтобы создать докер за минуту, то почему бы и нет
alexxxnf
06.12.2021 14:38pyproject.toml - это часть стандарта PEP 517 и PEP 518. Насколько я понимаю, pip-tools использует свой собственный подход не основанный на PEP.
kalbas
06.12.2021 15:13+2Ооо, зашел на сайт Poetry, почитал и понял, что эта штука по сути куда шире и роскошнее, чем описано в статье. Pip -- это просто package installer, а Poetry -- средство управления проектом на python (здесь и управление зависимостями, и изоляция, и публикация, и этот волшебный poetry run). До этого я также не вникал и думал, что это просто какая-то замена pip, потому что читал статьи типа этой. Спасибо в общем за ваш комментарий!
snp
06.12.2021 16:13Стандартный workflow для pip-tools:
pip-compile --output-file=requirements.txt requirements.in git add requirements.* git commit -v
Получаем обычный requirements.txt, такой же, каким он был и 10 лет назад, просто в каждой строчке жёстко прописана версия пакета, в т.ч. все зависимости (которые в requirements.in не требуется указывать). Никакой магии. Потом ставим:
.venv/bin/pip install -r requirements.txt
PEP-517/518 это, конечно, хорошо, но вариант с pip-tools выглядит проще, при этом получаем то же самый результат.
alexxxnf
06.12.2021 16:39+1У poetry есть то же самое:
poetry export -o requirements.txt
. Я это использую в Docker-образах, чтобы не тащить туда лишние зависимости.Чем это лучше или хуже pip-tools, я не знаю. Мне удобно.
B7W
06.12.2021 20:44Есть более правильный способ
poetry build
А в Dockerfile
ENV WHEEL "socks5_tune-$VERSION-py3-none-any.whl" COPY dist/$WHEEL /app/ RUN pip install --no-cache-dir /app/$WHEEL
glader
06.12.2021 13:46Подскажите, что делать, если нужны два списка пакетов, например для тестирования и для продакшена?
daniilgorbenko Автор
06.12.2021 14:03при установке пакетов можно использовать
# установить зависимость в общий список poetry add pygame # установить зависимость в качестве dev пакета poetry add pygame --dev
либо вручную вписать в toml файл для продакшена в блок [tool.poetry.dependencies]
[tool.poetry.dependencies] pygame = "^2.1.0"
для dev
[tool.poetry.dev-dependencies] Pympler = "^0.9"
и при установке делать так:
# установить все зависимости (в т.ч. dev) poetry install # игнорировать dev зависимости poetry install --no-dev
alexxxnf
06.12.2021 14:42Кроме dev-зависимостей, новая версия Poetry будет поддерживать ещё и произвольные группы: https://python-poetry.org/docs/master/managing-dependencies/#dependency-groups
dolfinus
06.12.2021 21:43+2Недавно наткнулся на вот такой баг:
https://github.com/python-poetry/poetry/issues/3139
Если сначала установить зависимости для одного окружения, а потом поверх установить зависимости для другого, poetry сначала удалит все пакеты первого окружения, и затем накатит второе. Как я понял, это было сделано для упрощения решения проблем с конфликтами версий установленных пакетов, поскольку так не нужно учитывать наличие уже установленных, но несовместимых друг с другом версий пакетов.
Но при этом он удаляет все пакеты старого окружения, в т.ч. и транзитивные зависимости. И если такой зависимостью случайно окажется virtualenv, он его удалит, и затем перестанет работать, т.к. сам от него зависит.
Да и если говорить о других зависимостях, сейчас это работает странно - poetry может считать, что зависимость установлена, хотя сам же ее и удалил при очистке окружения, и в итоге установка падает на пустом месте с кучей ошибок
domix32
06.12.2021 14:40+1То бишь cargo для питона? А как сами пакеты ставятся при наличии проекта и toml? Откуда пакеты берутся и в каком формате (eggs, wheels)? Появился новый Poetry registry с пакетами?
stepalxser
06.12.2021 16:35Стандартный источник pypi.org. Можно указывать свои кастомные.
Насчет формата не скажу, про предполагаю, что стандарт сейчас wheels.
amarao
06.12.2021 14:45+3Я так и не понял, что оно даст мне, если я перестану использовать pip и начну poetry. Что-то станет ещё более гибким, ок. А проблему оно какую решает?
Mel
06.12.2021 15:06+1Нормальный фриз зависимостей пакетов которые вы используете через poetry.lock что бы воспроизвести точно такое же окружение на 2 машине.
С обычным пипом частенько было когда на 2 машине устанавливались другие, обновленные подзависимости у пакетов и получались проблемы.amarao
06.12.2021 15:59+3Это не "фриз", это "lock". Да, из всех языков, только pip жил без лока и его, местами, не хватает.
snp
06.12.2021 16:15Собственно, pip-tools всё это и делает. В requirements.in пишем пакеты, которые нам нужны, а pip-tools создаёт requirements.txt, где вписаны абсолютно все пакеты, со всеми зависимостями и для каждого задана точная версия. Тот же самый лок.
SilverDrakon
06.12.2021 15:56А можно ли при помощи poetry скачать (не устанавливая) все нужные файлы зависимостей, чтобы их можно было перенести на сервер без интернета и там развернуть? (и умеет ли poetry инсталлировать скачанное заранее в оффлайн-режиме?)
stepalxser
06.12.2021 16:46https://pip.pypa.io/en/stable/cli/pip_wheel/
На сервере-сервере сборщике:pip wheel --wheel-dir /tmp/wheels -r requirements.txt
На офлайн-сервере, после копирования wheels через флешку:
pip install ./wheels/*
requirements.txt можно получить с помощью poetry.
Ну и сам детерминированный
vba
06.12.2021 16:26+3По мне так poetry нисколько не прекрасен, тормознутная поделка, которая с помощью непонятной магии пытается вам втюхать venv + pip в своей обертке. Совершено не подходит для проектов на conda, от слова совсем. По мне так pip на любом проекте хватает с лихвой и нет ему достойной альтернативы, пока.
tzlom
06.12.2021 18:40+2conda вещь в себе, то что в ней pip работает это скорее недосмотр а не фича, нормально с ним конда работать не умеет.
По сути - питон в окнах и питон в линуксе это две совершенно разные среды которые делают одинаково больно, но по разному.
NightShad0w
07.12.2021 00:30Главная особенность poetry не упомянута. Проект обещает наиболее корректное разрешение версий зависимостей, без внезапных неудач посреди установки сотни зависимостей, потому что где-то противоречия возникли.
dolfinus
07.12.2021 02:08+2Интересно каким образом он обещает это сделать, если на уровне API pypi и аналогичные ему репозитории не умеют отдавать метаданные пакета без его скачивания?
Только в этом году, после переключения в pip на новый резолвер, оказавшийся очень медленным поначалу, разработчики всерьез взялись за исправление этой проблемы:
https://github.com/pypa/warehouse/issues/8254
В итоге появился план вытаскивать из загружаемых .whl файлов список зависимостей и хранить его в отдельном файле, чтобы улучшить резолвинг зависимостей:
https://github.com/pypa/warehouse/pull/9972
И правки до сих пор не смержили. Плюс это повлияет только на новые версии пакетов, обсуждение способа парсинге зависимостей уже залитых пактов все ещё идёт.
А без них, что pip, что poetry находятся в одинаковой ситуации - чтобы скачать зависимости пакета, нужно сначала скачать пакет, распарсить его метаданные, потом скачать его зависимости, зависимости его зависимостей и т.п.
Более того, проблема решаема только для .whl, потому что он собирается для определенной версии Python и ОС. А вот если выгружать в pypi исходники пакета в .tar.gz, метаданные из него вынуть не выйдет, потому что зависимости могут быть указаны в setup.py, т.е. определяться динамически в момент запуска сборки.
Что такого революционного предлагает poetry, кроме requirements.lock файла? Так это файл ему точно так же придется подготавливать, скачивая пакеты из pypi
NightShad0w
07.12.2021 14:58Спасибо за замечание, я не был в курсе таких проблем в pypi.
Я с pipenv в ситуацию кривых разрешений версий попадаю часто, и это вынуждает разрешать версии в ручную, выясняя, какие пакеты в каком порядке ставить. Poetry меня обнадеживает.
Процитирую poetry readme, как дополнение к исходному комментарию:
Dependency resolution The dependency resolution is erratic and will fail even if there is a solution. Let's take an example: pipenv install oslo.utils==1.4.0 will fail with this error: Could not find a version that matches pbr!=0.7,!=2.1.0,<1.0,>=0.6,>=2.0.0 while Poetry will get you the right set of packages: poetry add oslo.utils=1.4.0 results in : - Installing pytz (2018.3) - Installing netifaces (0.10.6) - Installing netaddr (0.7.19) - Installing oslo.i18n (2.1.0) - Installing iso8601 (0.1.12) - Installing six (1.11.0) - Installing babel (2.5.3) - Installing pbr (0.11.1) - Installing oslo.utils (1.4.0) This is possible thanks to the efficient dependency resolver at the heart of Poetry. Here is a breakdown of what exactly happens here: oslo.utils (1.4.0) depends on: pbr (>=0.6,!=0.7,<1.0) Babel (>=1.3) six (>=1.9.0) iso8601 (>=0.1.9) oslo.i18n (>=1.3.0) netaddr (>=0.7.12) netifaces (>=0.10.4) What interests us is pbr (>=0.6,!=0.7,<1.0). At this point, poetry will choose pbr==0.11.1 which is the latest version that matches the constraint. Next it will try to select oslo.i18n==3.20.0 which is the latest version that matches oslo.i18n (>=1.3.0). However this version requires pbr (!=2.1.0,>=2.0.0) which is incompatible with pbr==0.11.1, so poetry will try to find a version of oslo.i18n that satisfies pbr (>=0.6,!=0.7,<1.0). By analyzing the releases of oslo.i18n, it will find oslo.i18n==2.1.0 which requires pbr (>=0.11,<2.0). At this point the rest of the resolution is straightforward since there is no more conflict.
SSSerg
Ни слова про packages и команду build...
daniilgorbenko Автор
старался выделить самое основное, что поможет начать работать с poetry
в самом начале написано, что цель статьи - немного познакомить с основными командами, а также в сравнении с pip указано, что не все моменты/преимущества выделены
информации пришлось поместить много, поэтому не всё добавил