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

StackOverflow https://stackoverflow.com/questions/1603940

  •  05-07-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

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

<Ол>
  • Если исключение из библиотеки перехвачено в коде разработчика, и вместо него создается новое исключение, исходная трассировка будет, конечно, отброшена. Вот как обычно обрабатываются исключения ... если вы просто разрешаете вызывать исходное исключение, но вы удаляете его, чтобы удалить все "верхние" значения. кадры, фактическое исключение не будет иметь смысла, так как последняя строка в трассировке сама по себе не сможет вызвать исключение.
  • Чтобы удалить последние несколько кадров, вы можете попросить сократить ваши трассировки ... такие вещи, как traceback.print_exception (), принимают " limit " параметр, который можно использовать для пропуска последних нескольких записей.
  • Тем не менее, вполне вероятно, что можно будет отследить трассировки, если вам действительно нужно ... но где бы вы это сделали? Если в каком-либо коде-обертке на самом верхнем уровне вы можете просто получить трассировку, взять фрагмент, чтобы удалить ненужные части, а затем использовать функции в " 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)
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top