How can I make my assertions smarter?

Michael Hudson mwh21 at cam.ac.uk
Mon Nov 1 08:35:53 EST 1999


Stuart Hungerford <stuart.hungerford at webone.com.au> writes:

> Hi all,
> 
> I'm using some simple functions to implement crude precondition,
> postcondition and invariant checking in Python classes.
> 
> (Tim: please be gentle ;-)
> 
> Is there some neat way to wrap these tests up so I can print any
> code expression that fails, e.g:
> 
>      Precondition failed foo.py line 42: spoon.shape == 'bent'
> 
> which would appear at line 42 of foo.py as
> 
>      pre(spoon.shape == 'bent')

Hmm... tricky.

Something like this might work (tho' not with python -O, not that that
should be a problem).

chuck it in a file called "pre.py". It will have problems with line
continutations & stuff, but I did just make it up on the spot (well,
about half an hour of spot; must now do something of some use).

class PreconditionViolation(AssertionError):
    def __init__(self,why):
        AssertionError.__init__(self,why)

def pre(cond):
    if cond:
        return
    try: 
        raise ""
    except:
        import sys
        frame = sys.exc_traceback.tb_frame.f_back
        lineno = frame.f_lineno
        filename = frame.f_code.co_filename    
    try:
        import re
        file = open(filename)
        for i in range(lineno):
            line = file.readline()
        match = re.match("\W*(pre\.)?pre\((.*)\);?\W*$",line)
        if match is not None:
            line = match.group(2)
        else:
            import string
            line = string.strip(line)
    except:
        line = "<not found>"
    line = "line %d of %s: %s"%(lineno,filename,line)
    raise PreconditionViolation, line
    
def checked_sqrt(x):
    from math import sqrt
    pre(x>=0)
    return sqrt(x)
    
if __name__=='__main__':
    print checked_sqrt(2)
    print checked_sqrt(-1)


then `python pre.py' gives:

1.41421356237
Traceback (innermost last):
  File "pre.py", line 39, in ?
    print checked_sqrt(-1)
  File "pre.py", line 34, in checked_sqrt
    pre(x>=0)
  File "pre.py", line 30, in pre
    raise PreconditionViolation, line
__main__.PreconditionViolation: line 34 of pre.py: x>=0

but, really, what's wrong with asserts?

Another approach would be to poke around with frame.f_lasti and
decompile the bytecode (!).

> I can see how to use environment variables or global variables to
> selectively enable precondtions etc, although any hints for doing that
> would be appreciated too.

That should be pretty straightforward.

> Thanks in advance,
> 
> Stu

HTH,
Michael




More information about the Python-list mailing list