def _make_invariant(fn, *, predicate=None):
    """
    Wrapper for calling cls.__invariant__ before and after calls to fn.
    If a predicate is supplied, it must return true for __invariant__ to run
    before the call to fn.
    """
    def wrapper(self, *args, **kwargs):
        if predicate is None or (predicate and predicate(self, args)):
            # useful for a first time run of __setattr__ where the attribute
            # does not exist on the instance yet
            self.__invariant__()

        result = fn(self, *args, **kwargs)

        if predicate is None or (predicate and predicate(self, args)):
            self.__invariant__()

        return result
    return wrapper