flet 0.70.0.dev6365__py3-none-any.whl → 0.70.0.dev6412__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 (44) hide show
  1. flet/__init__.py +2 -0
  2. flet/components/hooks/use_state.py +38 -15
  3. flet/controls/base_control.py +13 -10
  4. flet/controls/base_page.py +10 -2
  5. flet/controls/border.py +1 -1
  6. flet/controls/box.py +18 -16
  7. flet/controls/colors.py +5 -4
  8. flet/controls/context.py +1 -1
  9. flet/controls/control_event.py +2 -1
  10. flet/controls/core/dismissible.py +1 -5
  11. flet/controls/core/interactive_viewer.py +10 -23
  12. flet/controls/core/responsive_row.py +1 -2
  13. flet/controls/core/row.py +1 -2
  14. flet/controls/core/stack.py +27 -0
  15. flet/controls/core/view.py +2 -4
  16. flet/controls/core/window.py +12 -8
  17. flet/controls/cupertino/cupertino_colors.py +8 -6
  18. flet/controls/material/app_bar.py +5 -6
  19. flet/controls/material/auto_complete.py +41 -6
  20. flet/controls/material/chip.py +4 -11
  21. flet/controls/material/circle_avatar.py +5 -6
  22. flet/controls/material/dropdown.py +11 -5
  23. flet/controls/material/dropdownm2.py +4 -5
  24. flet/controls/material/expansion_panel.py +19 -15
  25. flet/controls/material/menu_bar.py +7 -5
  26. flet/controls/material/menu_item_button.py +1 -1
  27. flet/controls/material/snack_bar.py +1 -4
  28. flet/controls/material/submenu_button.py +19 -0
  29. flet/controls/material/switch.py +5 -0
  30. flet/controls/material/tabs.py +7 -12
  31. flet/controls/material/text_button.py +8 -0
  32. flet/controls/material/time_picker.py +8 -0
  33. flet/controls/page.py +48 -1
  34. flet/controls/services/shared_preferences.py +2 -1
  35. flet/controls/types.py +29 -3
  36. flet/pubsub/pubsub_hub.py +2 -1
  37. flet/testing/flet_test_app.py +11 -6
  38. flet/utils/pip.py +19 -14
  39. flet/version.py +1 -1
  40. {flet-0.70.0.dev6365.dist-info → flet-0.70.0.dev6412.dist-info}/METADATA +1 -1
  41. {flet-0.70.0.dev6365.dist-info → flet-0.70.0.dev6412.dist-info}/RECORD +44 -44
  42. {flet-0.70.0.dev6365.dist-info → flet-0.70.0.dev6412.dist-info}/WHEEL +0 -0
  43. {flet-0.70.0.dev6365.dist-info → flet-0.70.0.dev6412.dist-info}/entry_points.txt +0 -0
  44. {flet-0.70.0.dev6365.dist-info → flet-0.70.0.dev6412.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,9 @@
1
1
  from dataclasses import dataclass, field
2
2
  from typing import Optional
3
3
 
4
+ from flet import LayoutControl
4
5
  from flet.controls.base_control import control
5
- from flet.controls.control import Control
6
- from flet.controls.control_event import Event, EventHandler
6
+ from flet.controls.control_event import ControlEventHandler, Event, EventHandler
7
7
  from flet.controls.types import Number
8
8
 
9
9
  __all__ = ["AutoComplete", "AutoCompleteSelectEvent", "AutoCompleteSuggestion"]
@@ -11,22 +11,45 @@ __all__ = ["AutoComplete", "AutoCompleteSelectEvent", "AutoCompleteSuggestion"]
11
11
 
12
12
  @dataclass
13
13
  class AutoCompleteSuggestion:
14
+ """
15
+ Represents a suggestion item for the [`AutoComplete`][flet.] control.
16
+ """
17
+
14
18
  key: str
19
+ """A unique identifier or value used for filtering and selection."""
20
+
15
21
  value: str
22
+ """The display text shown to the user."""
16
23
 
17
24
 
18
25
  @dataclass
19
26
  class AutoCompleteSelectEvent(Event["AutoComplete"]):
27
+ """Event representing the selection of a suggestion in the AutoComplete control."""
28
+
29
+ index: int
30
+ """
31
+ The index of the selected suggestion from the corresponding
32
+ [`AutoComplete.suggestions`][flet.] list.
33
+ """
34
+
20
35
  selection: AutoCompleteSuggestion
36
+ """The selected suggestion."""
21
37
 
22
38
 
23
39
  @control("AutoComplete")
24
- class AutoComplete(Control):
40
+ class AutoComplete(LayoutControl):
25
41
  """
26
42
  Helps the user make a selection by entering some text and choosing from among a
27
43
  list of displayed options.
28
44
  """
29
45
 
46
+ value: str = ""
47
+ """
48
+ Current text displayed in the input field.
49
+
50
+ This value reflects user input even if it does not match any provided suggestion.
51
+ """
52
+
30
53
  suggestions: list[AutoCompleteSuggestion] = field(default_factory=list)
31
54
  """
32
55
  A list of [`AutoCompleteSuggestion`][flet.]
@@ -53,7 +76,19 @@ class AutoComplete(Control):
53
76
  Called when a suggestion is selected.
54
77
  """
55
78
 
79
+ on_change: Optional[ControlEventHandler["AutoComplete"]] = None
80
+ """
81
+ Called when the input text changes.
82
+ """
83
+
56
84
  @property
57
- def selected_index(self):
58
- # TODO: check availability of _selected_index + a default if not yet available
59
- return self._selected_index
85
+ def selected_index(self) -> Optional[int]:
86
+ """
87
+ The index of the (last) selected suggestion.
88
+
89
+ It is `None` until a suggestion has been selected from the UI.
90
+
91
+ Note:
92
+ This property is read-only.
93
+ """
94
+ return getattr(self, "_selected_index", None)
@@ -168,11 +168,8 @@ class Chip(LayoutControl):
168
168
 
169
169
  Defaults to `8.0`.
170
170
 
171
- Note:
172
- Must be non-negative.
173
-
174
171
  Raises:
175
- ValueError: If [`elevation_on_click`][(c).] is negative.
172
+ ValueError: If it is less than `0.0`.
176
173
  """
177
174
 
178
175
  clip_behavior: ClipBehavior = ClipBehavior.NONE
@@ -230,12 +227,8 @@ class Chip(LayoutControl):
230
227
  """
231
228
  Called when the user clicks on this chip.
232
229
 
233
- Note:
234
- Cannot be specified together with [`on_select`][(c).].
235
-
236
230
  Raises:
237
- ValueError: If both [`on_click`][(c).] and [`on_select`][(c).] callbacks
238
- are provided.
231
+ ValueError: If specified together with [`on_select`][(c).].
239
232
  """
240
233
 
241
234
  on_delete: Optional[ControlEventHandler["Chip"]] = None
@@ -249,8 +242,8 @@ class Chip(LayoutControl):
249
242
 
250
243
  It internally changes [`selected`][(c).] property to the opposite value.
251
244
 
252
- Note:
253
- Cannot be specified together with [`on_click`][(c).].
245
+ Raises:
246
+ ValueError: If specified together with [`on_click`][(c).].
254
247
  """
255
248
 
256
249
  on_focus: Optional[ControlEventHandler["Chip"]] = None
@@ -79,9 +79,8 @@ class CircleAvatar(LayoutControl):
79
79
  [`max_radius`][(c).] may be specified.
80
80
 
81
81
  Raises:
82
- ValueError: If [`radius`][(c).] is negative.
83
- ValueError: If [`radius`][(c).] is set while [`min_radius`][(c).]
84
- or [`max_radius`][(c).] is provided.
82
+ ValueError: If it is less than `0.0` or if it is
83
+ provided while [`min_radius`][(c).] or [`max_radius`][(c).] is set.
85
84
  """
86
85
 
87
86
  min_radius: Optional[Number] = None
@@ -92,7 +91,7 @@ class CircleAvatar(LayoutControl):
92
91
  Defaults to `0.0`.
93
92
 
94
93
  Raises:
95
- ValueError: If [`min_radius`][(c).] is negative.
94
+ ValueError: If it is negative.
96
95
  """
97
96
 
98
97
  max_radius: Optional[Number] = None
@@ -105,8 +104,8 @@ class CircleAvatar(LayoutControl):
105
104
  If `max_radius` is specified, then [`radius`][(c).] should not be specified.
106
105
 
107
106
  Raises:
108
- ValueError: If [`max_radius`][(c).] is negative.
109
- ValueError: If [`max_radius`][(c).] is provided while [`radius`][(c).] is set.
107
+ ValueError: If it is less than `0.0` or if it is
108
+ provided while [`radius`][(c).] is set.
110
109
  """
111
110
 
112
111
  on_image_error: Optional[ControlEventHandler["CircleAvatar"]] = None
@@ -29,7 +29,7 @@ __all__ = ["Dropdown", "DropdownOption"]
29
29
  class DropdownOption(Control):
30
30
  """
31
31
  Represents an item in a dropdown. Either `key` or `text` must be specified, else an
32
- `AssertionError` will be raised.
32
+ A `ValueError` will be raised.
33
33
  """
34
34
 
35
35
  key: Optional[str] = None
@@ -247,7 +247,8 @@ class Dropdown(LayoutControl):
247
247
  """
248
248
  Text that appears below the input border.
249
249
 
250
- If non-null, the border's color animates to red and the `helper_text` is not shown.
250
+ If non-null, the border's color animates to red and the [`helper_text`][(c).] is
251
+ not shown.
251
252
  """
252
253
 
253
254
  text_size: Optional[Number] = None
@@ -291,13 +292,18 @@ class Dropdown(LayoutControl):
291
292
 
292
293
  border_width: Number = 1
293
294
  """
294
- The width of the border in virtual pixels. Set to `0` to completely remove border.
295
+ The width of the border in virtual pixels.
296
+
297
+ Tip:
298
+ Set to `0` to completely remove the border.
295
299
  """
296
300
 
297
301
  border_color: Optional[ColorValue] = None
298
302
  """
299
- Border color. Could be `transparent` to
300
- hide the border.
303
+ Border color.
304
+
305
+ Tip:
306
+ Set to [`Colors.TRANSPARENT`][flet.] to hide the border.
301
307
  """
302
308
 
303
309
  border_radius: Optional[BorderRadiusValue] = None
@@ -19,8 +19,8 @@ __all__ = ["DropdownM2", "Option"]
19
19
  @control("Option")
20
20
  class Option(Control):
21
21
  """
22
- Represents an item in a dropdown. Either `key` or `text` must be specified, else an
23
- `AssertionError` will be raised.
22
+ Represents an item in a dropdown. Either `key` or `text` must be specified, else a
23
+ `ValueError` will be raised.
24
24
  """
25
25
 
26
26
  key: Optional[str] = None
@@ -58,9 +58,8 @@ class Option(Control):
58
58
 
59
59
  def before_update(self):
60
60
  super().before_update()
61
- assert self.key is not None or self.text is not None, (
62
- "key or text must be specified"
63
- )
61
+ if self.key is None and self.text is None:
62
+ raise ValueError("key or text must be specified")
64
63
 
65
64
 
66
65
  @control("DropdownM2")
@@ -64,13 +64,12 @@ class ExpansionPanel(LayoutControl, AdaptiveControl):
64
64
 
65
65
  expanded: bool = False
66
66
  """
67
- Whether expanded(`True`) or collapsed(`False`). Defaults to `False`.
67
+ Whether expanded(`True`) or collapsed(`False`).
68
68
  """
69
69
 
70
70
  can_tap_header: bool = False
71
71
  """
72
- If `True`, tapping on the panel's `header` will expand or collapse it. Defaults to
73
- `False`.
72
+ If `True`, tapping on the panel's `header` will expand or collapse it.
74
73
  """
75
74
 
76
75
  splash_color: Optional[ColorValue] = None
@@ -109,19 +108,21 @@ class ExpansionPanelList(LayoutControl):
109
108
 
110
109
  controls: list[ExpansionPanel] = field(default_factory=list)
111
110
  """
112
- A list of `ExpansionPanel`s to display inside `ExpansionPanelList`.
111
+ A list of panels to display.
113
112
  """
114
113
 
115
114
  divider_color: Optional[ColorValue] = None
116
115
  """
117
116
  The color of the divider when
118
- `ExpansionPanel.expanded` is `False`.
117
+ [`ExpansionPanel.expanded`][flet.] is `False`.
119
118
  """
120
119
 
121
120
  elevation: Number = 2
122
121
  """
123
- Defines the elevation of the children controls (`ExpansionPanel`s), while it is
124
- expanded. Default value is `2`.
122
+ Defines the elevation of the [`controls`][(c).], when expanded.
123
+
124
+ Raises:
125
+ ValueError: If it is less than zero.
125
126
  """
126
127
 
127
128
  expanded_header_padding: PaddingValue = field(
@@ -133,23 +134,26 @@ class ExpansionPanelList(LayoutControl):
133
134
 
134
135
  expand_icon_color: Optional[ColorValue] = None
135
136
  """
136
- The color of the icon. Defaults to
137
- `colors.BLACK_54` in light theme mode and `colors.WHITE_60` in dark theme mode.
137
+ The color of the icon.
138
+
139
+ Defaults to [`Colors.BLACK_54`][flet.] in light theme mode and
140
+ [`Colors.WHITE_60`][flet.] in dark theme mode.
138
141
  """
139
142
 
140
143
  spacing: Optional[Number] = None
141
144
  """
142
- The size of the gap between the `ExpansionPanel`s when expanded.
145
+ The size of the gap between the [`controls`][(c).]s when expanded.
143
146
  """
144
147
 
145
148
  on_change: Optional[ControlEventHandler["ExpansionPanelList"]] = None
146
149
  """
147
- Called when an `ExpansionPanel` is expanded or collapsed. The event's data
148
- (`e.data`), contains the index of the `ExpansionPanel` which triggered this event.
150
+ Called when an item of [`controls`][(c).] is expanded or collapsed.
151
+
152
+ The event's [`data`][flet.Event.], contains the index of the
153
+ child panel (in [`controls`][(c).]) which triggered this event.
149
154
  """
150
155
 
151
156
  def before_update(self):
152
157
  super().before_update()
153
- assert self.elevation is None or self.elevation >= 0, (
154
- "elevation cannot be negative"
155
- )
158
+ if self.elevation < 0:
159
+ raise ValueError("elevation must be greater than or equal to zero")
@@ -48,7 +48,10 @@ class MenuBar(Control):
48
48
 
49
49
  controls: list[Control] = field(default_factory=list)
50
50
  """
51
- The list of menu items that are the top level children of the `MenuBar`.
51
+ A list of top-level menu controls to display in this menu bar.
52
+
53
+ Raises:
54
+ ValueError: If none of the controls are visible.
52
55
  """
53
56
 
54
57
  clip_behavior: ClipBehavior = ClipBehavior.NONE
@@ -58,11 +61,10 @@ class MenuBar(Control):
58
61
 
59
62
  style: Optional[MenuStyle] = None
60
63
  """
61
- TBD
64
+ The menu bar style.
62
65
  """
63
66
 
64
67
  def before_update(self):
65
68
  super().before_update()
66
- assert any(c.visible for c in self.controls), (
67
- "MenuBar must have at minimum one visible control"
68
- )
69
+ if not any(c.visible for c in self.controls):
70
+ raise ValueError("MenuBar must have at minimum one visible control")
@@ -80,7 +80,7 @@ class MenuItemButton(LayoutControl):
80
80
 
81
81
  on_click: Optional[ControlEventHandler["MenuItemButton"]] = None
82
82
  """
83
- Called when the button is clicked.
83
+ Called when the button is clicked.If not defined the button will be disabled.
84
84
  """
85
85
 
86
86
  on_hover: Optional[ControlEventHandler["MenuItemButton"]] = None
@@ -219,11 +219,8 @@ class SnackBar(DialogControl):
219
219
 
220
220
  At a value of `0.0`, the `action` will not overflow to a new line.
221
221
 
222
- Note:
223
- Must be between `0.0` and `1.0` inclusive.
224
-
225
222
  Raises:
226
- ValueError: If [`action_overflow_threshold`][(c).] is not between `0` and `1`.
223
+ ValueError: If it is not between `0.0` and `1.0` inclusive.
227
224
  """
228
225
 
229
226
  on_action: Optional[ControlEventHandler["SnackBar"]] = None
@@ -19,6 +19,25 @@ class SubmenuButton(LayoutControl):
19
19
  A menu button that displays a cascading menu.
20
20
 
21
21
  Typically used in a [`MenuBar`][flet.] control.
22
+
23
+ ```python
24
+ ft.SubmenuButton(
25
+ content=ft.Text("Choose text style"),
26
+ key="smbutton",
27
+ expand=True,
28
+ menu_style=ft.MenuStyle(
29
+ alignment=ft.Alignment.BOTTOM_LEFT, side=ft.BorderSide(1)
30
+ ),
31
+ controls=[
32
+ ft.MenuItemButton(
33
+ content=ft.Text("Underlined"),
34
+ on_click=lambda e: print(f"{e.control.content.value}.on_click")
35
+ ),
36
+ ft.MenuItemButton(...),
37
+ ...
38
+ ]
39
+ )
40
+ ```
22
41
  """
23
42
 
24
43
  content: Optional[StrOrControl] = None
@@ -26,6 +26,11 @@ class Switch(LayoutControl, AdaptiveControl):
26
26
  two mutually exclusive options.
27
27
 
28
28
  For example, "On/Off", "Show/Hide".
29
+
30
+ ```python
31
+ ft.Switch(label="Unchecked switch", value=False)
32
+ ft.Switch(label="Disabled switch", disabled=True)
33
+ ```
29
34
  """
30
35
 
31
36
  label: Optional[StrOrControl] = None
@@ -172,7 +172,7 @@ class Tabs(LayoutControl, AdaptiveControl):
172
172
  it when adding/removing tabs.
173
173
 
174
174
  Raises:
175
- ValueError: If [`length`][(c).] is negative.
175
+ ValueError: If it is negative.
176
176
  """
177
177
 
178
178
  selected_index: int = 0
@@ -191,8 +191,7 @@ class Tabs(LayoutControl, AdaptiveControl):
191
191
  use [`move_to`][(c).] directly.
192
192
 
193
193
  Raises:
194
- IndexError: If [`selected_index`][(c).] is not in the range
195
- `[-length, length - 1]`.
194
+ IndexError: If it is not in the range `[-length, length - 1]`.
196
195
  """
197
196
 
198
197
  animation_duration: DurationValue = field(
@@ -353,18 +352,14 @@ class TabBar(LayoutControl, AdaptiveControl):
353
352
  otherwise [`TabAlignment.FILL`][flet.] is used.
354
353
 
355
354
  Note:
356
- - If [`scrollable`][(c).] is `False`, then
357
- [`tab_alignment`][(c).] must be either
358
- [`TabAlignment.FILL`][flet.] or
359
- [`TabAlignment.CENTER`][flet.].
360
- - If [`scrollable`][(c).] is `True`, then
361
- [`tab_alignment`][(c).] must be
362
- [`TabAlignment.START`][flet.],
363
- [`TabAlignment.START_OFFSET`][flet.]
355
+ - If [`scrollable`][(c).] is `False`, then [`tab_alignment`][(c).] must be
356
+ either [`TabAlignment.FILL`][flet.] or [`TabAlignment.CENTER`][flet.].
357
+ - If [`scrollable`][(c).] is `True`, then [`tab_alignment`][(c).] must be
358
+ [`TabAlignment.START`][flet.], [`TabAlignment.START_OFFSET`][flet.]
364
359
  or [`TabAlignment.CENTER`][flet.].
365
360
 
366
361
  Raises:
367
- ValueError: If [`tab_alignment`][(c).] is not valid for the current
362
+ ValueError: If it is not valid for the current
368
363
  [`scrollable`][(c).] configuration.
369
364
  """
370
365
 
@@ -22,6 +22,14 @@ class TextButton(LayoutControl, AdaptiveControl):
22
22
  Text buttons are used for the lowest priority actions, especially when presenting
23
23
  multiple options. Text buttons can be placed on a variety of backgrounds. Until the
24
24
  button is interacted with, its container isn’t visible.
25
+
26
+ ```python
27
+ ft.TextButton(
28
+ content="Text Button",
29
+ icon=ft.Icons.STAR_BORDER,
30
+ icon_color=ft.Colors.BLUE_300,
31
+ )
32
+ ```
25
33
  """
26
34
 
27
35
  content: Optional[StrOrControl] = None
@@ -38,6 +38,14 @@ class TimePicker(DialogControl):
38
38
 
39
39
  Depending on the `time_picker_entry_mode`, it will show either a Dial or
40
40
  an Input (hour and minute text fields) for picking a time.
41
+
42
+ ```python
43
+ ft.TimePicker(
44
+ value=time(1, 2),
45
+ time_picker_entry_mode=ft.TimePickerEntryMode.INPUT_ONLY,
46
+ open=True,
47
+ )
48
+ ```
41
49
  """
42
50
 
43
51
  value: Optional[time] = field(default_factory=lambda: datetime.now().time())
flet/controls/page.py CHANGED
@@ -42,6 +42,7 @@ from flet.controls.device_info import (
42
42
  WebDeviceInfo,
43
43
  WindowsDeviceInfo,
44
44
  )
45
+ from flet.controls.exceptions import FletUnsupportedPlatformException
45
46
  from flet.controls.multi_view import MultiView
46
47
  from flet.controls.query_string import QueryString
47
48
  from flet.controls.ref import Ref
@@ -54,6 +55,7 @@ from flet.controls.services.url_launcher import UrlLauncher
54
55
  from flet.controls.types import (
55
56
  AppLifecycleState,
56
57
  Brightness,
58
+ DeviceOrientation,
57
59
  PagePlatform,
58
60
  Url,
59
61
  UrlTarget,
@@ -198,7 +200,7 @@ class Page(BasePage):
198
200
  Used to enable or disable the context menu that appears when the user
199
201
  right-clicks on the web page.
200
202
 
201
- Note:
203
+ Limitation:
202
204
  Web only.
203
205
  """
204
206
 
@@ -939,3 +941,48 @@ class Page(BasePage):
939
941
  return from_dict(WindowsDeviceInfo, info)
940
942
  else:
941
943
  return None
944
+
945
+ async def set_allowed_device_orientations(
946
+ self, orientations: list[DeviceOrientation]
947
+ ) -> None:
948
+ """
949
+ Constrains the allowed orientations for the app when running on a mobile device.
950
+
951
+ Args:
952
+ orientations: A list of allowed device orientations.
953
+ Set to an empty list to use the system default behavior.
954
+
955
+ Raises:
956
+ FletUnsupportedPlatformException: If the method is called
957
+ on a non-mobile platform.
958
+
959
+ Limitations:
960
+ - **Android**: On Android 16 (API 36) or later, this method won't be able to
961
+ change the orientation of **devices with a display width ≥ 600 dp**
962
+ cannot change orientation. For more details see Android 16 docs
963
+ [here](https://developer.android.com/about/versions/16/behavior-changes-16#ignore-orientation).
964
+ Also, Android limits the [orientations](https://developer.android.com/reference/android/R.attr#screenOrientation) to the following combinations:
965
+ - `[]` → `unspecified`
966
+ - `[PORTRAIT_UP]` → `portrait`
967
+ - `[LANDSCAPE_LEFT]` → `landscape`
968
+ - `[PORTRAIT_DOWN]` → `reversePortrait`
969
+ - `[PORTRAIT_UP, PORTRAIT_DOWN]` → `userPortrait`
970
+ - `[LANDSCAPE_RIGHT]` → `reverseLandscape`
971
+ - `[LANDSCAPE_LEFT, LANDSCAPE_RIGHT]` → `userLandscape`
972
+ - `[PORTRAIT_UP, LANDSCAPE_LEFT, LANDSCAPE_RIGHT]` → `user`
973
+ - `[PORTRAIT_UP, PORTRAIT_DOWN, LANDSCAPE_LEFT, LANDSCAPE_RIGHT]` → `fullUser`
974
+
975
+ - **iOS**: This setting will only be respected on iPad if multitasking is disabled.
976
+ You can decide to opt out of multitasking on iPad, then this will work
977
+ but your app will not support Slide Over and Split View multitasking
978
+ anymore. Should you decide to opt out of multitasking you can do this by
979
+ setting "Requires full screen" to true in the Xcode Deployment Info.
980
+ """ # noqa: E501
981
+ if not self.platform.is_mobile():
982
+ raise FletUnsupportedPlatformException(
983
+ "set_allowed_device_orientations is only supported on mobile platforms"
984
+ )
985
+ await self._invoke_method(
986
+ "set_allowed_device_orientations",
987
+ arguments={"orientations": orientations},
988
+ )
@@ -9,7 +9,8 @@ __all__ = ["SharedPreferences"]
9
9
  @control("SharedPreferences")
10
10
  class SharedPreferences(Service):
11
11
  async def set(self, key: str, value: Any) -> bool:
12
- assert value is not None
12
+ if value is None:
13
+ raise ValueError("value can't be None")
13
14
  return await self._invoke_method("set", {"key": key, "value": value})
14
15
 
15
16
  async def get(self, key: str):
flet/controls/types.py CHANGED
@@ -544,17 +544,43 @@ class Brightness(Enum):
544
544
 
545
545
  class Orientation(Enum):
546
546
  """
547
- Whether in portrait or landscape.
547
+ Represents the layout orientation.
548
548
  """
549
549
 
550
550
  PORTRAIT = "portrait"
551
551
  """
552
- Taller than wide.
552
+ Orientation with greater height than width.
553
553
  """
554
554
 
555
555
  LANDSCAPE = "landscape"
556
556
  """
557
- Wider than tall.
557
+ Orientation with greater width than height.
558
+ """
559
+
560
+
561
+ class DeviceOrientation(Enum):
562
+ """
563
+ Supported physical orientations for mobile devices.
564
+ """
565
+
566
+ PORTRAIT_UP = "portraitUp"
567
+ """
568
+ Device held upright in portrait mode.
569
+ """
570
+
571
+ PORTRAIT_DOWN = "portraitDown"
572
+ """
573
+ Device held upside-down in portrait mode.
574
+ """
575
+
576
+ LANDSCAPE_LEFT = "landscapeLeft"
577
+ """
578
+ Device rotated 90° counter-clockwise (home button or primary edge on the right).
579
+ """
580
+
581
+ LANDSCAPE_RIGHT = "landscapeRight"
582
+ """
583
+ Device rotated 90° clockwise (home button or primary edge on the left).
558
584
  """
559
585
 
560
586
 
flet/pubsub/pubsub_hub.py CHANGED
@@ -147,7 +147,8 @@ class PubSubHub:
147
147
  def __send(
148
148
  self, handler: Union[Callable, Callable[..., Awaitable[Any]]], args: Iterable
149
149
  ):
150
- assert self.__loop, "PubSub event loop is not set"
150
+ if not self.__loop:
151
+ raise RuntimeError("PubSub event loop is not set")
151
152
 
152
153
  if asyncio.iscoroutinefunction(handler):
153
154
  asyncio.run_coroutine_threadsafe(handler(*args), self.__loop)
@@ -136,7 +136,8 @@ class FletTestApp:
136
136
  """
137
137
  Returns an instance of Flet's app [`Page`][flet.].
138
138
  """
139
- assert self.__page
139
+ if self.__page is None:
140
+ raise RuntimeError("page is not initialized")
140
141
  return self.__page
141
142
 
142
143
  @property
@@ -145,7 +146,8 @@ class FletTestApp:
145
146
  Returns an instance of [`Tester`][flet.testing.] class
146
147
  that programmatically interacts with page controls and the test environment.
147
148
  """
148
- assert self.__tester
149
+ if self.__tester is None:
150
+ raise RuntimeError("tester is not initialized")
149
151
  return self.__tester
150
152
 
151
153
  async def start(self):
@@ -330,10 +332,13 @@ class FletTestApp:
330
332
  name: Screenshot name - will be used as a base for a screenshot filename.
331
333
  screenshot: Screenshot contents in PNG format.
332
334
  """
333
- assert self.test_platform, (
334
- "FLET_TEST_PLATFORM must be set to test with screenshots"
335
- )
336
- assert self.__test_path, "test_path must be set to test with screenshots"
335
+ if not self.test_platform:
336
+ raise RuntimeError(
337
+ "FLET_TEST_PLATFORM environment variable must be set "
338
+ "to test with screenshots"
339
+ )
340
+ if not self.__test_path:
341
+ raise RuntimeError("test_path must be set to test with screenshots")
337
342
 
338
343
  golden_image_path = (
339
344
  Path(self.__test_path).parent