1

私はcontract.pyで遊んでいます.Terrence WayのPython用のデザインバイコントラクトのリファレンス実装です。コントラクト (事前条件/事後条件/不変条件) に違反すると、実装は例外をスローしますが、メソッドに複数のコントラクトが関連付けられている場合に、どの特定のコントラクトが失敗したかを簡単に特定する方法は提供しません。

たとえば、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) の 2 番目の引数は、circbuf の行番号を参照しています。アサーションを含むinit docstring:

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

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

ただし、ファイルを開いて docstring の行番号を数えなければならないのは面倒です。どの契約が失敗したかを特定するためのより迅速な解決策を誰かが持っていますか?

(この例では前提条件が 1 つであるため、明らかですが、複数の前提条件が可能であることに注意してください)。

4

2 に答える 2

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])
于 2012-06-13T14:39:08.837 に答える