Привет, Хабрахабр! В этой статье буду делиться собственным опытом отладки большой незнакомой системы, но со стороны собственно написанного инструмента — pdbe. Он поможет с самого начала проекта разобраться в потоке выполнения кода в проекте. Если вам интересно, что спрятано под капотом и какие фичи вы можете использовать — прошу под кат.
Что такое pdbe
pdbe — это помощник встроенному Python-дебаггеру pdb, — позволяет вставить брейкпоинт (остановка программы для последующей отладки) под каждую функцию в любом файле в вашем проекте, во все файлы в указанной директории или во все файлы, которые спрятаны во всех директориях (рекурсивно обходит все директории в поисках файлов).
В арсенале pdbe спрятаны и другие интересные возможности, которые сделают его использование (и соответственно дебаг, может, даже в большей мере) более приятным и удобным.
Мотивация
Бывают разные ситуации в разработке, когда приходится изучать уже написанный код, который поддерживается (-лся) несколько лет — на работе, open source решения и фреймворки. Трудно понять с чего начать и как это работает.
Для себя я открыл pdbe — возможность вставить в каждую функцию проекта брейкпоинт, запустить проект, спровоцировать обработку на сервере (например, обновить страницу, вызвать функцию библиотеки, открыть сокеты) и начать отлаживать проект с самого начала процесса до конца обработки запроса, останавливаясь в каждой функции для ее изучения.
Есть и другие варианты — вы уже знаете проект, но отлаживать код все еще затруднительно, потому что идеально помнить как все внутри работает тяжело. Тогда можно «попросить» pdbe вставить брейкпоинты только в отдельное приложение проекта.
Установка
Здесь все просто, пакет написан на языке Python, поэтому установить можно с помощью pip.
$ pip3 install pdbe
Как использовать
Чтобы легче понять принципы работы, предположим, что у нас есть следующий код во всех python-файлах проекта, на примере которого вы увидите работоспособность pdbe.
def first_function():
...
def second_function():
...
def third_function():
...
Основные возможности
Импортируем брейкпоинты в виде import pdb; pdb.set_trace() в указанный файл (для файла флаг --file).
$ pdbe --file project/file_flag.py
(Иллюстрация покрытия отладкой следующих файлов на примере проекта)
В итоге получим следующее.
def first_function():
import pdb; pdb.set_trace()
...
def second_function():
import pdb; pdb.set_trace()
...
def third_function():
import pdb; pdb.set_trace()
...
Чтобы вернуть файл к первоначальному состоянию, пользуемся дополнительным флагом --clear. Все команды такого рода имеют возможность очистить файлы от брейкпоинтов.
$ pdbe --file project/file_flag.py --clear
Как упоминалось выше, иногда необходимо отладить часть приложения (папку, в которой несколько файлов), тогда стоит использовать флаг --dir.
$ pdbe --dir project/dir_flag
(Иллюстрация покрытия отладкой следующих файлов на примере проекта)
В итоге все файлы в указанном каталоге будут иметь выражение import pdb; pdb.set_trace() под каждой существующей в них функцией.
Тот же самый принцип и для директории, в которой могут быть спрятаны вложенные директории с файлами (флаг --ew, что аббревиатура от слова everywhere).
$ pdbe --ew project
В данном случае все вложенные файлы будут иметь внутри себя брейкпоинты.
Если вы уже находитесь в проекте, можно использовать точку вместо папки.
$ pdbe --ew .
(Иллюстрация покрытия отладкой следующих файлов на примере проекта)
Продвинутый уровень
Можно сохранить state (фактическое состояние файлов) вашей отладки. Это когда вы просите запомнить где находятся ваши брейкпоинты сейчас, чтобы в будущем, когда вы их оттуда удалите, вернуться к ним опять всего лишь одной-двумя командами pdbe. Обсудим на примере.
def first_function():
...
def second_function():
...
def third_function():
...
Как вы уже знаете, команда pdbe --file path/to/file.py превратит файл в следующее.
def first_function():
import pdb; pdb.set_trace()
...
def second_function():
import pdb; pdb.set_trace()
...
def third_function():
import pdb; pdb.set_trace()
...
Запомним, что мы внесли брейкпоинты в этот файл и дадим этому состоянию отладки название. Например, если файл содержит логику обработки сообщений, можно написать так.
$ pdbe --commit 'Message handler debug'
Потом, как только вам понадобиться проверить код на уровне пользователя, — очистить файл, чтобы режим отладки не включался.
$ pdbe --file path/to/file.py --clear
Как итог.
def first_function():
...
def second_function():
...
def third_function():
...
Через несколько часов, дней или тикетов вам снова нужно дебажить туже самую логику. Наверняка, и брейкпоинты ставить в тех же местах, да и вообще было бы хорошо вынести все это дело в абстракцию, чтобы было легче работать.
Смотрим наши логи коммитов.
$ pdbe --log
Результат:
commit | add336b6a204bb7b3abe76c296b67f92
date | 23:17:00 29-01-2018
message | Message handler debug
commit | 4401cbeae73aece0216de9f4874451b6
date | 23:11:22 29-01-2018
message | Users REST API get view
Вспоминаем по дате и/или сообщению коммитов, что именно нам надо. Используем хеш коммита для того, чтобы восстановить состояние нашей отладки на тот момент.
$ pdbe --checkout add336b6a204bb7b3abe76c296b67f92
В итоге все вернулось на момент коммита.
def first_function():
import pdb; pdb.set_trace()
...
def second_function():
import pdb; pdb.set_trace()
...
def third_function():
import pdb; pdb.set_trace()
...
Что планируется добавить
- Вставка logger`а. Иногда необходимо просто проследить порядок выполнения приложений.
- Дополнительная фича, в которую можно скормить название функции, класса или любого другого объека, а получить диаграму связей с объектом во всем проекте.
Спасибо, что уделили время публикации. Если вам интересен pdbe, заходите в гости на Github-страницу проекта. Если у вас есть отзывы или предложения, пишите в личные сообщения.