Привет, Хабрахабр! В этой статье буду делиться собственным опытом отладки большой незнакомой системы, но со стороны собственно написанного инструмента — 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()
        ...

Что планируется добавить


  1. Вставка logger`а. Иногда необходимо просто проследить порядок выполнения приложений.
  2. Дополнительная фича, в которую можно скормить название функции, класса или любого другого объека, а получить диаграму связей с объектом во всем проекте.

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

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