2009-06-19 52 views
1

我正在玩contract.py,这是Terrence Way为Python设计的合同的参考实现。当违反合同(先决条件/后置条件/不变条件)时,实现会抛出异常,但如果存在多个与方法关联的合约,则无法快速识别哪个特定合同失败。我如何知道Python的contract.py失败?

例如,如果我走circbuf.py例子,通过传递一个消极的说法,像这样违反了先决条件:

circbuf(-5) 

然后我得到一个回溯,看起来像这样:

Traceback (most recent call last): 
    File "circbuf.py", line 115, in <module> 
    circbuf(-5) 
    File "<string>", line 3, in __assert_circbuf___init___chk 
    File "build/bdist.macosx-10.5-i386/egg/contract.py", line 1204, in call_constructor_all 
    File "build/bdist.macosx-10.5-i386/egg/contract.py", line 1293, in _method_call_all 
    File "build/bdist.macosx-10.5-i386/egg/contract.py", line 1332, in _call_all 
    File "build/bdist.macosx-10.5-i386/egg/contract.py", line 1371, in _check_preconditions 
contract.PreconditionViolationError: ('__main__.circbuf.__init__', 4) 

我的预感是PreconditionViolationError(4)中的第二个参数是指circbuf中的行号。 初始化文档字符串包含断言:

def __init__(self, leng): 
    """Construct an empty circular buffer. 

    pre:: 
     leng > 0 
    post[self]:: 
     self.is_empty() and len(self.buf) == leng 
    """ 

然而,这是一个痛苦打开的文件和计数的文档字符串的行号。有没有人有更快的解决方案来确定哪个合同失败? (请注意,在这个例子中,有一个单一的前提条件,所以很明显,但是可能有多个前提条件)。

回答

1

这是一个老问题,但我可以回答它。我添加了一些输出,你会在#jlr001的评论中看到它。将下面的行添加到contract.py中,当它引发异常时,它将显示文档行号和触发它的语句。没有什么更多,但它至少会阻止你猜测哪种情况触发了它。

def _define_checker(name, args, contract, path): 
    """Define a function that does contract assertion checking. 

    args is a string argument declaration (ex: 'a, b, c = 1, *va, **ka') 
    contract is an element of the contracts list returned by parse_docstring 
    module is the containing module (not parent class) 

    Returns the newly-defined function. 

    pre:: 
     isstring(name) 
     isstring(args) 
     contract[0] in _CONTRACTS 
     len(contract[2]) > 0 
    post:: 
     isinstance(__return__, FunctionType) 
     __return__.__name__ == name 
    """ 
    output = StringIO() 
    output.write('def %s(%s):\n' % (name, args)) 
    # ttw001... raise new exception classes 
    ex = _EXCEPTIONS.get(contract[0], 'ContractViolationError') 
    output.write('\tfrom %s import forall, exists, implies, %s\n' % \ 
       (MODULE, ex)) 
    loc = '.'.join([x.__name__ for x in path]) 
    for c in contract[2]: 
     output.write('\tif not (') 
     output.write(c[0]) 
     # jlr001: adding conidition statement to output message, easier debugging 
     output.write('): raise %s("%s", %u, "%s")\n' % (ex, loc, c[1], c[0])) 
    # ...ttw001 

    # ttw016: return True for superclasses to use in preconditions 
    output.write('\treturn True') 
    # ...ttw016 

    return _define(name, output.getvalue(), path[0]) 
1

不修改他的代码,我不认为你可以,但由于这是蟒蛇...

如果你看看他在那里引发异常的用户,这我觉得是有可能推你正在寻找的信息...我不希望你能够追溯到更好,因为代码实际上包含在评论块中,然后处理。

的代码相当复杂,但是这可能是一个块看 - 也许,如果你倾倒了一些参数的个数可以计算出怎么回事...

def _check_preconditions(a, func, va, ka): 
    # ttw006: correctly weaken pre-conditions... 
    # ab002: Avoid generating AttributeError exceptions... 
    if hasattr(func, '__assert_pre'): 
     try: 
      func.__assert_pre(*va, **ka) 
     except PreconditionViolationError, args: 
      # if the pre-conditions fail, *all* super-preconditions 
      # must fail too, otherwise 
      for f in a: 
       if f is not func and hasattr(f, '__assert_pre'): 
        f.__assert_pre(*va, **ka) 
        raise InvalidPreconditionError(args) 
      # rr001: raise original PreconditionViolationError, not 
      # inner AttributeError... 
      # raise 
      raise args 
      # ...rr001 
    # ...ab002 
    # ...ttw006 
相关问题