2009-06-19 51 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 
相關問題