Рубрики
Без рубрики

traceback – Исключения и трассировки стека

Автор оригинала: Doug Hellmann.

Цель:

Извлечение, форматирование и печать исключений и трассировок стека.

Модуль traceback работает со стеком вызовов для создания сообщений об ошибках. traceback – это трассировка стека от точки обработчика исключения вниз по цепочке вызовов до точки, где было вызвано исключение. К трассировке также можно получить доступ из текущего стека вызовов вверх от точки вызова (и без контекста ошибки), что полезно для определения путей, по которым идет функция.

API высокого уровня в traceback использует экземпляры StackSummary и FrameSummary для хранения представления стека. Эти классы могут быть созданы из трассировки или текущего стека выполнения, а затем обработаны аналогичным образом.

Функции низкого уровня в traceback делятся на несколько общих категорий. Существуют функции для извлечения необработанных трассировок из текущей среды выполнения (либо обработчик исключений для трассировки, либо обычный стек). Извлеченная трассировка стека – это последовательность кортежей, содержащих имя файла, номер строки, имя функции и текст исходной строки.

После извлечения трассировку стека можно отформатировать с помощью таких функций, как format_exception () , format_stack () и т. Д. Функции форматирования возвращают список строк с сообщениями, отформатированными для печати . Также существуют сокращенные функции для печати форматированных значений.

Хотя функции в traceback по умолчанию имитируют поведение интерактивного интерпретатора, они также полезны для обработки исключений в ситуациях, когда выгрузка полной трассировки стека на консоль нежелательна. Например, веб-приложению может потребоваться отформатировать трассировку, чтобы она хорошо выглядела в HTML, а IDE может преобразовать элементы трассировки стека в интерактивный список, который позволяет пользователю просматривать источник.

Вспомогательные функции

Примеры в этом разделе используют модуль traceback_example.py .

traceback_example.py

import traceback
import sys


def produce_exception(recursion_level2):
    sys.stdout.flush()
    if recursion_level:
        produce_exception(recursion_level - 1)
    else:
        raise RuntimeError()


def call_function(f, recursion_level2):
    if recursion_level:
        return call_function(f, recursion_level - 1)
    else:
        return f()

Изучение стека

Чтобы проверить текущий стек, создайте StackSummary из walk_stack () .

traceback_stacksummary.py

import traceback
import sys

from traceback_example import call_function


def f():
    summary  traceback.StackSummary.extract(
        traceback.walk_stack(None)
    )
    print(''.join(summary.format()))


print('Calling f() directly:')
f()

print()
print('Calling f() from 3 levels deep:')
call_function(f)

Метод format () создает последовательность форматированных строк, готовых к печати.

$ python3 traceback_stacksummary.py

Calling f() directly:
  File "traceback_stacksummary.py", line 18, in f
    traceback.walk_stack(None)
  File "traceback_stacksummary.py", line 24, in 
    f()


Calling f() from 3 levels deep:
  File "traceback_stacksummary.py", line 18, in f
    traceback.walk_stack(None)
  File ".../traceback_example.py", line 26, in call_function
    return f()
  File ".../traceback_example.py", line 24, in call_function
    return call_function(f, recursion_level - 1)
  File ".../traceback_example.py", line 24, in call_function
    return call_function(f, recursion_level - 1)
  File "traceback_stacksummary.py", line 28, in 
    call_function(f)

StackSummary – это повторяемый контейнер, содержащий экземпляры FrameSummary .

traceback_framesummary.py

import traceback
import sys

from traceback_example import call_function

template  (
    '{fs.filename:<26}:{fs.lineno}:{fs.name}:\n'
    '    {fs.line}'
)


def f():
    summary  traceback.StackSummary.extract(
        traceback.walk_stack(None)
    )
    for fs in summary:
        print(template.format(fsfs))


print('Calling f() directly:')
f()

print()
print('Calling f() from 3 levels deep:')
call_function(f)

Каждый FrameSummary описывает кадр стека, включая информацию о том, где в исходных файлах программы находится контекст выполнения.

$ python3 traceback_framesummary.py

Calling f() directly:
traceback_framesummary.py :23:f:
    traceback.walk_stack(None)
traceback_framesummary.py :30::
    f()

Calling f() from 3 levels deep:
traceback_framesummary.py :23:f:
    traceback.walk_stack(None)
.../traceback_example.py:26:call_function:
    return f()
.../traceback_example.py:24:call_function:
    return call_function(f, recursion_level - 1)
.../traceback_example.py:24:call_function:
    return call_function(f, recursion_level - 1)
traceback_framesummary.py :34::
    call_function(f)

TracebackException

Класс TracebackException – это высокоуровневый интерфейс для создания StackSummary при обработке обратной трассировки.

traceback_tracebackexception.py

import traceback
import sys

from traceback_example import produce_exception

print('with no exception:')
exc_type, exc_value, exc_tb  sys.exc_info()
tbe  traceback.TracebackException(exc_type, exc_value, exc_tb)
print(''.join(tbe.format()))

print('\nwith exception:')
try:
    produce_exception()
except Exception as err:
    exc_type, exc_value, exc_tb  sys.exc_info()
    tbe  traceback.TracebackException(
        exc_type, exc_value, exc_tb,
    )
    print(''.join(tbe.format()))

    print('\nexception only:')
    print(''.join(tbe.format_exception_only()))

Метод format () создает отформатированную версию полной трассировки, а format_exception_only () показывает только сообщение об исключении.

$ python3 traceback_tracebackexception.py

with no exception:
None: None


with exception:
Traceback (most recent call last):
  File "traceback_tracebackexception.py", line 22, in 
    produce_exception()
  File ".../traceback_example.py", line 17, in produce_exception
    produce_exception(recursion_level - 1)
  File ".../traceback_example.py", line 17, in produce_exception
    produce_exception(recursion_level - 1)
  File ".../traceback_example.py", line 19, in produce_exception
    raise RuntimeError()
RuntimeError


exception only:
RuntimeError

API-интерфейсы исключений низкого уровня

Другой способ обработки отчетов об исключениях – использование print_exc () . Он использует sys.exc_info () для получения информации об исключении для текущего потока, форматирует результаты и печатает текст в дескриптор файла ( sys.stderr по умолчанию ).

traceback_print_exc.py

import traceback
import sys

from traceback_example import produce_exception

print('print_exc() with no exception:')
traceback.print_exc(filesys.stdout)
print()

try:
    produce_exception()
except Exception as err:
    print('print_exc():')
    traceback.print_exc(filesys.stdout)
    print()
    print('print_exc(1):')
    traceback.print_exc(limit1, filesys.stdout)

В этом примере дескриптор файла для sys.stdout заменяется так, чтобы информационные сообщения и сообщения трассировки были правильно смешаны:

$ python3 traceback_print_exc.py

print_exc() with no exception:
NoneType: None

print_exc():
Traceback (most recent call last):
  File "traceback_print_exc.py", line 20, in 
    produce_exception()
  File ".../traceback_example.py", line 17, in produce_exception
    produce_exception(recursion_level - 1)
  File ".../traceback_example.py", line 17, in produce_exception
    produce_exception(recursion_level - 1)
  File ".../traceback_example.py", line 19, in produce_exception
    raise RuntimeError()
RuntimeError

print_exc(1):
Traceback (most recent call last):
  File "traceback_print_exc.py", line 20, in 
    produce_exception()
RuntimeError

print_exc () – это просто ярлык для print_exception () , который требует явных аргументов.

traceback_print_exception.py

import traceback
import sys

from traceback_example import produce_exception

try:
    produce_exception()
except Exception as err:
    print('print_exception():')
    exc_type, exc_value, exc_tb  sys.exc_info()
    traceback.print_exception(exc_type, exc_value, exc_tb)

Аргументы для print_exception () создаются sys.exc_info () .

$ python3 traceback_print_exception.py

Traceback (most recent call last):
  File "traceback_print_exception.py", line 16, in 
    produce_exception()
  File ".../traceback_example.py", line 17, in produce_exception
    produce_exception(recursion_level - 1)
  File ".../traceback_example.py", line 17, in produce_exception
    produce_exception(recursion_level - 1)
  File ".../traceback_example.py", line 19, in produce_exception
    raise RuntimeError()
RuntimeError
print_exception():

print_exception () использует format_exception () для подготовки текста.

traceback_format_exception.py

import traceback
import sys
from pprint import pprint

from traceback_example import produce_exception

try:
    produce_exception()
except Exception as err:
    print('format_exception():')
    exc_type, exc_value, exc_tb  sys.exc_info()
    pprint(
        traceback.format_exception(exc_type, exc_value, exc_tb),
        width65,
    )

Те же три аргумента, тип исключения, значение исключения и трассировка, используются с format_exception () .

$ python3 traceback_format_exception.py

format_exception():
['Traceback (most recent call last):\n',
 '  File "traceback_format_exception.py", line 17, in
\n'
 '    produce_exception()\n',
 '  File '
 '".../traceback_example.py", '
 'line 17, in produce_exception\n'
 '    produce_exception(recursion_level - 1)\n',
 '  File '
 '".../traceback_example.py", '
 'line 17, in produce_exception\n'
 '    produce_exception(recursion_level - 1)\n',
 '  File '
 '".../traceback_example.py", '
 'line 19, in produce_exception\n'
 '    raise RuntimeError()\n',
 'RuntimeError\n']

Чтобы обработать трассировку другим способом, например, отформатировать ее по-другому, используйте extract_tb () , чтобы получить данные в удобной для использования форме.

traceback_extract_tb.py

import traceback
import sys
import os
from traceback_example import produce_exception

template  '{filename:<23}:{linenum}:{funcname}:\n    {source}'

try:
    produce_exception()
except Exception as err:
    print('format_exception():')
    exc_type, exc_value, exc_tb  sys.exc_info()
    for tb_info in traceback.extract_tb(exc_tb):
        filename, linenum, funcname, source  tb_info
        if funcname  '':
            funcname  funcname + '()'
        print(template.format(
            filenameos.path.basename(filename),
            linenumlinenum,
            sourcesource,
            funcnamefuncname)
        )

Возвращаемое значение – это список записей с каждого уровня стека, представленного трассировкой. Каждая запись представляет собой кортеж из четырех частей: имя исходного файла, номер строки в этом файле, имя функции и исходный текст из этой строки с удаленным пробелом (если источник доступен).

$ python3 traceback_extract_tb.py

format_exception():
traceback_extract_tb.py:18::
    produce_exception()
traceback_example.py   :17:produce_exception():
    produce_exception(recursion_level - 1)
traceback_example.py   :17:produce_exception():
    produce_exception(recursion_level - 1)
traceback_example.py   :19:produce_exception():
    raise RuntimeError()

API-интерфейсы стека низкого уровня

Есть аналогичный набор функций для выполнения тех же операций с текущим стеком вызовов вместо трассировки. print_stack () печатает текущий стек без создания исключения.

traceback_print_stack.py

import traceback
import sys

from traceback_example import call_function


def f():
    traceback.print_stack(filesys.stdout)


print('Calling f() directly:')
f()

print()
print('Calling f() from 3 levels deep:')
call_function(f)

Результат выглядит как трассировка без сообщения об ошибке.

$ python3 traceback_print_stack.py

Calling f() directly:
  File "traceback_print_stack.py", line 21, in 
    f()
  File "traceback_print_stack.py", line 17, in f
   

Calling f() from 3 levels deep:
  File "traceback_print_stack.py", line 25, in 
    call_function(f)
  File ".../traceback_example.py", line 24, in call_function
    return call_function(f, recursion_level - 1)
  File ".../traceback_example.py", line 24, in call_function
    return call_function(f, recursion_level - 1)
  File ".../traceback_example.py", line 26, in call_function
    return f()
  File "traceback_print_stack.py", line 17, in f

format_stack () подготавливает трассировку стека так же, как format_exception () готовит трассировку.

traceback_format_stack.py

import traceback
import sys
from pprint import pprint

from traceback_example import call_function


def f():
    return traceback.format_stack()


formatted_stack  call_function(f)
pprint(formatted_stack)

Он возвращает список строк, каждая из которых составляет одну строку вывода.

$ python3 traceback_format_stack.py

['  File "traceback_format_stack.py", line 21, in \n'
 '    formatted_stack = call_function(f)\n',
 '  File '
 '".../traceback_example.py", '
 'line 24, in call_function\n'
 '    return call_function(f, recursion_level - 1)\n',
 '  File '
 '".../traceback_example.py", '
 'line 24, in call_function\n'
 '    return call_function(f, recursion_level - 1)\n',
 '  File '
 '".../traceback_example.py", '
 'line 26, in call_function\n'
 '    return f()\n',
 '  File "traceback_format_stack.py", line 18, in f\n'
 '    return traceback.format_stack()\n']

Функция extract_stack () работает так же, как extract_tb () .

traceback_extract_stack.py

import traceback
import sys
import os

from traceback_example import call_function

template  '{filename:<26}:{linenum}:{funcname}:\n    {source}'


def f():
    return traceback.extract_stack()


stack  call_function(f)
for filename, linenum, funcname, source in stack:
    if funcname  '':
        funcname  funcname + '()'
    print(template.format(
        filenameos.path.basename(filename),
        linenumlinenum,
        sourcesource,
        funcnamefuncname)
    )

Он также принимает аргументы, не показанные здесь, чтобы начать с альтернативного места в кадре стека или ограничить глубину обхода.

$ python3 traceback_extract_stack.py

traceback_extract_stack.py:23::
    stack = call_function(f)
traceback_example.py      :24:call_function():
    return call_function(f, recursion_level - 1)
traceback_example.py      :24:call_function():
    return call_function(f, recursion_level - 1)
traceback_example.py      :26:call_function():
    return f()
traceback_extract_stack.py:20:f():
    return traceback.extract_stack()

Смотрите также