Inspect the error argument of a contract and infer the error type and the message if the error is given as a lambda.

    If the error argument is not given or if it is not given as a lambda function, return immediately.

    The error message is inferred as the single string-literal argument to a single call in the lambda body.

    :param decorator_inspection: inspection of a contract decorator
    :return: error type (None if not inferrable), error message (None if not inferrable)

def _error_type_and_message(
        decorator_inspection: icontract._represent.DecoratorInspection) -> Tuple[Optional[str], Optional[str]]:
    """
    Inspect the error argument of a contract and infer the error type and the message if the error is given as a lambda.

    If the error argument is not given or if it is not given as a lambda function, return immediately.

    The error message is inferred as the single string-literal argument to a single call in the lambda body.

    :param decorator_inspection: inspection of a contract decorator
    :return: error type (None if not inferrable), error message (None if not inferrable)
    """
    call_node = decorator_inspection.node

    error_arg_node = None  # type: Optional[ast.AST]
    for keyword in call_node.keywords:
        if keyword.arg == 'error':
            error_arg_node = keyword.value

    if error_arg_node is None and len(call_node.args) == 5:
        error_arg_node = call_node.args[4]

    if not isinstance(error_arg_node, ast.Lambda):
        return None, None

    body_node = error_arg_node.body

    # The body of the error lambda needs to be a callable, since it needs to return an instance of Exception
    if not isinstance(body_node, ast.Call):
        return None, None

    error_type = decorator_inspection.atok.get_text(node=body_node.func)

    error_message = None  # type: Optional[str]
    if len(body_node.args) == 1 and len(body_node.keywords) == 0:
        if isinstance(body_node.args[0], ast.Str):
            error_message = body_node.args[0].s

    elif len(body_node.args) == 0 and len(body_node.keywords) == 1:
        if isinstance(body_node.keywords[0].value, ast.Str):
            error_message = body_node.keywords[0].value.s

    else:
        # The error message could not be inferred.
        pass

    return error_type, error_message