Как изменить объект трассировки Python при создании исключения?

Я работаю над библиотекой Python, используемой сторонними разработчиками для написания расширений для нашего основного приложения.

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

заранее спасибо за любые советы!

5 ответов


насчет не изменения трассировки? Две вещи, которые вы просите, могут быть сделаны более легко по-разному.

  1. Если исключение из библиотеки поймано в коде разработчика и вместо этого возникает новое исключение, исходная трассировка, конечно, будет отброшена. Так обычно обрабатываются исключения... если вы просто позволяете оригинальному исключению быть поднятым, но вы munge его, чтобы удалить все" верхние " кадры, фактическое исключение не сделает смысл, так как последняя строка в обратной трассировке сама по себе не сможет вызвать исключение.
  2. чтобы удалить последние несколько кадров, вы можете запросить, чтобы ваши трассировки были сокращены... такие вещи, как вывод.print_exception () принимает параметр "limit", который можно использовать для пропуска последних нескольких записей.

тем не менее, это должно быть вполне возможно, чтобы munge tracebacks, если вам действительно нужно... но где ты это сделаешь? Если в каком-то коде обертки на самом верху уровень, затем вы можете просто захватить трассировку, взять срез, чтобы удалить детали, которые вы не хотите, а затем использовать функции в модуле "трассировка" для форматирования/печати по желанию.


вы можете легко удалить верхнюю часть трассировки, подняв с помощью элемента tb_next трассировки:

except:
    ei = sys.exc_info()
    raise ei[0], ei[1], ei[2].tb_next

tb_next-это атрибут read_only, поэтому я не знаю, как удалить материал снизу. Возможно, вы сможете ввернуть механизм свойств, чтобы разрешить доступ к свойству, но я не знаю, как это сделать.


взгляните на то, что jinja2 здесь:

https://github.com/mitsuhiko/jinja2/blob/5b498453b5898257b2287f14ef6c363799f1405a/jinja2/debug.py

это уродливо, но, похоже, делает то, что вам нужно. Я не буду копировать-вставлять пример здесь, потому что он длинный.


вы также можете быть заинтересованы в PEP-3134, который реализован в python 3 и позволяет вам привязать одно исключение/трассировку к вышестоящему исключению.

Это не совсем то же самое, что изменение обратной трассировки, но, вероятно, это был бы идеальный способ передать "короткую версию" пользователям библиотеки, все еще имея "длинную версию".


этот код может представлять интерес для вас.

он принимает трассировку и удаляет первый файл, который не должен отображаться. Затем он имитирует поведение Python:

Traceback (most recent call last):

будет отображаться, только если трассировка содержит более одного файла. Это выглядит так, как будто моего дополнительного кадра там не было.

вот мой код, если есть строка text:

try:
    exec(text)
except:
    # we want to format the exception as if no frame was on top.
    exp, val, tb = sys.exc_info()
    listing = traceback.format_exception(exp, val, tb)
    # remove the entry for the first frame
    del listing[1]
    files = [line for line in listing if line.startswith("  File")]
    if len(files) == 1:
        # only one file, remove the header.
        del listing[0]
    print("".join(listing), file=sys.stderr)
    sys.exit(1)