Делал оптимизацию своей библиотеки кеширования ответов от API. Нужно было выяснить, какие функции заставляют обращаться в API минуя кеш. Мне нужно было видеть полный стек вызова функции запроса в API.
Конечно же первое что приходит в голову это traceback.print_stack(). Но мне не нравится его многословное форматирование. Поэтому я решил сделать свой аналог.
Делается это совсем не сложно, достаточно посмотреть как работает функция print_stack() и сделать аналогично. Все дополнительные функции уже имеются в модуле traceback.
Первым делом достаём фрейм
frame = sys._getframe().f_back
Теперь преобразуем его в стек вызовов
stack = traceback.extract_stack(frame)
Теперь у нас есть список инстансов класса FrameSummary в порядке их вызова. Остаётся сделать вывод
for item in stack:
print(f"{os.path.basename(item.filename)}[{item.lineno}] -> {item.name}")
Получается что-то вроде такого
__main__.py[123] -> <module>
module1.py[456] -> func1
module2.py[789] -> func2
Как можно улучшить?
🔸 Фильтр по имени файла.
Удобно при работе через дебагер, например, в Pycharm. Пропускаются ненужные вызовы.
🔸 Выводить передаваемые аргументы.
Придется сделать свой extract_stack.
🔸 Добавить цвета
Пример реализации здесь. Просто вызовите эту функцию в том месте где требуется увидеть цепочку вызовов.
PS. Да, я знаю на сколько это странный способ дебага. Но такой инструмент потребовался под конкретную ситуацию и он справился хорошо.
PPS:
А теперь суровый хардкод! Всё в одну строку плюс некоторые дополнения в форматировании! (не повторяйте это дома!)
print_stack_simple = lambda: print(*[f"{' ' * i}{os.path.basename(item.filename)}[{item.lineno}] -> {item.name}{'()' if not '>' in item.name else ''}" for i, item in enumerate(traceback.extract_stack(sys._getframe().f_back)[:-1])], sep='\n')
#tricks