Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions slack_sdk/models/blocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
Option,
OptionGroup,
PlainTextObject,
RawNumberObject,
RawTextObject,
TableBlockColumnSettings,
TextObject,
Expand Down Expand Up @@ -93,6 +94,7 @@
"Option",
"OptionGroup",
"PlainTextObject",
"RawNumberObject",
"RawTextObject",
"TableBlockColumnSettings",
"TextObject",
Expand Down
22 changes: 22 additions & 0 deletions slack_sdk/models/blocks/basic_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,28 @@ def direct_from_link(link: Link, title: str = "") -> Dict[str, Any]:
return MarkdownTextObject.from_link(link, title).to_dict()


class RawNumberObject(JsonObject):
"""raw_number typed object."""

type = "raw_number"
attributes = {"value", "text", "type"}
logger = logging.getLogger(__name__)

def __init__(self, *, value: Union[int, float], text: str):
"""Defines an object containing a numeric value.

Args:
value (required): The numeric value.
text (required): The text used to display the value. The minimum length is 1 character.
"""
self.value = value
self.text = text

@JsonValidator("text attribute must have at least 1 character")
def _validate_text_min_length(self):
return len(self.text) >= 1


class RawTextObject(TextObject):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎲 note: This and the RawNumberObject above might later be moved to tests for composition objects perhaps?

"""raw_text typed text object."""

Expand Down
5 changes: 3 additions & 2 deletions slack_sdk/models/blocks/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .basic_components import (
MarkdownTextObject,
PlainTextObject,
RawNumberObject,
RawTextObject,
SlackFile,
TableBlockColumnSettings,
Expand Down Expand Up @@ -778,7 +779,7 @@ def attributes(self) -> Set[str]: # type: ignore[override]
def __init__(
self,
*,
rows: Sequence[Sequence[Union[Dict[str, Any], "RawTextObject", "RichTextBlock"]]],
rows: Sequence[Sequence[Union[Dict[str, Any], "RawTextObject", "RawNumberObject", "RichTextBlock"]]],
column_settings: Optional[Sequence[Optional[Union[Dict[str, Any], "TableBlockColumnSettings"]]]] = None,
block_id: Optional[str] = None,
**others: dict,
Expand All @@ -790,7 +791,7 @@ def __init__(
Args:
rows (required): An array consisting of table rows. Maximum 100 rows.
Each row object is an array with a max of 20 table cells.
Table cells can have a type of raw_text or rich_text.
Table cells can have a type of rich_text, raw_text, or raw_number.
column_settings: An array describing column behavior. If there are fewer items in the column_settings array
than there are columns in the table, then the items in the the column_settings array will describe
the same number of columns in the table as there are in the array itself.
Expand Down
64 changes: 64 additions & 0 deletions tests/slack_sdk/models/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
OverflowMenuElement,
PlainTextObject,
PlanBlock,
RawNumberObject,
RawTextObject,
RichTextBlock,
RichTextElementParts,
Expand Down Expand Up @@ -1358,6 +1359,40 @@ def test_parsing_empty_block_elements(self):
self.assertIsNotNone(block_dict["elements"][3].get("elements"))


# ----------------------------------------------
# RawNumberObject
# ----------------------------------------------


class RawNumberObjectTests(unittest.TestCase):
def test_basic_creation(self):
"""Test basic RawNumberObject creation"""
obj = RawNumberObject(value=42, text="42")
expected = {"type": "raw_number", "value": 42, "text": "42"}
self.assertDictEqual(expected, obj.to_dict())

def test_float_value(self):
"""Test RawNumberObject accepts a float value"""
obj = RawNumberObject(value=3.14, text="3.14")
expected = {"type": "raw_number", "value": 3.14, "text": "3.14"}
self.assertDictEqual(expected, obj.to_dict())

def test_text_length_validation_min(self):
"""Test that empty text fails validation"""
with self.assertRaises(SlackObjectFormationError):
RawNumberObject(value=0, text="").to_dict()

def test_text_length_validation_at_min(self):
"""Test that text with 1 character passes validation"""
obj = RawNumberObject(value=1, text="1")
obj.to_dict() # Should not raise

def test_attributes(self):
"""Test that RawNumberObject only has value, text, and type attributes"""
obj = RawNumberObject(value=42, text="42")
self.assertEqual(obj.attributes, {"value", "text", "type"})


# ----------------------------------------------
# RawTextObject
# ----------------------------------------------
Expand Down Expand Up @@ -1444,6 +1479,35 @@ def test_with_rich_text(self):
self.assertDictEqual(input, TableBlock(**input).to_dict())
self.assertDictEqual(input, Block.parse(input).to_dict())

def test_with_raw_number(self):
"""Test table block with raw_number cells"""
input = {
"type": "table",
"rows": [
[{"type": "raw_text", "text": "Widgets"}, {"type": "raw_number", "value": 42, "text": "42"}],
[
{
"type": "rich_text",
"elements": [{"type": "rich_text_section", "elements": [{"type": "text", "text": "Gadgets"}]}],
},
{"type": "raw_number", "value": 7, "text": "7"},
],
],
}
self.assertDictEqual(input, TableBlock(**input).to_dict())
self.assertDictEqual(input, Block.parse(input).to_dict())

def test_with_raw_number_cell_objects(self):
"""Test table using typed RawNumberObject cells"""
block = TableBlock(
rows=[[RawTextObject(text="Count"), RawNumberObject(value=42, text="42")]],
)
expected = {
"type": "table",
"rows": [[{"type": "raw_text", "text": "Count"}, {"type": "raw_number", "value": 42, "text": "42"}]],
}
self.assertDictEqual(expected, block.to_dict())

def test_minimal_table(self):
"""Test table with only required fields"""
input = {
Expand Down
Loading