![](https://habrastorage.org/getpro/habr/upload_files/8f4/185/45b/8f418545b94268e088cadb65a49d30ee.png)
Файлы блокнотов Jupyter, в смысле количества одного из самых быстрорастущих типов файлов на Github, предоставляют простой интерфейс для итераций при решении визуальных задач, будь то анализ наборов данных или написание документов с большим объёмом кода. Однако популярность блокнотов Jupyter сопровождается проблемами: в репозитории накапливается большое количество файлов ipynb, многие из которых находятся в нерабочем состоянии. В результате другим людям трудно повторно запустить или даже понять ваши блокноты. В этом руководстве рассказывается, как для автоматизации сквозного (end-to-end) тестирования блокнотов можно воспользоваться плагином pytest nbmake.
К старту флагманского курса о Data Science — области, в которой блокноты Jupyter незаменимы — делимся переводом статьи из блога CI Semaphore о том, как при помощи Semaphore проверить, что ваши блокноты Jupyter находятся в рабочем состоянии и для этого больше не запускать блокноты вручную.
Предварительные требования
Это руководство предполагает владение основными навыками тестирования проектов на Python, о них рассказывается в статье Непрерывная интеграция и развёртывание на Python с нуля. Прежде чем продолжить, пожалуйста, убедитесь, что вы знакомы с основами и на вашем компьютере установлен набор инструментов Python 3, таких как pip + virtualenv.
Демонстрационное приложение
Обычно проекты Python содержат папки с файлами блокнотов с расширением .ipynb, это может быть:
код доказательства концепции;
документация с примерами применения API;
длинный научный туториал.
В этой статье мы разберём, как автоматизировать простые сквозные тесты некоторых блокнотов, содержащих упражнения на Python. Благодарим pytudes за предоставленные для нашего примера материалы; воспользуемся этим примером проекта, не стесняйтесь делать форк и клонировать его с GitHub:
![fig: fig:](https://habrastorage.org/getpro/habr/upload_files/6cf/f80/2e9/6cff802e935f5dffdecefe879cc2cdd8.png)
Внутри репозитория вы найдёте содержащую блокноты папку, она называется ipynb. Установите зависимости из requirements.txt, а при необходимости сначала создайте виртуальную среду.
Прежде чем перейти к следующему шагу, посмотрите, можно ли запустить эти блокноты в вашем редакторе.
Локальное тестирование блокнота
Вполне вероятно, что до этого момента при тестировании вы запускали блокноты вручную через пользовательский интерфейс Jupyter Lab или аналогичный клиент. Однако этот подход отнимает много времени и подвержен ошибкам.
Давайте начнём автоматизировать этот процесс в вашей среде разработки; первым шагом в автоматизации станет nbmake. Nbmake — это пакет python и плагин к pytest. Он разработан автором этого руководства и используется известными научными организациями, такими как Dask, Quansight и Kitware. Вы можете установить nbmake с помощью pip:
pip install nbmake==0.5
Перед первым тестированием блокнотов давайте проверим, всё ли правильно настроено, указав pytest просто собрать (но не запускать) все тест-кейсы для блокнотов.
? pytest --collect-only --nbmake "./ipynb"
================================ test session starts =================================
platform darwin -- Python 3.8.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /Users/a/git/alex-treebeard/semaphore-demo-python-jupyter-notebooks
plugins: nbmake-0.5
collected 3 items
============================= 3 tests collected in 0.01s =============================
Мы видим, что pytest собрал несколько элементов.
Примечание: если вы получаете сообщение unrecognized arguments: --nbmake, оно означает, что плагин nbmake не установлен. Такое может произойти, если ваш CLI вызывает двоичный файл pytest за пределами текущей виртуальной среды. Проверьте, где находится ваш двоичный файл pytest, с помощью команды which pytest.
Теперь, когда мы проверили, что nbmake и pytest видят ваши блокноты и работают вместе, давайте выполним настоящие тесты:
? pytest --nbmake "./ipynb"
================================ test session starts =================================
platform darwin -- Python 3.8.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /Users/a/git/alex-treebeard/semaphore-demo-python-jupyter-notebooks
plugins: nbmake-0.5
collected 3 items
ipynb/Boggle.ipynb . [ 33%]
ipynb/Cheryl-and-Eve.ipynb . [ 66%]
ipynb/Differentiation.ipynb . [100%]
================================= 3 passed in 37.65s =================================
Отлично, блокноты прошли тесты. Однако это простые блокноты в демонстрационном проекте. Очень маловероятно, что все ваши блокноты пройдут тесты с первого раза, поэтому давайте рассмотрим некоторые подходы к запуску сложных проектов.
Игнорирование ожидаемых ошибок в блокноте
Не все блокноты можно легко протестировать автоматически. Некоторые из них будут содержать ячейки, требующие от пользователя ввода данных, или блокноты, которые для демонстрации некоторой функциональности вызывают необработанные исключения.
К счастью, чтобы указать nbmake, что такие блокноты нужно игнорировать и продолжать работу после возникновения ошибок, в метаданные нашего блокнота мы можем поместить директивы. Возможно, вы раньше не использовали метаданные блокнота, поэтому самое время упомянуть, что, несмотря на их расширение ipynb, блокноты — это просто JSON-файлы. Чтобы добиться от них нового поведения, добавьте новые поля:
откройте файл .ipynb в простом текстовом редакторе, например Sublime;
в метаданных блокнота найдите поле kernelspec;
добавьте объект execution в качестве родственного элемента kernelspec.
Должно получиться что-то вроде этого:
{
"cells": [ ... ],
"metadata": {
"kernelspec": { ... },
"execution": {
"allow_errors": true,
"timeout": 300
}
}
}
Теперь можно перезапустить блокнот, чтобы проверить, что JSON валиден, а ошибки игнорируются.
Ускорение тестов с помощью pytest-xdist
В крупных проектах может быть много блокнотов, каждый из которых требует много времени на установку пакетов, извлечение данных из сети и выполнение анализа. Если ваши тесты занимают более нескольких секунд, стоит проверить, как на время выполнения повлияет распараллеливание. Сделать это можно с помощью другого плагина pytest — pytest-xdist. Сначала установите пакет xdist. Это похожий на nbmake плагин pytest, он добавит новые параметры командной строки:
pip install pytest-xdist
Запустите команду ниже с количеством рабочих процессов, равным auto:
pytest --nbmake -n=auto "./ipynb"
Запись выполненных блокнотов обратно в репозиторий
По умолчанию тесты доступны только для чтения, то есть ваш файл ipynb на диске остаётся неизменным. Обычно это хорошее значение по умолчанию, потому что во время выполнения блокнота ваш редактор может быть открыт. Однако в некоторых ситуациях может потребоваться сохранить результаты теста на диске. Например, если вам нужно:
отладить неработающие блокноты путём просмотра выходных данных;
создать коммит в вашем репозитории с блокнотами в воспроизводимом состоянии;
встроить выполненные блокноты в сайт с документацией при помощи nbsphinx или jupyter book.
Мы можем направить nbmake на сохранение выполненных блокнотов на диск с помощью флага overwrite:
pytest --nbmake --overwrite "./ipynb"
Исключение блокнотов из тестов
Некоторые блокноты может быть трудно протестировать автоматически из-за необходимости ввода данных через stdin самим пользователем или длительного времени запуска. Чтобы отменить выбор, воспользуйтесь флагом игнорирования pytest:
pytest --nbmake docs --overwrite --ignore=docs/landing-page.ipynb
Примечание: это не сработает, если вы выбираете все блокноты с помощью шаблона поиска, например (*ipynb), вручную переопределяющего флаги игнорирования pytest.
Автоматизация тестирования блокнотов на Semaphore CI
С помощью вышеописанных методов можно создать автоматизированный процесс тестирования с использованием непрерывной интеграции (CI) Semaphore. Ключ здесь — прагматизм: нужно найти способ протестировать большую часть ваших блокнотов и проигнорировать сложные блокноты; это хороший шаг к улучшению качества.
Начните с создания содержащего ваши блокноты проекта для репозитория. Выберите “Choose repository”:
![](https://habrastorage.org/getpro/habr/upload_files/17d/6db/11f/17d6db11f1843123bbaa850ade768cb4.png)
Затем подключите Semaphore к репозиторию с вашими блокнотами:
![](https://habrastorage.org/getpro/habr/upload_files/dd3/bfe/d5e/dd3bfed5e8fe6290fcea1b2e1a9abff5.png)
Пока пропустите “Add People”, чтобы мы могли настроить рабочий процесс с нуля (даже если вы работаете с деморепозиторием). Semaphore предоставляет некоторую начальную конфигурацию, настроим её перед запуском:
![](https://habrastorage.org/getpro/habr/upload_files/f5d/643/720/f5d643720e5dbad22798b9c653b54731.png)
Создайте простой рабочий процесс в один блок; ниже о процессе в деталях:
Названием блока будет Test.
Названием задачи — Test Notebooks.
В поле Commands введите команды ниже:
checkout
cache restore
pip install -r requirements.txt
pip install nbmake pytest-xdist
cache store
pytest --nbmake -n=auto ./ipynb
Чтобы лучше понять происходящее, давайте разберёмся, что делает каждая команда:
checkout клонирует репозиторий с GitHub;
cache restore загружает зависимости Python из кэша Semaphore. Это ускоряет процесс установки;
pip устанавливает зависимости и инструменты;
cache store сохраняет загруженные зависимости обратно в кэш;
pytest запускает тесты nbmake.
Теперь мы можем запустить рабочий процесс. Не беспокойтесь, если конвейер выйдет из строя: далее мы рассмотрим распространённые проблемы.
![](https://habrastorage.org/getpro/habr/upload_files/544/11a/da5/54411ada5c785e7402cc5c4680ade5ac.png)
Конвейер должен заработать сразу же:
![](https://habrastorage.org/getpro/habr/upload_files/b9c/2b5/972/b9c2b5972b0061489481460b696e9ee3.png)
Устранение некоторых распространённых ошибок
Добавление отсутствующего ядра Jupyter в среду CI
Если вы используете имя ядра, отличное от имени по умолчанию — python3, то при выполнении ноутбуков в свежей среде CI увидите сообщение об ошибке: Error - No such kernel: 'mycustomkernel'. Чтобы установить пользовательское ядро, воспользуйтесь командой ipykernel:
python -m ipykernel install --user --name mycustomkernel
Если в своих блокнотах вы работаете с другим языком, например С++, ваш процесс установки ядра может быть другим.
Добавление недостающих секретов в среду CI
В некоторых случаях ваш блокнот получает данные от API, требующих токена или аутентифицированного CLI. Всё, что работает в вашей среде разработки, должно работать и на Semaphore. Чтобы увидеть, как настроить секреты, сначала посмотрите этот пост. Как только вы установили секреты в Semaphore, чтобы прочитать их из переменной среды в средах CI, вам может потребоваться настроить блокнот.
Добавление недостающих зависимостей в среду CI
Стек Data Science на Python часто требует установки собственных библиотек. Если вы работаете с CONDA, вполне вероятно, что они будут присутствовать в вашем нормальном процессе установки. Если же вы используете стандартные библиотеки Python, их присутствие немного менее вероятно.
Если вы пытаетесь установить необходимые вам библиотеки, посмотрите на статью о создании образа docker в CI. С ним тестирование упрощается, и по сравнению со стандартными средами Semaphore этот подход стабильнее во времени.
Пожалуйста, помните совет о прагматизме; 90 % полезности часто можно достичь за 10 % времени. Следование совету может привести к компромиссам, таким как игнорирование блокнотов, на которых запускаются требующие GPU модели ML.
Заключение
В этом руководстве показано, как можно автоматизировать тестирование блокнотов Jupyter, чтобы поддерживать их воспроизводимость. Блокноты оказались эффективным инструментом для построения технических нарративов. Однако из-за новизны некоторые команды разработчиков программного обеспечения исключают их использование до тех пор, пока не появятся более чёткие процессы для тестирования, ревью и повторного использования их содержимого.
Прежде чем технологии блокнотов органично впишутся в проекты ПО, предстоит пройти определённый путь, но сейчас самое время начать его. Возможно, вы захотите изучить некоторые из следующих пунктов дальнейшей работы, чтобы научиться лучше работать с блокнотами:
для удаления громоздких выходных данных блокнота перед коммитом запустите pre-commit и nbstripout;
для компиляции ваших блокнотов в красивый сайт с документацией используйте jupyter book;
для просмотра блокнотов в пул-реквестах используйте ReviewNB.
Действительно, процессы в разработке ПО и в научных исследованих всё дальше уходят с локальных компьютеров на арендуемые мощности самого разного рода, в том числе потому, что требуют всё больших ресурсов. То же касается и растущих объёмов данных, работа с которыми преобразилась в несколько смежных, но очень разных областей; среди них центральное место занимает Data Science. Если вам интересна эта сфера, вы можете присмотреться к нашему курсу Data Science, итог которого — это 16 проектов, то есть 2-3 года постоянного самостоятельного изучения науки о данных.
![](https://habrastorage.org/getpro/habr/upload_files/b45/280/730/b45280730c1a24801d1b188873cf5cc4.png)
Узнайте, как прокачаться и в других специальностях или освоить их с нуля:
Другие профессии и курсы
ПРОФЕССИИ
КУРСЫ
uyrij
А тесты пишем прямо в том же .ypnb? Где и модели и расчеты? Ни декораторов/фикстур ничего такого нет? Просто накидать по блокноту asserts и пусть pytest считает процент фейлов, так?
nikolay_karelin
У меня возник тот же вопрос. Написал автору оригинального блога.