понедельник, 1 августа 2016 г.

Создаем и публикуем модуль Python



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

Разницы с C++ тут большой нет — программой может быть как один файл, так и группа файлов. Упрощенно можно сказать, что один файл — это модуль (module), а набор модулей в пределах одной директории — пакет (package) или библиотека. Пакет также может содержать в себе дочерние пакеты. Поскольку язык интерпретируемый, то запускать на выполнение отдельные файлы можно следующим образом:
$ python foo.py
Если у вас в системе установлен какой-либо пакет, либо вы просто находитесь в директории, где есть пакет, то запустить его можно так:
$ python -m bar.foo
Где foo — это файл foo.py в пакете bar. У пакетов есть также скрипты с зарезервированными названиями, которые запускаются автоматически. Так, если в пакете bar есть скрипт __main__.py, то он будет запущен автоматически при выполнении python -m bar.

Также стоит обратить внимание на файл __init__.py. Именно его наличие говорит Питону, что данная директория является пакетом. Часто бывает, что этот файл оставляют пустым, но можно там разместить какие-то общие для всех модулей вещи.

Теперь посмотрим на небольшой пакет из реальной жизни и его структуру. Для пояснений я буду использовать свой проект ZXTools, который предназначен для работы со старыми дисками от ZX-Spectrum. Как-нибудь я подробнее расскажу о процессе разбора дискет от Спектрума. Пока же посмотрим на структуру проекта. Он состоит из двух директорий (test и zxtools) и из нескольких файлов в корне. Далее рассмотрим зачем там каждый из них.

LICENSE

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

README.rst

Файл README также должен быть хорошо знаком тем, кто уже публиковал свои работы или использовал чужие. Тут указывается полезная информация о проекте, для чего он предназначен и как им пользоваться. Обратите внимание на формат файла. Чаще встречаются файлы README.md, что означает файл в формате Markdown, но для проектов на Python лучше использовать reStructuredText, так как только его корректно поддерживает Python Package Index. А ведь именно на PyPI публикуются пакеты, которые потом легко устанавливаются с помощью пакета pip. GitHub прекрасно поддерживает RST формат, поэтому вы ничего не потеряете.

Makefile

«Что в проекте на Python делает Makefile?» — спросите вы. А делает он то же, что и в C++ — автоматизирует некоторые шаги. В моем проекте он используется для удобной очистки директории (знакомая цель clean), для запуска юнит-тестов (цель test), для анализа тестового покрытия (цель coverage) и для статического анализа (цель lint). Если вы ведете разработку под Windows, то Makefile возможно окажется не самым привычным средством. Тогда используйте привычный и удобный именно вам механизм, но не слишком усложняйте.

setup.py

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

Полезно тут же указать какие командные скрипты необходимо создать при установке. Такие скрипты сильно упрощают использование вашего пакета, так как не нужно будет помнить в каком пакете находятся нужные команды и не нужно писать длинную строку их вызова. В примере можно видеть раздел entry_points, в котором определены две команды:
entry_points={
        'console_scripts': [
            'zeus2txt = zxtools.zeus2txt:main',
            'hobeta = zxtools.hobeta:main',
        ],
    },
Команды имеют следующий формат: <имя пакета>.<имя модуля>:<имя функции>.

Также стоит обратить внимание на параметр test_suite. В нем указывается пакет, который отвечает за тестирование вашего проекта. В данном случае указан пакет test.

Публикация, запуск тестов и continuous integration

Я уже упоминал, что самое популярное место для публикации пакетов — это индекс PyPI. Помимо этого, для открытых проектов TravisCI предоставляет бесплатную возможность запуска тестов на каждый коммит, а codecov.io позволяет отслеживать изменение покрытия и сигнализирует о проблемах. Именно эти средства я использовал в ZXTools. В следующий раз подробнее расскажу как опубликовать пакет, автоматически запускать проверку тестов, считать покрытие и как добавить красивые бейджики с информацией об этих процессах.

Книги по теме:

  1. Марк Лутц. Программирование на Python. Том 1
  2. Марк Лутц. Программирование на Python. Том 2

Комментировать в ВКонтакте