class_docstr: Executor for Slack component.
class_docstr_tok: ["Executor","for","Slack","component","."]
docstr: Send message via Slack channel and wait for response.
  
  When the bot send message to the channel, user should reply in thread with
  "approve" or "lgtm" for approval, "decline", "reject" for decline.
  
  This example uses Slack RealTime Message (RTM) API which is only available
  for **classic slack bot** (https://api.slack.com/rtm). (Events API requires
  listening server endpoint which is not easy to be integrated with TFX
  pipelines.)
  
  Args:
    slack_token: The user-defined function to obtain token to send and receive
      messages.
    slack_channel_id: The id of the Slack channel to send and receive
      messages.
    model_uri: The URI of the model waiting for human review.
  
  Returns:
    A _SlackResponse instance.
  
  Raises:
    ConnectionError:
      When connection to slack server cannot be established.
docstr_tok: ["Send","message","via","Slack","channel","and","wait","for","response",".","When","the","bot","send","message","to","the","channel",",","user","should","reply","in","thread","with","''","approve","''","or","``","lgtm","''","for","approval",",","``","decline","''",",","``","reject","''","for","decline",".","This","example","uses","Slack","RealTime","Message","(","RTM",")","API","which","is","only","available","for","*","*","classic","slack","bot","*","*","(","https",":","\/\/api.slack.com\/rtm",")",".","(","Events","API","requires","listening","server","endpoint","which","is","not","easy","to","be","integrated","with","TFX","pipelines",".",")","Args",":","slack_token",":","The","user-defined","function","to","obtain","token","to","send","and","receive","messages",".","slack_channel_id",":","The","id","of","the","Slack","channel","to","send","and","receive","messages",".","model_uri",":","The","URI","of","the","model","waiting","for","human","review",".","Returns",":","A","_SlackResponse","instance",".","Raises",":","ConnectionError",":","When","connection","to","slack","server","can","not","be","established","."]
code: def _fetch_slack_blessing(
      self, slack_token: str, slack_channel_id: str, model_uri: str
  ) -> _SlackResponse:
      """Send message via Slack channel and wait for response.
  
      When the bot send message to the channel, user should reply in thread with
      "approve" or "lgtm" for approval, "decline", "reject" for decline.
  
      This example uses Slack RealTime Message (RTM) API which is only available
      for **classic slack bot** (https://api.slack.com/rtm). (Events API requires
      listening server endpoint which is not easy to be integrated with TFX
      pipelines.)
  
      Args:
        slack_token: The user-defined function to obtain token to send and receive
          messages.
        slack_channel_id: The id of the Slack channel to send and receive
          messages.
        model_uri: The URI of the model waiting for human review.
  
      Returns:
        A _SlackResponse instance.
  
      Raises:
        ConnectionError:
          When connection to slack server cannot be established.
      """
      # pylint: disable=unused-argument, unused-variable
      rtm_client = slack.RTMClient(token=slack_token)
      thread_ts = None
      result = None
  
      @slack.RTMClient.run_on(event="hello")
      def on_hello(web_client, **payload):
          nonlocal thread_ts
          resp = web_client.chat_postMessage(
              channel=slack_channel_id,
              text=(
                  f"Please review the model in the following URI: {model_uri}\n"
                  f"Reply in thread by `{_APPROVE_TEXT}` for approval, "
                  f"or `{_DECLINE_TEXT}` for decline."
              ),
          )
          thread_ts = resp.data["ts"]
  
      @slack.RTMClient.run_on(event="message")
      def on_message(data, rtm_client, web_client, **payload):
          nonlocal result
          if (
              data.get("channel") != slack_channel_id
              or data.get("thread_ts") != thread_ts
              or data.get("user") is None
              or data.get("subtype") == "bot_message"
          ):
              # Not a relevent user message.
              return
  
          user_reply = data["text"].lower()
          if user_reply in _APPROVE_TEXT:
              absl.logging.info(
                  "User %s approved the model at %s",
                  data["user"],
                  model_uri,
              )
              rtm_client.stop()
              result = _SlackResponse(
                  approved=True,
                  user_id=data["user"],
                  message=data["text"],
                  slack_channel_id=slack_channel_id,
                  thread_ts=thread_ts,
              )
          elif user_reply in _DECLINE_TEXT:
              absl.logging.info(
                  "User %s declined the model at %s",
                  data["user"],
                  model_uri,
              )
              rtm_client.stop()
              result = _SlackResponse(
                  approved=False,
                  user_id=data["user"],
                  message=data["text"],
                  slack_channel_id=slack_channel_id,
                  thread_ts=thread_ts,
              )
          else:
              web_client.chat_postMessage(
                  channel=slack_channel_id,
                  thread_ts=thread_ts,
                  text=(
                      f'Unrecognized text "{data["text"]}".\n'
                      f"Please reply in thread by `{_APPROVE_TEXT}` for approval, "
                      f"or `{_DECLINE_TEXT}` for decline."
                  ),
              )
  
      absl.logging.info("Will start listening user Slack response.")
      rtm_client.start()
      absl.logging.info("User reply: %s", result)
      return result
  
imports: import os
  import signal
  from typing import Any, Dict, List
  import absl
  import attr
  import slack
  from tfx import types
  from tfx.components.util import model_utils
  from tfx.dsl.components.base import base_executor
  from tfx.types import artifact_utils
  from tfx.utils import io_utils
label_desc: Use image node_id 1 for calling the Executor obj's underlying member method code with example usage: obj._fetch_slack_blessing(slack_token, slack_channel_id, model_uri) and returns: result