Skip to content

Commit b9f4666

Browse files
authored
feat(models): allow raw_number cells in TableBlock rows (#1964)
1 parent 0824928 commit b9f4666

4 files changed

Lines changed: 91 additions & 2 deletions

File tree

‎slack_sdk/models/blocks/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
Option,
1717
OptionGroup,
1818
PlainTextObject,
19+
RawNumberObject,
1920
RawTextObject,
2021
TableBlockColumnSettings,
2122
TextObject,
@@ -93,6 +94,7 @@
9394
"Option",
9495
"OptionGroup",
9596
"PlainTextObject",
97+
"RawNumberObject",
9698
"RawTextObject",
9799
"TableBlockColumnSettings",
98100
"TextObject",

‎slack_sdk/models/blocks/basic_components.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,28 @@ def direct_from_link(link: Link, title: str = "") -> Dict[str, Any]:
151151
return MarkdownTextObject.from_link(link, title).to_dict()
152152

153153

154+
class RawNumberObject(JsonObject):
155+
"""raw_number typed object."""
156+
157+
type = "raw_number"
158+
attributes = {"value", "text", "type"}
159+
logger = logging.getLogger(__name__)
160+
161+
def __init__(self, *, value: Union[int, float], text: str):
162+
"""Defines an object containing a numeric value.
163+
164+
Args:
165+
value (required): The numeric value.
166+
text (required): The text used to display the value. The minimum length is 1 character.
167+
"""
168+
self.value = value
169+
self.text = text
170+
171+
@JsonValidator("text attribute must have at least 1 character")
172+
def _validate_text_min_length(self):
173+
return len(self.text) >= 1
174+
175+
154176
class RawTextObject(TextObject):
155177
"""raw_text typed text object."""
156178

‎slack_sdk/models/blocks/blocks.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .basic_components import (
1111
MarkdownTextObject,
1212
PlainTextObject,
13+
RawNumberObject,
1314
RawTextObject,
1415
SlackFile,
1516
TableBlockColumnSettings,
@@ -778,7 +779,7 @@ def attributes(self) -> Set[str]: # type: ignore[override]
778779
def __init__(
779780
self,
780781
*,
781-
rows: Sequence[Sequence[Union[Dict[str, Any], "RawTextObject", "RichTextBlock"]]],
782+
rows: Sequence[Sequence[Union[Dict[str, Any], "RawTextObject", "RawNumberObject", "RichTextBlock"]]],
782783
column_settings: Optional[Sequence[Optional[Union[Dict[str, Any], "TableBlockColumnSettings"]]]] = None,
783784
block_id: Optional[str] = None,
784785
**others: dict,
@@ -790,7 +791,7 @@ def __init__(
790791
Args:
791792
rows (required): An array consisting of table rows. Maximum 100 rows.
792793
Each row object is an array with a max of 20 table cells.
793-
Table cells can have a type of raw_text or rich_text.
794+
Table cells can have a type of rich_text, raw_text, or raw_number.
794795
column_settings: An array describing column behavior. If there are fewer items in the column_settings array
795796
than there are columns in the table, then the items in the the column_settings array will describe
796797
the same number of columns in the table as there are in the array itself.

‎tests/slack_sdk/models/test_blocks.py‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
OverflowMenuElement,
2727
PlainTextObject,
2828
PlanBlock,
29+
RawNumberObject,
2930
RawTextObject,
3031
RichTextBlock,
3132
RichTextElementParts,
@@ -1358,6 +1359,40 @@ def test_parsing_empty_block_elements(self):
13581359
self.assertIsNotNone(block_dict["elements"][3].get("elements"))
13591360

13601361

1362+
# ----------------------------------------------
1363+
# RawNumberObject
1364+
# ----------------------------------------------
1365+
1366+
1367+
class RawNumberObjectTests(unittest.TestCase):
1368+
def test_basic_creation(self):
1369+
"""Test basic RawNumberObject creation"""
1370+
obj = RawNumberObject(value=42, text="42")
1371+
expected = {"type": "raw_number", "value": 42, "text": "42"}
1372+
self.assertDictEqual(expected, obj.to_dict())
1373+
1374+
def test_float_value(self):
1375+
"""Test RawNumberObject accepts a float value"""
1376+
obj = RawNumberObject(value=3.14, text="3.14")
1377+
expected = {"type": "raw_number", "value": 3.14, "text": "3.14"}
1378+
self.assertDictEqual(expected, obj.to_dict())
1379+
1380+
def test_text_length_validation_min(self):
1381+
"""Test that empty text fails validation"""
1382+
with self.assertRaises(SlackObjectFormationError):
1383+
RawNumberObject(value=0, text="").to_dict()
1384+
1385+
def test_text_length_validation_at_min(self):
1386+
"""Test that text with 1 character passes validation"""
1387+
obj = RawNumberObject(value=1, text="1")
1388+
obj.to_dict() # Should not raise
1389+
1390+
def test_attributes(self):
1391+
"""Test that RawNumberObject only has value, text, and type attributes"""
1392+
obj = RawNumberObject(value=42, text="42")
1393+
self.assertEqual(obj.attributes, {"value", "text", "type"})
1394+
1395+
13611396
# ----------------------------------------------
13621397
# RawTextObject
13631398
# ----------------------------------------------
@@ -1444,6 +1479,35 @@ def test_with_rich_text(self):
14441479
self.assertDictEqual(input, TableBlock(**input).to_dict())
14451480
self.assertDictEqual(input, Block.parse(input).to_dict())
14461481

1482+
def test_with_raw_number(self):
1483+
"""Test table block with raw_number cells"""
1484+
input = {
1485+
"type": "table",
1486+
"rows": [
1487+
[{"type": "raw_text", "text": "Widgets"}, {"type": "raw_number", "value": 42, "text": "42"}],
1488+
[
1489+
{
1490+
"type": "rich_text",
1491+
"elements": [{"type": "rich_text_section", "elements": [{"type": "text", "text": "Gadgets"}]}],
1492+
},
1493+
{"type": "raw_number", "value": 7, "text": "7"},
1494+
],
1495+
],
1496+
}
1497+
self.assertDictEqual(input, TableBlock(**input).to_dict())
1498+
self.assertDictEqual(input, Block.parse(input).to_dict())
1499+
1500+
def test_with_raw_number_cell_objects(self):
1501+
"""Test table using typed RawNumberObject cells"""
1502+
block = TableBlock(
1503+
rows=[[RawTextObject(text="Count"), RawNumberObject(value=42, text="42")]],
1504+
)
1505+
expected = {
1506+
"type": "table",
1507+
"rows": [[{"type": "raw_text", "text": "Count"}, {"type": "raw_number", "value": 42, "text": "42"}]],
1508+
}
1509+
self.assertDictEqual(expected, block.to_dict())
1510+
14471511
def test_minimal_table(self):
14481512
"""Test table with only required fields"""
14491513
input = {

0 commit comments

Comments
 (0)