From a720785413b643fcf8d0f0834096f66a1d6c00ab Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 27 Aug 2026 20:31:15 -0700 Subject: [PATCH 1/3] feat(models): add AttachmentMention rich text element Add a typed `RichTextElementParts.AttachmentMention` builder for the `attachment_mention` rich text element, which renders as a rich app attachment or entity reference within a `rich_text` block. Fields follow the reference documentation: https://docs.slack.dev/reference/block-kit/block-elements/attachment-mention-element/ Adds `test_document` (the url-only payload shown in the docs) and `test_all_fields` (every optional field) asserting `to_dict()` output. Co-Authored-By: Claude --- slack_sdk/models/blocks/block_elements.py | 54 +++++++++++++++++++++++ tests/slack_sdk/models/test_elements.py | 34 ++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/slack_sdk/models/blocks/block_elements.py b/slack_sdk/models/blocks/block_elements.py index 7b52b0f95..3ead7558c 100644 --- a/slack_sdk/models/blocks/block_elements.py +++ b/slack_sdk/models/blocks/block_elements.py @@ -2096,6 +2096,60 @@ def to_dict(self, *args) -> dict: } return {k: v for k, v in result.items() if v is not None} + class AttachmentMention(RichTextElement): + type = "attachment_mention" + + @property + def attributes(self) -> Set[str]: # type: ignore[override] + return super().attributes.union( + { + "url", + "text", + "app_id", + "entity_id", + "icon_url", + "channel_id", + "ts", + "full_size_preview_enabled", + "icon_name", + "reference_object_type", + "product_name", + "style", + } + ) + + def __init__( + self, + *, + url: str, + text: Optional[str] = None, + app_id: Optional[str] = None, + entity_id: Optional[str] = None, + icon_url: Optional[str] = None, + channel_id: Optional[str] = None, + ts: Optional[str] = None, + full_size_preview_enabled: Optional[bool] = None, + icon_name: Optional[str] = None, + reference_object_type: Optional[str] = None, + product_name: Optional[str] = None, + style: Optional[Union[dict, "RichTextElementParts.TextStyle"]] = None, + **others: dict, + ): + super().__init__(type=self.type) + show_unknown_key_warning(self, others) + self.url = url + self.text = text + self.app_id = app_id + self.entity_id = entity_id + self.icon_url = icon_url + self.channel_id = channel_id + self.ts = ts + self.full_size_preview_enabled = full_size_preview_enabled + self.icon_name = icon_name + self.reference_object_type = reference_object_type + self.product_name = product_name + self.style = style + class Text(RichTextElement): type = "text" diff --git a/tests/slack_sdk/models/test_elements.py b/tests/slack_sdk/models/test_elements.py index 4a5a062d3..afcc4a233 100644 --- a/tests/slack_sdk/models/test_elements.py +++ b/tests/slack_sdk/models/test_elements.py @@ -1112,6 +1112,40 @@ def test_document(self): self.assertDictEqual(input, OverflowMenuElement(**input).to_dict()) +# ------------------------------------------------- +# Rich text element parts +# ------------------------------------------------- + + +class AttachmentMentionElementTests(unittest.TestCase): + def test_all_fields(self): + input = { + "type": "attachment_mention", + "url": "https://example.com/attachment", + "text": "Fallback text", + "app_id": "A0123456789", + "entity_id": "E0123456789", + "icon_url": "https://example.com/icon.png", + "channel_id": "C0123456789", + "ts": "1234567890.123456", + "full_size_preview_enabled": True, + "icon_name": "sf-account", + "reference_object_type": "record", + "product_name": "Salesforce", + "style": {"bold": True}, + } + self.assertDictEqual(input, RichTextElementParts.AttachmentMention(**input).to_dict()) + + def test_document(self): + # Matches the docs reference example field-for-field: + # https://docs.slack.dev/reference/block-kit/block-elements/attachment-mention-element + input = { + "type": "attachment_mention", + "url": "https://example.com/attachment", + } + self.assertDictEqual(input, RichTextElementParts.AttachmentMention(**input).to_dict()) + + # ------------------------------------------------- # Input # ------------------------------------------------- From 939ba358cecb756134f8a7a4a5cf8017abb56fe8 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 27 Aug 2026 21:10:10 -0700 Subject: [PATCH 2/3] test(models): move rich text element parts section ahead of concrete elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Place the AttachmentMention test section as the first concrete-element section — right after the abstract base test classes (BlockElementTests, InteractiveElementTests), before ButtonElementTests — rather than buried mid-file. Deterministic anchor: insert after the last base/abstract test class, before the first concrete element section. Co-Authored-By: Claude --- tests/slack_sdk/models/test_elements.py | 68 ++++++++++++------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/slack_sdk/models/test_elements.py b/tests/slack_sdk/models/test_elements.py index afcc4a233..07237ade1 100644 --- a/tests/slack_sdk/models/test_elements.py +++ b/tests/slack_sdk/models/test_elements.py @@ -91,6 +91,40 @@ def test_with_input_interactive_element(self): self.assertDictEqual(input, InputInteractiveElement(**input).to_dict()) +# ------------------------------------------------- +# Rich text element parts +# ------------------------------------------------- + + +class AttachmentMentionElementTests(unittest.TestCase): + def test_all_fields(self): + input = { + "type": "attachment_mention", + "url": "https://example.com/attachment", + "text": "Fallback text", + "app_id": "A0123456789", + "entity_id": "E0123456789", + "icon_url": "https://example.com/icon.png", + "channel_id": "C0123456789", + "ts": "1234567890.123456", + "full_size_preview_enabled": True, + "icon_name": "sf-account", + "reference_object_type": "record", + "product_name": "Salesforce", + "style": {"bold": True}, + } + self.assertDictEqual(input, RichTextElementParts.AttachmentMention(**input).to_dict()) + + def test_document(self): + # Matches the docs reference example field-for-field: + # https://docs.slack.dev/reference/block-kit/block-elements/attachment-mention-element + input = { + "type": "attachment_mention", + "url": "https://example.com/attachment", + } + self.assertDictEqual(input, RichTextElementParts.AttachmentMention(**input).to_dict()) + + class ButtonElementTests(unittest.TestCase): def test_document_1(self): input = { @@ -1112,40 +1146,6 @@ def test_document(self): self.assertDictEqual(input, OverflowMenuElement(**input).to_dict()) -# ------------------------------------------------- -# Rich text element parts -# ------------------------------------------------- - - -class AttachmentMentionElementTests(unittest.TestCase): - def test_all_fields(self): - input = { - "type": "attachment_mention", - "url": "https://example.com/attachment", - "text": "Fallback text", - "app_id": "A0123456789", - "entity_id": "E0123456789", - "icon_url": "https://example.com/icon.png", - "channel_id": "C0123456789", - "ts": "1234567890.123456", - "full_size_preview_enabled": True, - "icon_name": "sf-account", - "reference_object_type": "record", - "product_name": "Salesforce", - "style": {"bold": True}, - } - self.assertDictEqual(input, RichTextElementParts.AttachmentMention(**input).to_dict()) - - def test_document(self): - # Matches the docs reference example field-for-field: - # https://docs.slack.dev/reference/block-kit/block-elements/attachment-mention-element - input = { - "type": "attachment_mention", - "url": "https://example.com/attachment", - } - self.assertDictEqual(input, RichTextElementParts.AttachmentMention(**input).to_dict()) - - # ------------------------------------------------- # Input # ------------------------------------------------- From 5af76e6ff10e1d2f40cbf14d36aa68c0d39118b9 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 27 Aug 2026 21:15:59 -0700 Subject: [PATCH 3/3] test(models): drop premature section banner for lone AttachmentMention test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file banners head groups of related classes; standalone concrete classes (ButtonElementTests, LinkButtonElementTests, …) sit bare. A one-member "Rich text element parts" banner over-promised a group and named the SDK container rather than the element, so drop it — the class sits bare like its neighbors. A banner earns its place once the group has ≥2 members. Co-Authored-By: Claude --- tests/slack_sdk/models/test_elements.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/slack_sdk/models/test_elements.py b/tests/slack_sdk/models/test_elements.py index 07237ade1..e856dedb9 100644 --- a/tests/slack_sdk/models/test_elements.py +++ b/tests/slack_sdk/models/test_elements.py @@ -91,11 +91,6 @@ def test_with_input_interactive_element(self): self.assertDictEqual(input, InputInteractiveElement(**input).to_dict()) -# ------------------------------------------------- -# Rich text element parts -# ------------------------------------------------- - - class AttachmentMentionElementTests(unittest.TestCase): def test_all_fields(self): input = {