|
| 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` |
0 commit comments