flet 0.70.0.dev5774__py3-none-any.whl → 0.70.0.dev5835__py3-none-any.whl

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.

Potentially problematic release.


This version of flet might be problematic. Click here for more details.

Files changed (96) hide show
  1. flet/__init__.py +32 -4
  2. flet/components/__init__.py +0 -0
  3. flet/components/component.py +346 -0
  4. flet/components/component_decorator.py +24 -0
  5. flet/components/component_owned.py +22 -0
  6. flet/components/hooks/__init__.py +0 -0
  7. flet/components/hooks/hook.py +12 -0
  8. flet/components/hooks/use_callback.py +28 -0
  9. flet/components/hooks/use_context.py +91 -0
  10. flet/components/hooks/use_effect.py +104 -0
  11. flet/components/hooks/use_memo.py +52 -0
  12. flet/components/hooks/use_state.py +58 -0
  13. flet/components/memo.py +34 -0
  14. flet/components/observable.py +269 -0
  15. flet/components/public_utils.py +10 -0
  16. flet/components/utils.py +85 -0
  17. flet/controls/base_control.py +34 -10
  18. flet/controls/base_page.py +44 -40
  19. flet/controls/context.py +22 -1
  20. flet/controls/control.py +12 -6
  21. flet/controls/control_event.py +19 -2
  22. flet/controls/core/animated_switcher.py +3 -2
  23. flet/controls/core/autofill_group.py +6 -2
  24. flet/controls/core/column.py +5 -0
  25. flet/controls/core/dismissible.py +12 -10
  26. flet/controls/core/drag_target.py +20 -10
  27. flet/controls/core/draggable.py +9 -9
  28. flet/controls/core/icon.py +16 -12
  29. flet/controls/core/interactive_viewer.py +24 -23
  30. flet/controls/core/pagelet.py +3 -2
  31. flet/controls/core/reorderable_draggable.py +3 -2
  32. flet/controls/core/row.py +5 -0
  33. flet/controls/core/safe_area.py +3 -2
  34. flet/controls/core/text_span.py +5 -3
  35. flet/controls/core/view.py +6 -6
  36. flet/controls/core/window_drag_area.py +3 -2
  37. flet/controls/cupertino/cupertino_action_sheet.py +10 -5
  38. flet/controls/cupertino/cupertino_action_sheet_action.py +3 -4
  39. flet/controls/cupertino/cupertino_activity_indicator.py +4 -3
  40. flet/controls/cupertino/cupertino_alert_dialog.py +6 -3
  41. flet/controls/cupertino/cupertino_button.py +6 -5
  42. flet/controls/cupertino/cupertino_context_menu.py +8 -4
  43. flet/controls/cupertino/cupertino_context_menu_action.py +3 -4
  44. flet/controls/cupertino/cupertino_date_picker.py +44 -28
  45. flet/controls/cupertino/cupertino_dialog_action.py +3 -4
  46. flet/controls/cupertino/cupertino_list_tile.py +3 -4
  47. flet/controls/cupertino/cupertino_navigation_bar.py +6 -5
  48. flet/controls/cupertino/cupertino_picker.py +14 -10
  49. flet/controls/cupertino/cupertino_segmented_button.py +6 -5
  50. flet/controls/cupertino/cupertino_slider.py +16 -12
  51. flet/controls/cupertino/cupertino_sliding_segmented_button.py +6 -5
  52. flet/controls/cupertino/cupertino_timer_picker.py +38 -31
  53. flet/controls/id_counter.py +24 -0
  54. flet/controls/material/alert_dialog.py +6 -5
  55. flet/controls/material/app_bar.py +17 -14
  56. flet/controls/material/banner.py +13 -11
  57. flet/controls/material/bottom_app_bar.py +5 -4
  58. flet/controls/material/bottom_sheet.py +5 -4
  59. flet/controls/material/button.py +12 -4
  60. flet/controls/material/chip.py +13 -12
  61. flet/controls/material/circle_avatar.py +17 -13
  62. flet/controls/material/datatable.py +48 -41
  63. flet/controls/material/divider.py +30 -14
  64. flet/controls/material/dropdown.py +5 -3
  65. flet/controls/material/expansion_tile.py +11 -22
  66. flet/controls/material/floating_action_button.py +32 -23
  67. flet/controls/material/icon_button.py +7 -3
  68. flet/controls/material/navigation_rail.py +14 -11
  69. flet/controls/material/outlined_button.py +7 -3
  70. flet/controls/material/progress_bar.py +18 -10
  71. flet/controls/material/radio_group.py +5 -1
  72. flet/controls/material/range_slider.py +13 -13
  73. flet/controls/material/segmented_button.py +21 -17
  74. flet/controls/material/selection_area.py +3 -2
  75. flet/controls/material/slider.py +16 -12
  76. flet/controls/material/snack_bar.py +18 -10
  77. flet/controls/material/switch.py +6 -5
  78. flet/controls/material/tabs.py +18 -14
  79. flet/controls/material/textfield.py +32 -15
  80. flet/controls/material/vertical_divider.py +20 -12
  81. flet/controls/object_patch.py +434 -197
  82. flet/controls/page.py +205 -85
  83. flet/controls/services/haptic_feedback.py +0 -3
  84. flet/controls/services/shake_detector.py +0 -3
  85. flet/messaging/flet_socket_server.py +13 -6
  86. flet/messaging/session.py +103 -10
  87. flet/{controls/session_storage.py → messaging/session_store.py} +2 -2
  88. flet/version.py +1 -1
  89. {flet-0.70.0.dev5774.dist-info → flet-0.70.0.dev5835.dist-info}/METADATA +5 -5
  90. {flet-0.70.0.dev5774.dist-info → flet-0.70.0.dev5835.dist-info}/RECORD +93 -80
  91. flet/controls/cache.py +0 -87
  92. flet/controls/control_id.py +0 -22
  93. flet/controls/core/state_view.py +0 -60
  94. {flet-0.70.0.dev5774.dist-info → flet-0.70.0.dev5835.dist-info}/WHEEL +0 -0
  95. {flet-0.70.0.dev5774.dist-info → flet-0.70.0.dev5835.dist-info}/entry_points.txt +0 -0
  96. {flet-0.70.0.dev5774.dist-info → flet-0.70.0.dev5835.dist-info}/top_level.txt +0 -0
@@ -27,17 +27,17 @@ class CupertinoTimerPicker(LayoutControl):
27
27
  duration is bound between `0` and `23` hours `59` minutes `59` seconds.
28
28
 
29
29
  Raises:
30
- AssertionError: If [`value`][(c).] is negative.
31
- AssertionError: If [`value`][(c).] is 24 hours or more.
32
- AssertionError: If [`minute_interval`][(c).] is not a positive integer
30
+ ValueError: If [`value`][(c).] is negative.
31
+ ValueError: If [`value`][(c).] is 24 hours or more.
32
+ ValueError: If [`minute_interval`][(c).] is not a positive integer
33
33
  factor of `60`.
34
- AssertionError: If [`second_interval`][(c).] is not a positive integer
34
+ ValueError: If [`second_interval`][(c).] is not a positive integer
35
35
  factor of `60`.
36
- AssertionError: If [`value`][(c).] is not a multiple
36
+ ValueError: If [`value`][(c).] is not a multiple
37
37
  of [`minute_interval`][(c).].
38
- AssertionError: If [`value`][(c).] is not a multiple
38
+ ValueError: If [`value`][(c).] is not a multiple
39
39
  of [`second_interval`][(c).].
40
- AssertionError: If [`item_extent`][(c).] is not strictly greater than `0.0`.
40
+ ValueError: If [`item_extent`][(c).] is not strictly greater than `0.0`.
41
41
  """
42
42
 
43
43
  value: DurationValue = field(default_factory=lambda: Duration())
@@ -95,32 +95,39 @@ class CupertinoTimerPicker(LayoutControl):
95
95
 
96
96
  def before_update(self):
97
97
  super().before_update()
98
- # normalize for use in below assertion checks
98
+ # normalize for use in below validation checks
99
99
  value = (
100
100
  self.value
101
101
  if isinstance(self.value, Duration)
102
102
  else Duration(seconds=self.value)
103
103
  )
104
- assert value >= Duration(), "value must be a non-negative duration"
105
- assert value < Duration(hours=24), (
106
- f"value must be strictly less than 24 hours, got {value.in_hours} hours"
107
- )
108
- assert self.minute_interval > 0 and 60 % self.minute_interval == 0, (
109
- f"minute_interval ({self.minute_interval}) must be a positive "
110
- "integer factor of 60"
111
- )
112
- assert self.second_interval > 0 and 60 % self.second_interval == 0, (
113
- f"second_interval ({self.second_interval}) must be a positive "
114
- "integer factor of 60"
115
- )
116
- assert value.in_minutes % self.minute_interval == 0, (
117
- f"value ({value.in_minutes} minutes) must be a multiple "
118
- f"of minute_interval ({self.minute_interval})"
119
- )
120
- assert value.in_seconds % self.second_interval == 0, (
121
- f"value ({value.in_seconds} seconds) must be a multiple "
122
- f"of second_interval ({self.second_interval})"
123
- )
124
- assert self.item_extent > 0, (
125
- f"item_extent must be strictly greater than 0.0, got {self.item_extent}"
126
- )
104
+ if value < Duration():
105
+ raise ValueError("value must be a non-negative duration")
106
+ if value >= Duration(hours=24):
107
+ raise ValueError(
108
+ f"value must be strictly less than 24 hours, got {value.in_hours} hours"
109
+ )
110
+ if not (self.minute_interval > 0 and 60 % self.minute_interval == 0):
111
+ raise ValueError(
112
+ f"minute_interval ({self.minute_interval}) must be a positive "
113
+ "integer factor of 60"
114
+ )
115
+ if not (self.second_interval > 0 and 60 % self.second_interval == 0):
116
+ raise ValueError(
117
+ f"second_interval ({self.second_interval}) must be a positive "
118
+ "integer factor of 60"
119
+ )
120
+ if value.in_minutes % self.minute_interval != 0:
121
+ raise ValueError(
122
+ f"value ({value.in_minutes} minutes) must be a multiple "
123
+ f"of minute_interval ({self.minute_interval})"
124
+ )
125
+ if value.in_seconds % self.second_interval != 0:
126
+ raise ValueError(
127
+ f"value ({value.in_seconds} seconds) must be a multiple "
128
+ f"of second_interval ({self.second_interval})"
129
+ )
130
+ if self.item_extent <= 0:
131
+ raise ValueError(
132
+ f"item_extent must be strictly greater than 0.0, got {self.item_extent}"
133
+ )
@@ -0,0 +1,24 @@
1
+ import itertools
2
+ import threading
3
+ from typing import Optional
4
+
5
+ from flet.utils.locks import NopeLock
6
+ from flet.utils.platform_utils import is_pyodide
7
+
8
+
9
+ class IdCounter:
10
+ def __init__(
11
+ self, start: int = 1, step: int = 1, lock: Optional[threading.Lock] = None
12
+ ):
13
+ self._counter = itertools.count(start, step)
14
+ self._lock = lock or (NopeLock() if is_pyodide() else threading.Lock())
15
+
16
+ def next(self) -> int:
17
+ with self._lock:
18
+ return next(self._counter)
19
+
20
+ def __call__(self) -> int: # for dataclass default_factory
21
+ return self.next()
22
+
23
+
24
+ ControlId = IdCounter(start=3)
@@ -29,7 +29,7 @@ class AlertDialog(DialogControl):
29
29
  below the `content`.
30
30
 
31
31
  Raises:
32
- AssertionError: If none of [`title`][(c).], [`content`][(c).], or
32
+ ValueError: If none of [`title`][(c).], [`content`][(c).], or
33
33
  [`actions`][(c).] are provided, as the dialog would have nothing to display.
34
34
  """
35
35
 
@@ -230,7 +230,8 @@ class AlertDialog(DialogControl):
230
230
 
231
231
  def before_update(self):
232
232
  super().before_update()
233
- assert self.title or self.content or self.actions, (
234
- "AlertDialog has nothing to display. Provide at minimum one of the "
235
- "following: title, content, actions"
236
- )
233
+ if not (self.title or self.content or self.actions):
234
+ raise ValueError(
235
+ "AlertDialog has nothing to display. Provide at minimum one of the "
236
+ "following: title, content, actions"
237
+ )
@@ -20,9 +20,9 @@ class AppBar(AdaptiveControl):
20
20
  A material design app bar.
21
21
 
22
22
  Raises:
23
- AssertionError: If [`elevation`][(c).] or [`elevation_on_scroll`][(c).]
24
- is negative.
25
- AssertionError: If [`toolbar_opacity`][(c).] is not between `0.0`
23
+ ValueError: If [`elevation`][(c).] is negative.
24
+ ValueError: If [`elevation_on_scroll`][(c).] is negative.
25
+ ValueError: If [`toolbar_opacity`][(c).] is not between `0.0`
26
26
  and `1.0` inclusive.
27
27
  """
28
28
 
@@ -193,14 +193,17 @@ class AppBar(AdaptiveControl):
193
193
 
194
194
  def before_update(self):
195
195
  super().before_update()
196
- assert self.elevation is None or self.elevation >= 0, (
197
- f"elevation must be greater than or equal to 0, got {self.elevation}"
198
- )
199
- assert self.elevation_on_scroll is None or self.elevation_on_scroll >= 0, (
200
- "elevation_on_scroll must be greater than or equal to 0, "
201
- f"got {self.elevation_on_scroll}"
202
- )
203
- assert 0 <= self.toolbar_opacity <= 1, (
204
- "toolbar_opacity must be between 0.0 and 1.0 inclusive, "
205
- f"got {self.toolbar_opacity}"
206
- )
196
+ if self.elevation is not None and self.elevation < 0:
197
+ raise ValueError(
198
+ f"elevation must be greater than or equal to 0, got {self.elevation}"
199
+ )
200
+ if self.elevation_on_scroll is not None and self.elevation_on_scroll < 0:
201
+ raise ValueError(
202
+ "elevation_on_scroll must be greater than or equal to 0, "
203
+ f"got {self.elevation_on_scroll}"
204
+ )
205
+ if not (0 <= self.toolbar_opacity <= 1):
206
+ raise ValueError(
207
+ "toolbar_opacity must be between 0.0 and 1.0 inclusive, "
208
+ f"got {self.toolbar_opacity}"
209
+ )
@@ -28,9 +28,9 @@ class Banner(DialogControl):
28
28
  them at any time.
29
29
 
30
30
  Raises:
31
- AssertionError: if [`content`][(c).] is not visible.
32
- AssertionError: if [`elevation`][(c).] is negative.
33
- AssertionError: if [`actions`][(c).] does not contain at least one visible
31
+ ValueError: if [`content`][(c).] is not visible.
32
+ ValueError: if [`elevation`][(c).] is negative.
33
+ ValueError: if [`actions`][(c).] does not contain at least one visible
34
34
  action Control.
35
35
  """
36
36
 
@@ -128,11 +128,13 @@ class Banner(DialogControl):
128
128
 
129
129
  def before_update(self):
130
130
  super().before_update()
131
- assert self.elevation is None or self.elevation >= 0, (
132
- f"elevation must be greater than or equal to 0, got {self.elevation}"
133
- )
134
- if isinstance(self.content, Control):
135
- assert self.content.visible, "content must be visible"
136
- assert any(a.visible for a in self.actions), (
137
- "actions must contain at minimum one visible action Control"
138
- )
131
+ if self.elevation is not None and self.elevation < 0:
132
+ raise ValueError(
133
+ f"elevation must be greater than or equal to 0, got {self.elevation}"
134
+ )
135
+ if isinstance(self.content, Control) and not self.content.visible:
136
+ raise ValueError("content must be visible")
137
+ if not any(a.visible for a in self.actions):
138
+ raise ValueError(
139
+ "actions must contain at minimum one visible action Control"
140
+ )
@@ -20,7 +20,7 @@ class BottomAppBar(LayoutControl):
20
20
  A material design bottom app bar.
21
21
 
22
22
  Raises:
23
- AssertionError: If [`elevation`][(c).] is negative.
23
+ ValueError: If [`elevation`][(c).] is negative.
24
24
  """
25
25
 
26
26
  content: Optional[Control] = None
@@ -74,6 +74,7 @@ class BottomAppBar(LayoutControl):
74
74
 
75
75
  def before_update(self):
76
76
  super().before_update()
77
- assert self.elevation is None or self.elevation >= 0, (
78
- f"elevation must be greater than or equal to 0, got {self.elevation}"
79
- )
77
+ if self.elevation is not None and self.elevation < 0:
78
+ raise ValueError(
79
+ f"elevation must be greater than or equal to 0, got {self.elevation}"
80
+ )
@@ -20,7 +20,7 @@ class BottomSheet(DialogControl):
20
20
  from interacting with the rest of the app.
21
21
 
22
22
  Raises:
23
- AssertionError: If [`elevation`][(c).] is negative.
23
+ ValueError: If [`elevation`][(c).] is negative.
24
24
  """
25
25
 
26
26
  content: Control
@@ -99,6 +99,7 @@ class BottomSheet(DialogControl):
99
99
 
100
100
  def before_update(self):
101
101
  super().before_update()
102
- assert self.elevation is None or self.elevation >= 0, (
103
- f"elevation must be greater than or equal to zero, got {self.elevation}"
104
- )
102
+ if self.elevation is not None and self.elevation < 0:
103
+ raise ValueError(
104
+ f"elevation must be greater than or equal to zero, got {self.elevation}"
105
+ )
@@ -22,9 +22,14 @@ __all__ = ["Button"]
22
22
  @control("Button")
23
23
  class Button(LayoutControl, AdaptiveControl):
24
24
  """
25
- A customizable button control that can display text, icons, or both.
25
+ A material button.
26
26
 
27
- It supports various styles, colors, and event handlers for user interaction.
27
+ It supports various styles, colors, event handlers for user interaction,
28
+ and can be used to display text, icons, etc.
29
+
30
+ Raises:
31
+ ValueError: If neither [`icon`][(c).] nor [`content`][(c).]
32
+ (string or visible control) is provided.
28
33
  """
29
34
 
30
35
  content: Optional[StrOrControl] = None
@@ -45,11 +50,14 @@ class Button(LayoutControl, AdaptiveControl):
45
50
 
46
51
  def before_update(self):
47
52
  super().before_update()
48
- assert (
53
+ if not (
49
54
  self.icon
50
55
  or isinstance(self.content, str)
51
56
  or (isinstance(self.content, Control) and self.content.visible)
52
- ), "At least icon or content (string or visible Control) must be provided"
57
+ ):
58
+ raise ValueError(
59
+ "At least icon or content (string or visible Control) must be provided"
60
+ )
53
61
 
54
62
  if (
55
63
  self.style is not None
@@ -28,9 +28,9 @@ class Chip(LayoutControl):
28
28
  Chips are compact elements that represent an attribute, text, entity, or action.
29
29
 
30
30
  Raises:
31
- AssertionError: If [`elevation`][(c).] or [`elevation_on_click`][(c).] is
31
+ ValueError: If [`elevation`][(c).] or [`elevation_on_click`][(c).] is
32
32
  negative.
33
- AssertionError: If callback for both [`on_click`][(c).] and [`on_select`][(c).]
33
+ ValueError: If callback for both [`on_click`][(c).] and [`on_select`][(c).]
34
34
  are specified.
35
35
  """
36
36
 
@@ -254,13 +254,14 @@ class Chip(LayoutControl):
254
254
 
255
255
  def before_update(self):
256
256
  super().before_update()
257
- assert self.on_select is None or self.on_click is None, (
258
- "on_select and on_click cannot be used together"
259
- )
260
- assert self.elevation is None or self.elevation >= 0.0, (
261
- f"elevation must be greater than or equal to 0, got {self.elevation}"
262
- )
263
- assert self.elevation_on_click is None or self.elevation_on_click >= 0.0, (
264
- "elevation_on_click must be greater than or equal to 0, got "
265
- "{self.elevation_on_click}"
266
- )
257
+ if self.on_select is not None and self.on_click is not None:
258
+ raise ValueError("on_select and on_click cannot be used together")
259
+ if self.elevation is not None and self.elevation < 0.0:
260
+ raise ValueError(
261
+ f"elevation must be greater than or equal to 0, got {self.elevation}"
262
+ )
263
+ if self.elevation_on_click is not None and self.elevation_on_click < 0.0:
264
+ raise ValueError(
265
+ "elevation_on_click must be greater than or equal to 0, got "
266
+ f"{self.elevation_on_click}"
267
+ )
@@ -21,9 +21,9 @@ class CircleAvatar(LayoutControl):
21
21
  and if this also fails, then [`bgcolor`][(c).] is used.
22
22
 
23
23
  Raises:
24
- AssertionError: If [`radius`][(c).] or [`min_radius`][(c).]
24
+ ValueError: If [`radius`][(c).] or [`min_radius`][(c).]
25
25
  or [`max_radius`][(c).] is negative.
26
- AssertionError: If [`radius`][(c).] is set and [`min_radius`][(c).]
26
+ ValueError: If [`radius`][(c).] is set and [`min_radius`][(c).]
27
27
  or [`max_radius`][(c).] is not None.
28
28
  """
29
29
 
@@ -107,15 +107,19 @@ class CircleAvatar(LayoutControl):
107
107
 
108
108
  def before_update(self):
109
109
  super().before_update()
110
- assert self.radius is None or self.radius >= 0, (
111
- f"radius must be greater than or equal to 0, got {self.radius}"
112
- )
113
- assert self.min_radius is None or self.min_radius >= 0, (
114
- f"min_radius must be greater than or equal to 0, got {self.min_radius}"
115
- )
116
- assert self.max_radius is None or self.max_radius >= 0, (
117
- f"max_radius must be greater than or equal to 0, got {self.max_radius}"
118
- )
119
- assert self.radius is None or (
110
+ if self.radius is not None and self.radius < 0:
111
+ raise ValueError(
112
+ f"radius must be greater than or equal to 0, got {self.radius}"
113
+ )
114
+ if self.min_radius is not None and self.min_radius < 0:
115
+ raise ValueError(
116
+ f"min_radius must be greater than or equal to 0, got {self.min_radius}"
117
+ )
118
+ if self.max_radius is not None and self.max_radius < 0:
119
+ raise ValueError(
120
+ f"max_radius must be greater than or equal to 0, got {self.max_radius}"
121
+ )
122
+ if self.radius is not None and not (
120
123
  self.min_radius is None and self.max_radius is None
121
- ), "If radius is set, min_radius and max_radius must be None"
124
+ ):
125
+ raise ValueError("If radius is set, min_radius and max_radius must be None")
@@ -36,7 +36,7 @@ class DataColumn(Control):
36
36
  Column configuration for a [`DataTable`][flet.].
37
37
 
38
38
  Raises:
39
- AssertionError: If the [`label`][(c).] is neither a string nor
39
+ ValueError: If the [`label`][(c).] is neither a string nor
40
40
  a visible control.
41
41
  """
42
42
 
@@ -82,9 +82,11 @@ class DataColumn(Control):
82
82
 
83
83
  def before_update(self):
84
84
  super().before_update()
85
- assert isinstance(self.label, str) or (
86
- isinstance(self.label, Control) and self.label.visible
87
- ), "label must a string or a visible control"
85
+ if not (
86
+ isinstance(self.label, str)
87
+ or (isinstance(self.label, Control) and self.label.visible)
88
+ ):
89
+ raise ValueError("label must a string or a visible control")
88
90
 
89
91
 
90
92
  @control("DataCell")
@@ -93,7 +95,7 @@ class DataCell(Control):
93
95
  The data for a cell of a [`DataTable`][flet.].
94
96
 
95
97
  Raises:
96
- AssertionError: If the [`content`][(c).] is neither a string nor a visible
98
+ ValueError: If the [`content`][(c).] is neither a string nor a visible
97
99
  control.
98
100
  """
99
101
 
@@ -185,8 +187,8 @@ class DataCell(Control):
185
187
 
186
188
  def before_update(self):
187
189
  super().before_update()
188
- if isinstance(self.content, Control):
189
- assert self.content.visible, "content must be visible"
190
+ if isinstance(self.content, Control) and not self.content.visible:
191
+ raise ValueError("content must be visible")
190
192
 
191
193
 
192
194
  @control("DataRow")
@@ -197,6 +199,9 @@ class DataRow(Control):
197
199
  One row configuration must be provided for each row to display in the table.
198
200
 
199
201
  The data for this row of the table is provided in the [`cells`][(c).] property.
202
+
203
+ Raises:
204
+ ValueError: If [`cells`][(c).] does not contain at least one visible DataCell.
200
205
  """
201
206
 
202
207
  cells: list[DataCell] = field(default_factory=list)
@@ -267,9 +272,8 @@ class DataRow(Control):
267
272
 
268
273
  def before_update(self):
269
274
  super().before_update()
270
- assert any(cell.visible for cell in self.cells), (
271
- "cells must contain at minimum one visible DataCell"
272
- )
275
+ if not any(cell.visible for cell in self.cells):
276
+ raise ValueError("cells must contain at minimum one visible DataCell")
273
277
 
274
278
 
275
279
  @control("DataTable")
@@ -278,13 +282,13 @@ class DataTable(LayoutControl):
278
282
  A Material Design data table.
279
283
 
280
284
  Raises:
281
- AssertionError: If there are no visible [`columns`][(c).].
282
- AssertionError: If any visible row does not contain exactly as many visible
285
+ ValueError: If there are no visible [`columns`][(c).].
286
+ ValueError: If any visible row does not contain exactly as many visible
283
287
  [`DataRow.cells`][flet.] as there are visible [`columns`][(c).].
284
- AssertionError: If [`data_row_min_height`][(c).] is greater than
288
+ ValueError: If [`data_row_min_height`][(c).] is greater than
285
289
  [`data_row_max_height`][(c).].
286
- AssertionError: If [`divider_thickness`][(c).] is negative.
287
- AssertionError: If [`sort_column_index`][(c).] is out of range.
290
+ ValueError: If [`divider_thickness`][(c).] is negative.
291
+ ValueError: If [`sort_column_index`][(c).] is out of range.
288
292
  """
289
293
 
290
294
  columns: list[DataColumn]
@@ -488,34 +492,37 @@ class DataTable(LayoutControl):
488
492
  list(filter(lambda column: column.visible, self.columns))
489
493
  )
490
494
  visible_rows = list(filter(lambda row: row.visible, self.rows))
491
- assert visible_columns_count > 0, (
492
- "columns must contain at minimum one visible DataColumn"
493
- )
494
- assert all(
495
+ if visible_columns_count == 0:
496
+ raise ValueError("columns must contain at minimum one visible DataColumn")
497
+ if not all(
495
498
  [
496
499
  len([c for c in row.cells if c.visible]) == visible_columns_count
497
500
  for row in visible_rows
498
501
  ]
499
- ), (
500
- f"each visible DataRow must contain exactly as many visible DataCells as "
501
- f"there are visible DataColumns ({visible_columns_count})"
502
- )
503
- assert (
504
- self.data_row_min_height is None
505
- or self.data_row_max_height is None
506
- or (self.data_row_min_height <= self.data_row_max_height)
507
- ), (
508
- f"data_row_min_height ({self.data_row_min_height}) must be less than or "
509
- f"equal to data_row_max_height ({self.data_row_max_height})"
510
- )
511
- assert self.divider_thickness is None or self.divider_thickness >= 0, (
512
- f"divider_thickness must be greater than or equal to 0, "
513
- f"got {self.divider_thickness}"
514
- )
515
- assert self.sort_column_index is None or (
502
+ ):
503
+ raise ValueError(
504
+ f"each visible DataRow must contain exactly as many visible DataCells "
505
+ f"as there are visible DataColumns ({visible_columns_count})"
506
+ )
507
+ if (
508
+ self.data_row_min_height is not None
509
+ and self.data_row_max_height is not None
510
+ and self.data_row_min_height > self.data_row_max_height
511
+ ):
512
+ raise ValueError(
513
+ f"data_row_min_height ({self.data_row_min_height}) must be less than "
514
+ f"or equal to data_row_max_height ({self.data_row_max_height})"
515
+ )
516
+ if self.divider_thickness is not None and self.divider_thickness < 0:
517
+ raise ValueError(
518
+ f"divider_thickness must be greater than or equal to 0, "
519
+ f"got {self.divider_thickness}"
520
+ )
521
+ if self.sort_column_index is not None and not (
516
522
  0 <= self.sort_column_index < visible_columns_count
517
- ), (
518
- f"sort_column_index ({self.sort_column_index}) must be greater than or "
519
- f"equal to 0 and less than the "
520
- f"number of visible columns ({visible_columns_count})"
521
- )
523
+ ):
524
+ raise ValueError(
525
+ f"sort_column_index ({self.sort_column_index}) must be greater than or "
526
+ f"equal to 0 and less than the "
527
+ f"number of visible columns ({visible_columns_count})"
528
+ )
@@ -1,6 +1,7 @@
1
1
  from typing import Optional
2
2
 
3
3
  from flet.controls.base_control import control
4
+ from flet.controls.border_radius import BorderRadiusValue
4
5
  from flet.controls.control import Control
5
6
  from flet.controls.types import ColorValue, Number
6
7
 
@@ -11,6 +12,12 @@ __all__ = ["Divider"]
11
12
  class Divider(Control):
12
13
  """
13
14
  A thin horizontal line (divider), with padding on either side.
15
+
16
+ Raises:
17
+ ValueError: If [`height`][(c).] is negative.
18
+ ValueError: If [`thickness`][(c).] is negative.
19
+ ValueError: If [`leading_indent`][(c).] is negative.
20
+ ValueError: If [`trailing_indent`][(c).] is negative.
14
21
  """
15
22
 
16
23
  color: Optional[ColorValue] = None
@@ -56,19 +63,28 @@ class Divider(Control):
56
63
  If that is also `None`, defaults to `0.0`.
57
64
  """
58
65
 
66
+ radius: Optional[BorderRadiusValue] = None
67
+ """
68
+ The border radius of the divider.
69
+ """
70
+
59
71
  def before_update(self):
60
72
  super().before_update()
61
- assert self.height is None or self.height >= 0, (
62
- f"height must be greater than or equal to 0, got {self.height}"
63
- )
64
- assert self.thickness is None or self.thickness >= 0, (
65
- f"thickness must be greater than or equal to 0, got {self.thickness}"
66
- )
67
- assert self.leading_indent is None or self.leading_indent >= 0, (
68
- "leading_indent must be greater than or equal to 0, "
69
- f"got {self.leading_indent}"
70
- )
71
- assert self.trailing_indent is None or self.trailing_indent >= 0, (
72
- "trailing_indent must be greater than or equal to 0, "
73
- f"got {self.trailing_indent}"
74
- )
73
+ if self.height is not None and self.height < 0:
74
+ raise ValueError(
75
+ f"height must be greater than or equal to 0, got {self.height}"
76
+ )
77
+ if self.thickness is not None and self.thickness < 0:
78
+ raise ValueError(
79
+ f"thickness must be greater than or equal to 0, got {self.thickness}"
80
+ )
81
+ if self.leading_indent is not None and self.leading_indent < 0:
82
+ raise ValueError(
83
+ f"leading_indent must be greater than or equal to 0, "
84
+ f"got {self.leading_indent}"
85
+ )
86
+ if self.trailing_indent is not None and self.trailing_indent < 0:
87
+ raise ValueError(
88
+ f"trailing_indent must be greater than or equal to 0, "
89
+ f"got {self.trailing_indent}"
90
+ )
@@ -30,6 +30,9 @@ class DropdownOption(Control):
30
30
  """
31
31
  Represents an item in a dropdown. Either `key` or `text` must be specified, else an
32
32
  `AssertionError` will be raised.
33
+
34
+ Raises:
35
+ ValueError: If neither [`key`][(c).] nor [`text`][(c).] are provided.
33
36
  """
34
37
 
35
38
  key: Optional[str] = None
@@ -66,9 +69,8 @@ class DropdownOption(Control):
66
69
 
67
70
  def before_update(self):
68
71
  super().before_update()
69
- assert self.key is not None or self.text is not None, (
70
- "key or text must be specified"
71
- )
72
+ if self.key is None and self.text is None:
73
+ raise ValueError("key or text must be specified")
72
74
 
73
75
 
74
76
  Option = DropdownOption