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))
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)
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
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)