Поднимите исключение с трассировкой, начиная с вызывающего

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

Запуск этого в питоне...

assert(False)

Дает вам это...

Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

Как видите, самый низкий уровень трассировки — assert(False). Поэтому я сделал свое собственное утверждение, которое печатается, когда утверждение выполняется успешно.

def custom_assert(condition):
    if condition:
        print("Yay! It werks!")
    else:
        raise Exception("Nay, it don't werks...")

custom_assert(False)

Но вместо того, что дает assert, мне custom_assert дает вот это.

Traceback (most recent call last):
  File "test.py", line 14, in <module>
    custom_assert(False)
  File "test.py", line 12, in custom_assert
    raise Exception("Nay, it don't werks...")
Exception: Nay, it don't werks...

Это, конечно, поведение по умолчанию. Совершенно полезно в 99,9999% случаев, но это тот единственный раз, когда его можно улучшить. Бесполезно знать, что метод, который я вызвал, чтобы вызвать ошибку, когда условие ложно, вызвал ошибку.

Как я могу заставить мой custom_assert вызвать исключение с трассировкой, начинающейся с вызывающей стороны, так же, как assert?

P.S.: Я не хочу его печатать, я хочу, чтобы исключение имело правильно измененную трассировку, чтобы оно правильно работало с отладчиками и другими инструментами!

Изменить

Чтобы уточнить, трассировка, которую я хочу, будет такой.

Traceback (most recent call last):
  File "test.py", line 14, in <module>
    custom_assert(False)
Exception: Nay, it don't werks...

person OdraEncoded    schedule 31.05.2015    source источник
comment
Проверьте traceback модуль, особенно extract_* вещи. Может быть, то, что вы хотите.   -  person Ami Tavory    schedule 01.06.2015
comment
Как должна выглядеть трассировка в последнем примере?   -  person f43d65    schedule 01.06.2015


Ответы (1)


По сути, то, что вы хотите сделать, похоже на это:

tb = None
try:
    raise Exception('foo')
except Exception:
    tb = sys.exc_info()[2]

tb.tb_frame = tb.tb_frame.f_back # This line doesn't work
raise Exception('Nay it doesnt werks').with_traceback(tb)

но вы не можете назначить tb_frame, и из-за того, что вы копаетесь в коде CPython, это структуры данных, сгенерированные C (а не python) (см. sys._getframe()). куча. Это похоже на то, что делает jinja2. Если это то, что вы решили сделать, удачи! (на тот момент это не входило в мои обязанности)

person AnilRedshift    schedule 02.06.2015