Frage

Hopefully, this will be my last question in the series (my project is almost over, unless the requirements change).

I'm working on writing some constraints for a class method using PyContract (not PyContracts). In one of my functions, I have an invariant. However, not all the variables that make up this postcondition are input params to the function; some are variables local to the scope of the function itself (loop counters, etc). How/can I capture them in the postcondition clause in my contract?

Here is an MWE of code that I've been working with:

def foo(*args, **kwargs):
    """
        pre:
            # some preconditions
        inv:
            # something that's clearly false
            1 == 2
        post:
            g < arg5
    """

    arg1 = kwargs['arg1']
    arg2 = kwargs['arg2']
    arg3 = kwargs['arg3']
    arg4 = kwargs['arg4']
    arg5 = kwargs['arg5']

    g = 0
    while g < arg5:
        vars = generate_data(arg1)
        best = max(arg2(var)for var in vars)
        if best >= arg3:
            return best
        # do stuff
        g += 1

The problem arises when PyContract tells me that it doesn't know the names g and arg5. I changed arg5 to kwargs['arg5'] in the contract, but PyContract still doesn't know what g is. How/Could I fix this problem?

The Error that I get is:

Traceback (most recent call last):
  File "/Users/ashwin/github/local/Genetic-Framework/Genetic-Framework/Genetic/GA.py", line 245, in <module>
    answer = runTSPGA(*settings, **settings)
  File "<string>", line 3, in __assert_runTSPGA_chk
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/contract.py", line 1135, in call_public_function_all
    return _call_one_all(func, va, ka)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/contract.py", line 1321, in _call_one_all
    func.__assert_post(old, result, *va, **ka)
  File "<string>", line 4, in __assert_runTSPGA_post
NameError: global name 'g' is not defined

Adding g to the postconditions declaration as follows also does not help:

post[kwargs, g]:

Further, it is interesting that the code for the invariant checking doesn't seem to run at all

War es hilfreich?

Lösung

The postconditions are being run after the function has completed running, which means that the stack frame containing the function locals (such as arg5 and g) is no longer in scope.

This isn't too surprising for a library implementing contracts though: the whole point is to declare constraints on the interface a function is supposed to implement, while you seem to want to check the internal state of the function that is not made visible in the return value.

Two ways you could move forward are:

  1. Make the function return the state that you want to check with a contract. This might not be appropriate though if the internal state isn't part of the function's interface.

  2. Use something other than PyContracts to enforce your constraints, such as the assert statement, or perhaps a raise AssertionError("while loop should have returned early") statement after the loop.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top