docs: 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