Хабрахабр

[Перевод] 10 шагов к успешному Python-проекту

Материал, перевод которого мы сегодня публикуем, посвящён инструментам, которые позволяют оснащать Python-проекты средствами форматирования кода, тестирования, непрерывной интеграции и анализа зависимостей. Это помогает ускорить процесс разработки, способствует повышению качества, единообразия и безопасности кода. Предполагается, что у читателя этого материала уже есть некоторый опыт Python-разработки и проект на Python, с которым он, в ходе чтения, будет экспериментировать. Если такого проекта у вас нет — здесь можно узнать о том, как подготовить среду разработки и создать Python-пакет. Примеры, которые будут здесь приводиться, подготовлены с использованием macOS и Python 3.7.

Шаг 1. Установка Black

Код проекта должен следовать соглашениям о стиле кода. Black — это Python-пакет, который автоматически форматирует код, приводя его внешний вид к стандарту PEP 8. Black — это сравнительно новый проект, но у него уже набралось больше миллиона загрузок. Его использование быстро стало признаком хорошего тона в Python-разработке. Вот руководство по Black.

О том, как его установить, можно узнать здесь. Я, в качестве редактора кода, использую Atom, поэтому я добавил в Atom пакет Python-Black. После установки этого пакета Atom будет переформатировать код после сохранения файла.

В итоге все, кто работает над проектом, будут использовать одни и те же правила форматирования кода, а в противном случае их пулл-запросы не будут приниматься. Пока мы говорим о Black — давайте оснастим этим средством среду разработки тех, кто вместе с нами трудится над проектом.

9b0 в первую нашедшуюся свободную строку файла requirements_dev.txt и выполните команду install -r requirements_dev.txt. Добавьте параметр black==18.

В некоторых руководствах по стилю, например — в Sphinx, требуется использовать длину строки, равную 79 символов. Black, по умолчанию, устанавливает длину строки кода равной 88 символов. В настройках пакета Black-Atom можно задать желаемую длину строки.

Теперь, когда мы обзавелись инструментом, который поможет экономить время на форматировании кода, подумаем о том, как ускорить и упростить отправку кода в PyPI.

Шаг 2. Создание файла .pypirc

Когда для отправки сборок приложения в TestPyPI и PyPI используется twine, сведения для входа в систему требуется вводить вручную. Если вы не знакомы с twine — взгляните на этот материал. Сейчас мы будем автоматизировать этот процесс.

Это средство, выгружая данные, берёт из данного файла URL, логин и пароль. Twine умеет работать с файлом .pypirc, который должен находиться в нашей домашней директории.

Итак, создадим в домашней директории файл .pypirc:

touch ~/.pypirc

Добавим в него следующий текст:

[distutils]
index-servers = pypi testpypi [testpypi]
repository: https://test.pypi.org/legacy
username = your_username
password = your_pypitest_password [pypi]
username = your_username
password = your_pypi_password

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

chmod 600 ~/.pypirc

Теперь ваш пакет можно загружать в TestPyPI пользуясь следующей командой:

twine upload -r testpypi dist/*

В обычный PyPI можно загружать пакеты так:

twine upload dist/*

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

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

Шаг 3. Установка и настройка pytest

Pytest — это самая популярная, лёгкая в использовании библиотека для тестирования кода, написанного на Python. В этом примере мы добавим в проект простые тесты. Вот, если вас интересуют подробности о pytest, хорошее вводное руководство по этому инструменту.

Добавим сведения о pytest в файл requirements_dev.txt:

pytest==4.3.0

Выполним установку пакета:

pip install requirements_dev.txt

Теперь выполним следующую команду, которая позволит pytest обнаружить наш пакет:

pip install -e .

Если вы деактивировали свою виртуальную среду разработки, то вам, для запуска тестов, понадобится снова выполнить обе команды pip.

Шаг 4. Создание тестов

Добавьте папку test в корневую директорию вашего проекта. Поместите в неё файл test_your_package_name.py. Мой файл называется test_notebookc.py. Если имя файла начинается с test_, pytest может автоматически обнаружить такой файл.

Модифицируйте этот код так, чтобы используемые в нём имена файлов и функций соответствовали бы вашим, опишите в нём собственные тесты. В файл test_notebookc.py я добавил следующий тест, который направлен на проверку того, правильное ли имя выводит функция.

"""Tests for `notebookc` package."""
import pytest
from notebookc import notebookc def test_convert(capsys): """Correct my_name argument prints""" notebookc.convert("Jill") captured = capsys.readouterr() assert "Jall" in captured.out

Что здесь происходит?

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

Далее — захватываем то, что выводит функция. После этого мы вызываем функцию (convert), передавая ей в качестве аргумента имя Jill. Она берёт параметр my_name и делает следующее: Тут стоит сказать, что рассматриваемая функция крайне проста.

print(f"I’ll convert a notebook for you some day, .")

Pytest проверяет, содержится ли Jall в том, что выводит функция. Там этой строки быть не должно, так как мы передаём функции Jill. Вот документация по pytest, в которой можно найти сведения о перехвате вывода.

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

В ходе теста выявлена ошибка

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

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

Успешное завершение теста

Тест позволяет убедиться в том, что если кто-то передаёт нашей функции строку, эта строка попадёт в тот текст, который выводит эта функция. Теперь всё хорошо.

А именно, если она получает данные, тип которых отличается от строкового, она должна вызывать ошибку TypeError. Ещё можно написать тест, который проверяет функцию на то, как она обращается с переданными ей данными. Вот хороший материал по исключениям и по обработке ошибок в Python.

Это называется разработкой через тестировании (Test-Driven Development, TDD). Когда мы создавали предыдущий тест, мы писали код, который приводит к успешному завершению теста. Вот полезный материал по TDD. TDD — это доказавший свою ценность подход к программированию, помогающий писать код, в котором оказывается меньше ошибок, чем в нём было бы без использования TDD.

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

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

Шаг 5. Регистрация в сервисе Travis CI и его настройка

Travis CI — это «распределённый веб-сервис для сборки и тестирования программного обеспечения». Его недавно купила компания Idera. Существуют и другие системы непрерывной интеграции, но Travis CI — это популярный, бесплатный для опенсорсного применения и хорошо документированный инструмент, поэтому мы будем пользоваться именно им.

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

Далее, щёлкните по ссылке Review and add your authorized organizations на странице профиля. Cоздайте учётную запись на сайте https://travis-ci.org/. Щёлкните по Grant в разделе Organization access. Вам предложат ввести пароль для доступа к GitHub.

Настройка учётной записи Travis CI

Обычно для того чтобы обработка кода средствами Travis CI заработала бы, требуется что-то около минуты. Мне понадобилось синхронизировать аккаунт для того, чтобы в учётной записи появились бы сведения о notebooktoall и о репозитории notebookc. После этого нужно активировать репозиторий, воспользовавшись переключателем, показанным на следующем рисунке.

Активация репозитория

Тут нужно указать, может ли Travis выполнять сборку на основе отправленных в репозиторий пулл-запросов или веток. Теперь нужно щёлкнуть по кнопке Settings.

Настройка сборки проекта

Сейчас пришло время настроить проект, над которым мы работаем, что даст возможность Travis выполнять сборку проекта для каждого пулл-запроса.

Шаг 6. Создание файла .travis.yml

В корневой папке проекта создайте файл .travis.yml со следующим содержимым:

dist: xenial
language: python
python: 3.7.2
install: - pip install -r requirements_dev.txt - pip install -e . script: - pytest

Строка dist: xenial нужна для того чтобы указать Travis на необходимость использования для организации виртуального окружения Ubuntu Xenial 16.04. Для тестирования кода Python 3.7 нужна именно Ubuntu Xenial, подробности об этом можно почитать здесь.

Команда pip install -e . выполняет установку нашего пакета в виртуальном окружении Travis. Раздел install позволяет обеспечить установку пакетов, используемых при разработке проекта. После этого Travis, запуская pytest, сможет найти наш пакет.

Шаг 7. Тестирование в Travis CI

Выполните коммит изменений, отправьте их на GitHub, выполните PR. Travis должен, в течение нескольких секунд, начать работу.

Travis за работой

Вот чем занимается Travis, обрабатывая проект.

Действия, выполняемые Travis при обработке проекта

Обратите внимание на то, что если пулл-запрос оказался неудачным, то можно отправить изменения в ту же ветку и Travis автоматически примется за работу. Если PR оказался неудачным — Travis об этом сообщит.

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

Если же предположить, что всё прошло хорошо, если на странице находятся надписи зелёного цвета, значит проверка и сборка проекта выполнены успешно.

Сборка проекта выполнена успешно

Если вы видите тут сообщения об ошибках, выводимые красным цветом — проанализируйте их. Если же на странице нет ни зелёных, ни красных надписей, откройте меню More options и выберите пункт Requests. Исправьте это и ошибка исчезнет. Если вы видите сообщение об ошибке Build config file is required, это означает, что Travis не может найти в репозитории ваш файл .travis.yml.

Travis отправляет пользователям электронные письма в тех случаях, когда сборка проекта оказывается неудачной, и в тех случаях, когда это удаётся исправить.

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

Теперь проанализируем наш проект на предмет покрытия кода тестами.

Шаг 8. Оценка покрытия кода тестами

Отчёт о покрытии кода тестами позволяет узнать о том, какая часть кода проекта, пусть и небольшая, протестирована. Для создания подобных отчётов мы будем пользоваться пакетом pytest-cov.

В файл requirements_dev.txt добавим следующую строку:

pytest-cov==2.6.1

Выполним такую команду:

pytest --cov=my_project_name

В моём случае, после выполнения команды pytest --cov=notebookc был выведен следующий отчёт.

Отчёт о покрытии кода тестами

Таких показателей очень легко достичь в том случае, если весь проект состоит из нескольких строк кода. Как оказалось, весь код проекта обеспечен тестами.

Теперь поговорим о средстве, которое позволяет вести общедоступную историю состояния проекта в плане покрытия его кода тестами.

Шаг 9. Использование Coveralls

Проект Coveralls позволяет поддерживать исторические сведения о покрытии кода тестами.

Coveralls

Потом нужно подключить репозиторий. Для того, чтобы воспользоваться возможностями этого проекта, нужно зарегистрироваться на сайте https://coveralls.io/, используя данные учётной записи GitHub.

6. В файл requirements_dev.txt нужно добавить строку coveralls==1. Этот файл, кстати, на данном этапе работы над проектом должен выглядеть так: 0.

pip==19.0.3
wheel==0.33.0
twine==1.13.0
pytest==4.3.0
pytest-cov==2.6.1
coveralls==1.6.0

Отредактируем файл .travis.yml, приведя его к такому виду (в вашем случае здесь будет название вашего проекта):

dist: xenial
language: python
python: 3.7.2
install: — pip install -r requirements_dev.txt — pip install -e . script: — pytest --cov=my_package_name
after_success: — coveralls

Теперь, когда Travis будет собирать проект, он установит необходимые пакеты, запустит тесты и создаст отчёт о покрытии кода тестами. Затем этот отчёт будет отправлен на сервис Coveralls.

На то, чтобы отчёт о покрытии кода тестами попал бы в Coveralls, может потребоваться несколько минут. Выполните коммит, отправьте код в GitHub и понаблюдайте за тем, что происходит.

Обработка проекта, отчёт о покрытии кода тестами

Теперь среди проверок PR присутствует и проверка, выполняемая средствами Coveralls.

На странице Coveralls можно убедиться в том, что проект покрыт тестами на 100%.

Сведения о покрытии кода тестами

Теперь давайте оснастим наш проект ещё одним полезным инструментом.

Шаг 10. Работа с PyUp

Сервис PyUp.io позволяет разработчику узнавать о том, устарели ли используемые им зависимости, а также о том, имеют ли они уязвимости. Этот сервис автоматически выполняет пулл-запросы, направленные на обновление пакета на GitHub. Для того чтобы воспользоваться возможностями этого проекта, нужно зарегистрироваться, пользуясь учётной записью GitHub, на его сайте — https://pyup.io/. При добавлении репозитория рекомендуется установить периодичность обновлений (Update Schedules) в значение every week. При таком подходе, если у вашего проекта множество зависимостей, вы не столкнётесь со слишком большим количеством пулл-запросов.

Настройка обновлений

Вот как выглядят сведения о пакетах, некоторые из которых устарели, на сайте PyUp.io.

Сведения о пакетах

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

Итоги

Из этого материала вы узнали о том, как пользоваться при разработке Python-проектов такими средствами, как Black, pytest, Travis CI, Coveralls и PyUp. Они помогают контролировать зависимости проектов, форматировать и тестировать код, проверять и собирать проекты. Надеемся, вам эти инструменты пригодятся.

Уважаемые читатели! Какими инструментами вы пользуетесь при разработке Python-проектов?

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть