fizzer
fizzer

Reputation: 13806

Implementing C-like assert

I'm trying to implement an assert function. How can I get the text of the failing condition into the error message? If I have to parse it from the backtrace, can I portably rely on anything about the format of frames?

Upvotes: 1

Views: 282

Answers (3)

KingRadical
KingRadical

Reputation: 1312

AssertionError is just like any other exception in python, and assert is a simple statement that is equivalent to

if __debug__:
    if not expression: raise AssertionError

or

if __debug__:
    if not expression1: raise AssertionError(expression2)

so you can add a second parameter to your assertion to have additional output

from sys import exc_info
from traceback import print_exception
# assertions are simply exceptions in Python
try:
    assert False, "assert was false"
except AssertionError:
    print_exception(*exc_info())

outputs

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AssertionError: assert was false

Upvotes: 3

martineau
martineau

Reputation: 123481

If you're sure the expression to test is secure you could do something like this:

File my_assert.py:

import sys

def my_assert(condition):
    caller = sys._getframe(1)
    if not eval(condition, caller.f_globals, caller.f_locals):
        raise AssertionError(repr(condition) + " on line " +
                             str(caller.f_lineno) + ' in ' +
                             caller.f_code.co_name)

File test_my_assert.py:

from my_assert import my_assert

global_var = 42

def test():
    local_var = 17
    my_assert('local_var*2 < global_var') # OK
    my_assert('local_var > global_var')

test()

Output:

Traceback (most recent call last):
  File "test_my_assert.py", line 10, in <module>
    test()
  File "test_my_assert.py", line 8, in test
    my_assert('local_var > global_var')
  File "my_assert.py", line 8, in my_assert
    caller.f_code.co_name)
AssertionError: 'local_var > global_var' on line 8 in test

Upvotes: 2

Imre Kerr
Imre Kerr

Reputation: 2428

My very hackish solution:

def my_assert(condition):
    if not eval(condition):
        # error stuff

Then use it by placing the condition in quotation marks. It is then a string that can be printed in the error message.

Or, if you want it to actually raise an AssertionError:

def my_assert(condition):
    if not eval(condition):
        raise AssertionError(condition)

Upvotes: 0

Related Questions