Управления пакетами Python: Хронология

Тимур Салимов — Techlead DS

Введение

Цель этой презентации пролить свет на ситуацию с управлением пакетами и выделить важные этапы в эволюции инструментов, поскольку на исходной странице “History of Packaging” представлены только датированные вехи без контекста.

1996: site module

  • Как обстояли дела до этого?
    • Если необходимо что-то установить, то кладем это куда-то на диск и добавляем этот путь в переменную PATH.
  • Для решения этой задачи появился модуль site.
    • Он взял на себя эту небольшую манипуляцию и зародил обсуждение о методах передачи Python пакетов.

1998: distutils

  • В 1998 году началось обсуждение стандартизации процедуры распространения модулей Python - distutils-sig. И выпущена первая версия модуля distutils.
  • В 2000 году distutils был добавлен в стандартную библиотеку Python 1.6.
    • Пример упаковки пакета при помощи distutils.
      • Структура проекта:
        •       <root>/
                ├── src/
                │  ├── __init__.py
                │  ├── foo.py
                │  └── bar.py
                └── setup.py
      • Управление происходит при помощи файла setup.py с следующим содержанием:
        •     from distutils.core import setup
              setup(name='foobar',
                    version='1.0',
                    package_dir={'foobar': 'src'},
                    packages=['foobar'],
                    )
      • Однако на данный момент Python завершает поддержку distutils, так что пример приведен только в образовательных целях.
  • Это был значительный шаг вперед.

2002: import hooks

  • Первые попытки разобраться с зависимостями были основаны на том, что Python позволяет перезаписывать функцию __builtin__.__import__ (PEP 302).
  • Расширение механизма импорта необходимо, когда вы хотите загружать нестандартные модули, хранящиеся нестандартным способом.
  • Пример использования import hooks.
    •   import __builtin__
        original_import = __builtin__.__import__
      
        def my_import(name, globals=globals(), locals=locals(), fromlist=[], level=-1):
            ...
      
        __builtin__.__import__ = my_import
        try:
            my_import({module_name})
        finally:
            __builtin__.__import__ = original_import
  • На данный момент для подобных манипуляций рекомендуется использовать библиотеку importlib.

2003: PyPI

  • В 2000 году началось обсуждение связанное с созданием централизованного индекса пакетов Python - catalog-sig.
    • 2002 год: PEP 301, описывающий PyPI.
    • 2003 год: PyPI начал свою работу.
    • 2005 год: добавлена возможность заливать файлы.
    • 2015 год: PEP 503, описывающий API репозитория пакетов Python.
  • С 2001 года начали публиковать стандарты, описывающие метаданные пакетов.
    • 2001 год: PEP 241 - стандарт метаданных пакета.
    • 2003 год: PEP 314 - стандарт описания зависимостей пакета.
    • 2009 год: PEP 345 добавил маркеры платформ у пакетов и их зависимостей.
    • 2017 год: PEP 566, последний на данный момент стандарт метаданных пакетов Python.

2004: setuptools

  • В 2004 год появляется приемник distutils - setuptools.
    • Была добавлена возможность указывать зависимости через install_requires.
    • Также был полноценный CLI интерфейс – easy_install.
    • И новый формат пакетов - egg.
  • Хотя библиотека setuptools решила большинство проблем с пакетами в момент появления и, вероятно, стала самой популярной библиотекой для упаковки, она до сих пор не является частью стандарта.

2007: virtualenv и venv

  • Изначально, в Python не было встроенной возможности создавать окружения, и такая возможность была реализована в виде хака.
  • На этой идее в 2007 году и появилась библиотека virtualenv, позволяющая создавать изолированные среды для установки и использования пакетов, а также ссылаться на разные версии Python в этих окружения.
    • Механизм работы virtualenv.
      • После создания виртуального окружения, будет создана директория примерно такого содержания:
        •     user@unix:/usr/home/test# virtualenv ENV
              user@unix:/usr/home/test/ENV# tree -L 3
              .
              ├── bin
              │   ├── activate
              │   ├── easy_install
              │   ├── python
              │   ├── python3 -> python
              │   └── python3.10 -> python
              ├── include
              │   └── python3.10m -> /usr/include/python3.10m
              └──lib
                   ├──python3.10
                   ├── abc.py -> /usr/lib/python3.7/abc.py
                   ├── .    .    .
                   ├── weakref.py -> /usr/lib/python3.7/weakref.py
                   ├── distutils
                   ├── site-packages
                   └── site.py

2012: venv

  • В 2012 году в стандартной библиотеке Python появился модуль venv, использующий новый стандарт PEP 405, который вводит механизм для легковесных окружений.
    • Механизм работы venv:
      • Создадим виртуальное окружение при помощи venv и посмотрим содержимое полученной папки:
        •     user@unix:/usr/home/test2# python3 -m venv ENV
              user@unix:/usr/home/test2# tree -L 3
              .
              └── ENV
                ├── bin
                │   ├── activate
                │   ├── easy_install
                │   ├── easy_install-3.10
                │   ├── python -> python3
                │   └── python3 -> /usr/bin/python3
                ├── include
                ├── lib
                │   └── python3.10
                ├── lib64 -> lib
                ├── pyvenv.cfg
                └── share
      • Содержимое pyenv.cfg:
        •     user@unix:/usr/home/test2# cat ENV/pyvenv.cfg
              home = /usr/bin
              include-system-site-packages = false
              version = 3.10.0
  • virtualenv продолжает независимо развиваться, не смотря на то, что часть его функций была перенесена в стандартную библиотеку Python в виде модуля venv.

2008: pip

  • В 2008 году появляется pip, как замена easy_install из setuptools.
    • Стоит отметить, что если distutils и setuptools решали задачи не только установки, но и сборки пакетов, pip изначально концентрировался на вопросе установки пакетов.
    • pip представил сообществу формат файла requirements.txt, в котором можно указать требуемые библиотеки и их версии.
  • pip объединил под собой существующие форматы и решения и стал стандартом установки пакетов на языке Python.
  • Изначально pip использовал setuptools для сборки пакетов из зависимостей, однако с появлением новых стандартов, описывающих build backend, pip перестал зависеть от setuptools и стал выполнять роль build frontend.
  • На самом деле, звучит забавно, но сообществу Python потребовалось всего-то 10 лет.. чтобы получить возможность не в ручную удалять пакеты.
  • На протяжении всего своего развития вплоть до настоящего момент pip позиционирует себя как инструмент установки пакетов на Python. Он не выполняет роль менеджера проекта.

2011 -2013: PyPA

2012 - 2022: Anaconda

  • В 2012 году Continuum Analytics выпускает первую версию Anaconda, которая представляет собой дистрибутив с Python пакетами.
  • В скорее было принято решение разделить дистрибутив на отдельные компоненты, иначе при обновлении необходимо бы было обновлять весь дистрибутив целиком. Таким образом появились conda packages.
  • Так как уже были реализованы и использовались conda packages для них в этом же году разработали первую версию пакетного менеджера, который назвали conda.
  • Был также создан отрытый репозиторий для conda packages – repo.anaconda.com, и для сообщества открыли возможность создавать свои “каналы” для пакетного менеджера conda.

2021: Mamba.org

  • В 2021 году выходят первые релизы открытых альтернатив для стека Anaconda от сообщества “Mamba Org”.
    • Это сообщество появилось благодаря объединению нескольких разных сообществ по разработке научных пакетов и инструментов для Python вокруг канала conda-forge – Quansight, QuantStack и несколько крупных контрибьютеров conda-forge.
    • Были выпущены следующие альтернативы:
      • Quetz
      • Mamba
      • Boa
  • В 2022 году Continuum Analytics интегрирует solver libmamba от “Mamba Org” в пакетный менеджер conda.

2012: wheels

  • В 2012 году выходит альтернативный формат python пакетов - wheels, описанный в PEP 427.
  • wheels становится приоритетный форматом поставки пакетов.
  • wheels достаточно похож на формат conda package, однако у них есть расхождения на уровне наименований, а также работы с shared libs.

2015 - 2021: pyproject.toml

Достаточно важный сдвиг в парадигме управления пакетами Python.

  • 2015 год: PEP 518 и PEP 508 задали указание зависимостей в pyproject.toml.
  • 2015 год: PEP 513, добавивший в качестве варианта платформы manylinux. А в 2019 появится последняя версия стандарта уже для формата пакетов wheels.
  • 2017 год: PEP 517 введение build backend.
  • В 2020 году стандарт PEP 508 обновляется в PEP 631, описывая работу уже в pyproject.toml. В этом же году принимается стандарт PEP 621, в котором фиксируется, что теперь в файле pyproject.toml указываются и все метаданные пакета. Таким образом, вместе с PEP 518, PEP 517 и PEP 631 унифицируя конфигурацию Python пакета, приводя наконец всё к одному файлу.
  • В 2021 году принимается PEP 660, который задаёт стандарт того, как делать редактируемые сборки пакетов на основе pyproject.toml.

2017: pipenv

  • Как было сказано ранее, pip взял на себя роль установщика пакетов, но не полноценного менеджера проекта.
  • В ответ на это в 2017 году появился pipenv, который сейчас находится под управлением PyPA. pipenv обладает следующей функциональностью:
    • Обеспечивает по-настоящему детерминированные сборки, благодаря возможности зафиксировать все зависимости в Pipfile.lock из Pipfile, при этом оставляя возможность указывать только то, что вы хотите.
    • Автоматически устанавливать необходимую версию Python, когда доступен pyenv.
    • Автоматически создает виртуальные окружения, при этом позволяя настраивать пути создания.
    • Автоматически генерирует Pipfile, который выполняет рольrequerements.txt, позволяя при этом задавать не только зависимости проекта, но зависимости необходимые на этапе разработки.
    • Автоматически добавляет/удаляет пакеты в Pipfile при их установке или удалении.