Регистрация пакета на PyPi

Подготовка проекта

Структура проекта

Для того, чтобы python-проект можно было устанавливать при помощи pip и распространять через хранилище пакетов pypi, он должен иметь определенную структуру и содержать ключевые для установки файлы.

Классическим считается следующее расположение файлов:

root-dir/   # рабочая папка с проектом
      setup.py
      setup.cfg
      LICENSE.txt
      README.md
      mypackage/
        __init__.py
        foo.py
        bar.py
        baz.py

Рассмотрим назначение и содержимое основных файлов в проекте

setyp.py

setup.py является ключевым файлом в процессе установки. Он должен находиться в корневой директории проекта. Пример этого файла можно посмотреть в шаблоне python-проекта PyPA.

setup.py выполняет две основные функции:

  • Это файл, в котором выполняется конфигурация проекта. В первую очередь, он должен содержать глобальную setup() функцию, ключевые аргументы к которой и определяют индивидуальную настройку вашего проекта. С описанием основных аргументов можно ознакомиться в официальном руководстве.
  • Это интерфейс командной строки для выполнения различных команд, имеющих отношение к созданию и распространению пакета. Чтобы получить список доступных команд, необходимо выполнить python setup.py --help-commands.

Упрощенный вариант setup.py:

from distutils.core import setup

setup(
  name = 'mypackage',
  packages = ['mypackage'], # должно совпадать со значением name
  version = '0.1',
  description = 'A random package',
  author = 'Dou Jones',
  author_email = 'doujones@gmail.com',
  url = 'https://github.com/doujones/mypackage',
  keywords = ['testing', 'logging', 'example'],
  classifiers = [],
)

setup.cfg

setup.cfg представляет собой ini-файл, который содержит настройки по-умолчанию для setup.py команд. Пример этого файла можно посмотреть все в том же шаблоне python-проекта PyPA.

README.rst

Каждый проект должен содержать readme-файл с описанием цели проекта. В случае распространения исходного кода через pypi, оптимальным вариантом является rst файл, в формате reStructuredText. Основная причина в том, что движок pypi при загрузке исходного кода автоматически распознает readme-файл в таком формате и отображает его содержимое на странице с информацией о пакете. Markdown-файлы тоже подойдут для этих целей, но в этом случае нужно будет добавить указание используемого формата в файл setup.cfg.

В качестве примера качественного rst-файла могу привести в пример описание проекта httpie: readme.rst.

MANIFEST.in

Файл "MANIFEST.in" нужен в определенных случаях, когда в состав пакета необходимо включать дополнительные файлы, которые python setup.py sdist (или bdist_wheel) не добавляют автоматически. Список файлов, которые автоматические добавляются в архив с исходным кодом можно посмотреть на странице официальной документации к distutils.

За деталями по заполнению этого файла можно обратиться к документации по шаблону MANIFEST.in. В случае заполнения этого файла для django-приложений, в нем необходимо указывать пути к файлам с шаблонами и статическим файлам (javascript, css и так далее).

Создание распространяемого пакета

Минимальным условием успешной публикации проекта на PyPi является наличие распространяемого пакета с исходным кодом. Создать его можно выполнив в корне проекта команду

$ python setup.py sdist

В директории пакета будет создана папка dist, а внутри этой папки архив package-x.y.z.tar.gx, который и будет содержать распространяемый исходный код пакета. Полученный архив можно скопировать на любой компьютер и установить командой

$ pip install /path/to/package-x.y.z.tar.gx

Такой вариант пакета представляет собой распространяемый "исходный код" и все еще требует выполнение процесса сборки в ходе установки с помощью pip. Даже если пакет написан на чистом python (не содержит C-расширений), при установке необходимо будет извлечь метаданные из setup.py.

Альтернативой являются python-"колеса" (wheel). Wheel - это установочный пакет, который можно устанавливать минуя процесс сборки. Установка wheel значительно быстрее, чем установка из архива с исходным кодом.

Если проект написан на чистом python-е (не содержит компилируемых расширений) и поддерживает обе версии языка (2 и 3), то создаваемые wheel будут называться универсальными.

Создание универсальных wheel выполняется командой

$ python setup.py bdist_wheel --universal

После выполнения этой команды, в папке ./dist внутри проекта появится файл package-x.y.z-py2.py3-none-any.whl.

Как альтернатива, флаг --universal можно установить в файле setup.cfg в корне проекта:

[bdist_wheel]
universal=1

Но помните: флаг --universal можно использовать только в случае, если:

  • Проект запускается с версиями языка 2 и 3 без изменений (не требует 2to3)
  • Проект не содержит C-расширений

Подробнее про wheel можно почитать в официальном руководстве по подготовке и распространению python-пакетов.

Регистрация пакета на PyPi

Регистрируемся на основном сайте PyPi и на тестовом PyPi Test. Для упрощения дальнейших действий, можно использовать один и тот же email и пароль на обоих сайтах. Первый сайт - основной, с него происходит установка пакета, когда вы набираете в командной строке pip install что-то-там, на него мы будем заливать код после всех приготовлений и проверок. Второй сайт, как следует и названия, используется для проверки и выполнения тестовых загрузок. С его помощью можно проверить весь процесс на наличие ошибок до загрузки кода на официальный PyPi.

Согласно официальному руководству по использованию PyPiTest, их база данных регулярно очищается. Так что, не удивляйтесь, если через некоторое время ваша учетная запись и, вероятно, загруженные в качестве экспериментов пакеты, пропадут с сайта.

Регистрация на этих сайтах ничем не отличается от любого другого: на почту приходит письмо со ссылкой, кликаем, подтверждаем и все готово. В домашней папке создаем файл pypirc, в котором указываем учетные данные, использовавшиеся при регистрации:

[distutils]
index-servers =
  pypi
  pypitest

[pypi]
repository=https://pypi.python.org/pypi
username=<ваш логин>
password=<ваш пароль>

[pypitest]
repository=https://testpypi.python.org/pypi
username=<ваш логин>
password=<ваш пароль>

Строку с паролем можно оставить пустой. В этом случае загрузку пакета на pypi нужно будет производить с указанием параметра -p PASSWORD (в случае использования twine) или просто ввести пароль по запросу в командной строке в процессе загрузки.

После этого переходим в директорию с нашим проектом, и регистрируем его на pypitest. Сделать это можно двумя способами, не рекомендованным

python setup.py register -r https://testpypi.python.org/pypi

и при помощи twine:

$ twine register -r https://testpypi.python.org/pypi dist/project_name-x.y.z.tar.gz

Второй вариант является предпочтительным, так как в этом случае для передачи данных используется зашифрованное https соединение. Но в этом случае сначала необходимо установить пакет twine при помощи pip install twine. Подробнее об этом пакете и о том, как его использовать, можно прочитать в документации на github.

После успешной регистрации переходим к основному процессу - загрузке кода на сервер. Тут у нас снова есть два варианта:

python setup.py sdist upload -r pypitest

или с использованием twine:

twine upload dist/* -r testpypi

И снова, как и в случае с регистрацией, второй вариант является предпочтительным: передаются учетные данные от вашего pypi-аккаунта, и в первом случае используется открытый текст через http, а во втором - https.

После успешной загрузки можно провести тестовую установку пакета используя testpypi репозиторий:

pip install -i https://testpypi.python.org/pypi 

Если все прошло отлично, повторяем регистрацию и загрузку пакета для настоящего pypi-сервера:

twine register dist/project_name-x.y.z.tar.gz
twine upload dist/*

и мы закончили, поздравляю!

Ссылки: