Как я могу изменить объект трассировки Python при возникновении исключения?
Вопрос
Я работаю над библиотекой Python, используемой сторонними разработчиками для написания расширений для нашего основного приложения.
Я хотел бы знать, возможно ли изменить трассировку при возникновении исключений, поэтому последний кадр стека - это вызов библиотечной функции в коде разработчика, а не строка в библиотеке, которая вызвала исключение. Внизу стека также есть несколько фреймов, содержащих ссылки на функции, используемые при первой загрузке кода, который в идеале я бы тоже хотел удалить.
Заранее спасибо за любой совет!
Решение
Как насчет того, чтобы не изменять трассировку? Две вещи, которые вы запрашиваете, могут быть выполнены более легко по-другому.
<Ол>Тем не менее, вполне вероятно, что можно будет отследить трассировки, если вам действительно нужно ... но где бы вы это сделали? Если в каком-либо коде-обертке на самом верхнем уровне вы можете просто получить трассировку, взять фрагмент, чтобы удалить ненужные части, а затем использовать функции в " traceback " модуль для форматирования / печати по желанию.
Другие советы
Вы можете легко удалить верхнюю часть трассировки, подняв ее с помощью элемента tb_next трассировки:
except:
ei = sys.exc_info()
raise ei[0], ei[1], ei[2].tb_next
tb_next - это атрибут read_only, поэтому я не знаю, как удалить что-то снизу. Возможно, вам удастся испортить механизм свойств, чтобы разрешить доступ к свойству, но я не знаю, как это сделать.
Посмотрите, что здесь делает jinja2:
https://githubobjjjjjj /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)