Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Poetry и управление зависимостями Python: Настройка окружения

В этом уроке мы более подробно рассмотрим работу с зависимостями с помощью poetry. Заданием прошлого урока было создание проекта с именем hello. Примеры из этого урока будут показаны применительно к тому проекту-примеру.

Добавление и удаление зависимостей

Добавим к проекту hello зависимость — пакет colorama. Это популярная библиотека, которая позволяет раскрасить текст в терминале. Добавим зависимости командой poetry add ИМЯ:

poetry add colorama

Using version ^0.4.5 for colorama

Updating dependencies
Resolving dependencies... (0.8s)

Writing lock file

Package operations: 1 install, 0 updates, 0 removals

  • Installing colorama (0.4.5)

Теперь взглянем на секцию tool.poetry.dependencies файла pyproject.toml. Там окажется следующее:

[tool.poetry.dependencies]
python = "^3.10"
colorama = "^0.4.5"

Как видите, colorama не только установилась в виртуальное окружение, но еще и появилась в списке зависимостей проекта. Если кто-то захочет запустить ваш код, он просто выполнит команду poetry install и получит все необходимые зависимости.

Обратите внимание на текст "^0.4.5". Он означает не только конкретную версию 0.4.5, но и все версии, совместимые с ней.

Для версии 0.4.5 совместимыми будут считаться версии вплоть до "0.5.0". Так же можно указывать конкретную версию, перечислить несколько допустимых версий или вручную указать диапазон. Все это разнообразие описано в документации.

Теперь попробуем удалить зависимости командой poetry remove ИМЯ. Из файла pyproject.toml удаляемые пакеты тоже автоматически уберутся:

poetry remove colorama

Updating dependencies
Resolving dependencies... (0.1s)

Writing lock file

Package operations: 0 installs, 0 updates, 1 removal

  • Removing colorama (0.4.5)

Группы зависимостей

Многие инструменты для разработки Python-проектов написаны на Python. При этом для запуска кода они, как правило, не требуются.

Возьмем, к примеру, pytest — популярный фреймворк для написания тестов. У этого пакета много собственных зависимостей. В большом проекте подобные инструменты разработки могут занимать приличное количество места.

Проблема в том, что все эти зависимости пользователю не нужны — он же не будет запускать тесты. Тем не менее пользователь получает все зависимости вместе с программой и тратит место на хранение зависимостей.

К счастью, Poetry позволяет описать такие пакеты в виде группы зависимостей. Все созданные группы будут учтены при создании виртуального окружения, но к конечному пользователю попадут только зависимости из основной группы — то есть из [tool.poetry.dependencies].

Добавим пакет pytest к проекту hello. Укажем для него группу dev — это сокращение от слова development, так принято называть инструменты и среду разработки. Посмотрим, как это работает:

poetry add --group dev pytest

Using version ^7.1.3 for pytest

Updating dependencies
Resolving dependencies... (0.8s)

Writing lock file
...

 • Installing pytest (7.1.3)

Когда будете выполнять команду самостоятельно, обратите внимание, сколько пакетов будет установлено вместе с нужным нам pytest.

Теперь в файле pyproject.toml добавилась новая запись:

[tool.poetry.group.dev.dependencies]
pytest = "^7.1.3"

В итоге мы можем запустить pytest. Только не забывайте писать poetry run pytest вместо pytest — программа установлена в виртуальное окружение и снаружи не видна. Попробуем запустить:

poetry run pytest

# Пока pytest не запустил тесты,
# потому что мы же еще не написали их

====== test session starts ========
platform linux -- Python 3.10.4, ...
rootdir: /.../first
collected 0 items

====== no tests ran in 0.00s ======

Команда poetry run запускает не только команды из виртуального окружения — она запускает любые программы в контексте виртуального окружения. Например, с помощью системной программы which можно узнать, где находится исполняемый файл pytest:

poetry run which pytest

/../hello/.venv/bin/pytest

Теперь попробуем удалить зависимость. Для этого надо указать ее группу:

poetry remove --group dev pytest
Updating dependencies
Resolving dependencies... (0.1s)

Writing lock file
...
  • Removing pytest (7.1.3)

Обновление зависимостей

Для обновления всех зависимостей нужно выполнить команду poetry update, а чтобы выполнить обновление конкретной зависимости — poetry update ИМЯ.

Зависимости обновятся в соответствии с указанными диапазонами.

Lock-файл

На предыдущем шаге каждая новая установка зависимостей приводила сначала к созданию, а потом и обновлению lock-файла poetry.lock.

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

Зависимости зависимостей называются транзитивными, и с ними все не просто. Система зависимостей может быть очень запутанной. Для такой ситуации придумали специальный термин — «ад зависимостей» или dependency hell.

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

  • В нашем проекте есть зависимый пакет A с зафиксированной версией 1.3.2
  • У зависимости А есть зависимый пакет B с версией *

В такой ситуации и без lock-файла команда poetry install поставила бы:

  • Для A — указанную версию
  • Для B — последнюю доступную версию из репозитория

Другими словами, выбор версии не детерминирован. Если автор обновит B и нарушит обратную совместимость, то пакет А перестанет работать — весь проект просто сломается.

Можно вручную отслеживать зависимости всех зависимостей и явно прописывать их версии в pyproject.toml. Но такой способ вряд ли сработает, потому что пакеты постоянно обновляются и меняются. Еще отслеживать вручную сложно, потому что связей слишком много — даже в проекте с пятью зависимостями будут сотни транзитивных зависимостей.

Другой выход — требовать, чтобы создатели всех библиотек всегда указывали версии. Этот вариант тоже не сработает, на этот раз из-за человеческого фактора.

Есть одно решение, которое точно сработает — это lock-файл. По сути это автоматизированное отслеживание зависимостей. Содержимое lock-файла выглядит примерно так:

[[package]]
name = "colorama"
version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "a07e5731d39f80ad23e37e53ffb7d54de3b1534e6306267399f3b25fcce783ad"

[metadata.files]
colorama = [
    {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
    {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
...

Первый запуск установки зависимостей сформирует этот файл. Туда запишутся все установленные зависимости, в том числе транзитивные с версиями и хеш-суммами.

При дальнейших запусках команда poetry install всегда ставит то, что указано в lock-файле. Это сработает, даже если удалить папку .venv или добавить новые версии пакетов в файл pyproject.toml. Повторный запуск через любой промежуток времени приведет к тому же результату. Теперь с уверенностью можно сказать — проект запустится в любое время и для любого пользователя.

Наличие lock-файла никак не влияет на поведение команды update для прямых зависимостей. Представим, что у пакета из нашего файла pyproject.toml вышла новая версия.

В этом случае Poetry уточнит, можно ли обновить его до новой версии. Если да, то загрузится новая версия, а lock-файл обновится автоматически.

Если устанавливать пакеты не хочется, то для такого есть команда poetry update --lock. Она проверит, какие из новых версий подходят под указанные в конфигурации версии и обновит только lock-файл.


Самостоятельная работа

  1. Добавьте colorama как обычную зависимость в ваш проект hello
  2. Добавьте ipython в группу dev-зависимостей
  3. Запустите IPython
  4. Выполните в IPython from colorama import Fore. Импортирование должно пройти успешно
  5. Попробуйте парочку примеров из описания пакета colorama

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

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

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 25 апреля
профессия
от 5 025 ₽ в месяц
новый
Сбор, анализ и интерпретация данных
9 месяцев
с нуля
Старт 25 апреля

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»