slackblocks 3.2.0__tar.gz → 4.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {slackblocks-3.2.0 → slackblocks-4.0.0}/CHANGELOG.md +11 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/PKG-INFO +2 -2
- {slackblocks-3.2.0 → slackblocks-4.0.0}/README.md +1 -1
- {slackblocks-3.2.0 → slackblocks-4.0.0}/pyproject.toml +2 -2
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/__init__.py +1 -1
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/_limits.py +4 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/blocks.py +40 -18
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/messages.py +12 -1
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/modals.py +2 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/objects.py +9 -9
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/views.py +1 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/uv.lock +1 -1
- {slackblocks-3.2.0 → slackblocks-4.0.0}/.gitignore +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/LICENSE +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/LICENSE.BSD-3-Clause +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/conformance/skiplist.txt +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/generator/generate_limits.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/_core.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/_layout.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/_surfaces.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/attachments.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/builder.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/elements.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/errors.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/py.typed +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/rich_text/__init__.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/rich_text/elements.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/rich_text/objects.py +0 -0
- {slackblocks-3.2.0 → slackblocks-4.0.0}/slackblocks/utils.py +0 -0
|
@@ -5,6 +5,17 @@ All notable changes to `slackblocks` are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.0.0] — 2026-11-14
|
|
9
|
+
|
|
10
|
+
- Coordinate the ten-language 4.0.0 release with shared contract 1.6.0. Supported runtime floors are unchanged. See the 4.0.0 migration guide for Go imports, sparse-setting types and stricter validation.
|
|
11
|
+
|
|
12
|
+
- Require non-empty numeric display labels in both plain and data tables, matching the isolated Slack validation probe.
|
|
13
|
+
|
|
14
|
+
- Preserve skipped columns in sparse table column settings through native APIs and supported parsers. Null entries count toward the existing 20-column-settings limit.
|
|
15
|
+
- Reject non-finite numeric cells while preserving arbitrary-size Python integers.
|
|
16
|
+
|
|
17
|
+
- Add numeric plain-table cells and enforce Slack’s documented 10,000-character per-table and message-wide limits (spec 1.6.0). Count displayed cell text as Unicode code points, including composed blocks and attachments; ragged rows and partial column settings remain valid. Previously accepted over-limit tables now fail validation. Supported runtime floors are unchanged.
|
|
18
|
+
|
|
8
19
|
## [3.2.0] — 2026-10-31
|
|
9
20
|
|
|
10
21
|
- Add native layout blocks, rows and items with typed widths/alignment, closed child and fallback roles, checked nesting and receiving-surface validation (spec 1.5.0).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: slackblocks
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: Python wrapper for the Slack Blocks API
|
|
5
5
|
Project-URL: Homepage, https://github.com/nicklambourne/slackblocks
|
|
6
6
|
Project-URL: Repository, https://github.com/nicklambourne/slackblocks
|
|
@@ -55,7 +55,7 @@ This release conforms to the shared cross-language slackblocks specification.
|
|
|
55
55
|
pip install slackblocks
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
`slackblocks
|
|
58
|
+
`slackblocks 4.x` requires Python 3.10 or newer. Users on Python 3.8 / 3.9 should pin to the `1.x` line — see the [Compatibility](https://nicklambourne.github.io/slackblocks/usage/compatibility) page.
|
|
59
59
|
|
|
60
60
|
## Quickstart
|
|
61
61
|
|
|
@@ -28,7 +28,7 @@ This release conforms to the shared cross-language slackblocks specification.
|
|
|
28
28
|
pip install slackblocks
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
`slackblocks
|
|
31
|
+
`slackblocks 4.x` requires Python 3.10 or newer. Users on Python 3.8 / 3.9 should pin to the `1.x` line — see the [Compatibility](https://nicklambourne.github.io/slackblocks/usage/compatibility) page.
|
|
32
32
|
|
|
33
33
|
## Quickstart
|
|
34
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "slackblocks"
|
|
3
|
-
version = "
|
|
3
|
+
version = "4.0.0"
|
|
4
4
|
description = "Python wrapper for the Slack Blocks API"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Nicholas Lambourne", email = "dev@ndl.im" },
|
|
@@ -58,7 +58,7 @@ docs = [
|
|
|
58
58
|
]
|
|
59
59
|
|
|
60
60
|
[build-system]
|
|
61
|
-
requires = ["hatchling<1.
|
|
61
|
+
requires = ["hatchling<1.34"]
|
|
62
62
|
build-backend = "hatchling.build"
|
|
63
63
|
|
|
64
64
|
[tool.ruff]
|
|
@@ -131,7 +131,7 @@ name = "slackblocks"
|
|
|
131
131
|
|
|
132
132
|
# The version of the shared conformance spec (spec/SPEC.md) this
|
|
133
133
|
# implementation conforms to.
|
|
134
|
-
SPEC_VERSION: str = "1.
|
|
134
|
+
SPEC_VERSION: str = "1.6.0"
|
|
135
135
|
|
|
136
136
|
# Literal exports are visible to strict external type checkers.
|
|
137
137
|
__all__ = [
|
|
@@ -159,6 +159,10 @@ TABLE_ROWS_MAX_ITEMS = 100
|
|
|
159
159
|
TABLE_COLUMNS_MAX_ITEMS = 20
|
|
160
160
|
# table.column_settings.max_items
|
|
161
161
|
TABLE_COLUMN_SETTINGS_MAX_ITEMS = 20
|
|
162
|
+
# table.content.max_length
|
|
163
|
+
TABLE_CONTENT_MAX_LENGTH = 10000
|
|
164
|
+
# table.total_content.max_length
|
|
165
|
+
TABLE_TOTAL_CONTENT_MAX_LENGTH = 10000
|
|
162
166
|
# data_table.rows.min_items
|
|
163
167
|
DATA_TABLE_ROWS_MIN_ITEMS = 2
|
|
164
168
|
# data_table.rows.max_items
|
|
@@ -59,6 +59,7 @@ from slackblocks._limits import (
|
|
|
59
59
|
SECTION_TEXT_MAX_LENGTH,
|
|
60
60
|
TABLE_COLUMN_SETTINGS_MAX_ITEMS,
|
|
61
61
|
TABLE_COLUMNS_MAX_ITEMS,
|
|
62
|
+
TABLE_CONTENT_MAX_LENGTH,
|
|
62
63
|
TABLE_ROWS_MAX_ITEMS,
|
|
63
64
|
VIDEO_ALT_TEXT_MAX_LENGTH,
|
|
64
65
|
VIDEO_AUTHOR_NAME_MAX_LENGTH,
|
|
@@ -163,6 +164,7 @@ ALLOWED_INPUT_ELEMENTS = (
|
|
|
163
164
|
|
|
164
165
|
ALLOWED_TABLE_CELL_ELEMENTS = (
|
|
165
166
|
RawText,
|
|
167
|
+
RawNumber,
|
|
166
168
|
RichTextList,
|
|
167
169
|
RichTextCodeBlock,
|
|
168
170
|
RichTextQuote,
|
|
@@ -416,7 +418,8 @@ class DividerBlock(Block):
|
|
|
416
418
|
|
|
417
419
|
class FileBlock(Block):
|
|
418
420
|
"""
|
|
419
|
-
|
|
421
|
+
A retrieved remote-file representation (e.g. a PDF), not an outgoing message block.
|
|
422
|
+
Register and share remote files with the Files API, then read back this representation.
|
|
420
423
|
|
|
421
424
|
For details on how remote files are exposed to Slack, see
|
|
422
425
|
<https://api.slack.com/messaging/files#adding>.
|
|
@@ -818,21 +821,22 @@ class TableBlock(Block):
|
|
|
818
821
|
A `TableBlock` displays data in a table format.
|
|
819
822
|
|
|
820
823
|
Args:
|
|
821
|
-
rows: a list of lists of `RawText` or `RichTextObject` objects.
|
|
822
|
-
column_settings:
|
|
824
|
+
rows: a list of lists of `RawText`, `RawNumber` or `RichTextObject` objects.
|
|
825
|
+
column_settings: settings for leading columns; omitted trailing columns use Slack defaults.
|
|
823
826
|
block_id: you can use this field to provide a deterministic identifier for the block.
|
|
824
827
|
|
|
825
828
|
Throws:
|
|
826
|
-
InvalidUsageError: when items in `rows` are not `RawText` or `RichTextObject` objects.
|
|
829
|
+
InvalidUsageError: when items in `rows` are not `RawText`, `RawNumber` or `RichTextObject` objects.
|
|
827
830
|
InvalidUsageError: when the number of rows is greater than 100.
|
|
828
831
|
InvalidUsageError: when the number of columns in a row is greater than 20.
|
|
829
832
|
InvalidUsageError: when the number of column_settings is greater than 20.
|
|
833
|
+
LengthError: when displayed cell text exceeds 10,000 Unicode code points.
|
|
830
834
|
"""
|
|
831
835
|
|
|
832
836
|
def __init__(
|
|
833
837
|
self,
|
|
834
|
-
rows: list[list[RawText | RichTextObject]],
|
|
835
|
-
column_settings: list[ColumnSettings] | None = None,
|
|
838
|
+
rows: list[list[RawText | RawNumber | RichTextObject]],
|
|
839
|
+
column_settings: list[ColumnSettings | None] | None = None,
|
|
836
840
|
block_id: str | None = None,
|
|
837
841
|
) -> None:
|
|
838
842
|
super().__init__(type_=BlockType.TABLE, block_id=block_id)
|
|
@@ -858,7 +862,13 @@ class TableBlock(Block):
|
|
|
858
862
|
self.rows.append(validated_row)
|
|
859
863
|
if column_settings and len(column_settings) > TABLE_COLUMN_SETTINGS_MAX_ITEMS:
|
|
860
864
|
raise LengthError("`column_settings` can have a maximum of 20 items.")
|
|
865
|
+
if column_settings is not None:
|
|
866
|
+
for setting in column_settings:
|
|
867
|
+
if setting is not None and not isinstance(setting, ColumnSettings):
|
|
868
|
+
raise TypeMismatchError("Column settings must be ColumnSettings or None.")
|
|
861
869
|
self.column_settings = column_settings
|
|
870
|
+
if _text_character_count(self._resolve()["rows"]) > TABLE_CONTENT_MAX_LENGTH:
|
|
871
|
+
raise LengthError("Table cell text exceeds the 10,000-character limit.")
|
|
862
872
|
|
|
863
873
|
def _resolve(self) -> dict[str, Any]:
|
|
864
874
|
return resolve(
|
|
@@ -869,14 +879,14 @@ class TableBlock(Block):
|
|
|
869
879
|
}
|
|
870
880
|
)
|
|
871
881
|
|
|
872
|
-
def _resolve_cell(self, cell: RawText | RichTextObject) -> dict[str, Any]:
|
|
882
|
+
def _resolve_cell(self, cell: RawText | RawNumber | RichTextObject) -> dict[str, Any]:
|
|
873
883
|
"""
|
|
874
884
|
Resolve a table cell to its JSON representation.
|
|
875
885
|
|
|
876
|
-
RawText cells are resolved directly.
|
|
886
|
+
RawText and RawNumber cells are resolved directly.
|
|
877
887
|
RichTextObject cells are wrapped in a rich_text structure.
|
|
878
888
|
"""
|
|
879
|
-
if isinstance(cell, RawText):
|
|
889
|
+
if isinstance(cell, (RawText, RawNumber)):
|
|
880
890
|
return cell._resolve()
|
|
881
891
|
else:
|
|
882
892
|
# Wrap RichTextObject in rich_text structure
|
|
@@ -1098,7 +1108,10 @@ class CardBlock(Block):
|
|
|
1098
1108
|
title: the card's title (max 150 chars). Can be a string or `Text` object.
|
|
1099
1109
|
subtitle: the card's subtitle (max 150 chars). Can be a string or `Text` object.
|
|
1100
1110
|
body: the card's body text (max 200 chars). Can be a string or `Text` object.
|
|
1101
|
-
actions: up to three `Button` elements
|
|
1111
|
+
actions: up to three `Button` elements, serialized in the supplied order.
|
|
1112
|
+
Slack right-aligns buttons with primary last. With two buttons,
|
|
1113
|
+
danger precedes the other button in that group; with three,
|
|
1114
|
+
danger sits at the card's far left.
|
|
1102
1115
|
slack_icon: a `SlackIcon` naming a Slack-provided icon. Cannot be
|
|
1103
1116
|
combined with `icon`.
|
|
1104
1117
|
subtext: additional text displayed at the bottom of the card
|
|
@@ -1406,8 +1419,11 @@ class DataTableBlock(Block):
|
|
|
1406
1419
|
for cell in row:
|
|
1407
1420
|
if not isinstance(cell, RawText | RawNumber | RichTextBlock):
|
|
1408
1421
|
raise TypeMismatchError("Unsupported data table cell type.")
|
|
1409
|
-
if
|
|
1410
|
-
|
|
1422
|
+
if (
|
|
1423
|
+
isinstance(cell, RawText | RawNumber)
|
|
1424
|
+
and len(cell.text) < DATA_TABLE_CELL_TEXT_MIN_LENGTH
|
|
1425
|
+
):
|
|
1426
|
+
raise LengthError("Data table raw text and numeric labels cannot be empty.")
|
|
1411
1427
|
if any(isinstance(cell, RichTextBlock) for cell in rows[0]):
|
|
1412
1428
|
raise TypeMismatchError("Data table header cells cannot contain rich text.")
|
|
1413
1429
|
self.page_size = validate_int(
|
|
@@ -1443,12 +1459,18 @@ class DataTableBlock(Block):
|
|
|
1443
1459
|
|
|
1444
1460
|
def _text_character_count(value: Any) -> int:
|
|
1445
1461
|
if isinstance(value, dict):
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1462
|
+
if value.get("type") in {"raw_text", "raw_number", "text", "link"}:
|
|
1463
|
+
text = value.get("text")
|
|
1464
|
+
return len(text) if isinstance(text, str) else 0
|
|
1465
|
+
if value.get("type") in {
|
|
1466
|
+
"rich_text",
|
|
1467
|
+
"rich_text_section",
|
|
1468
|
+
"rich_text_list",
|
|
1469
|
+
"rich_text_quote",
|
|
1470
|
+
"rich_text_preformatted",
|
|
1471
|
+
}:
|
|
1472
|
+
return _text_character_count(value.get("elements", []))
|
|
1473
|
+
return 0
|
|
1452
1474
|
if isinstance(value, list):
|
|
1453
1475
|
return sum(_text_character_count(item) for item in value)
|
|
1454
1476
|
return 0
|
|
@@ -21,6 +21,7 @@ from slackblocks._limits import (
|
|
|
21
21
|
MESSAGE_BLOCKS_MAX_ITEMS,
|
|
22
22
|
MESSAGE_CHANNEL_MIN_LENGTH,
|
|
23
23
|
MESSAGE_DATA_VISUALIZATIONS_MAX_ITEMS,
|
|
24
|
+
TABLE_TOTAL_CONTENT_MAX_LENGTH,
|
|
24
25
|
)
|
|
25
26
|
from slackblocks._surfaces import validate_surface_blocks
|
|
26
27
|
from slackblocks.utils import coerce_to_list, validate_string_nonnull
|
|
@@ -74,6 +75,13 @@ def _validate_message_totals(
|
|
|
74
75
|
f"Markdown block text ({markdown} characters) exceeds the message-wide limit of "
|
|
75
76
|
f"{MARKDOWN_TOTAL_TEXT_MAX_LENGTH} characters."
|
|
76
77
|
)
|
|
78
|
+
table = sum(
|
|
79
|
+
_text_character_count(block["rows"])
|
|
80
|
+
for block in rendered_blocks
|
|
81
|
+
if block.get("type") == "table"
|
|
82
|
+
)
|
|
83
|
+
if table > TABLE_TOTAL_CONTENT_MAX_LENGTH:
|
|
84
|
+
raise LengthError("Table cell text exceeds the message-wide 10,000-character limit.")
|
|
77
85
|
data_table = sum(
|
|
78
86
|
_text_character_count(block["rows"])
|
|
79
87
|
for block in rendered_blocks
|
|
@@ -99,9 +107,11 @@ class _MessagePayloadMixin:
|
|
|
99
107
|
raise NotImplementedError
|
|
100
108
|
|
|
101
109
|
def to_dict(self) -> dict[str, Any]:
|
|
110
|
+
"""Return a fresh Slack-shaped dictionary, validating the resolved payload."""
|
|
102
111
|
return self._resolve()
|
|
103
112
|
|
|
104
113
|
def json(self) -> str:
|
|
114
|
+
"""Return the validated Slack-shaped payload as indented JSON."""
|
|
105
115
|
return dumps(self._resolve(), indent=4)
|
|
106
116
|
|
|
107
117
|
def __repr__(self) -> str:
|
|
@@ -111,6 +121,7 @@ class _MessagePayloadMixin:
|
|
|
111
121
|
return self._resolve()[item]
|
|
112
122
|
|
|
113
123
|
def keys(self) -> list[str]:
|
|
124
|
+
"""Return the serialized field names for mapping-style SDK argument unpacking."""
|
|
114
125
|
return list(self._resolve().keys())
|
|
115
126
|
|
|
116
127
|
|
|
@@ -184,7 +195,7 @@ class Message(BaseMessage):
|
|
|
184
195
|
automatically unfurl.
|
|
185
196
|
metadata: optional message metadata, including `event_type` and `event_payload`.
|
|
186
197
|
Throws:
|
|
187
|
-
|
|
198
|
+
InvalidUsageError: in the event that the items passed to `blocks`
|
|
188
199
|
are not valid [`Blocks`](/slackblocks/latest/reference/blocks).
|
|
189
200
|
"""
|
|
190
201
|
|
|
@@ -26,7 +26,9 @@ class Modal(ModalView):
|
|
|
26
26
|
return dumps(self._resolve(), indent=4)
|
|
27
27
|
|
|
28
28
|
def to_dict(self) -> dict[str, Any]:
|
|
29
|
+
"""Return a fresh Slack-shaped dictionary, validating the resolved payload."""
|
|
29
30
|
return self._resolve()
|
|
30
31
|
|
|
31
32
|
def json(self) -> str:
|
|
33
|
+
"""Return the validated Slack-shaped payload as indented JSON."""
|
|
32
34
|
return dumps(self._resolve(), indent=4)
|
|
@@ -6,6 +6,7 @@ See: <https://api.slack.com/reference/block-kit/composition-objects>.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import math
|
|
9
10
|
import re
|
|
10
11
|
from abc import ABC, abstractmethod
|
|
11
12
|
from enum import Enum
|
|
@@ -19,7 +20,6 @@ from slackblocks._limits import (
|
|
|
19
20
|
CONFIRMATION_TEXT_MAX_LENGTH,
|
|
20
21
|
CONFIRMATION_TITLE_MAX_LENGTH,
|
|
21
22
|
CONVERSATION_FILTER_INCLUDE_MIN_ITEMS,
|
|
22
|
-
DATA_TABLE_CELL_TEXT_MIN_LENGTH,
|
|
23
23
|
DATA_VISUALIZATION_AXIS_LABEL_MAX_LENGTH,
|
|
24
24
|
DATA_VISUALIZATION_CATEGORIES_MAX_ITEMS,
|
|
25
25
|
DATA_VISUALIZATION_CATEGORIES_MIN_ITEMS,
|
|
@@ -130,7 +130,7 @@ class Text(CompositionObject):
|
|
|
130
130
|
names, user names will not automatically be rendered as links.
|
|
131
131
|
|
|
132
132
|
Throws:
|
|
133
|
-
|
|
133
|
+
InvalidUsageError: if the provided `text` fails validation.
|
|
134
134
|
"""
|
|
135
135
|
|
|
136
136
|
def __init__(
|
|
@@ -641,7 +641,7 @@ class ConversationFilter(CompositionObject):
|
|
|
641
641
|
exclude_bot_users: whether to remove bot users from the list of conversations.
|
|
642
642
|
|
|
643
643
|
Throws:
|
|
644
|
-
|
|
644
|
+
InvalidUsageError: in the event that the user provides none of `include`,
|
|
645
645
|
`exclude_external_shared_channels`, or `exclude_bot_users` arguments.
|
|
646
646
|
"""
|
|
647
647
|
|
|
@@ -907,7 +907,7 @@ class RawText:
|
|
|
907
907
|
escaped into text format (e.g. `:smile:`).
|
|
908
908
|
|
|
909
909
|
Throws:
|
|
910
|
-
|
|
910
|
+
InvalidUsageError: if the provided `text` fails validation.
|
|
911
911
|
"""
|
|
912
912
|
|
|
913
913
|
def __init__(
|
|
@@ -931,14 +931,14 @@ class RawText:
|
|
|
931
931
|
|
|
932
932
|
class RawNumber(RenderableMixin):
|
|
933
933
|
"""
|
|
934
|
-
A numeric cell for a
|
|
934
|
+
A numeric cell for a table or
|
|
935
935
|
[`DataTableBlock`](/slackblocks/latest/reference/blocks/#blocks.DataTableBlock).
|
|
936
936
|
|
|
937
937
|
See: <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>.
|
|
938
938
|
|
|
939
939
|
Args:
|
|
940
940
|
value: the numeric value Slack uses for sorting and display.
|
|
941
|
-
text: the non-empty text Slack displays
|
|
941
|
+
text: the non-empty text Slack displays.
|
|
942
942
|
|
|
943
943
|
Throws:
|
|
944
944
|
InvalidUsageError: if any of the provided arguments fail validation.
|
|
@@ -947,11 +947,11 @@ class RawNumber(RenderableMixin):
|
|
|
947
947
|
def __init__(self, value: int | float, text: str) -> None:
|
|
948
948
|
if isinstance(value, bool) or not isinstance(value, int | float):
|
|
949
949
|
raise TypeMismatchError("`value` must be a number.")
|
|
950
|
+
if isinstance(value, float) and not math.isfinite(value):
|
|
951
|
+
raise InvalidUsageError("`value` must be finite.")
|
|
950
952
|
self.type = "raw_number"
|
|
951
953
|
self.value = value
|
|
952
|
-
self.text = validate_string_nonnull(
|
|
953
|
-
text, field_name="text", min_length=DATA_TABLE_CELL_TEXT_MIN_LENGTH
|
|
954
|
-
)
|
|
954
|
+
self.text = validate_string_nonnull(text, field_name="text", min_length=1)
|
|
955
955
|
|
|
956
956
|
def _resolve(self) -> dict[str, Any]:
|
|
957
957
|
return {"type": self.type, "value": self.value, "text": self.text}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|