| Name | slack-blocksmith JSON |
| Version |
1.2.2
JSON |
| download |
| home_page | None |
| Summary | A Python package for building Slack Block Kit structures with dedicated classes using builder pattern |
| upload_time | 2025-10-27 20:09:46 |
| maintainer | None |
| docs_url | None |
| author | None |
| requires_python | >=3.8 |
| license | MIT |
| keywords |
api
block-kit
bot
builder
messaging
slack
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# Slack Block Kit Builder
> **Package Type**: Python Library
> **Primary Use**: Slack Block Kit JSON Generation
> **Pattern**: Builder Pattern with Method Chaining
> **Validation**: Pydantic-based Type Safety
> **Target**: Slack API Integration
A comprehensive Python package for building Slack Block Kit structures with dedicated classes using the builder pattern. Provides a type-safe, intuitive API for creating Slack messages, modals, and home tabs without the complexity of raw JSON construction.
## ๐ Quick Reference
**Main Classes:**
- `Message` - Build Slack messages with blocks
- `Modal` - Build interactive modals
- `HomeTab` - Build home tab interfaces
- `Section`, `Actions`, `Context` - Block containers
- `Button`, `SelectMenu`, `Input` - Interactive elements
- `PlainText`, `MrkdwnText` - Text objects
**Key Methods:**
- `.create()` - Initialize objects
- `.build()` - Generate JSON output
- `.add_*()` - Add blocks/elements (Message builder)
- `.add_*_block()` - Add pre-created block objects directly
- `.set_*()` - Configure properties (Builder pattern)
- `.from_payload()` - Parse existing Slack messages from JSON
### ๐ค AI Agent Decision Tree
**Need to create a Slack message?**
```
Start with Message.create()
โโโ Add text content? โ .add_section(text)
โโโ Add interactive buttons? โ .add_actions([Button.create(text, action_id)])
โโโ Add form inputs? โ .add_input(label, InputElement.create(action_id))
โโโ Add images? โ .add_image(url, alt_text)
โโโ Add context info? โ .add_context([text_or_elements])
```
**Need interactive elements?**
```
Button โ Button.create(text, action_id)
Dropdown โ StaticSelect.create(action_id, placeholder, options)
Text Input โ PlainTextInput.create(action_id)
Date Picker โ DatePicker.create(action_id)
Multi-select โ MultiStaticSelect.create(action_id, placeholder, options)
```
**Need text formatting?**
```
Plain text โ PlainText.create(text)
Markdown โ MrkdwnText.create(text)
```
**Need a modal?**
```
Start with Modal.create(title)
โโโ Add inputs โ .add_input(label, element)
โโโ Set buttons โ .submit(text).close(text)
โโโ Add metadata โ .callback_id(id).private_metadata(data)
```
**Need to parse existing messages?**
```
Parse from JSON โ Message.from_payload(payload)
โโโ Modify content โ .add_section(text)
โโโ Update buttons โ .add_actions([Button.create(...)])
โโโ Build back โ .build() for Slack API
```
## ๐ Features
- **๐๏ธ Builder Pattern**: Fluent method chaining for intuitive API design
- **๐ Type Safety**: Full pydantic validation with comprehensive type hints
- **๐ฆ Complete Coverage**: All Slack Block Kit blocks, elements, and composition objects
- **๐ Easy Migration**: Clear 1:1 mapping to Slack Block Kit JSON structure
- **๐ฏ Direct Object Methods**: Add pre-created blocks directly for better flexibility
- **๐ Message Parsing**: Parse existing Slack messages from JSON payloads (`from_payload`)
- **โจ Code Quality**: Ruff linting, mypy type checking, comprehensive test coverage
- **๐ Rich Documentation**: Extensive examples, API reference, and migration guides
- **โก Performance**: Optimized for both development and production use
## ๐ฆ Installation
### Using pip
```bash
pip install slack-block-kit-builder
```
### Using uv (recommended)
```bash
uv add slack-block-kit-builder
```
### Development Installation
```bash
git clone https://github.com/your-org/slack-block-kit-builder.git
cd slack-block-kit-builder
uv pip install -e ".[dev]"
```
## ๐ฏ Why Use slack-block-kit-builder?
### Before: Raw JSON Construction
```python
# Complex, error-prone, hard to maintain
message = {
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Hello *World*! ๐"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Click Me"
},
"action_id": "btn_click",
"style": "primary"
}
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Built with slack-block-kit-builder"
}
]
}
]
}
```
### After: Builder Pattern
```python
# Clean, type-safe, maintainable
from slack_blocksmith import Message, Section, Button, MrkdwnText
message = (
Message.create()
.add_section(
text=MrkdwnText.create("Hello *World*! ๐"),
accessory=Button.create("Click Me", "btn_click").style("primary")
)
.add_divider()
.add_context(["Built with slack-block-kit-builder"])
.build()
)
```
## ๐ค AI Agent Usage Patterns
### Common Import Patterns
```python
# Basic imports for most use cases
from slack_blocksmith import Message, Section, Button, PlainText
# Full imports for complex applications
from slack_blocksmith import (
Message, Modal, HomeTab,
Section, Actions, Context, Input, Header,
Button, StaticSelect, PlainTextInput, DatePicker,
PlainText, MrkdwnText, Option
)
```
### Standard Message Creation Pattern
```python
# Pattern: Create -> Configure -> Build
message = (
Message.create()
.add_section("Text content")
.add_actions([Button.create("Action", "action_id")])
.build()
)
```
### Element Configuration Pattern
```python
# Pattern: Create -> Set Properties -> Build
button = (
Button.create("Click Me", "btn_1")
.style("primary")
.confirm(confirmation_dialog)
.build()
)
```
### Common Error Patterns
```python
# โ Wrong: Missing action_id
Button.create("Text") # ValidationError
# โ
Correct: Include action_id
Button.create("Text", "action_id")
# โ Wrong: Invalid style
Button.create("Text", "btn").style("invalid") # ValidationError
# โ
Correct: Valid styles
Button.create("Text", "btn").style("primary") # or "danger"
```
## ๐ Quick Start
### Basic Message
```python
from slack_blocksmith import Message, Section, Button, PlainText
message = (
Message.create()
.add_section("Hello World! ๐")
.add_divider()
.add_section(
text="This is a *markdown* message with a button:",
accessory=Button.create("Click Me!", "btn_click")
)
.add_context(["Built with slack-block-kit-builder"])
.build()
)
```
### Interactive Message
```python
from slack_blocksmith import Message, Button, StaticSelect, Option
message = (
Message.create()
.add_header("Task Management")
.add_section("Choose an action:")
.add_actions([
Button.create("Approve", "btn_approve").style("primary"),
Button.create("Reject", "btn_reject").style("danger"),
StaticSelect.create("priority", "Priority", [
Option.create("High", "high"),
Option.create("Medium", "medium"),
Option.create("Low", "low")
])
])
.build()
)
```
### Direct Object Methods
For more flexibility, you can create blocks independently and add them directly:
```python
from slack_blocksmith import Message, Section, Divider, Header, Actions, Button, PlainText
# Create blocks independently
section = Section.create(
text=PlainText.create("Hello World!"),
block_id="section1"
)
divider = Divider.create(block_id="divider1")
header = Header.create(
text="My Header",
block_id="header1"
)
button = Button.create("Click Me", "btn_click")
actions = Actions.create(
elements=[button],
block_id="actions1"
)
# Add blocks directly to message
message = (Message.create()
.add_section_block(section)
.add_divider_block(divider)
.add_header_block(header)
.add_actions_block(actions)
.build())
```
**Available Direct Object Methods:**
- `.add_section_block(section: Section)` - Add pre-created Section block
- `.add_divider_block(divider: Divider)` - Add pre-created Divider block
- `.add_image_block(image: ImageBlock)` - Add pre-created ImageBlock
- `.add_actions_block(actions: Actions)` - Add pre-created Actions block
- `.add_context_block(context: Context)` - Add pre-created Context block
- `.add_input_block(input_block: Input)` - Add pre-created Input block
- `.add_file_block(file_block: File)` - Add pre-created File block
- `.add_header_block(header: Header)` - Add pre-created Header block
- `.add_video_block(video: Video)` - Add pre-created Video block
- `.add_rich_text_block(rich_text: RichText)` - Add pre-created RichText block
**Benefits of Direct Object Methods:**
- **Reusability**: Create blocks once, use in multiple messages
- **Better Organization**: Separate block creation from message building
- **Type Safety**: Direct object methods provide better type checking
- **Flexibility**: Mix and match different approaches as needed
### ๐ Parsing Existing Messages (`from_payload`)
Parse existing Slack messages from JSON payloads and modify them:
```python
from slack_blocksmith import Message, MrkdwnText
# Parse a message from Slack payload JSON
slack_payload = {
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Integration Test Results"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Status*: Running tests..."
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "View Details"
},
"action_id": "view_details",
"url": "https://example.com"
}
}
]
}
# Parse the payload into a Message object
message = Message.from_payload(slack_payload)
# Modify the message
updated_message = message.add_section(
text=MrkdwnText.create("*New*: Tests completed successfully!")
)
# Build back to dictionary for Slack API
updated_payload = updated_message.build()
```
**Use Cases:**
- **Action Handlers**: Parse incoming messages from button clicks, form submissions
- **Message Updates**: Modify existing messages based on user interactions
- **Workflow Integration**: Process messages from external systems
- **Testing**: Parse and validate message structures
**Supported Input Formats:**
```python
# From dictionary
message = Message.from_payload({"blocks": [...]})
# From JSON string
message = Message.from_payload('{"blocks": [...]}')
# With message properties
message = Message.from_payload({
"blocks": [...],
"response_type": "ephemeral",
"replace_original": True,
"metadata": {"key": "value"}
})
```
**Error Handling:**
```python
try:
message = Message.from_payload(invalid_payload)
except ValueError as e:
print(f"Invalid payload: {e}")
```
### Modal
```python
from slack_blocksmith import Modal, PlainTextInput, DatePicker, StaticSelect, Option
modal = (
Modal.create("User Registration")
.add_header("New User Registration")
.add_input("Full Name", PlainTextInput.create("full_name").placeholder("Enter name"))
.add_input("Start Date", DatePicker.create("start_date").placeholder("Select date"))
.add_input("Department", StaticSelect.create("dept", "Select department", [
Option.create("Engineering", "eng"),
Option.create("Marketing", "marketing")
]))
.submit("Register")
.close("Cancel")
.build()
)
```
## ๐ API Reference for AI Agents
### Class Hierarchy
```
Base Classes:
โโโ BaseModel (pydantic)
โโโ Element (interactive elements)
โโโ Block (container blocks)
โโโ TextObject (text formatting)
Message Builders:
โโโ Message
โโโ Modal
โโโ HomeTab
Blocks:
โโโ Section (text + optional accessory)
โโโ Actions (interactive elements container)
โโโ Context (small text/images)
โโโ Input (form input with label)
โโโ Header (large text)
โโโ Divider (separator)
โโโ Image (image display)
โโโ File (file display)
โโโ Video (video display)
โโโ RichText (rich formatting)
Elements:
โโโ Button (interactive button)
โโโ StaticSelect (dropdown menu)
โโโ MultiStaticSelect (multi-select dropdown)
โโโ PlainTextInput (text input field)
โโโ EmailInput (email input field)
โโโ NumberInput (number input field)
โโโ URLInput (URL input field)
โโโ DatePicker (date selection)
โโโ TimePicker (time selection)
โโโ DatetimePicker (date+time selection)
โโโ Checkboxes (multiple checkboxes)
โโโ RadioButtons (radio button group)
โโโ OverflowMenu (overflow menu)
โโโ FileInput (file upload)
โโโ RichTextInput (rich text input)
โโโ Image (image element)
Composition Objects:
โโโ PlainText (plain text object)
โโโ MrkdwnText (markdown text object)
โโโ Option (select menu option)
โโโ OptionGroup (grouped options)
โโโ ConfirmationDialog (confirmation dialog)
โโโ Filter (conversation filter)
โโโ ConversationFilter (conversation filter)
```
### Method Patterns by Class Type
**Message Builders:**
- `.create()` - Initialize
- `.add_section(text, fields, accessory)` - Add text section
- `.add_actions(elements)` - Add interactive elements
- `.add_context(elements)` - Add context elements
- `.add_input(label, element)` - Add form input
- `.add_header(text)` - Add header
- `.add_divider()` - Add separator
- `.add_image(url, alt_text)` - Add image
- `.add_file(url)` - Add file
- `.add_video(url, alt_text)` - Add video
- `.add_rich_text(elements)` - Add rich text
- `.add_block(block)` - Add custom block
- `.build()` - Generate JSON
**Interactive Elements:**
- `.create(text, action_id)` - Initialize with required params
- `.style("primary"|"danger")` - Set button style
- `.confirm(dialog)` - Set confirmation dialog
- `.placeholder(text)` - Set placeholder text
- `.initial_value(value)` - Set initial value
- `.build()` - Generate JSON
**Text Objects:**
- `.create(text)` - Initialize with text
- `.emoji(True|False)` - Enable/disable emoji
- `.verbatim(True|False)` - Enable/disable verbatim (MrkdwnText)
- `.build()` - Generate JSON
## ๐ Comprehensive API Reference
### ๐๏ธ Message Builders
#### `Message`
The primary class for building Slack messages with blocks.
```python
from slack_blocksmith import Message
message = (
Message.create()
.add_section("Hello World!")
.add_divider()
.add_actions([...])
.build()
)
```
**Key Methods:**
- `.add_section()` - Add text sections with optional fields and accessories
- `.add_divider()` - Add visual separators
- `.add_actions()` - Add interactive elements container
- `.add_context()` - Add small text/images at bottom
- `.add_input()` - Add form inputs with labels
- `.add_header()` - Add large header text
- `.add_image()` - Add image blocks
- `.add_file()` - Add file display blocks
- `.add_video()` - Add video display blocks
- `.add_rich_text()` - Add rich text formatting
- `.add_block()` - Add any custom block
- `.add_*_block()` - Add pre-created block objects directly
- `.build()` - Return complete message dictionary
#### `Modal`
Build interactive modals for user input.
```python
from slack_blocksmith import Modal, PlainTextInput, DatePicker
modal = (
Modal.create("User Registration")
.add_header("New User Registration")
.add_input("Name", PlainTextInput.create("name"))
.add_input("Date", DatePicker.create("date"))
.submit("Register")
.close("Cancel")
.build()
)
```
**Key Methods:**
- `.add_header()` - Add modal title
- `.add_input()` - Add form inputs
- `.submit()` - Set submit button text
- `.close()` - Set close button text
- `.callback_id()` - Set callback identifier
- `.private_metadata()` - Set private metadata
#### `HomeTab`
Build home tab interfaces for Slack apps.
```python
from slack_blocksmith import HomeTab
home_tab = (
HomeTab.create()
.add_header("Welcome to My App")
.add_section("Dashboard content here")
.build()
)
```
### ๐งฑ Blocks
#### `Section`
Text blocks with optional fields and accessories.
```python
from slack_blocksmith import Section, Button, MrkdwnText
section = (
Section.create()
.text("Main text content")
.fields(["Field 1", "Field 2"])
.accessory(Button.create("Action", "btn_1"))
.build()
)
```
#### `Actions`
Container for interactive elements (buttons, selects, etc.).
```python
from slack_blocksmith import Actions, Button, StaticSelect
actions = (
Actions.create()
.add_element(Button.create("Approve", "btn_approve"))
.add_element(StaticSelect.create("priority", "Priority", options))
.build()
)
```
#### `Context`
Small text/images at the bottom of messages.
```python
from slack_blocksmith import Context, PlainText, Image
context = (
Context.create()
.add_element(PlainText.create("Status: Active"))
.add_element(Image.create("https://example.com/icon.png", "Icon"))
.build()
)
```
#### `Input`
Form input blocks with labels and validation.
```python
from slack_blocksmith import Input, PlainTextInput
input_block = (
Input.create("Full Name")
.element(PlainTextInput.create("name").placeholder("Enter your name"))
.optional(False)
.hint("This will be displayed publicly")
.build()
)
```
#### `Header`
Large header text blocks.
```python
from slack_blocksmith import Header
header = (
Header.create("Important Announcement")
.build()
)
```
#### `Image`
Display image blocks.
```python
from slack_blocksmith import Image
image = (
Image.create("https://example.com/image.jpg", "Image description")
.title("Image Title")
.build()
)
```
#### `Video`
Display video blocks.
```python
from slack_blocksmith import Video
video = (
Video.create("https://example.com/video.mp4", "Video description")
.title("Video Title")
.thumbnail_url("https://example.com/thumb.jpg")
.build()
)
```
#### `File`
Display file blocks.
```python
from slack_blocksmith import File
file = (
File.create("https://example.com/document.pdf")
.title("Important Document")
.description("Quarterly report")
.build()
)
```
#### `RichText`
Rich text formatting blocks.
```python
from slack_blocksmith import RichText
rich_text = (
RichText.create()
.add_section("Bold text", style="bold")
.add_list(["Item 1", "Item 2"])
.build()
)
```
### ๐๏ธ Elements
#### Buttons
Interactive buttons with various styles and confirmations.
```python
from slack_blocksmith import Button, ConfirmationDialog
# Basic button
button = Button.create("Click Me", "btn_1").build()
# Styled button
button = (
Button.create("Delete", "btn_delete")
.style("danger")
.confirm(ConfirmationDialog.create(
"Delete Item",
"Are you sure?",
"Delete",
"Cancel"
))
.build()
)
```
#### Input Fields
Various input field types for forms.
```python
from slack_blocksmith import (
PlainTextInput, EmailInput, NumberInput,
URLInput, DatePicker, TimePicker, DatetimePicker
)
# Text input
text_input = (
PlainTextInput.create("name")
.placeholder("Enter your name")
.multiline(True)
.max_length(100)
.build()
)
# Email input
email_input = (
EmailInput.create("email")
.placeholder("user@example.com")
.build()
)
# Number input
number_input = (
NumberInput.create("age")
.min_value(0)
.max_value(120)
.is_decimal_allowed(False)
.build()
)
# Date picker
date_picker = (
DatePicker.create("start_date")
.placeholder("Select date")
.initial_date("2024-01-01")
.build()
)
```
#### Select Menus
Various select menu types for user choices.
```python
from slack_blocksmith import (
StaticSelect, ExternalSelect, UsersSelect,
ConversationsSelect, ChannelsSelect, Option, OptionGroup
)
# Static select
static_select = (
StaticSelect.create("priority", "Choose Priority", [
Option.create("High", "high"),
Option.create("Medium", "medium"),
Option.create("Low", "low")
])
.placeholder("Select priority")
.build()
)
# Multi-select
multi_select = (
MultiStaticSelect.create("tags", "Choose Tags", [
Option.create("Bug", "bug"),
Option.create("Feature", "feature"),
Option.create("Enhancement", "enhancement")
])
.placeholder("Select tags")
.max_selected_items(3)
.build()
)
# User select
user_select = (
UsersSelect.create("assignee", "Assign to")
.placeholder("Select user")
.initial_user("U123456")
.build()
)
```
#### Other Elements
```python
from slack_blocksmith import (
Checkboxes, RadioButtons, OverflowMenu,
FileInput, RichTextInput
)
# Checkboxes
checkboxes = (
Checkboxes.create("notifications", [
Option.create("Email", "email"),
Option.create("SMS", "sms"),
Option.create("Push", "push")
])
.build()
)
# Radio buttons
radio_buttons = (
RadioButtons.create("preference", [
Option.create("Option 1", "opt1"),
Option.create("Option 2", "opt2")
])
.build()
)
# Overflow menu
overflow = (
OverflowMenu.create("actions", [
Option.create("Edit", "edit"),
Option.create("Delete", "delete"),
Option.create("Share", "share")
])
.build()
)
# File input
file_input = (
FileInput.create("upload")
.filetypes(["pdf", "doc", "docx"])
.max_files(5)
.build()
)
```
### ๐งฉ Composition Objects
#### Text Objects
Text formatting and display objects.
```python
from slack_blocksmith import PlainText, MrkdwnText
# Plain text
plain_text = (
PlainText.create("Hello World")
.emoji(True)
.build()
)
# Markdown text
markdown_text = (
MrkdwnText.create("Hello *World*! :wave:")
.verbatim(False)
.build()
)
```
#### Options and Option Groups
Selection options for menus and selects.
```python
from slack_blocksmith import Option, OptionGroup
# Single option
option = (
Option.create("High Priority", "high")
.description("Urgent tasks")
.build()
)
# Option group
option_group = (
OptionGroup.create("Priority Levels", [
Option.create("High", "high"),
Option.create("Medium", "medium"),
Option.create("Low", "low")
])
.build()
)
```
#### Confirmation Dialogs
Confirmation dialogs for destructive actions.
```python
from slack_blocksmith import ConfirmationDialog
confirm_dialog = (
ConfirmationDialog.create(
"Delete Item",
"Are you sure you want to delete this item? This action cannot be undone.",
"Delete",
"Cancel"
)
.style("danger")
.build()
)
```
#### Filters
Filters for conversation and user selection.
```python
from slack_blocksmith import Filter, ConversationFilter
# Basic filter
filter_obj = (
Filter.create()
.include(["public", "private"])
.exclude_external_shared_channels(True)
.exclude_bot_users(True)
.build()
)
# Conversation filter
conv_filter = (
ConversationFilter.create()
.include(["public", "private"])
.exclude_external_shared_channels(True)
.build()
)
```
## ๐ฏ Real-World Examples
### ๐ฏ Direct Object Methods Example
Using pre-created blocks for better organization and reusability.
```python
from slack_blocksmith import Message, Section, Divider, Header, Actions, Button, PlainText, MrkdwnText
# Create reusable blocks
def create_header_block(title: str) -> Header:
return Header.create(title, block_id=f"header_{title.lower().replace(' ', '_')}")
def create_section_block(text: str, block_id: str) -> Section:
return Section.create(
text=MrkdwnText.create(text),
block_id=block_id
)
def create_actions_block(buttons: list, block_id: str) -> Actions:
return Actions.create(
elements=buttons,
block_id=block_id
)
# Create blocks independently
header = create_header_block("Project Status")
divider = Divider.create(block_id="divider1")
status_section = create_section_block(
"**Current Status:**\nโข 3 tasks in progress\nโข 2 pending review\nโข 1 completed today",
"status_section"
)
progress_section = create_section_block(
"**Progress:**\nโข Sprint 1: 85% complete\nโข Sprint 2: 45% complete",
"progress_section"
)
# Create action buttons
approve_btn = Button.create("โ
Approve", "btn_approve").style("primary")
reject_btn = Button.create("โ Reject", "btn_reject").style("danger")
info_btn = Button.create("โน๏ธ More Info", "btn_info")
actions = create_actions_block([approve_btn, reject_btn, info_btn], "actions1")
# Build message using direct object methods
message = (Message.create()
.add_header_block(header)
.add_divider_block(divider)
.add_section_block(status_section)
.add_section_block(progress_section)
.add_actions_block(actions)
.build())
```
### ๐ Action Handler with Message Parsing
Handling Slack interactions by parsing and modifying existing messages.
```python
from slack_blocksmith import Message, MrkdwnText, Button
from slack_sdk import WebClient
def handle_button_click(payload: dict, slack_client: WebClient):
"""Handle button click by parsing and updating the message."""
# Parse the original message from Slack payload
original_message = Message.from_payload(payload['message'])
# Extract action information
action_id = payload['actions'][0]['action_id']
user_id = payload['user']['id']
# Modify the message based on the action
if action_id == 'approve_task':
# Add approval confirmation
updated_message = original_message.add_section(
text=MrkdwnText.create(f"โ
*Approved by* <@{user_id}>"),
block_id="approval_status"
)
# Update the button to show it was clicked
# (In practice, you'd modify the existing button or remove it)
updated_message = updated_message.add_section(
text=MrkdwnText.create("Task has been approved and moved to next stage."),
block_id="status_update"
)
elif action_id == 'reject_task':
# Add rejection reason
updated_message = original_message.add_section(
text=MrkdwnText.create(f"โ *Rejected by* <@{user_id}>"),
block_id="rejection_status"
)
# Add input for rejection reason
updated_message = updated_message.add_input(
"Rejection Reason",
PlainTextInput.create("rejection_reason")
.placeholder("Please provide a reason for rejection")
.multiline(True)
)
# Update the message in Slack
slack_client.chat_update(
channel=payload['channel']['id'],
ts=payload['message']['ts'],
blocks=updated_message.build()['blocks']
)
# Example usage in Flask/Slack app
@app.route('/slack/interactive', methods=['POST'])
def handle_interactive():
payload = json.loads(request.form['payload'])
if payload['type'] == 'block_actions':
handle_button_click(payload, slack_client)
return '', 200
```
### ๐ Form Message
Complete form with various input types and validation.
```python
from slack_blocksmith import (
Message, PlainTextInput, EmailInput, NumberInput,
DatePicker, StaticSelect, Option, Checkboxes
)
message = (
Message.create()
.add_header("Employee Registration Form")
.add_section("Please complete the following information:")
.add_input("Full Name",
PlainTextInput.create("full_name")
.placeholder("Enter your full name")
.max_length(100)
)
.add_input("Email Address",
EmailInput.create("email")
.placeholder("user@company.com")
)
.add_input("Age",
NumberInput.create("age")
.min_value(18)
.max_value(65)
.is_decimal_allowed(False)
)
.add_input("Start Date",
DatePicker.create("start_date")
.placeholder("Select your start date")
)
.add_input("Department",
StaticSelect.create("department", "Choose Department", [
Option.create("Engineering", "eng"),
Option.create("Marketing", "marketing"),
Option.create("Sales", "sales"),
Option.create("HR", "hr")
])
.placeholder("Select department")
)
.add_input("Notifications",
Checkboxes.create("notifications", [
Option.create("Email Updates", "email"),
Option.create("SMS Alerts", "sms"),
Option.create("Push Notifications", "push")
])
)
.add_context(["All fields are required for processing"])
.build()
)
```
### โ
Approval Workflow
Complex approval system with confirmation dialogs and status tracking.
```python
from slack_blocksmith import (
Message, Button, ConfirmationDialog,
StaticSelect, Option, Context
)
# Approval confirmation dialog
approve_confirm = (
ConfirmationDialog.create(
"Approve Purchase Request",
"Are you sure you want to approve this purchase request for $2,499.00?",
"Yes, Approve",
"Cancel"
)
.style("primary")
)
# Rejection confirmation dialog
reject_confirm = (
ConfirmationDialog.create(
"Reject Purchase Request",
"Please provide a reason for rejection:",
"Reject",
"Cancel"
)
.style("danger")
)
message = (
Message.create()
.add_header("Purchase Request Approval")
.add_section(
text="**Request Details:**\n"
"โข Item: MacBook Pro 16-inch\n"
"โข Amount: $2,499.00\n"
"โข Requested by: John Doe\n"
"โข Department: Engineering\n"
"โข Justification: Development workstation upgrade"
)
.add_section(
text="**Budget Impact:**\n"
"โข Remaining Q4 budget: $15,000\n"
"โข This purchase: $2,499 (16.7% of remaining budget)"
)
.add_input("Priority Level",
StaticSelect.create("priority", "Set Priority", [
Option.create("High - Approve Immediately", "high"),
Option.create("Medium - Standard Review", "medium"),
Option.create("Low - Budget Review Required", "low")
])
.placeholder("Select priority level")
)
.add_actions([
Button.create("โ
Approve", "btn_approve")
.style("primary")
.confirm(approve_confirm),
Button.create("โ Reject", "btn_reject")
.style("danger")
.confirm(reject_confirm),
Button.create("๐ Request More Info", "btn_info")
.style("secondary")
])
.add_context([
"Request ID: PR-2024-001",
"Submitted: 2024-01-15",
"Status: Pending Approval"
])
.build()
)
```
### ๐ Home Tab Dashboard
Comprehensive home tab with multiple sections and interactive elements.
```python
from slack_blocksmith import (
HomeTab, Section, Actions, Button,
StaticSelect, Option, Context, Image
)
home_tab = (
HomeTab.create()
.add_header("Welcome to Project Management Dashboard")
.add_section(
text="**Today's Overview**\n"
"โข 5 tasks due today\n"
"โข 3 pending approvals\n"
"โข 2 team meetings scheduled"
)
.add_section(
text="**Quick Actions**",
accessory=StaticSelect.create("quick_action", "Choose Action", [
Option.create("Create New Task", "create_task"),
Option.create("Schedule Meeting", "schedule_meeting"),
Option.create("Review Reports", "review_reports"),
Option.create("Team Status", "team_status")
])
.placeholder("Select action")
)
.add_section(
text="**Recent Activity**\n"
"โข Task 'Update documentation' completed by Alice\n"
"โข Meeting 'Sprint Planning' scheduled for 2:00 PM\n"
"โข Report 'Q4 Metrics' generated"
)
.add_actions([
Button.create("๐ View Reports", "btn_reports"),
Button.create("๐ฅ Team Status", "btn_team"),
Button.create("๐
Calendar", "btn_calendar"),
Button.create("โ๏ธ Settings", "btn_settings")
])
.add_context([
"Last updated: 2024-01-15 10:30 AM",
"Next sync: 2024-01-15 11:00 AM"
])
.build()
)
```
### ๐๏ธ Interactive Modal
Complex modal with multiple input types and validation.
```python
from slack_blocksmith import (
Modal, PlainTextInput, EmailInput, NumberInput,
DatePicker, TimePicker, StaticSelect, MultiStaticSelect,
Checkboxes, RadioButtons, Option, OptionGroup
)
modal = (
Modal.create("Event Registration")
.add_header("Conference Registration Form")
.add_section("Please provide your information to complete registration.")
.add_input("Full Name",
PlainTextInput.create("full_name")
.placeholder("Enter your full name")
.max_length(100)
)
.add_input("Email",
EmailInput.create("email")
.placeholder("your.email@company.com")
)
.add_input("Phone Number",
PlainTextInput.create("phone")
.placeholder("+1 (555) 123-4567")
)
.add_input("Company",
PlainTextInput.create("company")
.placeholder("Your company name")
)
.add_input("Job Title",
PlainTextInput.create("job_title")
.placeholder("Your current job title")
)
.add_input("Registration Date",
DatePicker.create("reg_date")
.placeholder("Select registration date")
.initial_date("2024-03-15")
)
.add_input("Preferred Time",
TimePicker.create("pref_time")
.placeholder("Select preferred time")
.initial_time("09:00")
)
.add_input("Experience Level",
StaticSelect.create("experience", "Select Experience Level", [
Option.create("Beginner (0-2 years)", "beginner"),
Option.create("Intermediate (3-5 years)", "intermediate"),
Option.create("Advanced (6+ years)", "advanced"),
Option.create("Expert (10+ years)", "expert")
])
.placeholder("Choose your experience level")
)
.add_input("Interested Topics",
MultiStaticSelect.create("topics", "Select Topics of Interest", [
Option.create("Machine Learning", "ml"),
Option.create("Web Development", "web"),
Option.create("Data Science", "data"),
Option.create("DevOps", "devops"),
Option.create("Mobile Development", "mobile"),
Option.create("Cloud Computing", "cloud")
])
.placeholder("Select multiple topics")
.max_selected_items(4)
)
.add_input("Dietary Restrictions",
Checkboxes.create("dietary", [
Option.create("Vegetarian", "vegetarian"),
Option.create("Vegan", "vegan"),
Option.create("Gluten-Free", "gluten_free"),
Option.create("Kosher", "kosher"),
Option.create("Halal", "halal")
])
)
.add_input("T-Shirt Size",
RadioButtons.create("tshirt_size", [
Option.create("Small", "S"),
Option.create("Medium", "M"),
Option.create("Large", "L"),
Option.create("Extra Large", "XL"),
Option.create("2X Large", "2XL")
])
)
.add_section("**Terms and Conditions**\n"
"By submitting this form, you agree to our terms of service and privacy policy.")
.submit("Complete Registration")
.close("Cancel")
.callback_id("event_registration")
.private_metadata("conference_2024")
.build()
)
```
### ๐ Data Visualization Message
Message with rich formatting and data presentation.
```python
from slack_blocksmith import (
Message, Section, Context, Image,
Button, StaticSelect, Option
)
message = (
Message.create()
.add_header("Q4 2023 Sales Report")
.add_section(
text="**Sales Performance Summary**\n"
"โข Total Revenue: $2,450,000 (+15% vs Q3)\n"
"โข New Customers: 342 (+23% vs Q3)\n"
"โข Customer Satisfaction: 4.8/5.0 (+0.3 vs Q3)\n"
"โข Team Performance: 98% of goals met"
)
.add_section(
text="**Top Performing Products**\n"
"1. ๐ Product A: $850,000 (34.7%)\n"
"2. ๐ผ Product B: $620,000 (25.3%)\n"
"3. ๐ฏ Product C: $480,000 (19.6%)\n"
"4. ๐ฑ Product D: $500,000 (20.4%)"
)
.add_section(
text="**Regional Breakdown**",
accessory=StaticSelect.create("region", "View by Region", [
Option.create("North America", "na"),
Option.create("Europe", "eu"),
Option.create("Asia Pacific", "apac"),
Option.create("Latin America", "latam")
])
.placeholder("Select region")
)
.add_image(
"https://example.com/sales-chart.png",
"Q4 2023 Sales Performance Chart"
)
.add_actions([
Button.create("๐ Detailed Report", "btn_detailed_report"),
Button.create("๐ Export Data", "btn_export"),
Button.create("๐
Schedule Review", "btn_schedule")
])
.add_context([
"Report generated: 2024-01-15 09:00 AM",
"Next report: 2024-02-15",
"Data source: Salesforce CRM"
])
.build()
)
```
## ๐ Migration from Raw JSON
### Before: Complex JSON Construction
```python
# Error-prone, hard to maintain, no validation
message = {
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Hello *World*! ๐"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Click Me"
},
"action_id": "btn_1",
"style": "primary"
}
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Built with slack-block-kit-builder"
}
]
}
]
}
```
### After: Clean Builder Pattern
```python
# Type-safe, maintainable, validated
from slack_blocksmith import Message, MrkdwnText, Button
message = (
Message.create()
.add_section(
text=MrkdwnText.create("Hello *World*! ๐"),
accessory=Button.create("Click Me", "btn_1").style("primary")
)
.add_divider()
.add_context(["Built with slack-block-kit-builder"])
.build()
)
```
### Migration Benefits
| Aspect | Raw JSON | slack-block-kit-builder |
|--------|----------|-------------------------|
| **Type Safety** | โ No validation | โ
Full pydantic validation |
| **IDE Support** | โ No autocomplete | โ
Full autocomplete & hints |
| **Error Prevention** | โ Runtime errors | โ
Compile-time validation |
| **Maintainability** | โ Hard to modify | โ
Easy to refactor |
| **Readability** | โ Nested dictionaries | โ
Fluent method chaining |
| **Documentation** | โ No inline help | โ
Rich docstrings |
## ๐ง Troubleshooting for AI Agents
### Common Validation Errors
```python
# Error: "action_id is required"
# Solution: Always provide action_id for interactive elements
Button.create("Text", "action_id") # โ
Correct
Button.create("Text") # โ Missing action_id
# Error: "Invalid style value"
# Solution: Use only 'primary' or 'danger' for button styles
Button.create("Text", "btn").style("primary") # โ
Correct
Button.create("Text", "btn").style("invalid") # โ Invalid style
# Error: "Text cannot exceed 2000 characters"
# Solution: Keep text under 2000 characters
PlainText.create("Short text") # โ
Correct
PlainText.create("Very long text...") # โ Too long if > 2000 chars
```
### Method Chaining Patterns
```python
# โ
Correct: Chain methods before calling build()
element = (
Button.create("Text", "action_id")
.style("primary")
.confirm(dialog)
.build()
)
# โ Wrong: Calling build() too early
element = Button.create("Text", "action_id").build()
element.style("primary") # This won't work
```
### Import Resolution
```python
# โ
Correct: Import from main package
from slack_blocksmith import Message, Button
# โ
Correct: Import specific classes
from slack_blocksmith import Message
from slack_blocksmith import Button
# โ Wrong: Import from submodules (not recommended)
from slack_blocksmith.message import Message
```
### JSON Output Format
```python
# All .build() methods return standard Python dictionaries
message_dict = Message.create().add_section("Hello").build()
# Returns: {"blocks": [{"type": "section", "text": {"type": "mrkdwn", "text": "Hello"}}]}
# Use with Slack API
slack_client.chat_postMessage(
channel="#general",
blocks=message_dict["blocks"]
)
```
## ๐ ๏ธ Advanced Usage
### Custom Validation
```python
from slack_blocksmith import Message, PlainTextInput, validator
from pydantic import BaseModel
class CustomInput(PlainTextInput):
@validator('value')
def validate_email(cls, v):
if '@' not in v:
raise ValueError('Must be a valid email')
return v
message = (
Message.create()
.add_input("Email", CustomInput.create("email"))
.build()
)
```
### Dynamic Content Generation
```python
from slack_blocksmith import Message, Section, Button, Option, StaticSelect
def create_task_message(tasks):
message = Message.create().add_header("Task Dashboard")
for task in tasks:
message.add_section(
text=f"**{task['title']}**\n{task['description']}",
accessory=StaticSelect.create(
f"status_{task['id']}",
"Status",
[Option.create(status, status) for status in task['statuses']]
)
)
return message.build()
```
### Error Handling
```python
from slack_blocksmith import Message, Button
from pydantic import ValidationError
try:
message = (
Message.create()
.add_section("Hello World")
.add_actions([
Button.create("Click Me", "btn_1")
.style("invalid_style") # This will raise ValidationError
])
.build()
)
except ValidationError as e:
print(f"Validation error: {e}")
```
## ๐งช Testing
### Unit Testing
```python
import pytest
from slack_blocksmith import Message, Button
def test_message_creation():
message = (
Message.create()
.add_section("Test message")
.add_actions([Button.create("Test", "btn_test")])
.build()
)
assert len(message["blocks"]) == 2
assert message["blocks"][0]["type"] == "section"
assert message["blocks"][1]["type"] == "actions"
def test_button_validation():
with pytest.raises(ValidationError):
Button.create("", "btn_1") # Empty text should fail
```
### Integration Testing
```python
def test_slack_api_integration():
message = Message.create().add_section("Test").build()
# Test with actual Slack API
response = slack_client.chat_postMessage(
channel="#test",
blocks=message["blocks"]
)
assert response["ok"] is True
```
## ๐ Performance
### Benchmarks
- **Message Creation**: ~0.1ms per message
- **Validation**: ~0.05ms per block
- **Memory Usage**: ~2KB per message
- **Serialization**: ~0.02ms per message
### Optimization Tips
```python
# Reuse common elements
approve_button = Button.create("Approve", "btn_approve").style("primary")
# Use list comprehensions for dynamic content
options = [Option.create(f"Option {i}", f"opt_{i}") for i in range(10)]
# Cache frequently used messages
@lru_cache(maxsize=100)
def get_welcome_message(user_id):
return Message.create().add_section(f"Welcome {user_id}").build()
```
## ๐ง Development
### Setup Development Environment
```bash
# Clone the repository
git clone https://github.com/your-org/slack-block-kit-builder.git
cd slack-block-kit-builder
# Install with development dependencies
uv sync --group dev
# Install pre-commit hooks
pre-commit install
```
### Code Quality Tools
```bash
# Run linting
ruff check .
# Run type checking
mypy slack_blocksmith/
# Run tests
pytest
# Run tests with coverage
pytest --cov=slack_blocksmith --cov-report=html
# Format code
ruff format .
```
### Project Structure
```
slack-block-kit-builder/
โโโ slack_blocksmith/ # Main package
โ โโโ __init__.py # Package exports
โ โโโ composition.py # Text, Option, Dialog objects
โ โโโ elements.py # Interactive elements
โ โโโ blocks.py # Block containers
โ โโโ message.py # Message builders
โ โโโ validators.py # Custom validation
โโโ examples/ # Usage examples
โ โโโ basic_message.py
โ โโโ interactive_message.py
โ โโโ modal_example.py
โโโ tests/ # Test suite
โ โโโ test_composition.py
โ โโโ test_elements.py
โ โโโ test_blocks.py
โ โโโ test_message.py
โโโ docs/ # Documentation
โโโ README.md
โโโ pyproject.toml
```
## ๐ค Contributing
We welcome contributions! Here's how to get started:
### 1. Fork and Clone
```bash
git clone https://github.com/your-username/slack-block-kit-builder.git
cd slack-block-kit-builder
```
### 2. Create Feature Branch
```bash
git checkout -b feature/amazing-feature
```
### 3. Make Changes
- Follow the existing code style
- Add tests for new functionality
- Update documentation as needed
### 4. Run Quality Checks
```bash
ruff check .
mypy slack_blocksmith/
pytest
```
### 5. Submit Pull Request
- Provide a clear description of changes
- Include tests for new functionality
- Ensure all checks pass
### Contribution Guidelines
- **Code Style**: Follow PEP 8, use ruff for formatting
- **Type Hints**: All functions must have type hints
- **Tests**: Maintain 100% test coverage
- **Documentation**: Update docstrings and README
- **Commits**: Use conventional commit messages
## ๐ Acknowledgments
- **Slack Team** for the amazing Block Kit framework
- **Pydantic Team** for the excellent validation library
- **Python Community** for the rich ecosystem of tools
---
Raw data
{
"_id": null,
"home_page": null,
"name": "slack-blocksmith",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "Peter Popov <ppopov1357@gmail.com>",
"keywords": "api, block-kit, bot, builder, messaging, slack",
"author": null,
"author_email": "Peter Popov <ppopov1357@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/18/81/8cd38f3c1c825c4edd29cf836a7789df46aa1bee2891d80c090f7c41dbe7/slack_blocksmith-1.2.2.tar.gz",
"platform": null,
"description": "# Slack Block Kit Builder\n\n> **Package Type**: Python Library \n> **Primary Use**: Slack Block Kit JSON Generation \n> **Pattern**: Builder Pattern with Method Chaining \n> **Validation**: Pydantic-based Type Safety \n> **Target**: Slack API Integration \n\nA comprehensive Python package for building Slack Block Kit structures with dedicated classes using the builder pattern. Provides a type-safe, intuitive API for creating Slack messages, modals, and home tabs without the complexity of raw JSON construction.\n\n## \ud83d\udccb Quick Reference\n\n**Main Classes:**\n- `Message` - Build Slack messages with blocks\n- `Modal` - Build interactive modals \n- `HomeTab` - Build home tab interfaces\n- `Section`, `Actions`, `Context` - Block containers\n- `Button`, `SelectMenu`, `Input` - Interactive elements\n- `PlainText`, `MrkdwnText` - Text objects\n\n**Key Methods:**\n- `.create()` - Initialize objects\n- `.build()` - Generate JSON output\n- `.add_*()` - Add blocks/elements (Message builder)\n- `.add_*_block()` - Add pre-created block objects directly\n- `.set_*()` - Configure properties (Builder pattern)\n- `.from_payload()` - Parse existing Slack messages from JSON\n\n### \ud83e\udd16 AI Agent Decision Tree\n\n**Need to create a Slack message?**\n```\nStart with Message.create()\n\u251c\u2500\u2500 Add text content? \u2192 .add_section(text)\n\u251c\u2500\u2500 Add interactive buttons? \u2192 .add_actions([Button.create(text, action_id)])\n\u251c\u2500\u2500 Add form inputs? \u2192 .add_input(label, InputElement.create(action_id))\n\u251c\u2500\u2500 Add images? \u2192 .add_image(url, alt_text)\n\u2514\u2500\u2500 Add context info? \u2192 .add_context([text_or_elements])\n```\n\n**Need interactive elements?**\n```\nButton \u2192 Button.create(text, action_id)\nDropdown \u2192 StaticSelect.create(action_id, placeholder, options)\nText Input \u2192 PlainTextInput.create(action_id)\nDate Picker \u2192 DatePicker.create(action_id)\nMulti-select \u2192 MultiStaticSelect.create(action_id, placeholder, options)\n```\n\n**Need text formatting?**\n```\nPlain text \u2192 PlainText.create(text)\nMarkdown \u2192 MrkdwnText.create(text)\n```\n\n**Need a modal?**\n```\nStart with Modal.create(title)\n\u251c\u2500\u2500 Add inputs \u2192 .add_input(label, element)\n\u251c\u2500\u2500 Set buttons \u2192 .submit(text).close(text)\n\u2514\u2500\u2500 Add metadata \u2192 .callback_id(id).private_metadata(data)\n```\n\n**Need to parse existing messages?**\n```\nParse from JSON \u2192 Message.from_payload(payload)\n\u251c\u2500\u2500 Modify content \u2192 .add_section(text)\n\u251c\u2500\u2500 Update buttons \u2192 .add_actions([Button.create(...)])\n\u2514\u2500\u2500 Build back \u2192 .build() for Slack API\n```\n\n## \ud83d\ude80 Features\n\n- **\ud83c\udfd7\ufe0f Builder Pattern**: Fluent method chaining for intuitive API design\n- **\ud83d\udd12 Type Safety**: Full pydantic validation with comprehensive type hints\n- **\ud83d\udce6 Complete Coverage**: All Slack Block Kit blocks, elements, and composition objects\n- **\ud83d\udd04 Easy Migration**: Clear 1:1 mapping to Slack Block Kit JSON structure\n- **\ud83c\udfaf Direct Object Methods**: Add pre-created blocks directly for better flexibility\n- **\ud83d\udd04 Message Parsing**: Parse existing Slack messages from JSON payloads (`from_payload`)\n- **\u2728 Code Quality**: Ruff linting, mypy type checking, comprehensive test coverage\n- **\ud83d\udcda Rich Documentation**: Extensive examples, API reference, and migration guides\n- **\u26a1 Performance**: Optimized for both development and production use\n\n## \ud83d\udce6 Installation\n\n### Using pip\n```bash\npip install slack-block-kit-builder\n```\n\n### Using uv (recommended)\n```bash\nuv add slack-block-kit-builder\n```\n\n### Development Installation\n```bash\ngit clone https://github.com/your-org/slack-block-kit-builder.git\ncd slack-block-kit-builder\nuv pip install -e \".[dev]\"\n```\n\n## \ud83c\udfaf Why Use slack-block-kit-builder?\n\n### Before: Raw JSON Construction\n```python\n# Complex, error-prone, hard to maintain\nmessage = {\n \"blocks\": [\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"Hello *World*! \ud83d\udc4b\"\n },\n \"accessory\": {\n \"type\": \"button\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"Click Me\"\n },\n \"action_id\": \"btn_click\",\n \"style\": \"primary\"\n }\n },\n {\n \"type\": \"divider\"\n },\n {\n \"type\": \"context\",\n \"elements\": [\n {\n \"type\": \"mrkdwn\",\n \"text\": \"Built with slack-block-kit-builder\"\n }\n ]\n }\n ]\n}\n```\n\n### After: Builder Pattern\n```python\n# Clean, type-safe, maintainable\nfrom slack_blocksmith import Message, Section, Button, MrkdwnText\n\nmessage = (\n Message.create()\n .add_section(\n text=MrkdwnText.create(\"Hello *World*! \ud83d\udc4b\"),\n accessory=Button.create(\"Click Me\", \"btn_click\").style(\"primary\")\n )\n .add_divider()\n .add_context([\"Built with slack-block-kit-builder\"])\n .build()\n)\n```\n\n## \ud83e\udd16 AI Agent Usage Patterns\n\n### Common Import Patterns\n```python\n# Basic imports for most use cases\nfrom slack_blocksmith import Message, Section, Button, PlainText\n\n# Full imports for complex applications\nfrom slack_blocksmith import (\n Message, Modal, HomeTab,\n Section, Actions, Context, Input, Header,\n Button, StaticSelect, PlainTextInput, DatePicker,\n PlainText, MrkdwnText, Option\n)\n```\n\n### Standard Message Creation Pattern\n```python\n# Pattern: Create -> Configure -> Build\nmessage = (\n Message.create()\n .add_section(\"Text content\")\n .add_actions([Button.create(\"Action\", \"action_id\")])\n .build()\n)\n```\n\n### Element Configuration Pattern\n```python\n# Pattern: Create -> Set Properties -> Build\nbutton = (\n Button.create(\"Click Me\", \"btn_1\")\n .style(\"primary\")\n .confirm(confirmation_dialog)\n .build()\n)\n```\n\n### Common Error Patterns\n```python\n# \u274c Wrong: Missing action_id\nButton.create(\"Text\") # ValidationError\n\n# \u2705 Correct: Include action_id\nButton.create(\"Text\", \"action_id\")\n\n# \u274c Wrong: Invalid style\nButton.create(\"Text\", \"btn\").style(\"invalid\") # ValidationError\n\n# \u2705 Correct: Valid styles\nButton.create(\"Text\", \"btn\").style(\"primary\") # or \"danger\"\n```\n\n## \ud83d\ude80 Quick Start\n\n### Basic Message\n\n```python\nfrom slack_blocksmith import Message, Section, Button, PlainText\n\nmessage = (\n Message.create()\n .add_section(\"Hello World! \ud83d\udc4b\")\n .add_divider()\n .add_section(\n text=\"This is a *markdown* message with a button:\",\n accessory=Button.create(\"Click Me!\", \"btn_click\")\n )\n .add_context([\"Built with slack-block-kit-builder\"])\n .build()\n)\n```\n\n### Interactive Message\n\n```python\nfrom slack_blocksmith import Message, Button, StaticSelect, Option\n\nmessage = (\n Message.create()\n .add_header(\"Task Management\")\n .add_section(\"Choose an action:\")\n .add_actions([\n Button.create(\"Approve\", \"btn_approve\").style(\"primary\"),\n Button.create(\"Reject\", \"btn_reject\").style(\"danger\"),\n StaticSelect.create(\"priority\", \"Priority\", [\n Option.create(\"High\", \"high\"),\n Option.create(\"Medium\", \"medium\"),\n Option.create(\"Low\", \"low\")\n ])\n ])\n .build()\n)\n```\n\n### Direct Object Methods\n\nFor more flexibility, you can create blocks independently and add them directly:\n\n```python\nfrom slack_blocksmith import Message, Section, Divider, Header, Actions, Button, PlainText\n\n# Create blocks independently\nsection = Section.create(\n text=PlainText.create(\"Hello World!\"),\n block_id=\"section1\"\n)\n\ndivider = Divider.create(block_id=\"divider1\")\n\nheader = Header.create(\n text=\"My Header\",\n block_id=\"header1\"\n)\n\nbutton = Button.create(\"Click Me\", \"btn_click\")\nactions = Actions.create(\n elements=[button],\n block_id=\"actions1\"\n)\n\n# Add blocks directly to message\nmessage = (Message.create()\n .add_section_block(section)\n .add_divider_block(divider)\n .add_header_block(header)\n .add_actions_block(actions)\n .build())\n```\n\n**Available Direct Object Methods:**\n- `.add_section_block(section: Section)` - Add pre-created Section block\n- `.add_divider_block(divider: Divider)` - Add pre-created Divider block\n- `.add_image_block(image: ImageBlock)` - Add pre-created ImageBlock\n- `.add_actions_block(actions: Actions)` - Add pre-created Actions block\n- `.add_context_block(context: Context)` - Add pre-created Context block\n- `.add_input_block(input_block: Input)` - Add pre-created Input block\n- `.add_file_block(file_block: File)` - Add pre-created File block\n- `.add_header_block(header: Header)` - Add pre-created Header block\n- `.add_video_block(video: Video)` - Add pre-created Video block\n- `.add_rich_text_block(rich_text: RichText)` - Add pre-created RichText block\n\n**Benefits of Direct Object Methods:**\n- **Reusability**: Create blocks once, use in multiple messages\n- **Better Organization**: Separate block creation from message building\n- **Type Safety**: Direct object methods provide better type checking\n- **Flexibility**: Mix and match different approaches as needed\n\n### \ud83d\udd04 Parsing Existing Messages (`from_payload`)\n\nParse existing Slack messages from JSON payloads and modify them:\n\n```python\nfrom slack_blocksmith import Message, MrkdwnText\n\n# Parse a message from Slack payload JSON\nslack_payload = {\n \"blocks\": [\n {\n \"type\": \"header\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"Integration Test Results\"\n }\n },\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Status*: Running tests...\"\n },\n \"accessory\": {\n \"type\": \"button\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"View Details\"\n },\n \"action_id\": \"view_details\",\n \"url\": \"https://example.com\"\n }\n }\n ]\n}\n\n# Parse the payload into a Message object\nmessage = Message.from_payload(slack_payload)\n\n# Modify the message\nupdated_message = message.add_section(\n text=MrkdwnText.create(\"*New*: Tests completed successfully!\")\n)\n\n# Build back to dictionary for Slack API\nupdated_payload = updated_message.build()\n```\n\n**Use Cases:**\n- **Action Handlers**: Parse incoming messages from button clicks, form submissions\n- **Message Updates**: Modify existing messages based on user interactions\n- **Workflow Integration**: Process messages from external systems\n- **Testing**: Parse and validate message structures\n\n**Supported Input Formats:**\n```python\n# From dictionary\nmessage = Message.from_payload({\"blocks\": [...]})\n\n# From JSON string\nmessage = Message.from_payload('{\"blocks\": [...]}')\n\n# With message properties\nmessage = Message.from_payload({\n \"blocks\": [...],\n \"response_type\": \"ephemeral\",\n \"replace_original\": True,\n \"metadata\": {\"key\": \"value\"}\n})\n```\n\n**Error Handling:**\n```python\ntry:\n message = Message.from_payload(invalid_payload)\nexcept ValueError as e:\n print(f\"Invalid payload: {e}\")\n```\n\n### Modal\n\n```python\nfrom slack_blocksmith import Modal, PlainTextInput, DatePicker, StaticSelect, Option\n\nmodal = (\n Modal.create(\"User Registration\")\n .add_header(\"New User Registration\")\n .add_input(\"Full Name\", PlainTextInput.create(\"full_name\").placeholder(\"Enter name\"))\n .add_input(\"Start Date\", DatePicker.create(\"start_date\").placeholder(\"Select date\"))\n .add_input(\"Department\", StaticSelect.create(\"dept\", \"Select department\", [\n Option.create(\"Engineering\", \"eng\"),\n Option.create(\"Marketing\", \"marketing\")\n ]))\n .submit(\"Register\")\n .close(\"Cancel\")\n .build()\n)\n```\n\n## \ud83d\udcda API Reference for AI Agents\n\n### Class Hierarchy\n```\nBase Classes:\n\u251c\u2500\u2500 BaseModel (pydantic)\n\u251c\u2500\u2500 Element (interactive elements)\n\u251c\u2500\u2500 Block (container blocks)\n\u2514\u2500\u2500 TextObject (text formatting)\n\nMessage Builders:\n\u251c\u2500\u2500 Message\n\u251c\u2500\u2500 Modal \n\u2514\u2500\u2500 HomeTab\n\nBlocks:\n\u251c\u2500\u2500 Section (text + optional accessory)\n\u251c\u2500\u2500 Actions (interactive elements container)\n\u251c\u2500\u2500 Context (small text/images)\n\u251c\u2500\u2500 Input (form input with label)\n\u251c\u2500\u2500 Header (large text)\n\u251c\u2500\u2500 Divider (separator)\n\u251c\u2500\u2500 Image (image display)\n\u251c\u2500\u2500 File (file display)\n\u251c\u2500\u2500 Video (video display)\n\u2514\u2500\u2500 RichText (rich formatting)\n\nElements:\n\u251c\u2500\u2500 Button (interactive button)\n\u251c\u2500\u2500 StaticSelect (dropdown menu)\n\u251c\u2500\u2500 MultiStaticSelect (multi-select dropdown)\n\u251c\u2500\u2500 PlainTextInput (text input field)\n\u251c\u2500\u2500 EmailInput (email input field)\n\u251c\u2500\u2500 NumberInput (number input field)\n\u251c\u2500\u2500 URLInput (URL input field)\n\u251c\u2500\u2500 DatePicker (date selection)\n\u251c\u2500\u2500 TimePicker (time selection)\n\u251c\u2500\u2500 DatetimePicker (date+time selection)\n\u251c\u2500\u2500 Checkboxes (multiple checkboxes)\n\u251c\u2500\u2500 RadioButtons (radio button group)\n\u251c\u2500\u2500 OverflowMenu (overflow menu)\n\u251c\u2500\u2500 FileInput (file upload)\n\u251c\u2500\u2500 RichTextInput (rich text input)\n\u2514\u2500\u2500 Image (image element)\n\nComposition Objects:\n\u251c\u2500\u2500 PlainText (plain text object)\n\u251c\u2500\u2500 MrkdwnText (markdown text object)\n\u251c\u2500\u2500 Option (select menu option)\n\u251c\u2500\u2500 OptionGroup (grouped options)\n\u251c\u2500\u2500 ConfirmationDialog (confirmation dialog)\n\u251c\u2500\u2500 Filter (conversation filter)\n\u2514\u2500\u2500 ConversationFilter (conversation filter)\n```\n\n### Method Patterns by Class Type\n\n**Message Builders:**\n- `.create()` - Initialize\n- `.add_section(text, fields, accessory)` - Add text section\n- `.add_actions(elements)` - Add interactive elements\n- `.add_context(elements)` - Add context elements\n- `.add_input(label, element)` - Add form input\n- `.add_header(text)` - Add header\n- `.add_divider()` - Add separator\n- `.add_image(url, alt_text)` - Add image\n- `.add_file(url)` - Add file\n- `.add_video(url, alt_text)` - Add video\n- `.add_rich_text(elements)` - Add rich text\n- `.add_block(block)` - Add custom block\n- `.build()` - Generate JSON\n\n**Interactive Elements:**\n- `.create(text, action_id)` - Initialize with required params\n- `.style(\"primary\"|\"danger\")` - Set button style\n- `.confirm(dialog)` - Set confirmation dialog\n- `.placeholder(text)` - Set placeholder text\n- `.initial_value(value)` - Set initial value\n- `.build()` - Generate JSON\n\n**Text Objects:**\n- `.create(text)` - Initialize with text\n- `.emoji(True|False)` - Enable/disable emoji\n- `.verbatim(True|False)` - Enable/disable verbatim (MrkdwnText)\n- `.build()` - Generate JSON\n\n## \ud83d\udcda Comprehensive API Reference\n\n### \ud83c\udfd7\ufe0f Message Builders\n\n#### `Message`\nThe primary class for building Slack messages with blocks.\n\n```python\nfrom slack_blocksmith import Message\n\nmessage = (\n Message.create()\n .add_section(\"Hello World!\")\n .add_divider()\n .add_actions([...])\n .build()\n)\n```\n\n**Key Methods:**\n- `.add_section()` - Add text sections with optional fields and accessories\n- `.add_divider()` - Add visual separators\n- `.add_actions()` - Add interactive elements container\n- `.add_context()` - Add small text/images at bottom\n- `.add_input()` - Add form inputs with labels\n- `.add_header()` - Add large header text\n- `.add_image()` - Add image blocks\n- `.add_file()` - Add file display blocks\n- `.add_video()` - Add video display blocks\n- `.add_rich_text()` - Add rich text formatting\n- `.add_block()` - Add any custom block\n- `.add_*_block()` - Add pre-created block objects directly\n- `.build()` - Return complete message dictionary\n\n#### `Modal`\nBuild interactive modals for user input.\n\n```python\nfrom slack_blocksmith import Modal, PlainTextInput, DatePicker\n\nmodal = (\n Modal.create(\"User Registration\")\n .add_header(\"New User Registration\")\n .add_input(\"Name\", PlainTextInput.create(\"name\"))\n .add_input(\"Date\", DatePicker.create(\"date\"))\n .submit(\"Register\")\n .close(\"Cancel\")\n .build()\n)\n```\n\n**Key Methods:**\n- `.add_header()` - Add modal title\n- `.add_input()` - Add form inputs\n- `.submit()` - Set submit button text\n- `.close()` - Set close button text\n- `.callback_id()` - Set callback identifier\n- `.private_metadata()` - Set private metadata\n\n#### `HomeTab`\nBuild home tab interfaces for Slack apps.\n\n```python\nfrom slack_blocksmith import HomeTab\n\nhome_tab = (\n HomeTab.create()\n .add_header(\"Welcome to My App\")\n .add_section(\"Dashboard content here\")\n .build()\n)\n```\n\n### \ud83e\uddf1 Blocks\n\n#### `Section`\nText blocks with optional fields and accessories.\n\n```python\nfrom slack_blocksmith import Section, Button, MrkdwnText\n\nsection = (\n Section.create()\n .text(\"Main text content\")\n .fields([\"Field 1\", \"Field 2\"])\n .accessory(Button.create(\"Action\", \"btn_1\"))\n .build()\n)\n```\n\n#### `Actions`\nContainer for interactive elements (buttons, selects, etc.).\n\n```python\nfrom slack_blocksmith import Actions, Button, StaticSelect\n\nactions = (\n Actions.create()\n .add_element(Button.create(\"Approve\", \"btn_approve\"))\n .add_element(StaticSelect.create(\"priority\", \"Priority\", options))\n .build()\n)\n```\n\n#### `Context`\nSmall text/images at the bottom of messages.\n\n```python\nfrom slack_blocksmith import Context, PlainText, Image\n\ncontext = (\n Context.create()\n .add_element(PlainText.create(\"Status: Active\"))\n .add_element(Image.create(\"https://example.com/icon.png\", \"Icon\"))\n .build()\n)\n```\n\n#### `Input`\nForm input blocks with labels and validation.\n\n```python\nfrom slack_blocksmith import Input, PlainTextInput\n\ninput_block = (\n Input.create(\"Full Name\")\n .element(PlainTextInput.create(\"name\").placeholder(\"Enter your name\"))\n .optional(False)\n .hint(\"This will be displayed publicly\")\n .build()\n)\n```\n\n#### `Header`\nLarge header text blocks.\n\n```python\nfrom slack_blocksmith import Header\n\nheader = (\n Header.create(\"Important Announcement\")\n .build()\n)\n```\n\n#### `Image`\nDisplay image blocks.\n\n```python\nfrom slack_blocksmith import Image\n\nimage = (\n Image.create(\"https://example.com/image.jpg\", \"Image description\")\n .title(\"Image Title\")\n .build()\n)\n```\n\n#### `Video`\nDisplay video blocks.\n\n```python\nfrom slack_blocksmith import Video\n\nvideo = (\n Video.create(\"https://example.com/video.mp4\", \"Video description\")\n .title(\"Video Title\")\n .thumbnail_url(\"https://example.com/thumb.jpg\")\n .build()\n)\n```\n\n#### `File`\nDisplay file blocks.\n\n```python\nfrom slack_blocksmith import File\n\nfile = (\n File.create(\"https://example.com/document.pdf\")\n .title(\"Important Document\")\n .description(\"Quarterly report\")\n .build()\n)\n```\n\n#### `RichText`\nRich text formatting blocks.\n\n```python\nfrom slack_blocksmith import RichText\n\nrich_text = (\n RichText.create()\n .add_section(\"Bold text\", style=\"bold\")\n .add_list([\"Item 1\", \"Item 2\"])\n .build()\n)\n```\n\n### \ud83c\udf9b\ufe0f Elements\n\n#### Buttons\nInteractive buttons with various styles and confirmations.\n\n```python\nfrom slack_blocksmith import Button, ConfirmationDialog\n\n# Basic button\nbutton = Button.create(\"Click Me\", \"btn_1\").build()\n\n# Styled button\nbutton = (\n Button.create(\"Delete\", \"btn_delete\")\n .style(\"danger\")\n .confirm(ConfirmationDialog.create(\n \"Delete Item\",\n \"Are you sure?\",\n \"Delete\",\n \"Cancel\"\n ))\n .build()\n)\n```\n\n#### Input Fields\nVarious input field types for forms.\n\n```python\nfrom slack_blocksmith import (\n PlainTextInput, EmailInput, NumberInput, \n URLInput, DatePicker, TimePicker, DatetimePicker\n)\n\n# Text input\ntext_input = (\n PlainTextInput.create(\"name\")\n .placeholder(\"Enter your name\")\n .multiline(True)\n .max_length(100)\n .build()\n)\n\n# Email input\nemail_input = (\n EmailInput.create(\"email\")\n .placeholder(\"user@example.com\")\n .build()\n)\n\n# Number input\nnumber_input = (\n NumberInput.create(\"age\")\n .min_value(0)\n .max_value(120)\n .is_decimal_allowed(False)\n .build()\n)\n\n# Date picker\ndate_picker = (\n DatePicker.create(\"start_date\")\n .placeholder(\"Select date\")\n .initial_date(\"2024-01-01\")\n .build()\n)\n```\n\n#### Select Menus\nVarious select menu types for user choices.\n\n```python\nfrom slack_blocksmith import (\n StaticSelect, ExternalSelect, UsersSelect, \n ConversationsSelect, ChannelsSelect, Option, OptionGroup\n)\n\n# Static select\nstatic_select = (\n StaticSelect.create(\"priority\", \"Choose Priority\", [\n Option.create(\"High\", \"high\"),\n Option.create(\"Medium\", \"medium\"),\n Option.create(\"Low\", \"low\")\n ])\n .placeholder(\"Select priority\")\n .build()\n)\n\n# Multi-select\nmulti_select = (\n MultiStaticSelect.create(\"tags\", \"Choose Tags\", [\n Option.create(\"Bug\", \"bug\"),\n Option.create(\"Feature\", \"feature\"),\n Option.create(\"Enhancement\", \"enhancement\")\n ])\n .placeholder(\"Select tags\")\n .max_selected_items(3)\n .build()\n)\n\n# User select\nuser_select = (\n UsersSelect.create(\"assignee\", \"Assign to\")\n .placeholder(\"Select user\")\n .initial_user(\"U123456\")\n .build()\n)\n```\n\n#### Other Elements\n\n```python\nfrom slack_blocksmith import (\n Checkboxes, RadioButtons, OverflowMenu, \n FileInput, RichTextInput\n)\n\n# Checkboxes\ncheckboxes = (\n Checkboxes.create(\"notifications\", [\n Option.create(\"Email\", \"email\"),\n Option.create(\"SMS\", \"sms\"),\n Option.create(\"Push\", \"push\")\n ])\n .build()\n)\n\n# Radio buttons\nradio_buttons = (\n RadioButtons.create(\"preference\", [\n Option.create(\"Option 1\", \"opt1\"),\n Option.create(\"Option 2\", \"opt2\")\n ])\n .build()\n)\n\n# Overflow menu\noverflow = (\n OverflowMenu.create(\"actions\", [\n Option.create(\"Edit\", \"edit\"),\n Option.create(\"Delete\", \"delete\"),\n Option.create(\"Share\", \"share\")\n ])\n .build()\n)\n\n# File input\nfile_input = (\n FileInput.create(\"upload\")\n .filetypes([\"pdf\", \"doc\", \"docx\"])\n .max_files(5)\n .build()\n)\n```\n\n### \ud83e\udde9 Composition Objects\n\n#### Text Objects\nText formatting and display objects.\n\n```python\nfrom slack_blocksmith import PlainText, MrkdwnText\n\n# Plain text\nplain_text = (\n PlainText.create(\"Hello World\")\n .emoji(True)\n .build()\n)\n\n# Markdown text\nmarkdown_text = (\n MrkdwnText.create(\"Hello *World*! :wave:\")\n .verbatim(False)\n .build()\n)\n```\n\n#### Options and Option Groups\nSelection options for menus and selects.\n\n```python\nfrom slack_blocksmith import Option, OptionGroup\n\n# Single option\noption = (\n Option.create(\"High Priority\", \"high\")\n .description(\"Urgent tasks\")\n .build()\n)\n\n# Option group\noption_group = (\n OptionGroup.create(\"Priority Levels\", [\n Option.create(\"High\", \"high\"),\n Option.create(\"Medium\", \"medium\"),\n Option.create(\"Low\", \"low\")\n ])\n .build()\n)\n```\n\n#### Confirmation Dialogs\nConfirmation dialogs for destructive actions.\n\n```python\nfrom slack_blocksmith import ConfirmationDialog\n\nconfirm_dialog = (\n ConfirmationDialog.create(\n \"Delete Item\",\n \"Are you sure you want to delete this item? This action cannot be undone.\",\n \"Delete\",\n \"Cancel\"\n )\n .style(\"danger\")\n .build()\n)\n```\n\n#### Filters\nFilters for conversation and user selection.\n\n```python\nfrom slack_blocksmith import Filter, ConversationFilter\n\n# Basic filter\nfilter_obj = (\n Filter.create()\n .include([\"public\", \"private\"])\n .exclude_external_shared_channels(True)\n .exclude_bot_users(True)\n .build()\n)\n\n# Conversation filter\nconv_filter = (\n ConversationFilter.create()\n .include([\"public\", \"private\"])\n .exclude_external_shared_channels(True)\n .build()\n)\n```\n\n## \ud83c\udfaf Real-World Examples\n\n### \ud83c\udfaf Direct Object Methods Example\nUsing pre-created blocks for better organization and reusability.\n\n```python\nfrom slack_blocksmith import Message, Section, Divider, Header, Actions, Button, PlainText, MrkdwnText\n\n# Create reusable blocks\ndef create_header_block(title: str) -> Header:\n return Header.create(title, block_id=f\"header_{title.lower().replace(' ', '_')}\")\n\ndef create_section_block(text: str, block_id: str) -> Section:\n return Section.create(\n text=MrkdwnText.create(text),\n block_id=block_id\n )\n\ndef create_actions_block(buttons: list, block_id: str) -> Actions:\n return Actions.create(\n elements=buttons,\n block_id=block_id\n )\n\n# Create blocks independently\nheader = create_header_block(\"Project Status\")\ndivider = Divider.create(block_id=\"divider1\")\n\nstatus_section = create_section_block(\n \"**Current Status:**\\n\u2022 3 tasks in progress\\n\u2022 2 pending review\\n\u2022 1 completed today\",\n \"status_section\"\n)\n\nprogress_section = create_section_block(\n \"**Progress:**\\n\u2022 Sprint 1: 85% complete\\n\u2022 Sprint 2: 45% complete\",\n \"progress_section\"\n)\n\n# Create action buttons\napprove_btn = Button.create(\"\u2705 Approve\", \"btn_approve\").style(\"primary\")\nreject_btn = Button.create(\"\u274c Reject\", \"btn_reject\").style(\"danger\")\ninfo_btn = Button.create(\"\u2139\ufe0f More Info\", \"btn_info\")\n\nactions = create_actions_block([approve_btn, reject_btn, info_btn], \"actions1\")\n\n# Build message using direct object methods\nmessage = (Message.create()\n .add_header_block(header)\n .add_divider_block(divider)\n .add_section_block(status_section)\n .add_section_block(progress_section)\n .add_actions_block(actions)\n .build())\n```\n\n### \ud83d\udd04 Action Handler with Message Parsing\nHandling Slack interactions by parsing and modifying existing messages.\n\n```python\nfrom slack_blocksmith import Message, MrkdwnText, Button\nfrom slack_sdk import WebClient\n\ndef handle_button_click(payload: dict, slack_client: WebClient):\n \"\"\"Handle button click by parsing and updating the message.\"\"\"\n \n # Parse the original message from Slack payload\n original_message = Message.from_payload(payload['message'])\n \n # Extract action information\n action_id = payload['actions'][0]['action_id']\n user_id = payload['user']['id']\n \n # Modify the message based on the action\n if action_id == 'approve_task':\n # Add approval confirmation\n updated_message = original_message.add_section(\n text=MrkdwnText.create(f\"\u2705 *Approved by* <@{user_id}>\"),\n block_id=\"approval_status\"\n )\n \n # Update the button to show it was clicked\n # (In practice, you'd modify the existing button or remove it)\n updated_message = updated_message.add_section(\n text=MrkdwnText.create(\"Task has been approved and moved to next stage.\"),\n block_id=\"status_update\"\n )\n \n elif action_id == 'reject_task':\n # Add rejection reason\n updated_message = original_message.add_section(\n text=MrkdwnText.create(f\"\u274c *Rejected by* <@{user_id}>\"),\n block_id=\"rejection_status\"\n )\n \n # Add input for rejection reason\n updated_message = updated_message.add_input(\n \"Rejection Reason\",\n PlainTextInput.create(\"rejection_reason\")\n .placeholder(\"Please provide a reason for rejection\")\n .multiline(True)\n )\n \n # Update the message in Slack\n slack_client.chat_update(\n channel=payload['channel']['id'],\n ts=payload['message']['ts'],\n blocks=updated_message.build()['blocks']\n )\n\n# Example usage in Flask/Slack app\n@app.route('/slack/interactive', methods=['POST'])\ndef handle_interactive():\n payload = json.loads(request.form['payload'])\n \n if payload['type'] == 'block_actions':\n handle_button_click(payload, slack_client)\n \n return '', 200\n```\n\n### \ud83d\udcdd Form Message\nComplete form with various input types and validation.\n\n```python\nfrom slack_blocksmith import (\n Message, PlainTextInput, EmailInput, NumberInput, \n DatePicker, StaticSelect, Option, Checkboxes\n)\n\nmessage = (\n Message.create()\n .add_header(\"Employee Registration Form\")\n .add_section(\"Please complete the following information:\")\n .add_input(\"Full Name\", \n PlainTextInput.create(\"full_name\")\n .placeholder(\"Enter your full name\")\n .max_length(100)\n )\n .add_input(\"Email Address\", \n EmailInput.create(\"email\")\n .placeholder(\"user@company.com\")\n )\n .add_input(\"Age\", \n NumberInput.create(\"age\")\n .min_value(18)\n .max_value(65)\n .is_decimal_allowed(False)\n )\n .add_input(\"Start Date\", \n DatePicker.create(\"start_date\")\n .placeholder(\"Select your start date\")\n )\n .add_input(\"Department\", \n StaticSelect.create(\"department\", \"Choose Department\", [\n Option.create(\"Engineering\", \"eng\"),\n Option.create(\"Marketing\", \"marketing\"),\n Option.create(\"Sales\", \"sales\"),\n Option.create(\"HR\", \"hr\")\n ])\n .placeholder(\"Select department\")\n )\n .add_input(\"Notifications\", \n Checkboxes.create(\"notifications\", [\n Option.create(\"Email Updates\", \"email\"),\n Option.create(\"SMS Alerts\", \"sms\"),\n Option.create(\"Push Notifications\", \"push\")\n ])\n )\n .add_context([\"All fields are required for processing\"])\n .build()\n)\n```\n\n### \u2705 Approval Workflow\nComplex approval system with confirmation dialogs and status tracking.\n\n```python\nfrom slack_blocksmith import (\n Message, Button, ConfirmationDialog, \n StaticSelect, Option, Context\n)\n\n# Approval confirmation dialog\napprove_confirm = (\n ConfirmationDialog.create(\n \"Approve Purchase Request\",\n \"Are you sure you want to approve this purchase request for $2,499.00?\",\n \"Yes, Approve\",\n \"Cancel\"\n )\n .style(\"primary\")\n)\n\n# Rejection confirmation dialog\nreject_confirm = (\n ConfirmationDialog.create(\n \"Reject Purchase Request\",\n \"Please provide a reason for rejection:\",\n \"Reject\",\n \"Cancel\"\n )\n .style(\"danger\")\n)\n\nmessage = (\n Message.create()\n .add_header(\"Purchase Request Approval\")\n .add_section(\n text=\"**Request Details:**\\n\"\n \"\u2022 Item: MacBook Pro 16-inch\\n\"\n \"\u2022 Amount: $2,499.00\\n\"\n \"\u2022 Requested by: John Doe\\n\"\n \"\u2022 Department: Engineering\\n\"\n \"\u2022 Justification: Development workstation upgrade\"\n )\n .add_section(\n text=\"**Budget Impact:**\\n\"\n \"\u2022 Remaining Q4 budget: $15,000\\n\"\n \"\u2022 This purchase: $2,499 (16.7% of remaining budget)\"\n )\n .add_input(\"Priority Level\", \n StaticSelect.create(\"priority\", \"Set Priority\", [\n Option.create(\"High - Approve Immediately\", \"high\"),\n Option.create(\"Medium - Standard Review\", \"medium\"),\n Option.create(\"Low - Budget Review Required\", \"low\")\n ])\n .placeholder(\"Select priority level\")\n )\n .add_actions([\n Button.create(\"\u2705 Approve\", \"btn_approve\")\n .style(\"primary\")\n .confirm(approve_confirm),\n Button.create(\"\u274c Reject\", \"btn_reject\")\n .style(\"danger\")\n .confirm(reject_confirm),\n Button.create(\"\ud83d\udccb Request More Info\", \"btn_info\")\n .style(\"secondary\")\n ])\n .add_context([\n \"Request ID: PR-2024-001\",\n \"Submitted: 2024-01-15\",\n \"Status: Pending Approval\"\n ])\n .build()\n)\n```\n\n### \ud83c\udfe0 Home Tab Dashboard\nComprehensive home tab with multiple sections and interactive elements.\n\n```python\nfrom slack_blocksmith import (\n HomeTab, Section, Actions, Button, \n StaticSelect, Option, Context, Image\n)\n\nhome_tab = (\n HomeTab.create()\n .add_header(\"Welcome to Project Management Dashboard\")\n .add_section(\n text=\"**Today's Overview**\\n\"\n \"\u2022 5 tasks due today\\n\"\n \"\u2022 3 pending approvals\\n\"\n \"\u2022 2 team meetings scheduled\"\n )\n .add_section(\n text=\"**Quick Actions**\",\n accessory=StaticSelect.create(\"quick_action\", \"Choose Action\", [\n Option.create(\"Create New Task\", \"create_task\"),\n Option.create(\"Schedule Meeting\", \"schedule_meeting\"),\n Option.create(\"Review Reports\", \"review_reports\"),\n Option.create(\"Team Status\", \"team_status\")\n ])\n .placeholder(\"Select action\")\n )\n .add_section(\n text=\"**Recent Activity**\\n\"\n \"\u2022 Task 'Update documentation' completed by Alice\\n\"\n \"\u2022 Meeting 'Sprint Planning' scheduled for 2:00 PM\\n\"\n \"\u2022 Report 'Q4 Metrics' generated\"\n )\n .add_actions([\n Button.create(\"\ud83d\udcca View Reports\", \"btn_reports\"),\n Button.create(\"\ud83d\udc65 Team Status\", \"btn_team\"),\n Button.create(\"\ud83d\udcc5 Calendar\", \"btn_calendar\"),\n Button.create(\"\u2699\ufe0f Settings\", \"btn_settings\")\n ])\n .add_context([\n \"Last updated: 2024-01-15 10:30 AM\",\n \"Next sync: 2024-01-15 11:00 AM\"\n ])\n .build()\n)\n```\n\n### \ud83c\udf9b\ufe0f Interactive Modal\nComplex modal with multiple input types and validation.\n\n```python\nfrom slack_blocksmith import (\n Modal, PlainTextInput, EmailInput, NumberInput,\n DatePicker, TimePicker, StaticSelect, MultiStaticSelect,\n Checkboxes, RadioButtons, Option, OptionGroup\n)\n\nmodal = (\n Modal.create(\"Event Registration\")\n .add_header(\"Conference Registration Form\")\n .add_section(\"Please provide your information to complete registration.\")\n .add_input(\"Full Name\", \n PlainTextInput.create(\"full_name\")\n .placeholder(\"Enter your full name\")\n .max_length(100)\n )\n .add_input(\"Email\", \n EmailInput.create(\"email\")\n .placeholder(\"your.email@company.com\")\n )\n .add_input(\"Phone Number\", \n PlainTextInput.create(\"phone\")\n .placeholder(\"+1 (555) 123-4567\")\n )\n .add_input(\"Company\", \n PlainTextInput.create(\"company\")\n .placeholder(\"Your company name\")\n )\n .add_input(\"Job Title\", \n PlainTextInput.create(\"job_title\")\n .placeholder(\"Your current job title\")\n )\n .add_input(\"Registration Date\", \n DatePicker.create(\"reg_date\")\n .placeholder(\"Select registration date\")\n .initial_date(\"2024-03-15\")\n )\n .add_input(\"Preferred Time\", \n TimePicker.create(\"pref_time\")\n .placeholder(\"Select preferred time\")\n .initial_time(\"09:00\")\n )\n .add_input(\"Experience Level\", \n StaticSelect.create(\"experience\", \"Select Experience Level\", [\n Option.create(\"Beginner (0-2 years)\", \"beginner\"),\n Option.create(\"Intermediate (3-5 years)\", \"intermediate\"),\n Option.create(\"Advanced (6+ years)\", \"advanced\"),\n Option.create(\"Expert (10+ years)\", \"expert\")\n ])\n .placeholder(\"Choose your experience level\")\n )\n .add_input(\"Interested Topics\", \n MultiStaticSelect.create(\"topics\", \"Select Topics of Interest\", [\n Option.create(\"Machine Learning\", \"ml\"),\n Option.create(\"Web Development\", \"web\"),\n Option.create(\"Data Science\", \"data\"),\n Option.create(\"DevOps\", \"devops\"),\n Option.create(\"Mobile Development\", \"mobile\"),\n Option.create(\"Cloud Computing\", \"cloud\")\n ])\n .placeholder(\"Select multiple topics\")\n .max_selected_items(4)\n )\n .add_input(\"Dietary Restrictions\", \n Checkboxes.create(\"dietary\", [\n Option.create(\"Vegetarian\", \"vegetarian\"),\n Option.create(\"Vegan\", \"vegan\"),\n Option.create(\"Gluten-Free\", \"gluten_free\"),\n Option.create(\"Kosher\", \"kosher\"),\n Option.create(\"Halal\", \"halal\")\n ])\n )\n .add_input(\"T-Shirt Size\", \n RadioButtons.create(\"tshirt_size\", [\n Option.create(\"Small\", \"S\"),\n Option.create(\"Medium\", \"M\"),\n Option.create(\"Large\", \"L\"),\n Option.create(\"Extra Large\", \"XL\"),\n Option.create(\"2X Large\", \"2XL\")\n ])\n )\n .add_section(\"**Terms and Conditions**\\n\"\n \"By submitting this form, you agree to our terms of service and privacy policy.\")\n .submit(\"Complete Registration\")\n .close(\"Cancel\")\n .callback_id(\"event_registration\")\n .private_metadata(\"conference_2024\")\n .build()\n)\n```\n\n### \ud83d\udcca Data Visualization Message\nMessage with rich formatting and data presentation.\n\n```python\nfrom slack_blocksmith import (\n Message, Section, Context, Image, \n Button, StaticSelect, Option\n)\n\nmessage = (\n Message.create()\n .add_header(\"Q4 2023 Sales Report\")\n .add_section(\n text=\"**Sales Performance Summary**\\n\"\n \"\u2022 Total Revenue: $2,450,000 (+15% vs Q3)\\n\"\n \"\u2022 New Customers: 342 (+23% vs Q3)\\n\"\n \"\u2022 Customer Satisfaction: 4.8/5.0 (+0.3 vs Q3)\\n\"\n \"\u2022 Team Performance: 98% of goals met\"\n )\n .add_section(\n text=\"**Top Performing Products**\\n\"\n \"1. \ud83d\ude80 Product A: $850,000 (34.7%)\\n\"\n \"2. \ud83d\udcbc Product B: $620,000 (25.3%)\\n\"\n \"3. \ud83c\udfaf Product C: $480,000 (19.6%)\\n\"\n \"4. \ud83d\udcf1 Product D: $500,000 (20.4%)\"\n )\n .add_section(\n text=\"**Regional Breakdown**\",\n accessory=StaticSelect.create(\"region\", \"View by Region\", [\n Option.create(\"North America\", \"na\"),\n Option.create(\"Europe\", \"eu\"),\n Option.create(\"Asia Pacific\", \"apac\"),\n Option.create(\"Latin America\", \"latam\")\n ])\n .placeholder(\"Select region\")\n )\n .add_image(\n \"https://example.com/sales-chart.png\",\n \"Q4 2023 Sales Performance Chart\"\n )\n .add_actions([\n Button.create(\"\ud83d\udcc8 Detailed Report\", \"btn_detailed_report\"),\n Button.create(\"\ud83d\udcca Export Data\", \"btn_export\"),\n Button.create(\"\ud83d\udcc5 Schedule Review\", \"btn_schedule\")\n ])\n .add_context([\n \"Report generated: 2024-01-15 09:00 AM\",\n \"Next report: 2024-02-15\",\n \"Data source: Salesforce CRM\"\n ])\n .build()\n)\n```\n\n## \ud83d\udd04 Migration from Raw JSON\n\n### Before: Complex JSON Construction\n```python\n# Error-prone, hard to maintain, no validation\nmessage = {\n \"blocks\": [\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"Hello *World*! \ud83d\udc4b\"\n },\n \"accessory\": {\n \"type\": \"button\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"Click Me\"\n },\n \"action_id\": \"btn_1\",\n \"style\": \"primary\"\n }\n },\n {\n \"type\": \"divider\"\n },\n {\n \"type\": \"context\",\n \"elements\": [\n {\n \"type\": \"mrkdwn\",\n \"text\": \"Built with slack-block-kit-builder\"\n }\n ]\n }\n ]\n}\n```\n\n### After: Clean Builder Pattern\n```python\n# Type-safe, maintainable, validated\nfrom slack_blocksmith import Message, MrkdwnText, Button\n\nmessage = (\n Message.create()\n .add_section(\n text=MrkdwnText.create(\"Hello *World*! \ud83d\udc4b\"),\n accessory=Button.create(\"Click Me\", \"btn_1\").style(\"primary\")\n )\n .add_divider()\n .add_context([\"Built with slack-block-kit-builder\"])\n .build()\n)\n```\n\n### Migration Benefits\n\n| Aspect | Raw JSON | slack-block-kit-builder |\n|--------|----------|-------------------------|\n| **Type Safety** | \u274c No validation | \u2705 Full pydantic validation |\n| **IDE Support** | \u274c No autocomplete | \u2705 Full autocomplete & hints |\n| **Error Prevention** | \u274c Runtime errors | \u2705 Compile-time validation |\n| **Maintainability** | \u274c Hard to modify | \u2705 Easy to refactor |\n| **Readability** | \u274c Nested dictionaries | \u2705 Fluent method chaining |\n| **Documentation** | \u274c No inline help | \u2705 Rich docstrings |\n\n## \ud83d\udd27 Troubleshooting for AI Agents\n\n### Common Validation Errors\n```python\n# Error: \"action_id is required\"\n# Solution: Always provide action_id for interactive elements\nButton.create(\"Text\", \"action_id\") # \u2705 Correct\nButton.create(\"Text\") # \u274c Missing action_id\n\n# Error: \"Invalid style value\"\n# Solution: Use only 'primary' or 'danger' for button styles\nButton.create(\"Text\", \"btn\").style(\"primary\") # \u2705 Correct\nButton.create(\"Text\", \"btn\").style(\"invalid\") # \u274c Invalid style\n\n# Error: \"Text cannot exceed 2000 characters\"\n# Solution: Keep text under 2000 characters\nPlainText.create(\"Short text\") # \u2705 Correct\nPlainText.create(\"Very long text...\") # \u274c Too long if > 2000 chars\n```\n\n### Method Chaining Patterns\n```python\n# \u2705 Correct: Chain methods before calling build()\nelement = (\n Button.create(\"Text\", \"action_id\")\n .style(\"primary\")\n .confirm(dialog)\n .build()\n)\n\n# \u274c Wrong: Calling build() too early\nelement = Button.create(\"Text\", \"action_id\").build()\nelement.style(\"primary\") # This won't work\n```\n\n### Import Resolution\n```python\n# \u2705 Correct: Import from main package\nfrom slack_blocksmith import Message, Button\n\n# \u2705 Correct: Import specific classes\nfrom slack_blocksmith import Message\nfrom slack_blocksmith import Button\n\n# \u274c Wrong: Import from submodules (not recommended)\nfrom slack_blocksmith.message import Message\n```\n\n### JSON Output Format\n```python\n# All .build() methods return standard Python dictionaries\nmessage_dict = Message.create().add_section(\"Hello\").build()\n# Returns: {\"blocks\": [{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"Hello\"}}]}\n\n# Use with Slack API\nslack_client.chat_postMessage(\n channel=\"#general\",\n blocks=message_dict[\"blocks\"]\n)\n```\n\n## \ud83d\udee0\ufe0f Advanced Usage\n\n### Custom Validation\n```python\nfrom slack_blocksmith import Message, PlainTextInput, validator\nfrom pydantic import BaseModel\n\nclass CustomInput(PlainTextInput):\n @validator('value')\n def validate_email(cls, v):\n if '@' not in v:\n raise ValueError('Must be a valid email')\n return v\n\nmessage = (\n Message.create()\n .add_input(\"Email\", CustomInput.create(\"email\"))\n .build()\n)\n```\n\n### Dynamic Content Generation\n```python\nfrom slack_blocksmith import Message, Section, Button, Option, StaticSelect\n\ndef create_task_message(tasks):\n message = Message.create().add_header(\"Task Dashboard\")\n \n for task in tasks:\n message.add_section(\n text=f\"**{task['title']}**\\n{task['description']}\",\n accessory=StaticSelect.create(\n f\"status_{task['id']}\", \n \"Status\", \n [Option.create(status, status) for status in task['statuses']]\n )\n )\n \n return message.build()\n```\n\n### Error Handling\n```python\nfrom slack_blocksmith import Message, Button\nfrom pydantic import ValidationError\n\ntry:\n message = (\n Message.create()\n .add_section(\"Hello World\")\n .add_actions([\n Button.create(\"Click Me\", \"btn_1\")\n .style(\"invalid_style\") # This will raise ValidationError\n ])\n .build()\n )\nexcept ValidationError as e:\n print(f\"Validation error: {e}\")\n```\n\n## \ud83e\uddea Testing\n\n### Unit Testing\n```python\nimport pytest\nfrom slack_blocksmith import Message, Button\n\ndef test_message_creation():\n message = (\n Message.create()\n .add_section(\"Test message\")\n .add_actions([Button.create(\"Test\", \"btn_test\")])\n .build()\n )\n \n assert len(message[\"blocks\"]) == 2\n assert message[\"blocks\"][0][\"type\"] == \"section\"\n assert message[\"blocks\"][1][\"type\"] == \"actions\"\n\ndef test_button_validation():\n with pytest.raises(ValidationError):\n Button.create(\"\", \"btn_1\") # Empty text should fail\n```\n\n### Integration Testing\n```python\ndef test_slack_api_integration():\n message = Message.create().add_section(\"Test\").build()\n \n # Test with actual Slack API\n response = slack_client.chat_postMessage(\n channel=\"#test\",\n blocks=message[\"blocks\"]\n )\n \n assert response[\"ok\"] is True\n```\n\n## \ud83d\udcca Performance\n\n### Benchmarks\n- **Message Creation**: ~0.1ms per message\n- **Validation**: ~0.05ms per block\n- **Memory Usage**: ~2KB per message\n- **Serialization**: ~0.02ms per message\n\n### Optimization Tips\n```python\n# Reuse common elements\napprove_button = Button.create(\"Approve\", \"btn_approve\").style(\"primary\")\n\n# Use list comprehensions for dynamic content\noptions = [Option.create(f\"Option {i}\", f\"opt_{i}\") for i in range(10)]\n\n# Cache frequently used messages\n@lru_cache(maxsize=100)\ndef get_welcome_message(user_id):\n return Message.create().add_section(f\"Welcome {user_id}\").build()\n```\n\n## \ud83d\udd27 Development\n\n### Setup Development Environment\n```bash\n# Clone the repository\ngit clone https://github.com/your-org/slack-block-kit-builder.git\ncd slack-block-kit-builder\n\n# Install with development dependencies\nuv sync --group dev\n\n# Install pre-commit hooks\npre-commit install\n```\n\n### Code Quality Tools\n```bash\n# Run linting\nruff check .\n\n# Run type checking\nmypy slack_blocksmith/\n\n# Run tests\npytest\n\n# Run tests with coverage\npytest --cov=slack_blocksmith --cov-report=html\n\n# Format code\nruff format .\n```\n\n### Project Structure\n```\nslack-block-kit-builder/\n\u251c\u2500\u2500 slack_blocksmith/ # Main package\n\u2502 \u251c\u2500\u2500 __init__.py # Package exports\n\u2502 \u251c\u2500\u2500 composition.py # Text, Option, Dialog objects\n\u2502 \u251c\u2500\u2500 elements.py # Interactive elements\n\u2502 \u251c\u2500\u2500 blocks.py # Block containers\n\u2502 \u251c\u2500\u2500 message.py # Message builders\n\u2502 \u2514\u2500\u2500 validators.py # Custom validation\n\u251c\u2500\u2500 examples/ # Usage examples\n\u2502 \u251c\u2500\u2500 basic_message.py\n\u2502 \u251c\u2500\u2500 interactive_message.py\n\u2502 \u2514\u2500\u2500 modal_example.py\n\u251c\u2500\u2500 tests/ # Test suite\n\u2502 \u251c\u2500\u2500 test_composition.py\n\u2502 \u251c\u2500\u2500 test_elements.py\n\u2502 \u251c\u2500\u2500 test_blocks.py\n\u2502 \u2514\u2500\u2500 test_message.py\n\u251c\u2500\u2500 docs/ # Documentation\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n```\n\n## \ud83e\udd1d Contributing\n\nWe welcome contributions! Here's how to get started:\n\n### 1. Fork and Clone\n```bash\ngit clone https://github.com/your-username/slack-block-kit-builder.git\ncd slack-block-kit-builder\n```\n\n### 2. Create Feature Branch\n```bash\ngit checkout -b feature/amazing-feature\n```\n\n### 3. Make Changes\n- Follow the existing code style\n- Add tests for new functionality\n- Update documentation as needed\n\n### 4. Run Quality Checks\n```bash\nruff check .\nmypy slack_blocksmith/\npytest\n```\n\n### 5. Submit Pull Request\n- Provide a clear description of changes\n- Include tests for new functionality\n- Ensure all checks pass\n\n### Contribution Guidelines\n- **Code Style**: Follow PEP 8, use ruff for formatting\n- **Type Hints**: All functions must have type hints\n- **Tests**: Maintain 100% test coverage\n- **Documentation**: Update docstrings and README\n- **Commits**: Use conventional commit messages\n\n\n## \ud83d\ude4f Acknowledgments\n\n- **Slack Team** for the amazing Block Kit framework\n- **Pydantic Team** for the excellent validation library\n- **Python Community** for the rich ecosystem of tools\n\n\n\n---\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python package for building Slack Block Kit structures with dedicated classes using builder pattern",
"version": "1.2.2",
"project_urls": {
"Documentation": "https://github.com/ppopov212/slack-blocksmith#readme",
"Homepage": "https://github.com/ppopov212/slack-blocksmith",
"Issues": "https://github.com/ppopov212/slack-blocksmith/issues",
"Repository": "https://github.com/ppopov212/slack-blocksmith"
},
"split_keywords": [
"api",
" block-kit",
" bot",
" builder",
" messaging",
" slack"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "eb2e0e2d3dc3bf7ef53bfb3ed9599b37ed035ce567af1354a04f7c0b1e398925",
"md5": "c244be8505fe333437a79d1cde70f38a",
"sha256": "661469628aafded93109dd4c87ebd79f442163a1339808f6db10f7af4d7cdd65"
},
"downloads": -1,
"filename": "slack_blocksmith-1.2.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c244be8505fe333437a79d1cde70f38a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 31949,
"upload_time": "2025-10-27T20:09:45",
"upload_time_iso_8601": "2025-10-27T20:09:45.687559Z",
"url": "https://files.pythonhosted.org/packages/eb/2e/0e2d3dc3bf7ef53bfb3ed9599b37ed035ce567af1354a04f7c0b1e398925/slack_blocksmith-1.2.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "18818cd38f3c1c825c4edd29cf836a7789df46aa1bee2891d80c090f7c41dbe7",
"md5": "4f81c34a7a60a735ad757387bec005e0",
"sha256": "6fb0b1feeee5eebd62502b7f199b5696fa765ac40eacd7f0310ddb41d3d603a7"
},
"downloads": -1,
"filename": "slack_blocksmith-1.2.2.tar.gz",
"has_sig": false,
"md5_digest": "4f81c34a7a60a735ad757387bec005e0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 168132,
"upload_time": "2025-10-27T20:09:46",
"upload_time_iso_8601": "2025-10-27T20:09:46.947497Z",
"url": "https://files.pythonhosted.org/packages/18/81/8cd38f3c1c825c4edd29cf836a7789df46aa1bee2891d80c090f7c41dbe7/slack_blocksmith-1.2.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-27 20:09:46",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ppopov212",
"github_project": "slack-blocksmith#readme",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "slack-blocksmith"
}