pythonnative 0.11.0__tar.gz → 0.12.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.
Files changed (117) hide show
  1. {pythonnative-0.11.0/src/pythonnative.egg-info → pythonnative-0.12.0}/PKG-INFO +1 -1
  2. {pythonnative-0.11.0 → pythonnative-0.12.0}/pyproject.toml +2 -1
  3. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/__init__.py +35 -1
  4. pythonnative-0.12.0/src/pythonnative/alerts.py +112 -0
  5. pythonnative-0.12.0/src/pythonnative/animated.py +667 -0
  6. pythonnative-0.12.0/src/pythonnative/components.py +1215 -0
  7. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/hooks.py +145 -7
  8. pythonnative-0.12.0/src/pythonnative/native_modules/camera.py +331 -0
  9. pythonnative-0.12.0/src/pythonnative/native_modules/location.py +245 -0
  10. pythonnative-0.12.0/src/pythonnative/native_views/android.py +1602 -0
  11. pythonnative-0.12.0/src/pythonnative/native_views/ios.py +2497 -0
  12. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/page.py +93 -6
  13. pythonnative-0.12.0/src/pythonnative/platform.py +152 -0
  14. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/platform_metrics.py +112 -2
  15. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/reconciler.py +64 -3
  16. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/build.gradle +1 -0
  17. pythonnative-0.12.0/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PNVirtualListView.java +129 -0
  18. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/ViewController.swift +20 -0
  19. {pythonnative-0.11.0 → pythonnative-0.12.0/src/pythonnative.egg-info}/PKG-INFO +1 -1
  20. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative.egg-info/SOURCES.txt +10 -0
  21. pythonnative-0.12.0/tests/test_alert.py +68 -0
  22. pythonnative-0.12.0/tests/test_animated.py +168 -0
  23. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_cli.py +12 -0
  24. pythonnative-0.12.0/tests/test_metric_hooks.py +167 -0
  25. pythonnative-0.12.0/tests/test_new_components.py +185 -0
  26. pythonnative-0.12.0/tests/test_platform.py +63 -0
  27. pythonnative-0.12.0/tests/test_platform_metrics.py +119 -0
  28. pythonnative-0.12.0/tests/test_ref.py +130 -0
  29. pythonnative-0.11.0/src/pythonnative/components.py +0 -656
  30. pythonnative-0.11.0/src/pythonnative/native_modules/camera.py +0 -121
  31. pythonnative-0.11.0/src/pythonnative/native_modules/location.py +0 -84
  32. pythonnative-0.11.0/src/pythonnative/native_views/android.py +0 -794
  33. pythonnative-0.11.0/src/pythonnative/native_views/ios.py +0 -849
  34. pythonnative-0.11.0/tests/test_platform_metrics.py +0 -148
  35. {pythonnative-0.11.0 → pythonnative-0.12.0}/LICENSE +0 -0
  36. {pythonnative-0.11.0 → pythonnative-0.12.0}/README.md +0 -0
  37. {pythonnative-0.11.0 → pythonnative-0.12.0}/setup.cfg +0 -0
  38. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/_ios_log.py +0 -0
  39. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/cli/__init__.py +0 -0
  40. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/cli/pn.py +0 -0
  41. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/element.py +0 -0
  42. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/hot_reload.py +0 -0
  43. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/layout.py +0 -0
  44. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/native_modules/__init__.py +0 -0
  45. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/native_modules/file_system.py +0 -0
  46. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/native_modules/notifications.py +0 -0
  47. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/native_views/__init__.py +0 -0
  48. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/native_views/base.py +0 -0
  49. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/navigation.py +0 -0
  50. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/style.py +0 -0
  51. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/proguard-rules.pro +0 -0
  52. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +0 -0
  53. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +0 -0
  54. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +0 -0
  55. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -0
  56. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PageFragment.kt +0 -0
  57. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +0 -0
  58. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +0 -0
  59. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +0 -0
  60. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -0
  61. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -0
  62. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  63. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  64. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  65. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  66. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  67. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  68. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  69. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  70. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  71. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  72. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +0 -0
  73. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/values/colors.xml +0 -0
  74. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/values/strings.xml +0 -0
  75. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/values/themes.xml +0 -0
  76. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +0 -0
  77. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +0 -0
  78. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +0 -0
  79. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +0 -0
  80. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/build.gradle +0 -0
  81. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
  82. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +0 -0
  83. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/gradle.properties +0 -0
  84. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/gradlew +0 -0
  85. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/gradlew.bat +0 -0
  86. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/android_template/settings.gradle +0 -0
  87. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/AppDelegate.swift +0 -0
  88. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
  89. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  90. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +0 -0
  91. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +0 -0
  92. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/Base.lproj/Main.storyboard +0 -0
  93. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/Info.plist +0 -0
  94. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +0 -0
  95. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +0 -0
  96. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -0
  97. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +0 -0
  98. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +0 -0
  99. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +0 -0
  100. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative/utils.py +0 -0
  101. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative.egg-info/dependency_links.txt +0 -0
  102. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative.egg-info/entry_points.txt +0 -0
  103. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative.egg-info/requires.txt +0 -0
  104. {pythonnative-0.11.0 → pythonnative-0.12.0}/src/pythonnative.egg-info/top_level.txt +0 -0
  105. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_components.py +0 -0
  106. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_element.py +0 -0
  107. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_hooks.py +0 -0
  108. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_hot_reload.py +0 -0
  109. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_ios_log.py +0 -0
  110. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_layout.py +0 -0
  111. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_native_views.py +0 -0
  112. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_navigation.py +0 -0
  113. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_page.py +0 -0
  114. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_reconciler.py +0 -0
  115. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_smoke.py +0 -0
  116. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_style.py +0 -0
  117. {pythonnative-0.11.0 → pythonnative-0.12.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonnative
3
- Version: 0.11.0
3
+ Version: 0.12.0
4
4
  Summary: Cross-platform native UI toolkit for Android and iOS
5
5
  Author: Owen Carey
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pythonnative"
7
- version = "0.11.0"
7
+ version = "0.12.0"
8
8
  description = "Cross-platform native UI toolkit for Android and iOS"
9
9
  authors = [
10
10
  { name = "Owen Carey" }
@@ -60,6 +60,7 @@ Repository = "https://github.com/pythonnative/pythonnative"
60
60
  Issues = "https://github.com/pythonnative/pythonnative/issues"
61
61
  Documentation = "https://docs.pythonnative.com/"
62
62
 
63
+
63
64
  [tool.setuptools.packages.find]
64
65
  where = ["src"]
65
66
 
@@ -23,6 +23,8 @@ Key building blocks:
23
23
  factories.
24
24
  - **Styling** uses a single ``style`` dict per element (or a list of
25
25
  dicts), composable via [`StyleSheet`][pythonnative.StyleSheet].
26
+ - **Animations** use the ``Animated`` namespace, modeled on React
27
+ Native's animation API.
26
28
 
27
29
  Example:
28
30
  ```python
@@ -39,8 +41,10 @@ Example:
39
41
  ```
40
42
  """
41
43
 
42
- __version__ = "0.11.0"
44
+ __version__ = "0.12.0"
43
45
 
46
+ from .alerts import Alert
47
+ from .animated import Animated, AnimatedValue
44
48
  from .components import (
45
49
  ActivityIndicator,
46
50
  Button,
@@ -48,14 +52,19 @@ from .components import (
48
52
  ErrorBoundary,
49
53
  FlatList,
50
54
  Image,
55
+ KeyboardAvoidingView,
51
56
  Modal,
57
+ Picker,
52
58
  Pressable,
53
59
  ProgressBar,
60
+ RefreshControl,
54
61
  Row,
55
62
  SafeAreaView,
56
63
  ScrollView,
64
+ SectionList,
57
65
  Slider,
58
66
  Spacer,
67
+ StatusBar,
59
68
  Switch,
60
69
  Text,
61
70
  TextInput,
@@ -71,12 +80,16 @@ from .hooks import (
71
80
  use_callback,
72
81
  use_context,
73
82
  use_effect,
83
+ use_keyboard_height,
74
84
  use_memo,
75
85
  use_navigation,
76
86
  use_reducer,
77
87
  use_ref,
88
+ use_safe_area_insets,
78
89
  use_state,
90
+ use_window_dimensions,
79
91
  )
92
+ from .native_modules import Camera, FileSystem, Location, Notifications
80
93
  from .navigation import (
81
94
  NavigationContainer,
82
95
  create_drawer_navigator,
@@ -86,6 +99,7 @@ from .navigation import (
86
99
  use_route,
87
100
  )
88
101
  from .page import create_page
102
+ from .platform import Platform
89
103
  from .style import StyleSheet, ThemeContext
90
104
 
91
105
  __all__ = [
@@ -96,14 +110,19 @@ __all__ = [
96
110
  "ErrorBoundary",
97
111
  "FlatList",
98
112
  "Image",
113
+ "KeyboardAvoidingView",
99
114
  "Modal",
115
+ "Picker",
100
116
  "Pressable",
101
117
  "ProgressBar",
118
+ "RefreshControl",
102
119
  "Row",
103
120
  "SafeAreaView",
104
121
  "ScrollView",
122
+ "SectionList",
105
123
  "Slider",
106
124
  "Spacer",
125
+ "StatusBar",
107
126
  "Switch",
108
127
  "Text",
109
128
  "TextInput",
@@ -120,12 +139,15 @@ __all__ = [
120
139
  "use_context",
121
140
  "use_effect",
122
141
  "use_focus_effect",
142
+ "use_keyboard_height",
123
143
  "use_memo",
124
144
  "use_navigation",
125
145
  "use_reducer",
126
146
  "use_ref",
127
147
  "use_route",
148
+ "use_safe_area_insets",
128
149
  "use_state",
150
+ "use_window_dimensions",
129
151
  "Provider",
130
152
  # Navigation
131
153
  "NavigationContainer",
@@ -135,4 +157,16 @@ __all__ = [
135
157
  # Styling
136
158
  "StyleSheet",
137
159
  "ThemeContext",
160
+ # Animation
161
+ "Animated",
162
+ "AnimatedValue",
163
+ # Imperative
164
+ "Alert",
165
+ # Native modules
166
+ "Camera",
167
+ "FileSystem",
168
+ "Location",
169
+ "Notifications",
170
+ # Platform
171
+ "Platform",
138
172
  ]
@@ -0,0 +1,112 @@
1
+ """Imperative system alerts.
2
+
3
+ Modeled on React Native's `Alert.alert()`. Alerts are not part of
4
+ the element tree — they're imperative, fire-and-forget calls that
5
+ trigger a native dialog.
6
+
7
+ Example:
8
+ ```python
9
+ import pythonnative as pn
10
+
11
+ def confirm_delete():
12
+ pn.Alert.show(
13
+ title="Delete item?",
14
+ message="This action cannot be undone.",
15
+ buttons=[
16
+ {"label": "Cancel", "style": "cancel"},
17
+ {
18
+ "label": "Delete",
19
+ "style": "destructive",
20
+ "on_press": delete_item,
21
+ },
22
+ ],
23
+ )
24
+ ```
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ from typing import Any, Callable, Dict, List, Optional
30
+
31
+ from .platform import Platform
32
+
33
+
34
+ class Alert:
35
+ """Imperative alert / action-sheet helper.
36
+
37
+ All methods are static. Use `Alert.show()` for an alert dialog
38
+ and pass ``style="action_sheet"`` for an iOS-style action sheet.
39
+ """
40
+
41
+ @staticmethod
42
+ def show(
43
+ *,
44
+ title: str,
45
+ message: Optional[str] = None,
46
+ buttons: Optional[List[Dict[str, Any]]] = None,
47
+ style: str = "alert",
48
+ ) -> None:
49
+ """Present a native alert dialog or action sheet.
50
+
51
+ Args:
52
+ title: Dialog title (required).
53
+ message: Optional body text.
54
+ buttons: Each button is ``{"label": str, "style":
55
+ "default"|"cancel"|"destructive", "on_press": callable}``.
56
+ Defaults to a single "OK" button.
57
+ style: ``"alert"`` (default) or ``"action_sheet"``.
58
+
59
+ On iOS this uses ``UIAlertController``; on Android it uses
60
+ ``AlertDialog.Builder``. On the test backend the call is a
61
+ no-op so unit tests don't need to mock UIKit/AndroidX.
62
+ """
63
+ if Platform.is_ios:
64
+ try:
65
+ from .native_views.ios import _present_alert as _ios_present_alert
66
+
67
+ _ios_present_alert(title=title, message=message, buttons=buttons or [], style=style)
68
+ except Exception:
69
+ pass
70
+ return
71
+ if Platform.is_android:
72
+ try:
73
+ from .native_views.android import _present_alert as _android_present_alert
74
+
75
+ _android_present_alert(title=title, message=message, buttons=buttons or [], style=style)
76
+ except Exception:
77
+ pass
78
+ return
79
+ # Test environment: record the call so unit tests can assert on it.
80
+ Alert._test_log.append(
81
+ {
82
+ "title": title,
83
+ "message": message,
84
+ "buttons": list(buttons or []),
85
+ "style": style,
86
+ }
87
+ )
88
+
89
+ @staticmethod
90
+ def confirm(
91
+ *,
92
+ title: str,
93
+ message: Optional[str] = None,
94
+ confirm_label: str = "OK",
95
+ cancel_label: str = "Cancel",
96
+ on_confirm: Optional[Callable[[], None]] = None,
97
+ on_cancel: Optional[Callable[[], None]] = None,
98
+ ) -> None:
99
+ """Convenience wrapper for two-button confirm/cancel dialogs."""
100
+ Alert.show(
101
+ title=title,
102
+ message=message,
103
+ buttons=[
104
+ {"label": cancel_label, "style": "cancel", "on_press": on_cancel},
105
+ {"label": confirm_label, "style": "default", "on_press": on_confirm},
106
+ ],
107
+ )
108
+
109
+ #: Records every Alert.show call when running off-device. Tests
110
+ #: should reset this list between cases via
111
+ #: ``Alert._test_log.clear()``.
112
+ _test_log: List[Dict[str, Any]] = []