Python проект: как грамотно организовать управление пакетами
Основные подходы к управлению зависимостями
Зависимости пакетов – это библиотеки и модули, без которых проект не может работать. Правильная фиксация версий и разрешение конфликтов – ключевая задача при разработке. В этом разделе рассматриваются несколько подходов: от базового requirements.txt до современных менеджеров, таких как Poetry и Pipenv.
Рекомендуемый подход: Poetry
Каким образом можно обеспечить воспроизводимость окружения и автоматическое разрешение зависимостей?
Poetry – современный инструмент, который объединяет управление зависимостями, сборку и публикацию пакетов. Он использует файл pyproject.toml для указания явных зависимостей и poetry.lock для точной фиксации всех подзависимостей.
# Установка Poetry (рекомендуется через pipx)
pip install poetry
# Создание нового проекта
poetry new myproject
cd myproject
# Добавление зависимости requests
poetry add requests
# Установка всех зависимостей из lock-файла
poetry installне работает import python (не работает импорт в python)
После выполнения poetry new создается структура каталогов и файл pyproject.toml. Команда poetry add скачивает пакет, разрешает все зависимости и обновляет poetry.lock. При развертывании poetry install читает lock-файл и восстанавливает окружение с точными версиями.
Возможная проблема: конфликты версий при добавлении новой зависимости, когда poetry не может найти совместимое сочетание.
Решение: выполнить poetry update для пересчета всего графа зависимостей или вручную скорректировать версии в pyproject.toml и затем выполнить poetry lock.
Вариант 1: Традиционный requirements.txt с virtualenv
Как организовать простой проект без дополнительных инструментов?
Этот метод предполагает создание виртуального окружения, установку пакетов через pip и последующую фиксацию списка командой pip freeze. При развертывании окружение восстанавливается из файла requirements.txt.
# Создание виртуального окружения
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Установка пакетов
pip install flask requests
# Фиксация версий
pip freeze > requirements.txt
# Восстановление окружения
pip install -r requirements.txtPython core package (базовые пакеты python)
Команда pip freeze выводит все пакеты, установленные в окружении, включая транзитивные. Это дает полную картину, но не разделяет прямые и второстепенные зависимости.
Возможная проблема: при обновлении одного пакета может измениться версия транзитивной зависимости, что способно нарушить работу другого пакета. Файл requirements.txt становится негибким.
Решение: использовать pip-tools для генерации файла из списка только прямых зависимостей (см. следующий вариант).
Вариант 2: Pip-tools (pip-compile)
Как автоматизировать создание зафиксированных зависимостей на основе требований верхнего уровня?
Pip-tools предлагает два основных компонента: pip-compile для генерации requirements.txt из файла с основными зависимостями (requirements.in) и pip-sync для приведения окружения в соответствие с этим файлом.
# Установка pip-tools
pip install pip-tools
# Создание requirements.in с прямыми зависимостями
echo "flask\nrequests" > requirements.in
# Генерация requirements.txt со всеми подзависимостями
pip-compile requirements.in
# Синхронизация окружения
pip-sync requirements.txt
Python package version (версия пакета python)
При изменении requirements.in достаточно повторно запустить pip-compile – он пересчитает дерево зависимостей и обновит requirements.txt.
Возможная проблема: необходимость поддерживать два файла (requirements.in и requirements.txt) и запускать pip-compile вручную.
Решение: автоматизировать процесс с помощью Makefile или скрипта, который при изменении .in вызывает pip-compile.
Вариант 3: Conda
Как управлять зависимостями, если нужны не только Python-пакеты, но и системные библиотеки?
Conda – менеджер пакетов из экосистемы Anaconda. Он может устанавливать пакеты из разных каналов, включая бинарные файлы (например, библиотеки на C++). Для фиксации используется файл environment.yml.
# Создание окружения из файла
conda env create -f environment.yml
# Активация
conda activate myenv
# Установка пакета
conda install numpy pandas
# Экспорт текущего окружения
conda env export > environment.ymlPython package dependencies (зависимости пакетов python)
Файл environment.yml содержит каналы, список зависимостей и их версии. Conda решает конфликты глобально, учитывая все пакеты.
Возможная проблема: смешивание Conda и pip может привести к непредсказуемому состоянию окружения.
Решение: использовать Conda для большинства пакетов, а pip – только для тех, которых нет в каналах Conda. Результат экспортировать в единый environment.yml.
Вариант 4: Pipenv
Как объединить виртуальное окружение и управление зависимостями с автоматическим созданием Pipfile.lock?
Pipenv создает Pipfile для явных зависимостей (обычных и для разработки) и Pipfile.lock для точной фиксации версий. Он автоматически управляет виртуальным окружением.
# Установка Pipenv
pip install pipenv
# Установка зависимостей из Pipfile (если он существует)
pipenv install
# Добавление пакета
pipenv install requests
# Добавление пакета для разработки
pipenv install pytest --dev
# Генерация lock-файла
pipenv lock
При развертывании выполняется pipenv sync, который устанавливает версии, указанные в Pipfile.lock.
Возможная проблема: Pipenv иногда медленнее Poetry, а разрешение зависимостей может давать ошибки при сложных графах.
Решение: обновить Pipenv до последней версии, при необходимости переключаться на Poetry.
Дополнительные сценарии управления зависимостями
1. Разделение зависимостей с помощью extras_require в setup.py
Для библиотек, распространяемых через PyPI, можно определить группы дополнительных зависимостей, которые устанавливаются при указании квадратных скобок.
# setup.py
from setuptools import setup, find_packages
setup(
name="mylib",
version="0.1",
packages=find_packages(),
install_requires=["requests>=2.25"],
extras_require={
"dev": ["pytest", "flake8"],
"docs": ["sphinx"]
},
)
# Установка с дополнительными зависимостями: pip install mylib[dev] # Установит requests, pytest, flake8
2. Использование приватного реестра пакетов
Если проект использует пакеты из приватного PyPI-сервера, можно указать дополнительные индексы.
# requirements.txt
--index-url https://pypi.org/simple/
--extra-index-url https://my-private-pypi.com/simple/
mypackage==1.0.0
pip install -r requirements.txt
В Poetry настройка выполняется в pyproject.toml:
[[tool.poetry.source]]
name = "private"
url = "https://my-private-pypi.com/simple/"
default = false
3. Разрешение конфликтов с помощью pip-compile и обновления отдельного пакета
Допустим, в requirements.in указаны flask и requests. После pip-compile файл requirements.txt содержит зафиксированные версии. Если нужно обновить только requests, используется опция --upgrade-package.
# Исходный requirements.in
flask
requests
# Первоначальная генерация
pip-compile
# Содержимое requirements.txt (фрагмент):
# flask==2.3.2
# requests==2.31.0
# Обновление только requests до последней совместимой
pip-compile --upgrade-package requests
# После обновления requirements.txt: # flask==2.3.2 # requests==2.32.0
4. Экспорт lock-файла Poetry в requirements.txt
Для совместимости с системами, ожидающими requirements.txt, Poetry позволяет сгенерировать этот файл из своего lock-файла.
poetry export -f requirements.txt -o requirements.txt --without-hashes
# Содержимое созданного requirements.txt: flask==2.3.2 requests==2.31.0 ...
5. Использование Pipenv с ключом --deploy в CI
Ключ --deploy проверяет, совпадает ли Pipfile.lock с Pipfile, и предотвращает установку, если lock-файл устарел.
# В CI-скрипте:
pipenv install --dev --deploy
# Если Pipfile.lock не обновлён, команда завершится с ошибкой. # Это гарантирует одинаковое окружение на всех этапах.
6. Пример конфликта зависимостей и его разрешение в Poetry
Предположим, pyproject.toml содержит:
[tool.poetry.dependencies]
python = "^3.8"
numpy = "^1.21"
pandas = "^1.3"
Pandas 1.3 требует numpy < 1.24, а numpy 1.21 допускает версии до 1.24. Однако если в репозитории уже есть более новые версии numpy (например, 1.24), poetry может не найти совместимого набора.
poetry add pandas
Updating dependencies Resolving dependencies... (1.5s) Solvers found problem: - numpy 1.24.0 is incompatible with pandas>=1.3 ...
# Решение: явно указать версию numpy, совместимую с pandas
poetry add numpy@^1.23 pandas@^1.3
# Или изменить версию pandas на более новую, поддерживающую numpy 1.24
7. Работа с Git-зависимостями в Poetry
Можно подключать пакеты напрямую из Git-репозитория.
[tool.poetry.dependencies]
my_package = {git = "https://github.com/user/my_package.git", branch = "main"}
poetry install
# Poetry клонирует репозиторий, создает яйцо и устанавливает
8. Использование pipenv run для изоляции скриптов
pipenv run python script.py
# Выполнит скрипт в контексте виртуального окружения, созданного Pipenv
Этот способ полезен в Makefile или в CI, когда не требуется явная активация окружения.