Skip to content

Commit 3c63542

Browse files
committed
chore: merge w main
2 parents 76fd2bb + 726538c commit 3c63542

9 files changed

Lines changed: 85 additions & 13 deletions

File tree

.github/workflows/ci-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ jobs:
174174
if: ${{ !success() && github.ref == 'refs/heads/main' && github.event_name != 'workflow_dispatch' }}
175175
steps:
176176
- name: Send notifications of failing tests
177-
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
177+
uses: slackapi/slack-github-action@03ea5433c137af7c0495bc0cad1af10403fc800c # v3.0.2
178178
with:
179179
errors: true
180180
webhook: ${{ secrets.SLACK_REGRESSION_FAILURES_WEBHOOK_URL }}

.github/workflows/dependencies.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
steps:
1313
- name: Collect metadata
1414
id: metadata
15-
uses: dependabot/fetch-metadata@ffa630c65fa7e0ecfa0625b5ceda64399aea1b36 # v3.0.0
15+
uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
1616
with:
1717
github-token: "${{ secrets.GITHUB_TOKEN }}"
1818
- name: Approve

.github/workflows/pypi-release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
scripts/build_pypi_package.sh
3434
3535
- name: Persist dist folder
36-
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
36+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
3737
with:
3838
name: release-dist
3939
path: dist/
@@ -60,7 +60,7 @@ jobs:
6060
- name: Publish release distributions to test.pypi.org
6161
# Using OIDC for PyPI publishing (no API tokens needed)
6262
# See: https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi
63-
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
63+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
6464
with:
6565
repository-url: https://test.pypi.org/legacy/
6666

@@ -84,4 +84,4 @@ jobs:
8484
- name: Publish release distributions to pypi.org
8585
# Using OIDC for PyPI publishing (no API tokens needed)
8686
# See: https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi
87-
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
87+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ Defined in `.github/workflows/ci-build.yml`, runs on push to `main`, all PRs, an
281281
3. Add tests mirroring the module structure
282282
4. Validate: `./scripts/run_validation.sh`
283283

284+
### Adding a New Block Kit Type
285+
286+
See [`slack_sdk/models/AGENTS.md`](slack_sdk/models/AGENTS.md) for detailed steps on defining, registering, exporting, and testing new Block Kit blocks, elements, and composition objects.
287+
284288
### Fixing a Bug
285289

286290
1. Write a test that reproduces the bug

slack_sdk/models/AGENTS.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# AGENTS.md — Block Kit Models
2+
3+
The `slack_sdk/models/` package provides Python classes for building [Block Kit](https://api.slack.com/block-kit) UI layouts. Each class serializes to/from the JSON payloads that the Slack API expects, with helper methods for parsing nested composition objects.
4+
5+
## Adding a New Block Kit Type
6+
7+
Block Kit models live in `slack_sdk/models/blocks/` across three files:
8+
9+
| File | Contents |
10+
| --- | --- |
11+
| `blocks.py` | Layout blocks (`SectionBlock`, `ActionsBlock`, `HeaderBlock`, etc.) |
12+
| `block_elements.py` | Interactive elements (`ButtonElement`, `StaticSelectElement`, `DatePickerElement`, etc.) |
13+
| `basic_components.py` | Composition objects (`TextObject`, `Option`, `ConfirmObject`, etc.) |
14+
15+
All types are exported from `slack_sdk/models/blocks/__init__.py`.
16+
17+
### Base class hierarchy
18+
19+
```
20+
JsonObject
21+
├── Block → layout blocks
22+
├── BlockElement → non-interactive elements
23+
│ └── InteractiveElement → elements with action_id
24+
│ └── InputInteractiveElement → elements usable inside InputBlock
25+
├── TextObject → PlainTextObject, MarkdownTextObject
26+
├── Option / OptionGroup
27+
└── ConfirmObject, etc.
28+
```
29+
30+
Choose the base class that matches the type you're adding.
31+
32+
### Steps
33+
34+
1. **Define the class** in the appropriate file. Follow this pattern:
35+
36+
```python
37+
class MyNewBlock(Block):
38+
type = "my_new_block"
39+
40+
@property
41+
def attributes(self) -> Set[str]:
42+
return super().attributes.union({"text", "optional_field"})
43+
44+
def __init__(self, *, text: Union[str, dict, TextObject], optional_field: Optional[str] = None, block_id: Optional[str] = None, **others: dict):
45+
super().__init__(type=self.type, block_id=block_id)
46+
show_unknown_key_warning(self, others)
47+
self.text = TextObject.parse(text, default_type=PlainTextObject.type)
48+
self.optional_field = optional_field
49+
```
50+
51+
Key conventions:
52+
- Set `type` class attribute to the Slack API type string
53+
- Override `attributes` to return the set of JSON field names for serialization
54+
- Call `super().__init__()` with `type=self.type`
55+
- Call `show_unknown_key_warning(self, others)` to log unexpected kwargs
56+
- Use `TextObject.parse()`, `ConfirmObject.parse()`, and `BlockElement.parse()` for nested composition objects
57+
58+
2. **Register for deserialization:**
59+
- **Elements:** Automatic — `BlockElement.parse()` discovers subclasses at runtime via `__subclasses__()`. No manual step needed.
60+
- **Blocks:** Manual — add an `elif` clause in `Block.parse()` (in `blocks.py`) mapping the type string to the new class.
61+
62+
3. **Export the class** — add it to the imports and `__all__` list in `slack_sdk/models/blocks/__init__.py`.
63+
64+
4. **Add tests** in `tests/slack_sdk/models/test_blocks.py`. Cover:
65+
- Round-trip: `input_dict == MyNewBlock(**input_dict).to_dict()`
66+
67+
5. **Validate:** `./scripts/run_validation.sh`

slack_sdk/oauth/installation_store/amazon_s3/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def save(self, installation: Installation):
106106

107107
def save_bot(self, bot: Bot):
108108
if bot.bot_token is None:
109-
self.logger.debug("Skipped saving a new row because of the absense of bot token in it")
109+
self.logger.debug("Skipped saving a new row because of the absence of bot token in it")
110110
return
111111

112112
none = "none"
@@ -273,7 +273,7 @@ def delete_bot(self, *, enterprise_id: Optional[str], team_id: Optional[str]) ->
273273
Key=content.get("Key"),
274274
)
275275
except Exception as e:
276-
message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}"
276+
message = f"Failed to delete bot installation data for enterprise: {e_id}, team: {t_id}: {e}"
277277
raise SlackClientConfigurationError(message)
278278

279279
async def async_delete_installation(
@@ -316,7 +316,7 @@ def delete_installation(
316316
)
317317
deleted_keys.append(key)
318318
except Exception as e:
319-
message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}"
319+
message = f"Failed to delete installation data for enterprise: {e_id}, team: {t_id}: {e}"
320320
raise SlackClientConfigurationError(message)
321321

322322
try:
@@ -328,7 +328,7 @@ def delete_installation(
328328
)
329329
deleted_keys.append(no_user_id_key)
330330
except Exception as e:
331-
message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}"
331+
message = f"Failed to delete installation data for enterprise: {e_id}, team: {t_id}: {e}"
332332
raise SlackClientConfigurationError(message)
333333

334334
# Check the remaining installation data
@@ -347,5 +347,5 @@ def delete_installation(
347347
Key=content.get("Key"),
348348
)
349349
except Exception as e:
350-
message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}"
350+
message = f"Failed to delete installation data for enterprise: {e_id}, team: {t_id}: {e}"
351351
raise SlackClientConfigurationError(message)

slack_sdk/oauth/installation_store/async_cacheable_installation_store.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ async def async_delete_bot(
9898
team_id=team_id,
9999
)
100100
key = f"{enterprise_id or ''}-{team_id or ''}"
101-
self.cached_bots.pop(key)
101+
if key in self.cached_bots:
102+
self.cached_bots.pop(key)
102103

103104
async def async_delete_installation(
104105
self,

slack_sdk/oauth/installation_store/file/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def save(self, installation: Installation):
7878

7979
def save_bot(self, bot: Bot):
8080
if bot.bot_token is None:
81-
self.logger.debug("Skipped saving a new row because of the absense of bot token in it")
81+
self.logger.debug("Skipped saving a new row because of the absence of bot token in it")
8282
return
8383

8484
none = "none"

slack_sdk/oauth/installation_store/sqlite3/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def save(self, installation: Installation):
217217

218218
def save_bot(self, bot: Bot):
219219
if bot.bot_token is None:
220-
self.logger.debug("Skipped saving a new row because of the absense of bot token in it")
220+
self.logger.debug("Skipped saving a new row because of the absence of bot token in it")
221221
return
222222

223223
with self.connect() as conn:

0 commit comments

Comments
 (0)