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,375 @@
1
+ """The view backend the reconciler commits to.
2
+
3
+ The reconciler talks to exactly one object, obtained from
4
+ [`get_registry`][pythonnative.native_views.get_registry], through a
5
+ small protocol: ``apply_mutations`` (one ordered batch of
6
+ create/update/insert/destroy/frame ops per commit, see
7
+ `pythonnative.mutations`), ``resolve_view``, ``measure_intrinsic``,
8
+ ``command``, and the animation hooks. Two implementations exist:
9
+
10
+ - [`BridgeBackend`][pythonnative.native_views.bridge_backend.BridgeBackend]
11
+ (iOS, Android, and the browser preview): serializes each commit and
12
+ hands it to the native runtime through the bridge; the Swift and
13
+ Kotlin component managers, or the preview page's DOM applier, own
14
+ every platform view. Python holds no native objects.
15
+ - [`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry]
16
+ (tests and SDK handler introspection): maps element type names to
17
+ Python [`ViewHandler`][pythonnative.native_views.base.ViewHandler]
18
+ implementations and owns the tag table itself.
19
+
20
+ Platform selection happens lazily on first use, so this package
21
+ imports on any platform. Tests install a mock with
22
+ [`set_registry`][pythonnative.native_views.set_registry].
23
+ """
24
+
25
+ import math
26
+ import sys
27
+ import threading
28
+ import time
29
+ from typing import Any, Dict, Optional, Sequence, Tuple
30
+
31
+ from ..mutations import CreateOp, DestroyOp, InsertOp, Mutation, SetFrameOp, UpdateOp
32
+ from .base import ViewHandler
33
+
34
+ # ======================================================================
35
+ # Tripwire log rate limiter
36
+ # ======================================================================
37
+ #
38
+ # Defensive NaN/Inf guards in ``set_frame`` and ``_apply_transform`` log
39
+ # a single line per occurrence. That's fine for one-off events, but
40
+ # ``Animated.View`` drives transforms at ~60 Hz; once an
41
+ # ``Animated.Value`` enters a stuck NaN state (e.g., a spring tick
42
+ # corrupted across a Fast Refresh), the tripwire would otherwise emit
43
+ # thousands of identical lines per second and drown the dev console.
44
+ #
45
+ # We instead log the first occurrence immediately, then suppress
46
+ # further messages with the same ``label`` for
47
+ # ``_TRIPWIRE_RATE_LIMIT_S`` seconds, and append a
48
+ # ``(+N similar in last Xs)`` suffix to the next message that escapes
49
+ # the window. The first sample plus a count is enough to diagnose; the
50
+ # bounded log keeps the dev console usable.
51
+
52
+ _TRIPWIRE_RATE_LIMIT_S: float = 1.0
53
+ _TRIPWIRE_LOG_LOCK = threading.Lock()
54
+ _TRIPWIRE_LAST_LOG_TIME: Dict[str, float] = {}
55
+ _TRIPWIRE_SUPPRESSED_COUNT: Dict[str, int] = {}
56
+
57
+
58
+ def _tripwire_log(label: str, message: str) -> None:
59
+ """Emit ``message`` to stderr, rate-limited per ``label``.
60
+
61
+ The first call for a given ``label`` always emits. Calls within
62
+ ``_TRIPWIRE_RATE_LIMIT_S`` seconds are silently counted. The next
63
+ call after the window appends ``(+N similar in last Xs)`` and
64
+ resets the counter.
65
+ """
66
+ now = time.monotonic()
67
+ write = False
68
+ suppressed = 0
69
+ with _TRIPWIRE_LOG_LOCK:
70
+ last = _TRIPWIRE_LAST_LOG_TIME.get(label)
71
+ if last is None or now - last >= _TRIPWIRE_RATE_LIMIT_S:
72
+ write = True
73
+ suppressed = _TRIPWIRE_SUPPRESSED_COUNT.get(label, 0)
74
+ _TRIPWIRE_SUPPRESSED_COUNT[label] = 0
75
+ _TRIPWIRE_LAST_LOG_TIME[label] = now
76
+ else:
77
+ _TRIPWIRE_SUPPRESSED_COUNT[label] = _TRIPWIRE_SUPPRESSED_COUNT.get(label, 0) + 1
78
+ if not write:
79
+ return
80
+ if suppressed > 0:
81
+ message = f"{message} (+{suppressed} similar in last {_TRIPWIRE_RATE_LIMIT_S:g}s)"
82
+ try:
83
+ print(message, file=sys.stderr, flush=True)
84
+ except Exception:
85
+ pass
86
+
87
+
88
+ class ViewRecord:
89
+ """One live native view tracked by the tag table."""
90
+
91
+ __slots__ = ("tag", "type_name", "view", "handler")
92
+
93
+ def __init__(self, tag: int, type_name: str, view: Any, handler: ViewHandler) -> None:
94
+ self.tag = tag
95
+ self.type_name = type_name
96
+ self.view = view
97
+ self.handler = handler
98
+
99
+
100
+ class NativeViewRegistry:
101
+ """Map element type names to handlers and tags to live native views.
102
+
103
+ The reconciler depends only on this protocol: ``apply_mutations``,
104
+ ``resolve_view``, ``measure_intrinsic``, and ``command``.
105
+ Implementations may host real platform handlers (Android/iOS/
106
+ browser) or mocks for tests.
107
+ """
108
+
109
+ def __init__(self) -> None:
110
+ self._handlers: Dict[str, ViewHandler] = {}
111
+ self._records: Dict[int, ViewRecord] = {}
112
+
113
+ def register(self, type_name: str, handler: ViewHandler) -> None:
114
+ """Register `handler` to service elements of type `type_name`.
115
+
116
+ Args:
117
+ type_name: The element type name (e.g., `"Text"`).
118
+ handler: A `ViewHandler` instance for the active platform.
119
+ """
120
+ self._handlers[type_name] = handler
121
+
122
+ def handler_for(self, type_name: str) -> Optional[ViewHandler]:
123
+ """Return the handler registered for ``type_name``, if any."""
124
+ return self._handlers.get(type_name)
125
+
126
+ # ------------------------------------------------------------------
127
+ # Tag table
128
+ # ------------------------------------------------------------------
129
+
130
+ def resolve_view(self, tag: int) -> Any:
131
+ """Return the native view registered under ``tag``, or ``None``."""
132
+ record = self._records.get(tag)
133
+ return record.view if record is not None else None
134
+
135
+ def record_for(self, tag: int) -> Optional[ViewRecord]:
136
+ """Return the full [`ViewRecord`][pythonnative.native_views.ViewRecord] for ``tag``."""
137
+ return self._records.get(tag)
138
+
139
+ def live_view_count(self) -> int:
140
+ """Number of views currently tracked (test/diagnostic helper)."""
141
+ return len(self._records)
142
+
143
+ # ------------------------------------------------------------------
144
+ # The commit channel
145
+ # ------------------------------------------------------------------
146
+
147
+ def apply_mutations(self, ops: Sequence[Mutation]) -> None:
148
+ """Apply one commit transaction.
149
+
150
+ Ops are applied strictly in order. Failures are isolated per
151
+ op: a handler exception is logged (rate-limited) and the
152
+ remaining ops still apply, so one bad prop can't desync the
153
+ whole native tree.
154
+
155
+ Args:
156
+ ops: Ordered mutations emitted by the reconciler.
157
+ """
158
+ for op in ops:
159
+ try:
160
+ self._apply_one(op)
161
+ except Exception as exc:
162
+ _tripwire_log(
163
+ f"apply:{type(op).__name__}",
164
+ f"[PN] apply_mutations: {type(op).__name__} failed: {type(exc).__name__}: {exc!r}",
165
+ )
166
+
167
+ def _apply_one(self, op: Mutation) -> None:
168
+ if isinstance(op, CreateOp):
169
+ handler = self._handlers.get(op.type_name)
170
+ if handler is None:
171
+ raise ValueError(f"Unknown element type: {op.type_name!r}")
172
+ view = handler.create(op.tag, op.props)
173
+ self._records[op.tag] = ViewRecord(op.tag, op.type_name, view, handler)
174
+ return
175
+ if isinstance(op, UpdateOp):
176
+ record = self._records.get(op.tag)
177
+ if record is not None:
178
+ record.handler.update(record.view, op.changed_props)
179
+ return
180
+ if isinstance(op, InsertOp):
181
+ parent = self._records.get(op.parent_tag)
182
+ child = self._records.get(op.child_tag)
183
+ if parent is not None and child is not None:
184
+ parent.handler.insert_child(parent.view, child.view, op.index)
185
+ return
186
+ if isinstance(op, DestroyOp):
187
+ record = self._records.pop(op.tag, None)
188
+ if record is not None:
189
+ record.handler.destroy(record.view)
190
+ return
191
+ if isinstance(op, SetFrameOp):
192
+ self._apply_frame(op)
193
+ return
194
+ raise TypeError(f"Unknown mutation op: {op!r}")
195
+
196
+ def _apply_frame(self, op: SetFrameOp) -> None:
197
+ record = self._records.get(op.tag)
198
+ if record is None:
199
+ return
200
+ # Tripwire: log non-finite layout values so we can diagnose
201
+ # crashes like iOS `CALayerInvalidGeometry` without losing the
202
+ # repro. Handlers are responsible for clamping before applying.
203
+ # Rate-limited via ``_tripwire_log`` to avoid floods when an
204
+ # animated value is stuck at NaN.
205
+ try:
206
+ finite = (
207
+ math.isfinite(op.x) and math.isfinite(op.y) and math.isfinite(op.width) and math.isfinite(op.height)
208
+ )
209
+ except (TypeError, ValueError):
210
+ finite = False
211
+ if not finite:
212
+ _tripwire_log(
213
+ "set_frame:nan",
214
+ f"[set_frame:nan] type={record.type_name!r} x={op.x!r} y={op.y!r} w={op.width!r} h={op.height!r}",
215
+ )
216
+ record.handler.set_frame(record.view, op.x, op.y, op.width, op.height)
217
+
218
+ # ------------------------------------------------------------------
219
+ # Imperative escape hatches (resolved through the tag table)
220
+ # ------------------------------------------------------------------
221
+
222
+ def measure_intrinsic(
223
+ self,
224
+ tag: int,
225
+ max_width: float,
226
+ max_height: float,
227
+ ) -> Tuple[float, float]:
228
+ """Return the natural ``(width, height)`` of a content-sized view.
229
+
230
+ Used by the layout engine for leaves whose intrinsic size
231
+ depends on their content (text, buttons, images).
232
+ """
233
+ record = self._records.get(tag)
234
+ if record is None:
235
+ return (0.0, 0.0)
236
+ return record.handler.measure_intrinsic(record.view, max_width, max_height)
237
+
238
+ def command(self, tag: int, name: str, args: Optional[Dict[str, Any]] = None) -> Any:
239
+ """Execute an imperative command against the view for ``tag``.
240
+
241
+ Args:
242
+ tag: Target view tag.
243
+ name: Command name (handler-specific, e.g.
244
+ ``"scroll_to_offset"``).
245
+ args: Optional command arguments.
246
+
247
+ Returns:
248
+ The handler's command result, or ``None`` when the tag is
249
+ unknown.
250
+ """
251
+ record = self._records.get(tag)
252
+ if record is None:
253
+ return None
254
+ return record.handler.command(record.view, name, args or {})
255
+
256
+ def set_animated_property(self, tag: int, prop_name: str, value: Any) -> None:
257
+ """Apply one Python-driven animation frame to the view for ``tag``."""
258
+ record = self._records.get(tag)
259
+ if record is not None:
260
+ record.handler.set_animated_property(record.view, prop_name, value)
261
+
262
+ def start_animation(self, tag: int, anim_id: int, prop_name: str, spec: Dict[str, Any]) -> bool:
263
+ """Start a natively-driven animation on the view for ``tag``.
264
+
265
+ Returns:
266
+ Whether the platform accepted the animation (``False``
267
+ means the caller should drive it from the Python ticker).
268
+ """
269
+ record = self._records.get(tag)
270
+ if record is None:
271
+ return False
272
+ return bool(record.handler.start_animation(record.view, anim_id, prop_name, spec))
273
+
274
+ def cancel_animation(self, tag: int, anim_id: int) -> Any:
275
+ """Cancel a natively-driven animation; returns the presentation value if known."""
276
+ record = self._records.get(tag)
277
+ if record is None:
278
+ return None
279
+ return record.handler.cancel_animation(record.view, anim_id)
280
+
281
+
282
+ # ======================================================================
283
+ # Singleton registry
284
+ # ======================================================================
285
+
286
+ _registry: Any = None
287
+
288
+
289
+ def _install_sdk_handlers(registry: Any) -> None:
290
+ """Copy decorator-registered SDK handlers + entry-point plugins.
291
+
292
+ Imported lazily so unit tests that never touch the SDK don't pay the
293
+ entry-point discovery cost. Only meaningful for the Python-handler
294
+ registry (tests); on the bridge platforms the native runtime owns
295
+ component managers and Python handlers are recorded but never run.
296
+ """
297
+ try:
298
+ from ..sdk._components import install_into_registry as _sdk_install
299
+ except Exception:
300
+ return
301
+ try:
302
+ _sdk_install(registry)
303
+ except Exception:
304
+ # A misbehaving plugin must not break PythonNative's startup.
305
+ pass
306
+
307
+
308
+ def _create_backend() -> Any:
309
+ """Build the backend for the active platform.
310
+
311
+ iOS, Android, and the browser preview (``PN_PLATFORM=web``) get the
312
+ bridge backend. Anywhere else (plain unit tests) there is no
313
+ renderer at all, so the registry is empty: tests inject a
314
+ ``pythonnative.testing.FakeBackend`` with ``set_registry`` and a
315
+ stray commit raises a clear "unknown element type" rather than
316
+ silently importing a platform module.
317
+ """
318
+ from ..utils import IS_NATIVE
319
+
320
+ if IS_NATIVE:
321
+ from .bridge_backend import BridgeBackend
322
+
323
+ return BridgeBackend()
324
+ registry = NativeViewRegistry()
325
+ _install_sdk_handlers(registry)
326
+ return registry
327
+
328
+
329
+ def get_registry() -> Any:
330
+ """Return the process-wide view backend, creating it on first use.
331
+
332
+ Returns:
333
+ A [`BridgeBackend`][pythonnative.native_views.bridge_backend.BridgeBackend]
334
+ on every bridge platform, otherwise a `NativeViewRegistry`
335
+ holding every decorator-registered SDK handler and any handlers
336
+ exposed by third-party packages via the
337
+ [`pythonnative.handlers`][pythonnative.sdk.ENTRY_POINT_GROUP]
338
+ entry point group.
339
+ """
340
+ global _registry
341
+ if _registry is not None:
342
+ return _registry
343
+ _registry = _create_backend()
344
+ return _registry
345
+
346
+
347
+ def refresh_registry() -> Any:
348
+ """Re-run SDK handler installation against the existing backend.
349
+
350
+ Call this after registering a new component at runtime if the
351
+ registry has already been instantiated. This is mostly useful in
352
+ REPL sessions and tests; the normal flow is "register, then call
353
+ [`get_registry`][pythonnative.native_views.get_registry]" and the
354
+ handlers come along automatically.
355
+ """
356
+ registry = get_registry()
357
+ _install_sdk_handlers(registry)
358
+ return registry
359
+
360
+
361
+ def set_registry(registry: Any) -> None:
362
+ """Install a custom backend (primarily for testing).
363
+
364
+ Replaces the lazy singleton so subsequent
365
+ [`get_registry`][pythonnative.native_views.get_registry] calls
366
+ return `registry`. Pass a mock to drive the reconciler from
367
+ unit tests without touching real native APIs. Pass ``None`` to
368
+ reset the singleton; the next ``get_registry`` call will then
369
+ rebuild it from scratch.
370
+
371
+ Args:
372
+ registry: The replacement backend, or ``None`` to clear.
373
+ """
374
+ global _registry
375
+ _registry = registry
@@ -0,0 +1,316 @@
1
+ """Shared base classes and utilities for native-view handlers.
2
+
3
+ Provides the [`ViewHandler`][pythonnative.native_views.base.ViewHandler]
4
+ protocol implemented by Android and iOS handlers, plus the
5
+ [`parse_color_int`][pythonnative.native_views.base.parse_color_int]
6
+ helper shared across platforms.
7
+
8
+ Layout itself is *not* a handler responsibility. The pure-Python flex
9
+ engine in ``pythonnative.layout`` owns sizing and positioning;
10
+ handlers receive computed frames via
11
+ [`set_frame`][pythonnative.native_views.base.ViewHandler.set_frame] and
12
+ optionally expose an intrinsic-size hook via
13
+ [`measure_intrinsic`][pythonnative.native_views.base.ViewHandler.measure_intrinsic]
14
+ for content-sized leaves (text, buttons, images).
15
+ """
16
+
17
+ import math
18
+ import re
19
+ from typing import Any, Dict, Optional, Tuple, Union
20
+
21
+
22
+ class ViewHandler:
23
+ """Protocol implemented by every native-view handler.
24
+
25
+ A `ViewHandler` knows how to create, update, re-parent, and destroy
26
+ native views of one element type. The reconciler never calls a
27
+ handler directly; it emits a batch of mutation ops
28
+ (`pythonnative.mutations`) that the
29
+ [`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry]
30
+ applies by dispatching to handlers. Handlers never need to know
31
+ about `Element` or `VNode`.
32
+
33
+ Event contract: props delivered to
34
+ [`create`][pythonnative.native_views.base.ViewHandler.create] /
35
+ [`update`][pythonnative.native_views.base.ViewHandler.update]
36
+ contain **no Python callables**. The set of event names wired on
37
+ the element arrives under the ``_pn_events`` key (see
38
+ [`event_names`][pythonnative.events.event_names]); handlers wire
39
+ platform listeners once at create time and forward firings through
40
+ [`dispatch_event`][pythonnative.events.dispatch_event] using the
41
+ tag passed to ``create``.
42
+
43
+ Subclasses must override ``create`` and ``update``. Container
44
+ handlers override the child-management methods; leaf handlers can
45
+ leave them as no-ops. Handlers whose intrinsic size depends on
46
+ content (text, buttons, images) override
47
+ [`measure_intrinsic`][pythonnative.native_views.base.ViewHandler.measure_intrinsic].
48
+ """
49
+
50
+ def create(self, tag: int, props: Dict[str, Any]) -> Any:
51
+ """Create a fresh native view and apply initial *visual* props.
52
+
53
+ Layout-related props (``width``, ``height``, ``flex``, ``padding``,
54
+ etc.) are consumed by the layout engine and applied via
55
+ [`set_frame`][pythonnative.native_views.base.ViewHandler.set_frame],
56
+ so handlers should ignore them here.
57
+
58
+ Args:
59
+ tag: The reconciler-assigned identity for this view. Used
60
+ when dispatching events back into Python.
61
+ props: Initial props dict (callable-free; event names under
62
+ ``_pn_events``).
63
+
64
+ Returns:
65
+ The platform-native view object.
66
+
67
+ Raises:
68
+ NotImplementedError: Subclasses must override.
69
+ """
70
+ raise NotImplementedError
71
+
72
+ def update(self, native_view: Any, changed_props: Dict[str, Any]) -> None:
73
+ """Apply only the *visual* props that changed since the last render.
74
+
75
+ Args:
76
+ native_view: The platform-native view to mutate.
77
+ changed_props: Props whose values changed (a value of
78
+ `None` indicates the prop was removed).
79
+
80
+ Raises:
81
+ NotImplementedError: Subclasses must override.
82
+ """
83
+ raise NotImplementedError
84
+
85
+ def insert_child(self, parent: Any, child: Any, index: int) -> None:
86
+ """Ensure `child` sits at `index` among `parent`'s children.
87
+
88
+ Must be **move-aware**: when `child` is already attached to
89
+ `parent`, reposition it instead of attaching twice. Handlers
90
+ should clamp `index` to the current child count. No-op for
91
+ leaf handlers.
92
+ """
93
+
94
+ def remove_child(self, parent: Any, child: Any) -> None:
95
+ """Remove `child` from `parent` without destroying it. No-op for leaf handlers."""
96
+
97
+ def destroy(self, native_view: Any) -> None:
98
+ """Release platform resources owned by ``native_view``.
99
+
100
+ Called exactly once when the reconciler unmounts the view.
101
+ The default is a no-op; override to detach listeners, cancel
102
+ in-flight work, or destroy widgets that the platform doesn't
103
+ garbage-collect.
104
+ """
105
+
106
+ def set_frame(self, native_view: Any, x: float, y: float, width: float, height: float) -> None:
107
+ """Position and size ``native_view`` relative to its parent.
108
+
109
+ Coordinates are in points and relative to the parent's content
110
+ origin. Default no-op so handlers that don't need explicit
111
+ positioning (e.g., `Modal`) can opt out.
112
+
113
+ Args:
114
+ native_view: The platform-native view.
115
+ x: X-coordinate (points) of the view's top-left corner
116
+ relative to its parent's content origin.
117
+ y: Y-coordinate (points) of the view's top-left corner.
118
+ width: View width in points.
119
+ height: View height in points.
120
+ """
121
+
122
+ def measure_intrinsic(
123
+ self,
124
+ native_view: Any,
125
+ max_width: float,
126
+ max_height: float,
127
+ ) -> Tuple[float, float]:
128
+ """Return the natural ``(width, height)`` of a content-sized view.
129
+
130
+ Used by the layout engine for leaves whose size depends on
131
+ their content (text, buttons, images). Either ``max_width`` or
132
+ ``max_height`` may be `math.inf` to indicate no constraint.
133
+
134
+ The default implementation returns ``(0, 0)``; override for
135
+ leaves whose size depends on their content. Container handlers
136
+ leave this alone; the engine sizes containers by laying out
137
+ their children.
138
+
139
+ Args:
140
+ native_view: The platform-native view to measure.
141
+ max_width: Maximum width in points (or `math.inf`).
142
+ max_height: Maximum height in points (or `math.inf`).
143
+
144
+ Returns:
145
+ ``(width, height)`` in points.
146
+ """
147
+ return (0.0, 0.0)
148
+
149
+ def command(self, native_view: Any, name: str, args: Dict[str, Any]) -> Any:
150
+ """Execute an imperative command (e.g. ``"scroll_to_offset"``).
151
+
152
+ Commands are the escape hatch for one-shot imperative actions
153
+ that don't fit declarative props: scrolling, focusing,
154
+ flashing indicators. Unknown commands should be ignored.
155
+
156
+ Args:
157
+ native_view: The platform-native view.
158
+ name: Command name.
159
+ args: Command arguments.
160
+
161
+ Returns:
162
+ An optional command-specific result.
163
+ """
164
+ return None
165
+
166
+ def set_animated_property(self, native_view: Any, prop_name: str, value: Any) -> None:
167
+ """Apply one frame of a Python-driven animation immediately.
168
+
169
+ This is the fallback path used by
170
+ animations the platform cannot drive natively. ``prop_name``
171
+ is one of ``opacity``, ``background_color``, ``translate_x``,
172
+ ``translate_y``, ``scale``, ``scale_x``, ``scale_y``,
173
+ ``rotate``.
174
+ """
175
+
176
+ def start_animation(
177
+ self,
178
+ native_view: Any,
179
+ anim_id: int,
180
+ prop_name: str,
181
+ spec: Dict[str, Any],
182
+ ) -> bool:
183
+ """Start a natively-driven animation, if the platform supports it.
184
+
185
+ ``spec`` describes the animation::
186
+
187
+ {"kind": "timing", "from": 0.0, "to": 1.0,
188
+ "duration_ms": 300.0, "easing": "ease_in_out"}
189
+ {"kind": "spring", "from": ..., "to": ...,
190
+ "stiffness": 100.0, "damping": 10.0, "mass": 1.0,
191
+ "initial_velocity": 0.0}
192
+
193
+ Implementations must invoke
194
+ ``pythonnative.animated.native_animation_completed(anim_id, finished)``
195
+ when the animation completes or is cancelled.
196
+
197
+ Returns:
198
+ ``True`` when the animation was started natively. ``False``
199
+ tells the caller to fall back to the Python ticker (the
200
+ default).
201
+ """
202
+ return False
203
+
204
+ def cancel_animation(self, native_view: Any, anim_id: int) -> Any:
205
+ """Cancel a natively-driven animation.
206
+
207
+ Returns:
208
+ The property's current (presentation) value when the
209
+ platform can read it, else ``None``.
210
+ """
211
+ return None
212
+
213
+
214
+ # ======================================================================
215
+ # Color parsing
216
+ # ======================================================================
217
+
218
+
219
+ def parse_color_int(color: Union[str, int]) -> int:
220
+ """Parse a color value into a signed 32-bit ARGB int.
221
+
222
+ Accepts `"#RRGGBB"`, `"#AARRGGBB"`, or a raw integer. Java APIs
223
+ such as `setBackgroundColor` expect a signed 32-bit int, so values
224
+ with a high alpha byte (e.g., `0xFF......`) must be converted to
225
+ their negative two's-complement equivalent.
226
+
227
+ Args:
228
+ color: Hex string (with or without leading `#`) or an int.
229
+
230
+ Returns:
231
+ Signed 32-bit ARGB int suitable for Android's color APIs.
232
+ """
233
+ if isinstance(color, int):
234
+ val = color
235
+ else:
236
+ c = color.strip().lstrip("#")
237
+ if len(c) == 6:
238
+ c = "FF" + c
239
+ val = int(c, 16)
240
+ if val > 0x7FFFFFFF:
241
+ val -= 0x100000000
242
+ return val
243
+
244
+
245
+ # ======================================================================
246
+ # Text helpers shared by every backend's Text handler
247
+ # ======================================================================
248
+
249
+ _WORD_START = re.compile(r"(?<!\S)(\S)")
250
+
251
+
252
+ def transform_text(text: Any, mode: Optional[str]) -> str:
253
+ """Apply a ``text_transform`` style value to ``text``.
254
+
255
+ Runs in Python before the string is handed to the native label, so
256
+ the displayed text and the intrinsic measurement agree on every
257
+ backend. ``"capitalize"`` upper-cases the first character of each
258
+ whitespace-separated word and leaves the rest untouched (matching
259
+ CSS / React Native rather than ``str.title()``, which would
260
+ lower-case the remainder). Unknown modes and ``"none"`` return the
261
+ text unchanged.
262
+ """
263
+ s = "" if text is None else str(text)
264
+ if mode == "uppercase":
265
+ return s.upper()
266
+ if mode == "lowercase":
267
+ return s.lower()
268
+ if mode == "capitalize":
269
+ return _WORD_START.sub(lambda m: m.group(1).upper(), s)
270
+ return s
271
+
272
+
273
+ def transform_spans(spans: Any, mode: Optional[str]) -> Any:
274
+ """Return ``spans`` with `transform_text` applied to each span's ``text``.
275
+
276
+ Rich text is flattened into one native string, so a run-by-run
277
+ transform matches what a single-string transform would produce for
278
+ ``uppercase`` / ``lowercase``. ``capitalize`` is evaluated per span,
279
+ which is also how CSS treats inline boxes.
280
+ """
281
+ if not mode or mode == "none" or not isinstance(spans, list):
282
+ return spans
283
+ out = []
284
+ for span in spans:
285
+ if isinstance(span, dict) and "text" in span:
286
+ copy = dict(span)
287
+ copy["text"] = transform_text(span.get("text"), mode)
288
+ out.append(copy)
289
+ else:
290
+ out.append(span)
291
+ return out
292
+
293
+
294
+ def shadow_offset_xy(value: Any) -> Tuple[float, float]:
295
+ """Coerce a ``shadow_offset`` / ``text_shadow_offset`` value to ``(dx, dy)``."""
296
+ if isinstance(value, dict):
297
+ return (float(value.get("width", 0) or 0), float(value.get("height", 0) or 0))
298
+ if isinstance(value, (tuple, list)) and len(value) >= 2:
299
+ return (float(value[0]), float(value[1]))
300
+ return (0.0, 0.0)
301
+
302
+
303
+ TEXT_SHADOW_STYLE_KEYS = ("text_shadow_color", "text_shadow_offset", "text_shadow_radius")
304
+ """Style keys that together describe a text shadow."""
305
+
306
+
307
+ # ======================================================================
308
+ # Helpers shared by Android and iOS measure callbacks
309
+ # ======================================================================
310
+
311
+
312
+ def _safe_max(value: float, fallback: float = 1e6) -> float:
313
+ """Clamp ``math.inf`` to a large finite value for native measure calls."""
314
+ if not math.isfinite(value):
315
+ return fallback
316
+ return max(0.0, value)