Управление зависимостями? Шо, опять?


Экосистема Python породила целую пачку способов управления зависимостями в проектах.
Прямо сейчас можно выбирать между setup.py, requirements.txt, setup.cfg, MANIFEST.in и Pipfile.
Но французского питониста Sebastien Eustace все эти способы не устроили, и он написал свою штуку для менеджмента питонячих пакетов — Poetry. Зачем он это сделал? Чтобы заменить все эти setup.py, requirements.txt, setup.cfg, MANIFEST.in и Pipfile чем-то простым и понятным. Плюс добавить кое-что полезное сверху.


image


Poetry позволяет рулить сразу кучей вещей — версией языка в вашем проекте, зависимостями, подключаемыми путями, скриптами тестирования/разработки, сборкой и публикацией билдов.Все необходимые пути, зависимости и скрипты описываются в специальном файле pyproject.toml.


Poetry лучше всего работает в паре с pyenv — системой управления множественными версиями Python и виртуальными окружениями.


Щупаем


Засучим рукава и посмотрим, как poetry работает в деле. Первым делом ставим pyenv, следуя официальной инструкции в доках.


# Обновляем pyenv, если он у вас не первой свежести
$ pyenv update

# Смотрим и выбираем версию Python для использования в проекте
$ pyenv install -l

# Ставим нужную версию языка, если у вас ее еще нет
$ pyenv install 3.7.3
# Маководы могут словить проблем с zlib, придется заюзать команду 
# CFLAGS="-I$(xcrun --show-sdk-path)/usr/include" pyenv install 3.7.3

# Прописываем нужный интерпретатор и привязываем его к текущей папке
$ pyenv local 3.7.3

# Ставим poetry
$ pip3 install poetry

# Конфигурим новый проект
$ poetry init
# Poetry задаст несколько вопросов и по итогу напишет файл pyproject.toml, в котором пропишет все настройки проекта

# Добавим пару пакетов в проект. Пакеты будут доступны только в виртуальное среде, которая сейчас активна в текущей папке.
$ poetry add flask celery
# Poetry все поставит и пропишет зависимости в pyproject.toml

# Если у вас есть пакеты, которые не поставить через PIP (например, кусок кода от другого подразделения вашей конторы), можно добавить зависимость вручную
$ poetry add my-package --path ../my-package/

# Посмотрим установленные зависимости в красивом виде
$ poetry show

# Теперь можно запускать команды в виртуальной среде Python 
$ poetry run python
#  Мы только что запустили интепретатор Python из нашей среды, в нем уже доступны flask и celery, которые мы поставили ранее.

Среда установлена и настроена, зависимости управляются одним пальцем, можно пилить код!


У вас, скорее всего, появятся в проекте команды запуска сервера, воркеров, скриптов деплоя и тестирования. Их можно засунуть в pyproject.toml и тоже рулить ими одним пальцем.


Добавляем в файл


my-script = "my_module:main"

и теперь можно запускать скрипт командой


poetry run my-script

Зачем это все?


Потратив десяток минут на освоение этой штуки, вы сэкономите время и нервы на управлении версиями языка и пакетов, отслеживании зависимостей и настройке путей. Особенно это поможет тем, кто хоть раз пробовал опубликовать свои наработки в pip :)


  • Резолвер зависимостей, способный всегда найти решение конфликтам версий пакетов (если оно вообще существует)
  • Автоматическое создание изолированных сред для запускапроектов.
  • Приятная консольная утилита, которая здорово упрощает запуск, тесты и деплой проектов.

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

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


  1. iroln
    13.06.2019 13:02
    +1

    pyenv — это не про управление виртуальными окружениями, а управление несколькими интерпретаторами Python в системе.


    По существу, зачем нужен poetry и сравнение с другими тулами ничего не сказано. Хотя бы про ресолвер зависимостей можно было упомянуть, которого нет в pip/pipenv.


    И кстати, вот новый проект, автор которого хочет исправить все родовые проблемы в Python packaging и объять необъятное :)
    https://github.com/dephell/dephell


    1. 57uff3r Автор
      13.06.2019 13:12

      Спасибо за комменты, добавил правки


  1. szelga
    13.06.2019 13:27

    управление пакетами в Python недостаточно походит на npm по интерфейсу. это надо срочно исправить.


  1. allexx
    13.06.2019 13:34

    Приходите на PyCon pycon.ru/2019/program/content/khaerov я рассажу что сейчас происходит в этом мире зависимостей.


  1. amarao
    13.06.2019 14:29
    +1

    После чего нам нужна so'шка для psycopg, которая требует dev- пакеты от postgres, которые требуют build-essentials, которые надо ставить вручную методом "сломалась установка".


    Просто нет. Очередная сломанная система управления зависимостями, которая решает не все задачи по управлению зависимостями.


    1. rSedoy
      13.06.2019 19:47

      на всякий случай, относительно недавно появился psycopg-binary, но вряд ли это хороший способ решения проблемы.


  1. totaki
    13.06.2019 22:25
    +1

    У poetry есть одна проблема, нет команды перевести зависимости в обычный requirements.txt и для установки зависимостей надо установить сам poetry. И если вы все-таки решили ставить зависимости через него, встает другая проблема. В нашей практике мы собираем приложения в Dockerfile и обычное дело копировать файл зависимостей и их устанавливать где-то перед копированием кода, чтобы слой закешировался. Так вот если вдруг внесете изменения в pyproject.toml не касающейся зависимостей у вас все равно будет пересобираться слой с ними. В итоге пришлось написать скрипт, который читает stdin из poetry show и poetry show --no-dev и генерить два *.txt файла. Мелочь, а не приятно.


    1. iroln
      14.06.2019 00:37

      нет команды перевести зависимости в обычный requirements.txt и для установки зависимостей надо установить сам poetry

      Может упомянутая мною выше тула вам поможет?
      https://dephell.readthedocs.io/en/latest/cmd-deps-convert.html


      dephell deps convert --from=poetry --to=pip

      Как-то так должно быть. Если что, можно спросить автора напрямую: orsinium


      1. totaki
        14.06.2019 08:55

        Не любитель тащить стороние зависимости ради пары строчек кода.
        get_requirements.py


        import sys
        
        for line in sys.stdin:
            name, version = line.strip().split()[:2]
            print('%s==%s' % (name, version))

        freeze.sh


        #!/usr/bin/env bash
        
        poetry show | python scripts/get_requirements.py > requirements-dev.txt
        poetry show --no-dev | python scripts/get_requirements.py > requirements.txt


  1. DatUser
    13.06.2019 22:25

    Извините, но классика (https://xkcd.com/927/):

    Situation: There are 14 competing standards
    «14?! Ridiculous! We need to develop one universal standard that covers everyone's use cases.» «Yeah!»
    Situation: There are 15 competing standards


    1. iroln
      14.06.2019 02:15

      Тут другая ситуация. Назовите хоть один стандарт для Python packaging. Да, есть тулы, есть PEPы, есть PyPA, но стандарта нет, а проблем хватает. :)


      "Python Packaging Authority" (PyPA) пытались/пытаются и пока не смогли привести в порядок packaging в питоне. Да, они многое улучшили, у нас есть pip, setuptools, wheel, pipenv, новый сайт PyPI (:, но код их тулов — это россыпи костылей и трудно поддерживаемые монстры (тот же pip). Вообще весь путь Python packaging — это история боли и страдания, а в рядах разработчиков шутят, что исправить это невозможно :).


      Заголовок спойлера


  1. tgz
    14.06.2019 11:02
    -1

    Пока они не научатся одной командой получать на выходе deb пакет, то так и будут изобретать велосипеды.