def test_json(self): self.assertDictEqual( { "text": { "text": "some text", "type": "mrkdwn" }, "block_id": "a_block", "type": "section", }, SectionBlock(text="some text", block_id="a_block").to_dict(), ) self.assertDictEqual( { "text": { "text": "some text", "type": "mrkdwn" }, "fields": [ { "text": "field0", "type": "mrkdwn" }, { "text": "field1", "type": "mrkdwn" }, { "text": "field2", "type": "mrkdwn" }, { "text": "field3", "type": "mrkdwn" }, { "text": "field4", "type": "mrkdwn" }, ], "type": "section", }, SectionBlock(text="some text", fields=[f"field{i}" for i in range(5)]).to_dict(), ) button = LinkButtonElement(text="Click me!", url="http://google.com") self.assertDictEqual( { "type": "section", "text": { "text": "some text", "type": "mrkdwn" }, "accessory": button.to_dict(), }, SectionBlock(text="some text", accessory=button).to_dict(), )
def test_send_blocks(self): client = WebhookClient("http://localhost:8888") resp = client.send( text="hello!", response_type="ephemeral", blocks=[ SectionBlock(text="Some text"), ImageBlock(image_url="image.jpg", alt_text="an image"), ], ) self.assertEqual("ok", resp.body) resp = client.send( text="hello!", response_type="ephemeral", blocks=[ { "type": "section", "text": { "type": "mrkdwn", "text": "This is a mrkdwn section block :ghost: *this is bold*, and ~this is crossed out~, and <https://google.com|this is a link>", }, }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Pick a date for the deadline." }, "accessory": { "type": "datepicker", "initial_date": "1990-04-28", "placeholder": { "type": "plain_text", "text": "Select a date", }, }, }, ], ) self.assertEqual("ok", resp.body) resp = client.send( text="hello!", response_type="ephemeral", blocks=[ SectionBlock(text="Some text"), ImageBlock(image_url="image.jpg", alt_text="an image"), ], ) self.assertEqual("ok", resp.body)
def build_slack_block_native(cls, msg1, msg2, data): blocks: List[SectionBlock] = [ SectionBlock(text=MarkdownTextObject.parse(f"*{msg1}*:\n{msg2}")), SectionBlock(fields=[]), ] names: List[str] = list(set(data.keys()) - set("user_comments")) fields = [ MarkdownTextObject.parse(f"*{name}*:\n{data[name]}") for name in names ] blocks[1].fields = fields return list(b.to_dict() for b in blocks)
def test_home_tab_construction(self): home_tab_view = View( type="home", blocks=[ SectionBlock( text=MarkdownTextObject( text="*Here's what you can do with Project Tracker:*" ), ), ActionsBlock( elements=[ ButtonElement( text=PlainTextObject(text="Create New Task", emoji=True), style="primary", value="create_task", ), ButtonElement( text=PlainTextObject(text="Create New Project", emoji=True), value="create_project", ), ButtonElement( text=PlainTextObject(text="Help", emoji=True), value="help", ), ], ), ContextBlock( elements=[ ImageElement( image_url="https://api.slack.com/img/blocks/bkb_template_images/placeholder.png", alt_text="placeholder", ), ], ), SectionBlock( text=MarkdownTextObject(text="*Your Configurations*"), ), DividerBlock(), SectionBlock( text=MarkdownTextObject( text="*#public-relations*\n<fakelink.toUrl.com|PR Strategy 2019> posts new tasks, comments, and project updates to <fakelink.toChannel.com|#public-relations>" ), accessory=ButtonElement( text=PlainTextObject(text="Edit", emoji=True), value="public-relations", ), ), ], ) home_tab_view.validate_json()
def labeled_button_block( label_text: str, button_text: str, value: str, action_id: str, ) -> dict[str, str]: """ Generate labeled button block. Labeled buttons have the label text on the left and the button on the right. Args: label_text (str): Label text to display. button_text (str): Button text to display. value (str): Hidden value to assign to the button. action_id (str): Action identifier to assign to the button. Returns: dict: View block with desired button. """ return SectionBlock( text=label_text, accessory=ButtonElement( text=button_text, value=value, action_id=action_id, ), ).to_dict()
def linked_labeled_button_block( url: str, label_text: str, button_text: str, value: str, action_id: str, ) -> dict[str, str]: """ Generate labeled button block. Linked labeled buttons have the link label text on the left and the button on the right. Args: url (str): URL for label. label_text (str): Label text to display. button_text (str): Button text to display. value (str): Hidden value to assign to the button. action_id (str): Action identifier to assign to the button. Returns: dict: View block with desired button. """ return SectionBlock( text=MarkdownTextObject.from_link(link=Link( url=url, text=label_text, )), accessory=ButtonElement( text=button_text, value=value, action_id=action_id, ), ).to_dict()
def legacy(): from slack_sdk.models.blocks import SectionBlock from slack_sdk.models.blocks.basic_components import TextObject fields = [] fields.append(TextObject(text="...", type="mrkdwn")) block = SectionBlock(text="", fields=fields) assert block is not None
def test_document_1(self): input = { "type": "section", "text": { "type": "mrkdwn", "text": "A message *with some bold text* and _some italicized text_.", }, } self.assertDictEqual(input, SectionBlock(**input).to_dict())
def test_parse(self): input = { "type": "section", "text": { "type": "plain_text", "text": "This is a plain text section block.", "emoji": True, }, } self.assertDictEqual(input, SectionBlock(**input).to_dict())
def test_basic_json(self): blocks = [ SectionBlock(text="Some text"), ImageBlock(image_url="image.jpg", alt_text="an image"), ] self.assertDictEqual( BlockAttachment(blocks=blocks).to_dict(), {"blocks": [b.to_dict() for b in blocks]}, )
def markdown_block(text: str) -> dict[str, str]: """ Generate general Markdown block. Args: text (str): Markdown text to display. Returns: dict: View block with desired Markdown text. """ return SectionBlock(text=MarkdownTextObject(text=text)).to_dict()
def test_document_2(self): input = { "type": "section", "text": { "text": "A message *with some bold text* and _some italicized text_.", "type": "mrkdwn", }, "fields": [ {"type": "mrkdwn", "text": "High"}, {"type": "plain_text", "emoji": True, "text": "String"}, ], } self.assertDictEqual(input, SectionBlock(**input).to_dict())
def test_issue_919_response_url_flag_options(self): client = WebhookClient("http://localhost:8888") resp = client.send( text="hello!", response_type="ephemeral", replace_original=True, blocks=[ SectionBlock(text="Some text"), ImageBlock(image_url="image.jpg", alt_text="an image"), ], ) self.assertEqual("ok", resp.body) resp = client.send( text="hello!", response_type="ephemeral", delete_original=True, blocks=[ SectionBlock(text="Some text"), ImageBlock(image_url="image.jpg", alt_text="an image"), ], ) self.assertEqual("ok", resp.body)
def test_document_3(self): input = { "type": "section", "text": { "text": "*Sally* has requested you set the deadline for the Nano launch project", "type": "mrkdwn", }, "accessory": { "type": "datepicker", "action_id": "datepicker123", "initial_date": "1990-04-28", "placeholder": {"type": "plain_text", "text": "Select a date"}, }, } self.assertDictEqual(input, SectionBlock(**input).to_dict())
def test_with_blocks(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = WebhookClient(url) response = webhook.send( text="fallback", blocks=[ SectionBlock( block_id="sb-id", text=MarkdownTextObject( text="This is a mrkdwn text section block."), fields=[ PlainTextObject(text="*this is plain_text text*", emoji=True), MarkdownTextObject(text="*this is mrkdwn text*"), PlainTextObject(text="*this is plain_text text*", emoji=True), ], ), DividerBlock(), ActionsBlock(elements=[ ButtonElement( text=PlainTextObject(text="Create New Task", emoji=True), style="primary", value="create_task", ), ButtonElement( text=PlainTextObject(text="Create New Project", emoji=True), value="create_project", ), ButtonElement( text=PlainTextObject(text="Help", emoji=True), value="help", ), ], ), ], ) self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body)
def slack_app(): if not signature_verifier.is_valid_request(request.get_data(), request.headers): return make_response("invalid request", 403) if "payload" in request.form: payload = json.loads(request.form["payload"]) if payload["type"] == "shortcut" and payload["callback_id"] == "test-shortcut": # Open a new modal by a global shortcut try: view = View( type="modal", callback_id="modal-id", title=PlainTextObject(text="Awesome Modal"), submit=PlainTextObject(text="Submit"), close=PlainTextObject(text="Cancel"), blocks=[ InputBlock( block_id="b-id", label=PlainTextObject(text="Input label"), element=PlainTextInputElement(action_id="a-id"), ) ], ) api_response = client.views_open( trigger_id=payload["trigger_id"], view=view, ) return make_response("", 200) except SlackApiError as e: code = e.response["error"] return make_response(f"Failed to open a modal due to {code}", 200) if ( payload["type"] == "view_submission" and payload["view"]["callback_id"] == "modal-id" ): # Handle a data submission request from the modal submitted_data = payload["view"]["state"]["values"] print( submitted_data ) # {'b-id': {'a-id': {'type': 'plain_text_input', 'value': 'your input'}}} return make_response( jsonify( { "response_action": "update", "view": View( type="modal", callback_id="modal-id", title=PlainTextObject(text="Accepted"), close=PlainTextObject(text="Close"), blocks=[ SectionBlock( block_id="b-id", text=PlainTextObject( text="Thanks for submitting the data!" ), ) ], ).to_dict(), } ), 200, ) return make_response("", 404)
def test_text_or_fields_populated(self): with self.assertRaises(SlackObjectFormationError): SectionBlock().to_dict()
def test_valid_construction(self): modal_view = View( type="modal", callback_id="modal-id", title=PlainTextObject(text="Awesome Modal"), submit=PlainTextObject(text="Submit"), close=PlainTextObject(text="Cancel"), blocks=[ InputBlock( block_id="b-id", label=PlainTextObject(text="Input label"), element=PlainTextInputElement(action_id="a-id"), ), InputBlock( block_id="cb-id", label=PlainTextObject(text="Label"), element=CheckboxesElement( action_id="a-cb-id", options=[ Option( text=PlainTextObject( text="*this is plain_text text*"), value="v1", ), Option( text=MarkdownTextObject( text="*this is mrkdwn text*"), value="v2", ), ], ), ), SectionBlock( block_id="sb-id", text=MarkdownTextObject( text="This is a mrkdwn text section block."), fields=[ PlainTextObject(text="*this is plain_text text*", emoji=True), MarkdownTextObject(text="*this is mrkdwn text*"), PlainTextObject(text="*this is plain_text text*", emoji=True), ], ), DividerBlock(), SectionBlock( block_id="rb-id", text=MarkdownTextObject( text= "This is a section block with radio button accessory"), accessory=RadioButtonsElement( initial_option=Option( text=PlainTextObject(text="Option 1"), value="option 1", description=PlainTextObject( text="Description for option 1"), ), options=[ Option( text=PlainTextObject(text="Option 1"), value="option 1", description=PlainTextObject( text="Description for option 1"), ), Option( text=PlainTextObject(text="Option 2"), value="option 2", description=PlainTextObject( text="Description for option 2"), ), ], ), ), ], ) modal_view.validate_json()
def handle_command(body: dict, ack: Ack, respond: Respond, client: WebClient, logger: Logger) -> None: logger.info(body) ack( text="Accepted!", blocks=[ SectionBlock( block_id="b", text=MarkdownTextObject(text=":white_check_mark: Accepted!"), ) ], ) respond(blocks=[ SectionBlock( block_id="b", text=MarkdownTextObject( text="You can add a button alongside text in your message. "), accessory=ButtonElement( action_id="a", text=PlainTextObject(text="Button"), value="click_me_123", ), ), ]) res = client.views_open( trigger_id=body["trigger_id"], view=View( type="modal", callback_id="view-id", title=PlainTextObject(text="My App"), submit=PlainTextObject(text="Submit"), close=PlainTextObject(text="Cancel"), blocks=[ InputBlock( element=PlainTextInputElement(action_id="text"), label=PlainTextObject(text="Label"), ), InputBlock( block_id="es_b", element=ExternalDataSelectElement( action_id="es_a", placeholder=PlainTextObject(text="Select an item"), min_query_length=0, ), label=PlainTextObject(text="Search"), ), InputBlock( block_id="mes_b", element=ExternalDataMultiSelectElement( action_id="mes_a", placeholder=PlainTextObject(text="Select an item"), min_query_length=0, ), label=PlainTextObject(text="Search (multi)"), ), ], ), ) logger.info(res)
import logging logging.basicConfig(level=logging.DEBUG) def legacy(): from slack_sdk.models.blocks import SectionBlock from slack_sdk.models.blocks.basic_components import TextObject fields = [] fields.append(TextObject(text="...", type="mrkdwn")) block = SectionBlock(text="", fields=fields) assert block is not None from slack_sdk.models.blocks import SectionBlock, TextObject fields = [] fields.append(TextObject(text="...", type="mrkdwn")) block = SectionBlock(text="", fields=fields) assert block is not None # # pip install mypy # mypy integration_tests/samples/issues/issue_868.py | grep integration_tests # # integration_tests/samples/issues/issue_868.py:26: error: Argument "fields" to "SectionBlock" has incompatible type "List[TextObject]"; expected "Optional[List[Union[str, Dict[Any, Any], TextObject]]]" # integration_tests/samples/issues/issue_868.py:26: note: "List" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance # integration_tests/samples/issues/issue_868.py:26: note: Consider using "Sequence" instead, which is covariant
def test_fields_length(self): with self.assertRaises(SlackObjectFormationError): SectionBlock(fields=[f"field{i}" for i in range(11)]).to_dict()
def test_issue_628(self): elem = SectionBlock(text="1234567890" * 300) elem.to_dict() # no exception with self.assertRaises(SlackObjectFormationError): elem = SectionBlock(text="1234567890" * 300 + "a") elem.to_dict()