Example #1
0
def _assert_invariant(contract: Contract, instance: Any) -> None:
    """Assert that the contract holds as a class invariant given the instance of the class."""
    if 'self' in contract.condition_arg_set:
        check = contract.condition(self=instance)
    else:
        check = contract.condition()

    if _not_check(check=check, contract=contract):
        if contract.error is not None and (inspect.ismethod(contract.error) or
                                           inspect.isfunction(contract.error)):
            assert contract.error_arg_set is not None, "Expected error_arg_set non-None if contract.error a function."
            assert contract.error_args is not None, "Expected error_args non-None if contract.error a function."

            if 'self' in contract.error_arg_set:
                raise contract.error(self=instance)
            else:
                raise contract.error()
        else:
            if 'self' in contract.condition_arg_set:
                msg = icontract._represent.generate_message(
                    contract=contract, condition_kwargs={"self": instance})
            else:
                msg = icontract._represent.generate_message(
                    contract=contract, condition_kwargs=dict())

            if contract.error is None:
                raise ViolationError(msg)
            elif isinstance(contract.error, type):
                raise contract.error(msg)
            else:
                raise NotImplementedError(
                    "Unhandled contract.error: {}".format(contract.error))
Example #2
0
def _assert_precondition(contract: Contract,
                         resolved_kwargs: Mapping[str, Any]) -> None:
    """
    Assert that the contract holds as a precondition.

    :param contract: contract to be verified
    :param resolved_kwargs:
        resolved keyword arguments of the call (including the default argument values of the decorated function)
    :return:
    """
    condition_kwargs = select_condition_kwargs(contract=contract,
                                               resolved_kwargs=resolved_kwargs)

    check = contract.condition(**condition_kwargs)

    if not_check(check=check, contract=contract):
        if contract.error is not None and (inspect.ismethod(contract.error) or
                                           inspect.isfunction(contract.error)):
            assert contract.error_arg_set is not None, "Expected error_arg_set non-None if contract.error a function."
            assert contract.error_args is not None, "Expected error_args non-None if contract.error a function."

            error_kwargs = {
                arg_name: value
                for arg_name, value in resolved_kwargs.items()
                if arg_name in contract.error_arg_set
            }

            missing_args = [
                arg_name for arg_name in contract.error_args
                if arg_name not in resolved_kwargs
            ]
            if missing_args:
                msg_parts = []
                if contract.location is not None:
                    msg_parts.append("{}:\n".format(contract.location))

                msg_parts.append((
                    "The argument(s) of the precondition error have not been set: {}. "
                    "Does the original function define them? Did you supply them in the call?"
                ).format(missing_args))

                raise TypeError(''.join(msg_parts))

            raise contract.error(**error_kwargs)

        else:
            msg = icontract._represent.generate_message(
                contract=contract, condition_kwargs=condition_kwargs)
            if contract.error is None:
                raise ViolationError(msg)
            elif isinstance(contract.error, type):
                raise contract.error(msg)
Example #3
0
def _create_violation_error(contract: Contract, resolved_kwargs: Mapping[str, Any]) -> BaseException:
    """Create the violation error based on the violated contract."""
    exception = None  # type: Optional[BaseException]

    if contract.error is None:
        try:
            msg = icontract._represent.generate_message(contract=contract, resolved_kwargs=resolved_kwargs)
        except Exception as err:
            parts = ["Failed to recompute the values of the contract condition:\n"]
            if contract.location is not None:
                parts.append("{}:\n".format(contract.location))

            if contract.description is not None:
                parts.append("{}: ".format(contract.description))

            parts.append(icontract._represent.represent_condition(condition=contract.condition))

            raise RuntimeError(''.join(parts)) from err

        exception = ViolationError(msg)
    elif inspect.ismethod(contract.error) or inspect.isfunction(contract.error):
        assert contract.error_arg_set is not None, ("Expected error_arg_set non-None if contract.error a function.")
        assert contract.error_args is not None, ("Expected error_args non-None if contract.error a function.")

        error_kwargs = select_error_kwargs(contract=contract, resolved_kwargs=resolved_kwargs)

        exception = cast(BaseException, contract.error(**error_kwargs))  # type: ignore

        if not isinstance(exception, BaseException):
            raise TypeError(
                "The exception returned by the contract's error {} does not inherit from BaseException.".format(
                    contract.error))
    elif isinstance(contract.error, type):
        if not issubclass(contract.error, BaseException):
            raise TypeError(
                "The exception class supplied in the contract's error {} is not a subclass of BaseException.".format(
                    contract.error))

        msg = icontract._represent.generate_message(contract=contract, resolved_kwargs=resolved_kwargs)
        exception = contract.error(msg)
    elif isinstance(contract.error, BaseException):
        exception = contract.error
    else:
        raise NotImplementedError(
            ("icontract does not know how to handle the error of type {} "
             "(expected a function, a subclass of BaseException or an instance of BaseException)").format(
                 type(contract.error)))

    assert exception is not None
    return exception
Example #4
0
def _assert_postcondition(contract: Contract,
                          resolved_kwargs: Mapping[str, Any]) -> None:
    """
    Assert that the contract holds as a postcondition.

    The arguments to the postcondition are given as ``resolved_kwargs`` which includes
    both argument values captured in snapshots and actual argument values and the result of a function.

    :param contract: contract to be verified
    :param resolved_kwargs: resolved keyword arguments (including the default values, ``result`` and ``OLD``)
    :return:
    """
    assert 'result' in resolved_kwargs, \
        "Expected 'result' to be set in the resolved keyword arguments of a postcondition."

    # Check that all arguments to the condition function have been set.
    missing_args = [
        arg_name for arg_name in contract.mandatory_args
        if arg_name not in resolved_kwargs
    ]
    if missing_args:
        msg_parts = []  # type: List[str]
        if contract.location is not None:
            msg_parts.append("{}:\n".format(contract.location))

        msg_parts.append((
            "The argument(s) of the postcondition have not been set: {}. "
            "Does the original function define them? Did you supply them in the call?"
        ).format(missing_args))

        raise TypeError(''.join(msg_parts))

    condition_kwargs = {
        arg_name: value
        for arg_name, value in resolved_kwargs.items()
        if arg_name in contract.condition_arg_set
    }

    check = contract.condition(**condition_kwargs)

    if _not_check(check=check, contract=contract):
        if contract.error is not None and (inspect.ismethod(contract.error) or
                                           inspect.isfunction(contract.error)):
            assert contract.error_arg_set is not None, "Expected error_arg_set non-None if contract.error a function."
            assert contract.error_args is not None, "Expected error_args non-None if contract.error a function."

            error_kwargs = {
                arg_name: value
                for arg_name, value in resolved_kwargs.items()
                if arg_name in contract.error_arg_set
            }

            missing_args = [
                arg_name for arg_name in contract.error_args
                if arg_name not in resolved_kwargs
            ]
            if missing_args:
                msg_parts = []
                if contract.location is not None:
                    msg_parts.append("{}:\n".format(contract.location))

                msg_parts.append((
                    "The argument(s) of the postcondition error have not been set: {}. "
                    "Does the original function define them? Did you supply them in the call?"
                ).format(missing_args))

                raise TypeError(''.join(msg_parts))

            raise contract.error(**error_kwargs)

        else:
            msg = icontract._represent.generate_message(
                contract=contract, condition_kwargs=condition_kwargs)
            if contract.error is None:
                raise ViolationError(msg)
            elif isinstance(contract.error, type):
                raise contract.error(msg)