2.7 bytecodehacks.dbc

This module implements a sort of design by contract. It's interfacae is similar to Guido van Rossum's metaclass version. However it doesn't currently mix well with inheritance, which makes it pretty useless.

One thing it does have over Guido's effort is the support for `old' values.

I'm not a expert in Eiffel (I've played with it a bit) or design by contract so I can't really explain this in the proper terminology. I can give a toy example though:

class Uncontracted:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def do(self):
        self.x = self.x + 1 # sneaky!
        return self.x/self.y

class Contracts:
    def pre___init__(self,x,y):
        assert y <> 0
    def post_do(self):
        assert Old.self.x == self.x
        assert Old.self.y == self.y
        assert Result > 0, "Result was %s"%`Result`
    def class_invariants(self):
        assert self.x > 0

Contracted = dbc.add_contracts(Uncontracted,Contracts)

Looking at the "post_do" method you might be tempted to think ``Oh, but self is a mutable object, so refering to the old value of "self.x" will always give the same value.'' This is in fact not the case - the attribute access is computed before the function begins.

If __debug__ is not true, then dbc.add_contracts is a no-op. There are also strength parameters that affect how many of the conditions are added by add_contracts.

add_contracts (target_class,contract_class[,strength])
Return a copy of target_class with contracts added from contract_class. It's perfectly possible for target_class and contract_class to be the same, which has the advantage that you can write your functions and conditions next to each other, but the disadvantage that target_class gets polluted with lots of unecessary methods.

__strength__
The default strength value. Defaults to "PRECONDITIONS|POSTCONDITIONS".

PRECONDITIONS
In add_contracts, if "strength & PRECONDITIONS" is true, for every method x in target_class where there is a method called ``pre_x'' in target_class, add the latter method as a precondition.
POSTCONDITIONS
In add_contracts, if "strength & POSTCONDITIONS" is true, for every method x in target_class where there is a method called ``post_x'' in target_class, add the latter method as a postcondition.
INVRIANTS
In add_contracts, if "strength & INVARIANTS" is true, and contract_class contains a method class_invariants then this method is added as a pre and post condition to every single method in target_class (except not as a precondition for __init__ - that would be a bit unfair).
EVERYTHING
EVERYTHING = PRECONDITIONS|POSTCONDITIONS|INVARIANTS.

Send comments to mwh@python.net