Инструменты упаковки Python: разбираем сложную историю дистрибуции

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Python-разработчики, желающие улучшить свои навыки в упаковке и дистрибуции проектов
  • Новички, сталкивающиеся с проблемами выбора инструментов для дистрибуции Python-пакетов
  • Специалисты, которые хотят понять эволюцию и текущее состояние систем упаковки в Python экосистеме

    Когда я впервые столкнулся с задачей упаковки Python-проекта для распространения, мой мозг почти взорвался: distutils, setuptools, distribute, distutils2... Почему нельзя просто иметь ОДИН стандартный инструмент? Мир дистрибуции Python-пакетов напоминает запутанное семейное древо, где все как-то связаны, но никто толком не объясняет, кто кому приходится родственником. Давайте распутаем этот клубок инструментов вместе, чтобы вы смогли принять осознанное решение и не тратить драгоценные часы на эксперименты. 🕵️‍♂️

Прокачать свои навыки в области Python-разработки и навсегда забыть о проблемах с упаковкой и дистрибуцией проектов можно на курсе Обучение Python-разработке от Skypro. Здесь вы не просто изучите современные инструменты упаковки, но и получите практический опыт создания полноценных приложений, готовых к публикации в PyPI. Обучение строится на реальных кейсах с профессиональными ревью кода.

История развития инструментов дистрибуции Python

История инструментов дистрибуции Python напоминает эволюционное древо с множеством мутаций, ответвлений и тупиковых ветвей. Все началось довольно невинно: в 2000 году в стандартной библиотеке Python появился модуль distutils, разработанный Грегом Уордом. Этот инструмент предлагал базовый механизм для упаковки и распространения Python-кода.

В 2004 году Филлип Дж. Эби, разочарованный ограничениями distutils, создал setuptools, значительно расширив возможности управления пакетами. Появилась поддержка зависимостей, автоматической загрузки пакетов из PyPI, установка в "режиме разработки" и многие другие возможности, которые мы принимаем как должное сегодня.

Антон Соловьев, тимлид Python-разработки

Однажды я присоединился к проекту, где codebase существовал уже около 10 лет. Первые компоненты были упакованы с помощью чистого distutils, затем постепенно команда перешла на setuptools. Когда я начал разбираться, почему некоторые модули устанавливаются не так, как ожидалось, то обнаружил настоящий зоопарк из различных подходов к упаковке.

"Почему у нас тут такое разнообразие?" — спросил я архитектора.

"Ну, сначала мы использовали distutils, потому что ничего другого не было. Затем setuptools казался революционным с его entrypoints и findpackages(). А distribute мы начали использовать, когда setuptools перестал активно поддерживаться. Потом они снова объединились... Честно говоря, сам не помню все переходы."

Мне пришлось стандартизировать систему сборки во всем проекте, и это заняло почти две недели. Переход на унифицированный setuptools сократил время сборки проекта на 40% и избавил от периодических загадочных ошибок установки.

Однако setuptools не был идеальным. Проблемы с совместимостью, непоследовательные обновления и трудности в поддержке привели к тому, что в 2008 году появилась "вилка" проекта — distribute. Он был совместим с setuptools, но с улучшенной поддержкой Python 3 и лучшей кодовой базой.

Примерно в то же время Python-сообщество инициировало проект distutils2 (временно известный как "packaging") — попытку стандартизировать систему упаковки и включить лучшие идеи из setuptools обратно в стандартную библиотеку. К сожалению, distutils2 никогда не был завершен.

В 2013 году произошло знаменательное событие: distribute был "воссоединен" с setuptools, который снова стал активно разрабатываться. Фактически, distribute прекратил существование, влившись в setuptools 0.7.

К 2014 году distutils2 был официально признан заброшенным, а setuptools укрепил свои позиции как de-facto стандарт для упаковки Python-проектов. В 2016 году появилось новое поколение инструментов — pip начал поддерживать формат wheel, появились flit, poetry и другие альтернативные системы упаковки, основанные на PEP 517/518.

Год Событие Значимость
2000 Появление distutils в стандартной библиотеке Первый стандартный инструмент упаковки
2004 Создание setuptools Революция в управлении зависимостями
2008 Появление distribute как форка setuptools Улучшенная поддержка Python 3
2011 Начало работы над distutils2 Попытка стандартизации
2013 Воссоединение distribute и setuptools Консолидация экосистемы
2014 Официальное признание distutils2 заброшенным Конец попытки стандартизации
2016+ Появление новых инструментов (poetry, flit) Современный подход к упаковке
Пошаговый план для смены профессии

Distutils: базовая система распространения пакетов

Distutils — это исходный, базовый инструмент для создания и распространения Python-пакетов, встроенный в стандартную библиотеку. Его имя происходит от "distribution utilities" — утилиты для дистрибуции. Несмотря на свой почтенный возраст, он до сих пор лежит в основе большинства современных решений для упаковки Python-кода.

Основные возможности distutils:

  • Компиляция модулей расширения на C
  • Создание дистрибутивов исходного кода (source distributions, sdist)
  • Установка пакетов в системные директории Python
  • Базовый механизм настройки через setup.py
  • Обработка метаданных пакета (версия, автор и т.д.)

Ключевым компонентом distutils является файл setup.py, который содержит информацию о пакете и инструкции для его установки. Вот простой пример такого файла:

Python
Скопировать код
from distutils.core import setup

setup(
name='MyPackage',
version='1.0',
description='A sample Python package',
author='Python Developer',
author_email='dev@example.com',
packages=['mypackage'],
)

Этот минимальный setup.py позволяет выполнять базовые операции с пакетом:

  • python setup.py build — сборка пакета
  • python setup.py install — установка пакета
  • python setup.py sdist — создание архива с исходным кодом

Однако у distutils есть существенные ограничения, которые привели к появлению более продвинутых альтернатив:

  • Нет механизма управления зависимостями
  • Отсутствие автоматической загрузки пакетов из репозиториев
  • Нет поддержки "разработческой" установки (develop/editable mode)
  • Ограниченная поддержка метаданных
  • Нет механизма точек входа (entry points) для создания консольных скриптов

Distutils остается в стандартной библиотеке, но фактически находится в режиме обслуживания. Новая функциональность не добавляется, хотя критические исправления всё еще вносятся. Python-сообщество рекомендует использовать более современные инструменты, которые построены поверх distutils или полностью его заменяют.

Дмитрий Орлов, DevOps-инженер

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

Всё изменилось, когда мы начали переходить на Python 3.10. Один из разработчиков решил добавить в пакет зависимость от библиотеки для работы с Prometheus. При установке начались странные ошибки: зависимости не устанавливались автоматически, а при ручной установке возникали конфликты версий.

"Почему мы до сих пор используем голый distutils? Ему же лет 20!" — спросил я автора пакета.

"Когда я писал этот код, setuptools казался излишним усложнением для такого простого пакета," — ответил он.

Мы потратили полдня на диагностику проблем, прежде чем решили перейти на setuptools. Замена четырех строк в setup.py решила все проблемы, а добавление зависимостей в install_requires автоматизировало установку нужных версий пакетов. Теперь у нас правило: даже для самых простых внутренних пакетов используем как минимум setuptools.

Setuptools и distribute: расширенные возможности и отличия

Setuptools стал ответом сообщества на ограничения distutils, предложив расширенный функционал для управления Python-пакетами. Фактически, setuptools создавался как надстройка над distutils, сохраняя обратную совместимость, но значительно расширяя возможности.

Основные преимущества setuptools по сравнению с distutils:

  • Управление зависимостями через параметр install_requires
  • Автоматический поиск пакетов с помощью find_packages()
  • "Разработческий" режим установки (develop)
  • Поддержка точек входа (entry points) для создания исполняемых скриптов
  • Namespace packages для распределения пакета по нескольким дистрибутивам
  • Расширенная поддержка метаданных и классификаторов
  • Easy Install — инструмент для автоматической загрузки и установки пакетов
  • Pkg_resources — API для работы с ресурсами пакета

Типичный setup.py для setuptools выглядит так:

Python
Скопировать код
from setuptools import setup, find_packages

setup(
name='MyPackage',
version='1.0',
description='A sample Python package',
author='Python Developer',
author_email='dev@example.com',
packages=find_packages(),
install_requires=[
'requests>=2.25.0',
'numpy',
],
entry_points={
'console_scripts': [
'mycommand=mypackage.cli:main',
],
},
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
],
)

Но в истории setuptools был неспокойный период. К концу 2000-х годов проект столкнулся с проблемами в развитии: недостаточно активная поддержка, проблемы с совместимостью с Python 3 и накопившийся технический долг. Это привело к появлению distribute — форка setuptools, нацеленного на решение этих проблем.

Distribute сохранял полную обратную совместимость с setuptools, но имел следующие улучшения:

  • Лучшая поддержка Python 3
  • Более чистая и поддерживаемая кодовая база
  • Регулярные выпуски новых версий
  • Активное сообщество разработчиков
  • Улучшенное тестирование

С точки зрения API и использования, distribute был практически неотличим от setuptools — код, работающий с одним, работал и с другим. Различия были "под капотом". Именно поэтому distribute быстро стал популярным и начал вытеснять оригинальный setuptools.

Эта ситуация не могла продолжаться вечно. В 2013 году произошло знаменательное событие — distribute "воссоединился" с setuptools. Фактически, код distribute был интегрирован в setuptools версии 0.7, а сам проект distribute был объявлен устаревшим. Разработчикам рекомендовалось переходить (или возвращаться) к setuptools.

Функция Distutils Setuptools Distribute
Управление зависимостями
Автоматический поиск пакетов
Разработческий режим
Точки входа
Namespace packages
Поддержка Python 3 Ограниченная Ранее слабая, сейчас хорошая
Современный статус В поддержке (legacy) Активно развивается Слит с setuptools

После воссоединения setuptools стал снова активно разрабатываться, получил лучшую поддержку Python 3 и современных практик упаковки. Сегодня setuptools — это де-факто стандарт для упаковки Python-проектов, хотя уже появляются и набирают популярность альтернативные инструменты, такие как poetry и flit. 🛠️

Distutils2: попытка стандартизации и современный статус

Distutils2 представлял собой амбициозную попытку стандартизировать и улучшить систему упаковки Python, перенеся лучшие идеи из setuptools обратно в стандартную библиотеку. Проект был запущен в 2009 году с целью решить проблемы, связанные с разрозненной экосистемой инструментов дистрибуции.

Ключевые цели distutils2 включали:

  • Создание стандартизированной, официальной системы упаковки Python
  • Перенос лучших функций setuptools в стандартную библиотеку
  • Отказ от императивного подхода (setup.py) в пользу декларативной конфигурации (setup.cfg)
  • Улучшенная поддержка метаданных и зависимостей
  • Более последовательный API для разработчиков пакетов
  • Внедрение PEP 345 (улучшенные метаданные) и PEP 386 (стандартизированные версии)

Одним из ключевых отличий distutils2 был переход от использования программного файла setup.py к конфигурационному файлу setup.cfg. Это позволяло описывать пакет декларативно, без выполнения произвольного Python-кода, что повышало безопасность и предсказуемость:

ini
Скопировать код
[metadata]
name = MyPackage
version = 1.0
description = A sample Python package
author = Python Developer
author-email = dev@example.com

[files]
packages = mypackage

[requires]
python-version = >=3.6

[install_requires]
requests = >=2.25.0
numpy =

Однако, несмотря на амбициозные цели и серьезную работу, проект столкнулся с рядом проблем:

  • Сложность координации разработки между многочисленными участниками
  • Трудности интеграции с существующей экосистемой
  • Потеря основных разработчиков и снижение активности
  • Запаздывание относительно быстро развивающихся альтернатив

К 2012 году разработка distutils2 значительно замедлилась, а в 2013 году большая часть работы фактически прекратилась. В 2014 году проект был официально признан неактивным.

Хотя distutils2 как цельный проект не увидел свет, многие его идеи и наработки не пропали даром. Они были реализованы в новых PEP и инструментах:

  • Концепция декларативной конфигурации позже была реализована в setuptools через setup.cfg и pyproject.toml
  • Работа над метаданными пакетов повлияла на разработку PEP 621
  • Разделение описания пакета и механизма сборки легло в основу PEP 517/518
  • Библиотека packaging, начатая как часть distutils2, выжила как отдельный проект

В чем же сейчас заключаются современные рекомендации Python-сообщества после "неудачи" distutils2? Вот текущий консенсус:

  • Setuptools остается наиболее широко используемым и рекомендуемым инструментом
  • Для новых проектов следует рассмотреть современные альтернативы, такие как poetry или flit
  • pyproject.toml (PEP 517/518) становится стандартом конфигурации для инструментов сборки
  • Пакеты должны поддерживать wheel-формат для более быстрой и надежной установки
  • pip утвердился как стандартный установщик пакетов, заменив easy_install

Несмотря на то, что distutils2 не стал тем универсальным решением, на которое надеялось сообщество, его влияние на развитие экосистемы Python-упаковки невозможно переоценить. Многие идеи и концепции, первоначально разработанные для distutils2, сейчас формируют основу современных инструментов и практик. 📦

Выбор оптимального инструмента для вашего Python-проекта

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

Вот мои рекомендации по выбору инструмента упаковки в 2023 году:

  • Setuptools — оптимальный выбор для большинства проектов. Он хорошо документирован, активно поддерживается, имеет огромную экосистему и совместим практически со всем.
  • Poetry — отличный выбор для новых проектов, особенно если вы цените современный, более декларативный подход и хотите иметь интегрированное управление зависимостями и виртуальными окружениями.
  • Flit — подходит для простых библиотек, особенно если вы хотите минимализировать конфигурацию и получить самый короткий путь к публикации в PyPI.
  • PDM — многообещающий новичок, сочетающий лучшие идеи poetry и pip, с хорошей совместимостью с PEP 517/518.
  • Hatch — современный инструмент с акцентом на управление средами, тестирование и публикацию.

Что касается других инструментов из нашего обзора:

  • Distutils — слишком ограничен для современной разработки. Не рекомендуется для новых проектов.
  • Distribute — больше не существует как отдельный проект, влился в setuptools.
  • Distutils2 — заброшен и никогда не был завершен. Не следует использовать.

При выборе инструмента упаковки, учитывайте следующие критерии:

  • Сложность проекта: Для сложных проектов с множеством зависимостей setuptools или poetry будут более подходящими.
  • Требования к совместимости: Если ваш пакет должен работать в различных средах и с различными версиями Python, setuptools обеспечивает наилучшую совместимость.
  • Опыт команды: Если ваша команда уже знакома с определенным инструментом, это может стать весомым аргументом в его пользу.
  • Требования CI/CD: Некоторые инструменты лучше интегрируются с конкретными платформами непрерывной интеграции.
  • Тип проекта: Библиотека, приложение или инструмент командной строки могут иметь разные оптимальные решения для упаковки.

Вот сравнительная таблица современных инструментов упаковки Python по ключевым функциям:

Функция Setuptools Poetry Flit PDM
Управление зависимостями ✅ Базовое ✅ Продвинутое ✅ Базовое ✅ Продвинутое
Разрешение зависимостей Через pip Встроенное Через pip Встроенное
Управление виртуальными окружениями
Публикация в PyPI ✅ Через twine ✅ Встроенная ✅ Встроенная ✅ Встроенная
Формат конфигурации setup.py, setup.cfg, pyproject.toml pyproject.toml pyproject.toml pyproject.toml
Сложность освоения Средняя Низкая Очень низкая Низкая
Поддержка C-расширений ✅ Нативная ✅ Через setuptools Ограниченная ✅ Через setuptools

Лично я рекомендую следующий подход:

  1. Для новых проектов начните с poetry, если у вас нет особых требований к совместимости или C-расширениям.
  2. Для проектов с C-расширениями или сложными требованиями к сборке используйте setuptools с pyproject.toml.
  3. Для простых библиотек без внешних зависимостей рассмотрите flit для максимально быстрого старта.
  4. Для существующих проектов на setuptools нет необходимости мигрировать, если у вас нет конкретных проблем.

Помните, что независимо от выбранного инструмента, следуйте современным практикам: используйте pyproject.toml для конфигурации, предоставляйте wheel-дистрибутивы, следуйте семантическому версионированию и поддерживайте актуальные метаданные для вашего пакета. 🚀

Выбор инструмента для упаковки Python-проектов — это не просто техническое решение, но и стратегический выбор, влияющий на долгосрочное развитие вашего проекта. Хотя история distutils, setuptools, distribute и distutils2 демонстрирует сложный путь эволюции этих инструментов, современная экосистема предлагает ясные ориентиры. Для большинства проектов setuptools остается "безопасным" выбором, в то время как poetry представляет собой современную альтернативу с интегрированным управлением зависимостями. Главное — не бояться экспериментировать и выбирать инструмент, соответствующий вашим конкретным потребностям, а не слепо следовать трендам.

Загрузка...