Version 1.4 - 31 August 2007 * From Aaron Bingham: "Avoid generating AttributeErrors. These can overwrite tracebacks generated by user code, making debugging very difficult. As a bonus, the code is shorter and easier to read." And, it's much faster in the case where the attribute doesn't exist. Python exception handling can be slow! * Also from Aaron Bingham: "Fix handling of constructor preconditions. Subclass constructors' parameter lists may be legitimately completely different from the superclass constructor's parameter list. Thus, for constructors we only evaluate preconditions of the current class's constructor and do not follow the mro. See Meyer, Object Oriented Software Construction, 2nd Edition, p. 466." * Allow the installed checker functions to be called from within contracts. So this is possible:: class B: def method(self, a): """pre: a > 5""" pass class D(B): def method(self, a): """pre: B.method.__assert_pre(self, a)""" pass Classes that inherit from more than one base class (multiple inheritance) can choose which pre-conditions they're enforcing, and which they're loosening. * The docstring "pre::" results in an infinite loop. Fixed. Version 1.3 - 02 June 2007 * From Ruben Reifenberg: "There is some behaviour in contract.py that might be a bug. The problem is line 1271: 1264: try: 1265: p = f.__assert_pre 1266: except AttributeError: 1267: pass 1268: else: 1269 p(*va, **ka) 1270: raise InvalidPreconditionError(args) 1271: raise 1272: # ...ttw006 It happened that 1271 re-raised the AttributeError from 1265 although a PreconditionViolation was going on. Changing 1271 to: 1271: raise args solved the problem (in my case, but I'm not sure whether this does not break something else.) Version 1.2 - 22 April 2006 * From Aaron Bingham: "The subclass's method defines no new pre- or postconditions; the script testunchecked.py thus exits normally, even though the superclass's contract is violated!" All methods need to have checking code installed, even if there are not any conditions in the method docstring, because the super-class may have conditions. A method without any docstring conditions is implicitly declaring "pre: True" Version 1.1 - 19 October 2005 * From Gintautas Miliauskas: "I discovered one problem though: you expect __import__(modname) to return the corresponding module, however, it does not work like that. For example, if you invoke __import__('a.b.c.d'), the result will be module , not module . Yes, I think this is dumb too, but that's how it works. A workaround is to use __import__ to import the module and then get the actual module from sys.modules." Version 1.0 - 22 June 2003 Version 1.0 beta 3 - 21 June 2003 * Support Jython (possibly Python 2.1) * Support Python 2.2 (doesn't have bool, True, False: those are added in Python 2.2.1) * Partial contract checking - by default in __debug__ mode checks all contracts, otherwise only check pre-conditions and invariants on entry * Can now pass in module names in checkmod()... This makes it easy to enable contracts: just do a contract.checkmod(__name__) at the end of a module. Version 1.0 beta 2 - 06 June 2003 * Use separate exception classes eg PreconditionViolationError, PostconditionViolationError instead of AssertionError * Correctly weaken pre-conditions: they are not ORed; instead, if a method fails its precondition and an overridden method's pre- conditions are still valid, raise an InvalidPreconditionError. * Support Re-Structured Text (ReST) by allowing :: after pre, post, inv keywords * Invariants aren't checked after constructor throws exception * Only scan for code objects actually defined in specified module, not just all objects in module namespace * Save docstring line numbers, useful when raising exceptions to tell where in the code the exception actually came from.