Repository: slackapi/python-slack-sdk
Pull request #1406 (2023-10-03 04:53:03)

Add RichTextInputElement to slack_sdk.models
## Summary

This pull request adds RichTextInputElement to slack_sdk.models utilities.

references:
* https://api.slack.com/reference/block-kit/block-elements#rich_text_input

### Category (place an `x` in each of the `[ ]`)

- [ ] **slack_sdk.web.WebClient (sync/async)** (Web API client)
- [ ] **slack_sdk.webhook.WebhookClient (sync/async)** (Incoming Webhook, response_url sender)
- [ ] **slack_sdk.socket_mode** (Socket Mode client)
- [ ] **slack_sdk.signature** (Request Signature Verifier)
- [ ] **slack_sdk.oauth** (OAuth Flow Utilities)
- [x] **slack_sdk.models** (UI component builders)
- [ ] **slack_sdk.scim** (SCIM API client)
- [ ] **slack_sdk.audit_logs** (Audit Logs API client)
- [ ] **slack_sdk.rtm_v2** (RTM client)
- [ ] `/docs-src` (Documents, have you run `./scripts/docs.sh`?)
- [ ] `/docs-src-v2` (Documents, have you run `./scripts/docs-v2.sh`?)
- [ ] `/tutorial` (PythOnBoardingBot tutorial)
- [ ] `tests`/`integration_tests` (Automated tests for this library)

## Requirements (place an `x` in each `[ ]`)

- [x] I've read and understood the [Contributing Guidelines](https://github.com/slackapi/python-slack-sdk/blob/main/.github/contributing.md) and have done my best effort to follow them.
- [x] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
- [x] I've run `python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.sh` after making the changes.


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1406?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) Report
> Merging [#1406](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1406?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) (a353286) into [main](https://app.codecov.io/gh/slackapi/python-slack-sdk/commit/398923a417525ed5014bb0695a5a21ad0420815a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) (398923a) will **increase** coverage by `0.02%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main    #1406      +/-   ##
==========================================
+ Coverage   85.37%   85.39%   +0.02%     
==========================================
  Files         111      111              
  Lines       11860    11871      +11     
==========================================
+ Hits        10125    10137      +12     
+ Misses       1735     1734       -1     
```


| [Files](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1406?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) | Coverage Δ | |
|---|---|---|
| [slack\_sdk/models/blocks/\_\_init\_\_.py](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1406?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi#diff-c2xhY2tfc2RrL21vZGVscy9ibG9ja3MvX19pbml0X18ucHk=) | `100.00% <100.00%> (ø)` | |
| [slack\_sdk/models/blocks/block\_elements.py](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1406?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi#diff-c2xhY2tfc2RrL21vZGVscy9ibG9ja3MvYmxvY2tfZWxlbWVudHMucHk=) | `95.63% <100.00%> (+0.09%)` | :arrow_up: |

... and [2 files with indirect coverage changes](https://app.codecov.io/gh/slackapi/python-slack-sdk/pull/1406/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)


Patch:
diff --git a/slack_sdk/models/blocks/__init__.py b/slack_sdk/models/blocks/__init__.py
index 3dfd87d..87febae 100644
--- a/slack_sdk/models/blocks/__init__.py
+++ b/slack_sdk/models/blocks/__init__.py
@@ -32,6 +32,7 @@ from .block_elements import InputInteractiveElement
 from .block_elements import InteractiveElement
 from .block_elements import LinkButtonElement
 from .block_elements import OverflowMenuElement
+from .block_elements import RichTextInputElement
 from .block_elements import PlainTextInputElement
 from .block_elements import EmailInputElement
 from .block_elements import UrlInputElement
@@ -81,6 +82,7 @@ __all__ = [
     "InteractiveElement",
     "LinkButtonElement",
     "OverflowMenuElement",
+    "RichTextInputElement",
     "PlainTextInputElement",
     "EmailInputElement",
     "UrlInputElement",
diff --git a/slack_sdk/models/blocks/block_elements.py b/slack_sdk/models/blocks/block_elements.py
index 4cf1519..c65bd7f 100644
--- a/slack_sdk/models/blocks/block_elements.py
+++ b/slack_sdk/models/blocks/block_elements.py
@@ -3,7 +3,7 @@ import logging
 import re
 import warnings
 from abc import ABCMeta
-from typing import Iterator, List, Optional, Set, Type, Union, Sequence
+from typing import Iterator, List, Optional, Set, Type, Union, Sequence, Dict, Any
 
 from slack_sdk.models import show_unknown_key_warning
 from slack_sdk.models.basic_objects import (
@@ -1331,6 +1331,45 @@ class ChannelMultiSelectElement(InputInteractiveElement):
         self.max_selected_items = max_selected_items
 
 
+# -------------------------------------------------
+# Rich Text Input Element
+# -------------------------------------------------
+
+
+class RichTextInputElement(InputInteractiveElement):
+    type = "rich_text_input"
+
+    @property
+    def attributes(self) -> Set[str]:
+        return super().attributes.union(
+            {
+                "initial_value",
+                "dispatch_action_config",
+            }
+        )
+
+    def __init__(
+        self,
+        *,
+        action_id: Optional[str] = None,
+        placeholder: Optional[Union[str, dict, TextObject]] = None,
+        initial_value: Optional[Dict[str, Any]] = None,  # TODO: Add rich_text block class and its element classes
+        dispatch_action_config: Optional[Union[dict, DispatchActionConfig]] = None,
+        focus_on_load: Optional[bool] = None,
+        **others: dict,
+    ):
+        super().__init__(
+            type=self.type,
+            action_id=action_id,
+            placeholder=TextObject.parse(placeholder, PlainTextObject.type),
+            focus_on_load=focus_on_load,
+        )
+        show_unknown_key_warning(self, others)
+
+        self.initial_value = initial_value
+        self.dispatch_action_config = dispatch_action_config
+
+
 # -------------------------------------------------
 # Plain Text Input Element
 # -------------------------------------------------


Test patch:
diff --git a/tests/slack_sdk/models/test_elements.py b/tests/slack_sdk/models/test_elements.py
index 1b246b0..fe63d5f 100644
--- a/tests/slack_sdk/models/test_elements.py
+++ b/tests/slack_sdk/models/test_elements.py
@@ -34,6 +34,7 @@ from slack_sdk.models.blocks.block_elements import (
     NumberInputElement,
     UrlInputElement,
     WorkflowButtonElement,
+    RichTextInputElement,
 )
 from . import STRING_3001_CHARS, STRING_301_CHARS
 
@@ -1013,6 +1014,26 @@ class OverflowMenuElementTests(unittest.TestCase):
 # -------------------------------------------------
 
 
+class RichTextInputElementTests(unittest.TestCase):
+    def test_simple(self):
+        input = {
+            "type": "rich_text_input",
+            "action_id": "rich_input",
+            "placeholder": {"type": "plain_text", "text": "Enter some plain text"},
+        }
+        self.assertDictEqual(input, RichTextInputElement(**input).to_dict())
+
+    def test_document(self):
+        input = {
+            "type": "rich_text_input",
+            "action_id": "rich_text_input-action",
+            "dispatch_action_config": {"trigger_actions_on": ["on_character_entered"]},
+            "focus_on_load": True,
+            "placeholder": {"type": "plain_text", "text": "Enter text"},
+        }
+        self.assertDictEqual(input, RichTextInputElement(**input).to_dict())
+
+
 class PlainTextInputElementTests(unittest.TestCase):
     def test_document_1(self):
         input = {