Пишем обертку над API, делаем из нее PIP-пакет, подключаем тестирование от Travis CI и смотрим на лицензии открытого ПО

a366758d9cce4775b49aa1d40633c057.png

Приветствую, Хабрахабр! Данная статья будет полезна желающим ознакомиться не только с оформлением собственного пакета Python Package Index (PIP), но и с различными вспомогательными инструментами, помогающими сопровождать разработку на всех стадиях — на примере авторской работы.

Необходимые инструменты:

  • среда разработки — написание объектно-ориентированного кода, тесно работающего с интерфейсом приложения (в нашем случае веб-сайта), другими словами — отправка и обработка запросов к API, и дополнительных вспомогательных файлов;
  • загрузка своих наработок в общий каталог пакетов — PyPI;
  • Github — создание репозитория с целью контроля качества, улучшения и перманентного обновления библиотеки, общего взаимодействия с областью открытого исходного кода;
  • одна из лицензий свободного программного обеспечения, в нашем случае — MIT License;
  • Travis CI — непрерывная сборка и тестирование разрабатываемого проекта в различных окружениях (например, разные версии языка или интерпретатора).

Данный список можно принимать за содержание статьи в соответствующем порядке.

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

Введение


Я — постоянный посетитель различных интернет-ресурсов, в том числе одного известного украинского сообщества программистов, а по совместительству и постоянно практикующий программист, — поэтому за недостатком идей ринулся конструировать реализацию статистики публикаций (на примере Хабрахабра) (см. рисунок ниже) для пользователей площадки. Не важно, в каком виде проект будет реализован, но промежуточной задачей является предмет обсуждения статьи — работа с API этого сайта, что в значительной мере облегчается написанием собственной обертки (PIP-пакета), включая несомненные дополнительные плюсы от разработки — например, интересная новая область и приобретенный опыт.

20758e946a8649fd97d373dff3ccb74e.png

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

Пример окончательного варианта — DouAPI (ссылка на github, держите ее открытой параллельно со статьей и обращайтесь для детализации описываемого, не забудьте прочитать описание репозитория). В нем отсутствуют нужные файлы для тестирования и какие-то вспомогательные решения (например, вынести в отдельное место объемный код, выполняющий форматирование строк или обработку дополнительных запросов), но только из-за отсутствия такого требования на данном этапе разработки.

Непосредственно структура самого пакета должна состоять из главного каталога, подкаталога с основным и вспомогательными файлами и файла дистрибуции «setup.py».

7dd65d75e35444d4808bfbe8687a7e41.png

Для большей ясности стоит начать описание реализации с модуля «api.py» (ссылка на github) — импортирование модуля Requests, позволяющего обращаться с HTTP-запросами на улучшеном уровне.

import requests

Создание непосредственно отдельного класса для обращения по заданным к API сайта по заданным URL определенным методом. Если ваша разработка будет ограничиваться какими-то факторами и создание дополнительного класса для запросов излишне — создавайте закрытый метод уже в основном классе, но если вы не знаете, как далеко зайдет проект, какие фичи вы захотите добавить и какая сложность вас ждет — лишним не будет, чтобы не тратить время на переписывание кода.
class DouAPI(object):

    def method(self, method, values=None):

        if values is not None: values['limit'] = 10000

        response = requests.get('https://api.dou.ua/{0}/'.format(method), params=values)

        if response.status_code == 200:
            return response.json()['results']
        else:
            message = 'A request to the Dou API was unsuccessful. The server returned HTTP {0} {1}.'
            return message.format(response.status_code, response.reason)

Вызов функции «method», принимающий название метода, которое соответствует необходимому URL и набору ключей-значений (HTTP Headers), возвращает результат в виде формата JSON (такой же набор ключей-значений) в успешном случае, и просто строку с кодом ошибки и причиной ответа в противном случае (так старайтесь не делать, лучше создавать отдельно свои пользовательские исключения, как написано здесь или здесь).
Класс, к которому дальше обращается программист через объект (все остальное, что выходит за рамки требуемых инструментов, заворачивайте в приватные переменные и методы), содержит одну функцию «lenta», возвращающую объект класса с методом запросов, передавая название метода «articles» и набор ключей-значений (например, категорию и автора).
class Dou():
    __slots__ = ('_dou')

    def __init__(self):
        self._dou = DouAPI()

    def lenta(self, category=None, tag=None, author=None, date_from=None, date_to=None):

        values = locals().copy()
        values.pop('self')

        values = {header:value for header, value in values.items() if value != None}

        return self._dou.method('articles', values=values)

Так в итоге выглядит пример использования обертки — импортируем необходимый класс, создаем объект, обращаемся к методу класса, указывая интересующие параметры, получаем в ответ данные в формате JSON.
from dou import Dou

dou = Dou()

news = dou.lenta(category = 'news', date_from='2016-06-01')

print(news)

Если проиллюстрировать процесс, взаимодействие происходит следующим образом:
2110aac9162045f48440a0ec1173cce8.png

Теперь рассмотрим момент с файлом
»__init__.py», позволяющим проинициализировать класс реализации на уровне обращения к каталогу, записываем в него следующее (ссылка на github).
from .api import Dou

Финальный этап — «setup.py» (ссылка на github) описывает ряд данных, которые необходимы для сборки проекта из исходников (подробнее здесь) — понятнее станет на практике, когда повзаимодействуете с архивацией и распределением пакета. Описывать что-либо излишне, все должно быть понятно интуитивно.
try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

setup(
    name='DouAPI',
    version='1.0.0',
    author='DmytryiStriletskyi',
    author_email='dmytryi.striletskyi@gmail.com',
    url='https://github.com/DmytryiStriletskyi/DouAPI',
    description='Dou API wrapper',
    download_url='https://github.com/DmytryiStriletskyi/DouAPI/archive/master.zip',
    license='MIT',

    packages=['dou'],
    install_requires=['requests'],

    classifiers=[
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ]
)

Python Package Index (PIP)


В сети существует множество инструкций по инсталляции пакетов в общий каталог, поэтому в данной статье я буду описывать один-единственный метод, который оказался наиболее удобным и продуктивным для меня:
  1. Регистрируем профиль в PyPI;
  2. устанавливаем утилиту «Twine» для регистрации и загрузки пакетов (подробнее здесь) прямо в корень проекта — «pip install twine»;
  3. комплектуем дистрибутив — «python setup.py sdist»;
  4. следующий этап — «колеса», это современный формат распространения (фактически заархивированные данные) пакетов — «python setup.py bdist_wheel» (подробнее здесь и здесь);
  5. регистрация проекта — необходимо передать указанные метаданные («setup.py»), которые расположены в файле PKG-INFO (находится внутри архивированного проекта);
  6. финальный этап — загрузить пакет — «twine upload dist/*».

Подробное руководство расположено по ссылке, есть вариант использования также тестового сервера и авторизации из каталога — здесь, в сети доступен материал на русском языке.

Остальные взаимодействия происходят через личный аккаунт в PyPI: удаление, редактирование, журнал историй, релизы, роли и так далее.

Репозиторий пакета


Если проделанная работа в перспективе может стать востребована аудиторией, нужно предпринять следующий ряд мер: собственно создать репозиторий, оформить титульный лист проекта (README.md), подключить тестирование и выбрать лицензию. Если с двумя первыми файлами понятно все, то следующие требуют уточнений.

Лицензия открытого программного обеспечения


Существует разнообразное множество лицензий, но лидирующие позиции занимают MIT License, Apache License и GPL. Я использую первую —
она разрешает использование и изменение кода любым образом (при условии наличия копирайта), а также имеет маленький размер. Существуют и минусы — отсутствует патентное право, присущее другим лицензиям, но маленьким проектам данная лицензия подходит хорошо.

Например, вот так выглядит лицензия в моем репозитории — MIT License, Github сам поставит наличие лицензии в верхнюю панельку репозитория.

Тестирование проекта


Travis CI — если описать простыми словами, то каждое изменение в вашем проекте тестируется на указанных вами окружениях. Данная площадка достаточно легкая в использовании — помещаем файл (ссылка на github) с названием ».travis.yml» в корневой каталог, в котором указывают: язык программирования, необходимые версии, интерпретаторы языка, какие зависимости установить при интеграции и разворачивании на сервере, плагин тестирования и еще ряд параметров.

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

add273cd254b46c39856356a2b6f49d5.png

Первым делом устанавливаем крюк на репозиторий, следом добавляем файл ».travis.yml», затем пушим изменения в проекте и наблюдаем за результатами.
fed911a7ec924ae3a77abaf1590d63ad.png

Буду рад, если данная статья поможет кому-нибудь в освоении нового материала или пробудит интерес к этой области. Присылайте свои вопросы и советы, если они у вас есть, в личные сообщения.

Комментарии (1)

  • 23 января 2017 в 21:15

    0

    script: nosetests

    А где собственно тесты-то?)

© Habrahabr.ru