pythonnative 0.40.0__cp313-cp313-win_amd64.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.
Files changed (418) hide show
  1. pythonnative/__init__.py +411 -0
  2. pythonnative/_ios_log.py +92 -0
  3. pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
  4. pythonnative/alerts.py +236 -0
  5. pythonnative/animated.py +1687 -0
  6. pythonnative/animation_graph.py +78 -0
  7. pythonnative/appearance.py +124 -0
  8. pythonnative/bootstrap.py +100 -0
  9. pythonnative/bridge/__init__.py +302 -0
  10. pythonnative/bridge/android.py +78 -0
  11. pythonnative/bridge/codec.py +170 -0
  12. pythonnative/bridge/commits.py +114 -0
  13. pythonnative/bridge/fake.py +243 -0
  14. pythonnative/bridge/ios.py +138 -0
  15. pythonnative/bridge/web.py +489 -0
  16. pythonnative/cli/__init__.py +7 -0
  17. pythonnative/cli/pn.py +1214 -0
  18. pythonnative/component.py +271 -0
  19. pythonnative/components/__init__.py +111 -0
  20. pythonnative/components/_base.py +166 -0
  21. pythonnative/components/controls.py +521 -0
  22. pythonnative/components/layout.py +518 -0
  23. pythonnative/components/lists.py +785 -0
  24. pythonnative/components/media.py +204 -0
  25. pythonnative/components/overlays.py +107 -0
  26. pythonnative/components/pressable.py +252 -0
  27. pythonnative/components/structural.py +167 -0
  28. pythonnative/components/text.py +291 -0
  29. pythonnative/devclient.py +824 -0
  30. pythonnative/devserver/__init__.py +34 -0
  31. pythonnative/devserver/server.py +718 -0
  32. pythonnative/devserver/static/animation_graph.js +82 -0
  33. pythonnative/devserver/static/bridge.js +147 -0
  34. pythonnative/devserver/static/colors.js +70 -0
  35. pythonnative/devserver/static/host.js +552 -0
  36. pythonnative/devserver/static/index.html +60 -0
  37. pythonnative/devserver/static/layout.js +85 -0
  38. pythonnative/devserver/static/preview.css +415 -0
  39. pythonnative/devserver/static/renderer.js +1994 -0
  40. pythonnative/devserver/static/shell.js +345 -0
  41. pythonnative/devserver/static/yoga/LICENSE +21 -0
  42. pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
  43. pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
  44. pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
  45. pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
  46. pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
  47. pythonnative/devserver/static/yoga/src/index.js +16 -0
  48. pythonnative/devserver/static/yoga/src/index.js.map +1 -0
  49. pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
  50. pythonnative/devserver/static/yoga/src/load.js +17 -0
  51. pythonnative/devserver/static/yoga/src/load.js.map +1 -0
  52. pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
  53. pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
  54. pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
  55. pythonnative/devserver/watcher.py +267 -0
  56. pythonnative/devserver/ws.py +421 -0
  57. pythonnative/diagnostics.py +241 -0
  58. pythonnative/element.py +159 -0
  59. pythonnative/equality.py +19 -0
  60. pythonnative/events.py +231 -0
  61. pythonnative/gestures.py +1333 -0
  62. pythonnative/hooks.py +1621 -0
  63. pythonnative/hosts/__init__.py +63 -0
  64. pythonnative/hosts/base.py +596 -0
  65. pythonnative/hosts/native.py +302 -0
  66. pythonnative/hot_reload.py +585 -0
  67. pythonnative/layout.py +328 -0
  68. pythonnative/mutations.py +142 -0
  69. pythonnative/native/android/build.gradle +52 -0
  70. pythonnative/native/android/gradle.properties +3 -0
  71. pythonnative/native/android/settings.gradle +12 -0
  72. pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
  73. pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
  74. pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
  75. pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
  76. pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
  77. pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
  78. pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
  79. pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
  80. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
  81. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
  82. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
  83. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
  84. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
  85. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
  86. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
  87. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
  88. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
  89. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
  90. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
  91. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
  92. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
  93. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
  94. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
  95. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
  96. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
  97. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
  98. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
  99. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
  100. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
  101. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
  102. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
  103. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
  104. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
  105. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
  106. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
  107. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
  108. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
  109. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
  110. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
  111. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
  112. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
  113. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
  114. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
  115. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
  116. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
  117. pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
  118. pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
  119. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
  120. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
  121. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
  122. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
  123. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
  124. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
  125. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
  126. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
  127. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
  128. pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
  129. pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
  130. pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
  131. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
  132. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
  133. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
  134. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
  135. pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
  136. pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
  137. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
  138. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
  139. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
  140. pythonnative/native/ios/Package.swift +23 -0
  141. pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
  142. pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
  143. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
  144. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
  145. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
  146. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
  147. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
  148. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
  149. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
  150. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
  151. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
  152. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
  153. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
  154. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
  155. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
  156. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
  157. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
  158. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
  159. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
  160. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
  161. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
  162. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
  163. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
  164. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
  165. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
  166. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
  167. pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
  168. pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
  169. pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
  170. pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
  171. pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
  172. pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
  173. pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
  174. pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
  175. pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
  176. pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
  177. pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
  178. pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
  179. pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
  180. pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
  181. pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
  182. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
  183. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
  184. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
  185. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
  186. pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
  187. pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
  188. pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
  189. pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
  190. pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
  191. pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
  192. pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
  193. pythonnative/native/yoga/LICENSE +21 -0
  194. pythonnative/native/yoga/Package.swift +9 -0
  195. pythonnative/native/yoga/VENDORED.md +2 -0
  196. pythonnative/native/yoga/include/PNStyle.h +10 -0
  197. pythonnative/native/yoga/include/module.modulemap +5 -0
  198. pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
  199. pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
  200. pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
  201. pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
  202. pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
  203. pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
  204. pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
  205. pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
  206. pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
  207. pythonnative/native/yoga/python.cpp +16 -0
  208. pythonnative/native/yoga/style.cpp +272 -0
  209. pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
  210. pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
  211. pythonnative/native/yoga/yoga/YGConfig.h +158 -0
  212. pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
  213. pythonnative/native/yoga/yoga/YGEnums.h +142 -0
  214. pythonnative/native/yoga/yoga/YGMacros.h +99 -0
  215. pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
  216. pythonnative/native/yoga/yoga/YGNode.h +304 -0
  217. pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
  218. pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
  219. pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
  220. pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
  221. pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
  222. pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
  223. pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
  224. pythonnative/native/yoga/yoga/YGValue.h +84 -0
  225. pythonnative/native/yoga/yoga/Yoga.h +21 -0
  226. pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
  227. pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
  228. pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
  229. pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
  230. pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
  231. pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
  232. pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
  233. pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
  234. pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
  235. pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
  236. pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
  237. pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
  238. pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
  239. pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
  240. pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
  241. pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
  242. pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
  243. pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
  244. pythonnative/native/yoga/yoga/config/Config.h +92 -0
  245. pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
  246. pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
  247. pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
  248. pythonnative/native/yoga/yoga/debug/Log.h +34 -0
  249. pythonnative/native/yoga/yoga/enums/Align.h +47 -0
  250. pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
  251. pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
  252. pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
  253. pythonnative/native/yoga/yoga/enums/Display.h +41 -0
  254. pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
  255. pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
  256. pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
  257. pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
  258. pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
  259. pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
  260. pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
  261. pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
  262. pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
  263. pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
  264. pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
  265. pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
  266. pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
  267. pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
  268. pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
  269. pythonnative/native/yoga/yoga/event/event.cpp +87 -0
  270. pythonnative/native/yoga/yoga/event/event.h +130 -0
  271. pythonnative/native/yoga/yoga/module.modulemap +21 -0
  272. pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
  273. pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
  274. pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
  275. pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
  276. pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
  277. pythonnative/native/yoga/yoga/node/Node.h +337 -0
  278. pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
  279. pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
  280. pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
  281. pythonnative/native/yoga/yoga/style/Style.h +757 -0
  282. pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
  283. pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
  284. pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
  285. pythonnative/native_modules/__init__.py +124 -0
  286. pythonnative/native_modules/app_state.py +99 -0
  287. pythonnative/native_modules/battery.py +75 -0
  288. pythonnative/native_modules/biometrics.py +42 -0
  289. pythonnative/native_modules/camera.py +65 -0
  290. pythonnative/native_modules/clipboard.py +46 -0
  291. pythonnative/native_modules/fallback.py +324 -0
  292. pythonnative/native_modules/file_system.py +145 -0
  293. pythonnative/native_modules/haptics.py +75 -0
  294. pythonnative/native_modules/linking.py +123 -0
  295. pythonnative/native_modules/location.py +75 -0
  296. pythonnative/native_modules/net_info.py +112 -0
  297. pythonnative/native_modules/notifications.py +129 -0
  298. pythonnative/native_modules/permissions.py +108 -0
  299. pythonnative/native_modules/registry.py +526 -0
  300. pythonnative/native_modules/secure_store.py +52 -0
  301. pythonnative/native_modules/share.py +51 -0
  302. pythonnative/native_views/__init__.py +375 -0
  303. pythonnative/native_views/base.py +316 -0
  304. pythonnative/native_views/bridge_backend.py +277 -0
  305. pythonnative/navigation/__init__.py +103 -0
  306. pythonnative/navigation/container.py +154 -0
  307. pythonnative/navigation/handle.py +540 -0
  308. pythonnative/navigation/hooks.py +133 -0
  309. pythonnative/navigation/host.py +58 -0
  310. pythonnative/navigation/linking.py +200 -0
  311. pythonnative/navigation/navigators.py +659 -0
  312. pythonnative/navigation/screen.py +149 -0
  313. pythonnative/navigation/state.py +269 -0
  314. pythonnative/net.py +248 -0
  315. pythonnative/platform.py +166 -0
  316. pythonnative/platform_metrics.py +252 -0
  317. pythonnative/preview.py +287 -0
  318. pythonnative/profiling.py +101 -0
  319. pythonnative/project/__init__.py +68 -0
  320. pythonnative/project/android.py +557 -0
  321. pythonnative/project/builder.py +817 -0
  322. pythonnative/project/config.py +773 -0
  323. pythonnative/project/deps.py +719 -0
  324. pythonnative/project/devices.py +304 -0
  325. pythonnative/project/doctor.py +283 -0
  326. pythonnative/project/fingerprint.py +171 -0
  327. pythonnative/project/icons.py +247 -0
  328. pythonnative/project/ios.py +325 -0
  329. pythonnative/project/lockfile.py +100 -0
  330. pythonnative/project/permissions.py +361 -0
  331. pythonnative/project/plugins.py +519 -0
  332. pythonnative/project/runtime_assets.py +183 -0
  333. pythonnative/py.typed +0 -0
  334. pythonnative/query.py +153 -0
  335. pythonnative/reconciler/__init__.py +29 -0
  336. pythonnative/reconciler/boundaries.py +375 -0
  337. pythonnative/reconciler/children.py +88 -0
  338. pythonnative/reconciler/core.py +1165 -0
  339. pythonnative/reconciler/layout_pass.py +393 -0
  340. pythonnative/reconciler/vnode.py +266 -0
  341. pythonnative/refresh.py +55 -0
  342. pythonnative/runtime.py +306 -0
  343. pythonnative/scheduler.py +159 -0
  344. pythonnative/sdk/__init__.py +153 -0
  345. pythonnative/sdk/_components.py +427 -0
  346. pythonnative/sdk/builtins.py +91 -0
  347. pythonnative/sdk/codegen.py +149 -0
  348. pythonnative/sdk/module_codegen.py +184 -0
  349. pythonnative/sdk/schema.py +224 -0
  350. pythonnative/sdk/templates/contracts.kt +46 -0
  351. pythonnative/sdk/templates/contracts.swift +46 -0
  352. pythonnative/storage.py +184 -0
  353. pythonnative/style.py +841 -0
  354. pythonnative/suspense.py +183 -0
  355. pythonnative/templates/android_template/app/build.gradle +75 -0
  356. pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
  357. pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
  358. pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
  359. pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
  360. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
  361. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
  362. pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  363. pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
  364. pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
  365. pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
  366. pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
  367. pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  368. pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  369. pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  370. pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  371. pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  372. pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  373. pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  374. pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  375. pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  376. pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  377. pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
  378. pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
  379. pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
  380. pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
  381. pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
  382. pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
  383. pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
  384. pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
  385. pythonnative/templates/android_template/build.gradle +10 -0
  386. pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
  387. pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
  388. pythonnative/templates/android_template/gradle.properties +23 -0
  389. pythonnative/templates/android_template/gradlew +185 -0
  390. pythonnative/templates/android_template/gradlew.bat +89 -0
  391. pythonnative/templates/android_template/settings.gradle +17 -0
  392. pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
  393. pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  394. pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
  395. pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
  396. pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
  397. pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
  398. pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
  399. pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
  400. pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
  401. pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
  402. pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
  403. pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  404. pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
  405. pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
  406. pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
  407. pythonnative/testing/__init__.py +53 -0
  408. pythonnative/testing/backend.py +276 -0
  409. pythonnative/testing/harness.py +369 -0
  410. pythonnative/utils.py +145 -0
  411. pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
  412. pythonnative-0.40.0.dist-info/METADATA +150 -0
  413. pythonnative-0.40.0.dist-info/RECORD +418 -0
  414. pythonnative-0.40.0.dist-info/WHEEL +5 -0
  415. pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
  416. pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
  417. pythonnative-0.40.0.dist-info/top_level.txt +1 -0
  418. pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
@@ -0,0 +1,166 @@
1
+ """Platform-aware constants and selectors.
2
+
3
+ A small, RN-style helper for branching app code on the host platform.
4
+ The public surface is the [`Platform`][pythonnative.Platform] class
5
+ exposing ``OS``, ``Version``, ``is_ios``, ``is_android``, ``is_web``,
6
+ and ``select`` so user code can write ``Platform.select({"ios": ..., ...})``
7
+ without importing the ``IS_*`` flags directly.
8
+
9
+ Example:
10
+ ```python
11
+ import pythonnative as pn
12
+
13
+ title_size = pn.Platform.select({"ios": 17, "android": 16, "default": 16})
14
+
15
+ @pn.component
16
+ def App():
17
+ return pn.Text(
18
+ f"Running on {pn.Platform.OS} {pn.Platform.Version}",
19
+ style={"font_size": title_size},
20
+ )
21
+ ```
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import os
27
+ import sys
28
+ from typing import Any, Dict, Optional
29
+
30
+ from .utils import IS_ANDROID, IS_IOS, IS_WEB
31
+
32
+
33
+ def _detect_os() -> str:
34
+ if IS_ANDROID:
35
+ return "android"
36
+ if IS_IOS:
37
+ return "ios"
38
+ if IS_WEB:
39
+ return "web"
40
+ return "test"
41
+
42
+
43
+ def _detect_version() -> str:
44
+ """Return a human-readable platform version string.
45
+
46
+ On device this asks the native ``Device`` module (``UIDevice
47
+ .systemVersion`` / ``Build.VERSION.RELEASE``); the browser preview
48
+ answers with the browser's user agent family. Off-device (the test
49
+ environment), returns the host Python's version so user code can
50
+ still introspect *something*.
51
+ """
52
+ if IS_IOS or IS_ANDROID or IS_WEB:
53
+ try:
54
+ from .native_modules.registry import native_module
55
+
56
+ info = native_module("Device").call("info")
57
+ if isinstance(info, dict) and info.get("os_version"):
58
+ return str(info["os_version"])
59
+ except Exception:
60
+ pass
61
+ sim_version = os.environ.get("SIMULATOR_RUNTIME_VERSION")
62
+ if sim_version:
63
+ return sim_version
64
+ return f"python-{sys.version_info.major}.{sys.version_info.minor}"
65
+
66
+
67
+ class _LazyVersion:
68
+ """Resolve ``Platform.Version`` on first access (it needs the bridge on device)."""
69
+
70
+ _value: Optional[str] = None
71
+
72
+ def __get__(self, obj: object, owner: Optional[type] = None) -> str:
73
+ if _LazyVersion._value is None:
74
+ _LazyVersion._value = _detect_version()
75
+ return _LazyVersion._value
76
+
77
+
78
+ class Platform:
79
+ """Platform-aware constants and the ``select`` dispatcher.
80
+
81
+ All attributes are read at import time. ``OS`` is one of
82
+ ``"ios"``, ``"android"``, ``"web"`` (the browser preview), or
83
+ ``"test"`` (when running off-device, e.g., in unit tests).
84
+ """
85
+
86
+ OS: str = _detect_os()
87
+ """``"ios"``, ``"android"``, ``"web"``, or ``"test"``."""
88
+
89
+ Version: str = _LazyVersion() # type: ignore[assignment]
90
+ """Best-effort OS version string (``"17.4"``, ``"14"``, ``"python-3.11"``)."""
91
+
92
+ is_ios: bool = IS_IOS
93
+ """``True`` when running inside an iOS app bundle."""
94
+
95
+ is_android: bool = IS_ANDROID
96
+ """``True`` when running inside an Android process."""
97
+
98
+ is_web: bool = IS_WEB
99
+ """``True`` when running the browser preview (``pn preview``)."""
100
+
101
+ is_test: bool = OS == "test"
102
+ """``True`` when running off-device (no native runtime)."""
103
+
104
+ @staticmethod
105
+ def select(spec: Dict[str, Any], default: Any = None) -> Any:
106
+ """Pick the value matching the current platform.
107
+
108
+ Looks up ``spec[Platform.OS]``, then falls back to
109
+ ``spec["native"]`` (matches iOS and Android, *not* the browser
110
+ preview, which is a development surface), then to
111
+ ``spec["default"]``, then to the explicit ``default`` argument.
112
+
113
+ Args:
114
+ spec: Mapping from platform name to value. Recognized keys:
115
+ ``"ios"``, ``"android"``, ``"web"``, ``"test"``,
116
+ ``"native"``, ``"default"``.
117
+ default: Value returned when ``spec`` has no matching key
118
+ and no ``"default"`` entry.
119
+
120
+ Returns:
121
+ The matching value, or ``default`` when nothing matches.
122
+
123
+ Example:
124
+ ```python
125
+ font = pn.Platform.select(
126
+ {"ios": "Helvetica", "android": "Roboto", "default": None}
127
+ )
128
+ ```
129
+ """
130
+ if Platform.OS in spec:
131
+ return spec[Platform.OS]
132
+ if (Platform.is_ios or Platform.is_android) and "native" in spec:
133
+ return spec["native"]
134
+ if "default" in spec:
135
+ return spec["default"]
136
+ return default
137
+
138
+
139
+ def get_platform() -> str:
140
+ """Return the active platform name.
141
+
142
+ Equivalent to reading ``Platform.OS``, exposed as a function for
143
+ introspection from non-component code.
144
+ """
145
+ return Platform.OS
146
+
147
+
148
+ def _set_platform_for_test(name: Optional[str]) -> None:
149
+ """Override ``Platform.OS`` for unit tests.
150
+
151
+ Production code should not call this. Tests can pass ``"ios"``,
152
+ ``"android"``, ``"web"``, ``"test"``, or ``None`` (to reset to
153
+ autodetect).
154
+ """
155
+ if name is None:
156
+ Platform.OS = _detect_os()
157
+ Platform.is_ios = IS_IOS
158
+ Platform.is_android = IS_ANDROID
159
+ Platform.is_web = IS_WEB
160
+ Platform.is_test = Platform.OS == "test"
161
+ return
162
+ Platform.OS = name
163
+ Platform.is_ios = name == "ios"
164
+ Platform.is_android = name == "android"
165
+ Platform.is_web = name == "web"
166
+ Platform.is_test = name == "test"
@@ -0,0 +1,252 @@
1
+ """Platform-level metrics shared between screen hosts and view handlers.
2
+
3
+ The screen host (`pythonnative.hosts`) is the only place that knows
4
+ about native window/safe-area state because it is the only piece of
5
+ code that holds a reference to the native ``UIViewController``
6
+ (iOS) or ``Activity`` (Android). Native view handlers, however, need
7
+ that state to size themselves correctly:
8
+
9
+ - A bottom tab bar must claim both its visible 49 pt / 56 dp content
10
+ height **and** the bottom safe-area inset so its background reaches
11
+ the edge of the screen and the home indicator / gesture bar does
12
+ not draw on top of the labels.
13
+ - A future safe-area-aware container can read the same values instead
14
+ of asking each native view for window metrics.
15
+
16
+ Rather than threading those values through every
17
+ [`measure_intrinsic`][pythonnative.native_views.base.ViewHandler.measure_intrinsic]
18
+ call signature, the screen host writes them here and handlers read
19
+ them on demand. Values are in **dp on Android** and **pt on iOS**,
20
+ i.e., the same "layout units" the layout engine uses on each
21
+ platform, so handlers can add them to other layout-unit values
22
+ without further conversion. On iOS the screen host consumes the top
23
+ safe-area inset by positioning the root view below it, then publishes
24
+ ``top=0`` here; Android publishes the raw system-bar insets because
25
+ the host view normally remains full-screen.
26
+
27
+ Example:
28
+ >>> from pythonnative.platform_metrics import (
29
+ ... get_safe_area_insets, set_safe_area_insets,
30
+ ... )
31
+ >>> set_safe_area_insets(top=44.0, left=0.0, bottom=34.0, right=0.0)
32
+ >>> get_safe_area_insets().bottom
33
+ 34.0
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import threading
39
+ from typing import Callable, List, NamedTuple
40
+
41
+
42
+ class SafeAreaInsets(NamedTuple):
43
+ """Safe-area insets in layout units (pt on iOS, dp on Android)."""
44
+
45
+ top: float
46
+ left: float
47
+ bottom: float
48
+ right: float
49
+
50
+
51
+ class WindowDimensions(NamedTuple):
52
+ """Viewport size in layout units (pt on iOS, dp on Android)."""
53
+
54
+ width: float
55
+ height: float
56
+
57
+
58
+ _safe_area_insets: SafeAreaInsets = SafeAreaInsets(0.0, 0.0, 0.0, 0.0)
59
+ _window_dimensions: WindowDimensions = WindowDimensions(0.0, 0.0)
60
+ _keyboard_height: float = 0.0
61
+
62
+ _subscribers: List[Callable[[], None]] = []
63
+ _subscribers_lock = threading.Lock()
64
+
65
+
66
+ def _notify_subscribers() -> None:
67
+ """Invoke every registered subscriber, swallowing exceptions.
68
+
69
+ Called from every metric setter so subscriber callbacks (the React
70
+ hooks ``use_window_dimensions``/``use_safe_area_insets``/
71
+ ``use_keyboard_height`` for example) can re-render in response to
72
+ any metric change. Subscribers are called serially in registration
73
+ order; any callback that raises is logged-and-skipped so a single
74
+ misbehaving subscriber can't take down the whole notification
75
+ cycle.
76
+ """
77
+ with _subscribers_lock:
78
+ callbacks = list(_subscribers)
79
+ for cb in callbacks:
80
+ try:
81
+ cb()
82
+ except Exception:
83
+ pass
84
+
85
+
86
+ def subscribe(callback: Callable[[], None]) -> Callable[[], None]:
87
+ """Register *callback* to fire whenever any metric changes.
88
+
89
+ Returns an unsubscribe function. Hooks pass a state setter so a
90
+ component re-renders whenever the platform reports a new value.
91
+ Threadsafe: multiple subscribers may register/unregister
92
+ concurrently.
93
+ """
94
+ with _subscribers_lock:
95
+ _subscribers.append(callback)
96
+
97
+ def _unsub() -> None:
98
+ with _subscribers_lock:
99
+ try:
100
+ _subscribers.remove(callback)
101
+ except ValueError:
102
+ pass
103
+
104
+ return _unsub
105
+
106
+
107
+ def set_safe_area_insets(top: float, left: float, bottom: float, right: float) -> None:
108
+ """Publish the current safe-area insets.
109
+
110
+ Called by the platform-specific screen host whenever it learns a
111
+ new value (e.g., on first layout, on rotation, on multitasking
112
+ split-view changes). Negative inputs are clamped to ``0.0`` so
113
+ handlers don't have to defend against bad data from native
114
+ callers.
115
+
116
+ Args:
117
+ top: Distance in layout units from the top of the host
118
+ container to the safe area (status bar / dynamic island /
119
+ navigation bar).
120
+ left: Inset from the left edge.
121
+ bottom: Inset from the bottom edge (home indicator / gesture
122
+ bar).
123
+ right: Inset from the right edge.
124
+ """
125
+ global _safe_area_insets
126
+ new_insets = SafeAreaInsets(
127
+ max(0.0, float(top)),
128
+ max(0.0, float(left)),
129
+ max(0.0, float(bottom)),
130
+ max(0.0, float(right)),
131
+ )
132
+ if new_insets == _safe_area_insets:
133
+ return
134
+ _safe_area_insets = new_insets
135
+ _notify_subscribers()
136
+
137
+
138
+ def get_safe_area_insets() -> SafeAreaInsets:
139
+ """Return the current safe-area insets.
140
+
141
+ The default value is ``(0, 0, 0, 0)``; handlers should still
142
+ function correctly in a unit-test environment where no
143
+ screen host has published insets.
144
+ """
145
+ return _safe_area_insets
146
+
147
+
148
+ def reset_safe_area_insets() -> None:
149
+ """Reset the insets back to ``(0, 0, 0, 0)``.
150
+
151
+ Intended for unit tests that need a clean slate between cases.
152
+ Production code should use
153
+ [`set_safe_area_insets`][pythonnative.platform_metrics.set_safe_area_insets]
154
+ instead.
155
+ """
156
+ global _safe_area_insets
157
+ _safe_area_insets = SafeAreaInsets(0.0, 0.0, 0.0, 0.0)
158
+
159
+
160
+ def set_window_dimensions(width: float, height: float) -> None:
161
+ """Publish the viewport size in layout units.
162
+
163
+ Called by the screen host on initial layout, rotation, and split-
164
+ view changes. Notifies subscribers (and therefore re-renders
165
+ components using ``use_window_dimensions``) only when the size
166
+ actually changes.
167
+ """
168
+ global _window_dimensions
169
+ new_dims = WindowDimensions(max(0.0, float(width)), max(0.0, float(height)))
170
+ if new_dims == _window_dimensions:
171
+ return
172
+ _window_dimensions = new_dims
173
+ _notify_subscribers()
174
+
175
+
176
+ def get_window_dimensions() -> WindowDimensions:
177
+ """Return the current viewport size, or ``(0, 0)`` before first layout."""
178
+ return _window_dimensions
179
+
180
+
181
+ def reset_window_dimensions() -> None:
182
+ """Reset window dimensions back to ``(0, 0)``. Intended for tests."""
183
+ global _window_dimensions
184
+ _window_dimensions = WindowDimensions(0.0, 0.0)
185
+
186
+
187
+ def set_keyboard_height(height: float) -> None:
188
+ """Publish the on-screen keyboard height in layout units.
189
+
190
+ Negative inputs are clamped to ``0.0``. Notifies subscribers only
191
+ when the value actually changes.
192
+ """
193
+ global _keyboard_height
194
+ new_h = max(0.0, float(height))
195
+ if new_h == _keyboard_height:
196
+ return
197
+ _keyboard_height = new_h
198
+ _notify_subscribers()
199
+
200
+
201
+ def get_keyboard_height() -> float:
202
+ """Return the current on-screen keyboard height, or ``0.0`` if hidden."""
203
+ return _keyboard_height
204
+
205
+
206
+ def reset_keyboard_height() -> None:
207
+ """Reset the keyboard height back to ``0.0``. Intended for tests."""
208
+ global _keyboard_height
209
+ _keyboard_height = 0.0
210
+
211
+
212
+ # ======================================================================
213
+ # Per-platform tab-bar defaults
214
+ # ======================================================================
215
+ #
216
+ # Only iOS exposes an explicit constant here. The iOS handler can't
217
+ # trust ``UITabBar.sizeThatFits_`` (it has historically returned 0 in
218
+ # some configurations) and the screen host deliberately extends the
219
+ # root view past the bottom safe area so the bar reaches the home
220
+ # indicator; both pieces conspire to require a single source of
221
+ # truth for the height formula.
222
+ #
223
+ # Android intentionally has no equivalent: ``BottomNavigationView``
224
+ # reports a reliable natural height via ``measure(…)`` once attached
225
+ # to the window, and the active-indicator pill is positioned against
226
+ # that natural height. Forcing our own height threw off the pill
227
+ # geometry, so the Android handler defers entirely to the system.
228
+
229
+ IOS_TAB_BAR_BASE_HEIGHT_PT: float = 49.0
230
+ """UIKit HIG tab-bar content height in points.
231
+
232
+ The total bar reaches ``IOS_TAB_BAR_BASE_HEIGHT_PT +
233
+ safe_area_insets.bottom`` so the pill background can extend over the
234
+ home indicator. Apple's HIG places the tab bar flush with the screen
235
+ edge and lets UIKit render its own internal padding for the home
236
+ indicator.
237
+ """
238
+
239
+
240
+ def ios_tab_bar_height() -> float:
241
+ """Return the iOS tab-bar intrinsic height in points.
242
+
243
+ Equal to ``IOS_TAB_BAR_BASE_HEIGHT_PT + safe_area_insets.bottom``
244
+ so the bar reaches the home indicator. The iOS screen host
245
+ deliberately extends the root view past the bottom safe area for
246
+ this very reason; the tab bar absorbs the inset and UIKit
247
+ renders the pill with internal padding for the home indicator.
248
+ The Swift ``TabBarManager`` applies the same formula natively;
249
+ this Python copy keeps the layout engine's expectations testable
250
+ off device.
251
+ """
252
+ return IOS_TAB_BAR_BASE_HEIGHT_PT + get_safe_area_insets().bottom
@@ -0,0 +1,287 @@
1
+ """Development server and browser preview.
2
+
3
+ The browser is a protocol-2 renderer with Yoga WebAssembly layout. Python runs
4
+ on the standard application asyncio loop; the transport's coordinator and
5
+ network threads forward messages to their owners. The dev server watches app
6
+ sources, synchronizes mobile clients, and applies compatible Fast Refresh.
7
+
8
+ PN_PLATFORM=web must be set before importing pythonnative; the CLI launches a
9
+ child process with that environment when needed.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import os
15
+ import sys
16
+ import threading
17
+ import time
18
+ import traceback
19
+ import webbrowser
20
+ from typing import Any, Callable, Dict, List, Optional
21
+
22
+ __all__ = ["PreviewSession", "serve"]
23
+
24
+ Logger = Callable[[str], None]
25
+
26
+
27
+ class PreviewSession:
28
+ """Everything one ``pn start`` invocation owns; see [`serve`][pythonnative.preview.serve]."""
29
+
30
+ def __init__(
31
+ self,
32
+ project_root: str,
33
+ entry_module: str,
34
+ *,
35
+ host: str = "0.0.0.0",
36
+ port: int = 8765,
37
+ project_name: str = "",
38
+ log: Optional[Logger] = None,
39
+ ) -> None:
40
+ from .bridge.web import WebTransport
41
+ from .devserver import DevServer
42
+
43
+ self.project_root = os.path.abspath(project_root)
44
+ self.entry_module = entry_module
45
+ self.log: Logger = log or (lambda line: print(line, file=sys.stderr, flush=True))
46
+ self.server = DevServer(
47
+ self.project_root, entry_module, host=host, port=port, project_name=project_name, log=self.log
48
+ )
49
+ self.transport = WebTransport(log=self.log)
50
+ self.transport.on_peer_changed = self._on_peer_changed
51
+ self.transport.on_dev_message = self._on_dev_message
52
+ self._stop = threading.Event()
53
+ self._unsubscribe: Optional[Callable[[], None]] = None
54
+
55
+ # -- lifecycle -------------------------------------------------------
56
+
57
+ def start(self) -> None:
58
+ """Install the transport, start the server, and begin watching."""
59
+ from . import bridge, diagnostics
60
+ from .utils import IS_WEB
61
+
62
+ if not IS_WEB:
63
+ raise RuntimeError(
64
+ "The browser preview needs PN_PLATFORM=web before pythonnative is imported "
65
+ "(`pn start` and `pn preview` set it for you)."
66
+ )
67
+ if self.project_root not in sys.path:
68
+ sys.path.insert(0, self.project_root)
69
+ os.environ.setdefault("PN_ENTRY_MODULE", self.entry_module)
70
+ os.environ.setdefault("PN_STORAGE_DIR", os.path.join(self.project_root, "build", "preview", "storage"))
71
+ diagnostics.set_dev_mode(True)
72
+ # Bottom of the reporter stack: screens register their own RedBox
73
+ # above this, so it only sees errors raised before a screen exists
74
+ # (a failing import of the entry module, say).
75
+ diagnostics.set_error_reporter(self, self._report_error)
76
+ bridge.set_transport(self.transport)
77
+ from .runtime import start as start_runtime
78
+
79
+ start_runtime()
80
+ self.server.set_preview_channel(self.transport)
81
+ self._unsubscribe = self.server.add_change_listener(self._on_sources_changed)
82
+ self.server.start()
83
+
84
+ def run(self) -> None:
85
+ """Run the main loop until ``stop`` (or Ctrl+C)."""
86
+ try:
87
+ self.transport.run_main_loop(until=self._stop.is_set)
88
+ except KeyboardInterrupt:
89
+ pass
90
+
91
+ def stop(self) -> None:
92
+ """Tear everything down."""
93
+ self._stop.set()
94
+ self.transport.stop()
95
+ if self._unsubscribe is not None:
96
+ self._unsubscribe()
97
+ self._unsubscribe = None
98
+ try:
99
+ self._destroy_hosts()
100
+ except Exception:
101
+ pass
102
+ self.server.stop()
103
+ from . import bridge, diagnostics
104
+
105
+ diagnostics.set_error_reporter(self, None)
106
+ bridge.set_transport(None)
107
+
108
+ # -- source changes ----------------------------------------------------
109
+
110
+ def _on_sources_changed(self, change: Any, snapshot: Any) -> None:
111
+ """Watcher thread: schedule a reload of the preview's own app."""
112
+ from .devserver.watcher import modules_for_paths
113
+
114
+ modules = modules_for_paths(list(change.changed) + list(change.removed))
115
+ if not modules:
116
+ return
117
+
118
+ def _apply() -> None:
119
+ from .hosts import live_hosts
120
+ from .hot_reload import apply_reload
121
+
122
+ hosts = list(live_hosts())
123
+ started = time.monotonic()
124
+ result = apply_reload(modules, hosts)
125
+ elapsed_ms = (time.monotonic() - started) * 1000.0
126
+ if result.mode == "error":
127
+ self.log("[pn] reload failed:")
128
+ for line in (result.error or "").rstrip().split("\n"):
129
+ self.log(f" {line}")
130
+ self.transport.send_dev({"type": "reload", "ok": False, "error": result.error, "modules": modules})
131
+ return
132
+ if result.mode == "none":
133
+ return
134
+ label = "Fast Refresh" if result.mode == "fast_refresh" else "Remounted"
135
+ self.log(f"[pn] {label}: {', '.join(result.reloaded)} ({elapsed_ms:.0f} ms)")
136
+ self.transport.send_dev(
137
+ {"type": "reload", "ok": True, "mode": result.mode, "modules": result.reloaded, "ms": elapsed_ms}
138
+ )
139
+
140
+ self.transport.post_to_application(_apply)
141
+
142
+ # -- peers -------------------------------------------------------------
143
+
144
+ def _on_peer_changed(self, connected: bool) -> None:
145
+ if connected:
146
+ self.log("[pn] browser preview connected")
147
+ self._send_hello()
148
+ return
149
+ self.log("[pn] browser preview disconnected")
150
+ self._destroy_hosts()
151
+
152
+ def _send_hello(self) -> None:
153
+ """Tell the page what to mount; it answers by creating the entry screen."""
154
+ self.transport.send_dev(
155
+ {
156
+ "type": "hello",
157
+ "entry": self.entry_module,
158
+ "project": self.server.project_name or os.path.basename(self.project_root),
159
+ }
160
+ )
161
+
162
+ def _report_error(self, exc: BaseException, phase: str) -> None:
163
+ """Print an error to the terminal and mirror it into the preview page."""
164
+ text = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)).rstrip()
165
+ self.log(f"[pn] error during {phase}:")
166
+ for line in text.split("\n"):
167
+ self.log(f" {line}")
168
+ self.transport.send_dev({"type": "error", "phase": phase, "text": text})
169
+
170
+ def _destroy_hosts(self) -> None:
171
+ """Unmount every screen the page created (it is gone, so are its views)."""
172
+ from .hosts.native import live_hosts
173
+ from .native_views import get_registry
174
+
175
+ for host in list(live_hosts()):
176
+ try:
177
+ host.on_destroy()
178
+ except Exception:
179
+ traceback.print_exc()
180
+ backend = get_registry()
181
+ reset = getattr(backend, "reset", None)
182
+ if callable(reset):
183
+ reset()
184
+
185
+ def _on_dev_message(self, payload: Dict[str, Any]) -> None:
186
+ kind = payload.get("type")
187
+ if kind == "log":
188
+ self.log(f"[browser] {payload.get('text', '')}")
189
+ elif kind == "error":
190
+ self.log(f"[browser error] {payload.get('text', '')}")
191
+ elif kind == "hello":
192
+ agent = str(payload.get("user_agent", ""))
193
+ device = payload.get("device", "")
194
+ size = f"{payload.get('width', '?')}x{payload.get('height', '?')}"
195
+ self.log(f"[pn] preview page: {device} {size} ({_browser_family(agent)})")
196
+ elif kind == "remount":
197
+ self.log("[pn] remounting the app")
198
+ self._destroy_hosts()
199
+ self._send_hello()
200
+
201
+ # -- info ----------------------------------------------------------------
202
+
203
+ def urls(self) -> List[str]:
204
+ """Every URL the server can be reached at (local first)."""
205
+ from .devserver import lan_addresses
206
+
207
+ info = self.server.info
208
+ urls = [info.url("localhost")]
209
+ for address in lan_addresses():
210
+ url = info.url(address)
211
+ if url not in urls:
212
+ urls.append(url)
213
+ return urls
214
+
215
+
216
+ def _browser_family(user_agent: str) -> str:
217
+ agent = user_agent.lower()
218
+ for needle, name in (("firefox", "Firefox"), ("edg/", "Edge"), ("chrome", "Chrome"), ("safari", "Safari")):
219
+ if needle in agent:
220
+ return name
221
+ return "browser"
222
+
223
+
224
+ def serve(
225
+ entry_module: str,
226
+ *,
227
+ project_root: Optional[str] = None,
228
+ host: str = "0.0.0.0",
229
+ port: int = 8765,
230
+ project_name: str = "",
231
+ open_browser: bool = False,
232
+ log: Optional[Logger] = None,
233
+ banner: bool = True,
234
+ ready: Optional[Callable[[PreviewSession], None]] = None,
235
+ ) -> None:
236
+ """Run the dev server (and browser preview) until interrupted.
237
+
238
+ Args:
239
+ entry_module: The app's entry module (``"app.main"``).
240
+ project_root: Directory containing ``app/``; defaults to the
241
+ current directory. Added to ``sys.path``.
242
+ host: Bind address (``0.0.0.0`` so devices can connect).
243
+ port: TCP port (``0`` picks a free one).
244
+ project_name: Shown in the preview page.
245
+ open_browser: Open the preview page in the default browser.
246
+ log: Where status lines go (stderr by default).
247
+ banner: Print the connection banner.
248
+ ready: Called once the server is listening (tests).
249
+
250
+ Raises:
251
+ RuntimeError: If ``PN_PLATFORM=web`` was not set before
252
+ PythonNative was imported (the CLI sets it for you).
253
+ OSError: If the port is taken.
254
+ """
255
+ session = PreviewSession(
256
+ project_root or os.getcwd(),
257
+ entry_module,
258
+ host=host,
259
+ port=port,
260
+ project_name=project_name,
261
+ log=log,
262
+ )
263
+ session.start()
264
+ urls = session.urls()
265
+ if banner:
266
+ emit = session.log
267
+ emit("")
268
+ emit(f" PythonNative dev server for {project_name or entry_module}")
269
+ emit("")
270
+ emit(f" Browser preview: {urls[0]}")
271
+ for url in urls[1:]:
272
+ emit(f" Devices (LAN): {url}")
273
+ emit("")
274
+ emit(" Debug builds made with `pn run` connect here automatically.")
275
+ emit(" Press Ctrl+C to stop.")
276
+ emit("")
277
+ if open_browser:
278
+ try:
279
+ webbrowser.open(urls[0])
280
+ except Exception:
281
+ pass
282
+ if ready is not None:
283
+ ready(session)
284
+ try:
285
+ session.run()
286
+ finally:
287
+ session.stop()