On Mon, Jan 25, 2016 at 7:24 PM David Mertz <mertz@gnosis.cx> wrote:
Just curious, Michael, what would you like the Python syntax version to look like if you *can* do whatever metaclass or stack hackery that's needed?  I'm a little confused when you mention a decorator and a context manager in the same sentence since those would seem like different approaches.

Now that you mention it, that does seem weird. Initially the pattern of trying to factor out a setup/cleanup feels like a context manager. But we also need to capture the function arguments and return value. So that feels like a decorator.

I started by implementing an abstract base class Contract that sets up the require/ensure behavior. One inherits and overrides to implement a particular contract. The overridden require/ensure functions would receive the arguments/result of a decorated function.

    class StayPositive(Contract):
        def require(self, *args, **kwargs):
            assert sum(args + list(kwargs.values())
        def ensure(self, result, *args, **kwargs):
            # ensure receives not only the result, but also same argument objs
            assert sum(result)

    @StayPositive
    def foo(i + am + happy):
        return i + am + happy

One thing I like here is that the require/ensure doesn't clutter the function definition with awkward decorator parameters. The contract terms are completely separate. This does put the burden on wisely naming the contract subclass name.

The combination of decorator and context manager was unnecessary. The internals of my Contract base class included an awkward ``with self:``. If I were to refactor, I'd separate out a context manager helper from the decorator object.

Seeing some of the stubs folks have written makes me think this ends with exec-ing a template a la namedtuple.