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,86 @@
1
+ import XCTest
2
+ @testable import PythonNativeKit
3
+
4
+ final class PNCommitTests: XCTestCase {
5
+ private let app = UUID().uuidString
6
+
7
+ private func commit(_ operations: [[Any]], revision: Int = 1) -> [String: Any] {
8
+ PNJSON.decodeObject(PNCommit.apply(PNJSON.encode([
9
+ "version": 2, "application": app, "surface": 1,
10
+ "revision": revision, "ops": operations,
11
+ ])))
12
+ }
13
+
14
+ override func tearDown() {
15
+ _ = PNCommit.apply(PNJSON.encode([
16
+ "version": 2, "application": UUID().uuidString, "surface": 1,
17
+ "revision": 1, "ops": [],
18
+ ]))
19
+ super.tearDown()
20
+ }
21
+
22
+ func testInvalidInsertionDoesNotPartiallyCreateWidgets() {
23
+ let result = commit([["c", 9101, "View", [:]], ["c", 9102, "Text", ["text": "pending"]], ["i", 9101, 9102, 3]])
24
+ XCTAssertEqual(result["ok"] as? Bool, false)
25
+ XCTAssertNil(PNViewRegistry.shared.view(for: 9101))
26
+ XCTAssertNil(PNViewRegistry.shared.view(for: 9102))
27
+ XCTAssertEqual(commit([["c", 9101, "View", [:]]])["ok"] as? Bool, true)
28
+ }
29
+
30
+ func testTypedUpdatesValidateTagsCreatedInTheSameCommit() {
31
+ let result = commit([["c", 9201, "TextInput", ["value": "valid"]], ["u", 9201, ["value": 12]]])
32
+ XCTAssertEqual(result["ok"] as? Bool, false)
33
+ XCTAssertNil(PNViewRegistry.shared.view(for: 9201))
34
+ }
35
+
36
+ func testHorizontalListMeasuresRowsAlongTheirWidth() {
37
+ let result = commit([
38
+ ["c", 9601, "VirtualList", ["keys": ["one"], "revision": 1, "horizontal": true, "width": 300, "height": 100]],
39
+ ["c", 9602, "View", ["_pn_list_key": "one", "width": 80, "height": 100]],
40
+ ["i", 9601, 9602, 0],
41
+ ])
42
+ XCTAssertEqual(result["ok"] as? Bool, true)
43
+ PNViewRegistry.shared.view(for: 9601)?.frame = CGRect(x: 0, y: 0, width: 300, height: 100)
44
+ let frames = PNLayout.compute(["roots": [Int64(9601)], "width": 300, "height": 100])
45
+ let row = frames.first { $0.first == 9602 }
46
+ XCTAssertEqual(row?[3], 80)
47
+ XCTAssertEqual(row?[4], 100)
48
+ }
49
+
50
+ func testPortalLaysOutAgainstItsViewportWithoutAScreenParent() {
51
+ XCTAssertEqual(commit([
52
+ ["c", 9700, "View", [:]],
53
+ ["c", 9701, "Portal", [:]],
54
+ ["c", 9702, "View", ["position": "absolute", "left": 24, "right": 24, "bottom": 40, "height": 80]],
55
+ ["c", 9703, "View", ["height": 30]],
56
+ ["c", 9704, "View", ["height": 20]],
57
+ ["i", 9701, 9702, 0],
58
+ ["i", 9701, 9703, 1],
59
+ ["i", 9701, 9704, 2],
60
+ ])["ok"] as? Bool, true)
61
+ let request: [String: Any] = ["roots": [Int64(9700)], "width": 320, "height": 640]
62
+ // The native overlay can be smaller than the screen, for example below a navigation bar.
63
+ PNViewRegistry.shared.view(for: 9701)?.frame = CGRect(x: 0, y: 0, width: 300, height: 600)
64
+ let frames = PNLayout.compute(request)
65
+ XCTAssertTrue(frames.flatMap { $0 }.allSatisfy { $0.isFinite })
66
+ XCTAssertEqual(frames.first { $0.first == 9701 }, [9701, 0, 0, 300, 600])
67
+ XCTAssertEqual(frames.first { $0.first == 9702 }, [9702, 24, 480, 252, 80])
68
+ XCTAssertEqual(frames.first { $0.first == 9704 }, [9704, 0, 30, 300, 20])
69
+ XCTAssertTrue(PNLayout.compute(request).isEmpty)
70
+
71
+ PNViewRegistry.shared.view(for: 9701)?.frame = CGRect(x: 0, y: 0, width: 400, height: 700)
72
+ let resized = PNLayout.compute(request)
73
+ XCTAssertEqual(resized.first { $0.first == 9702 }, [9702, 24, 580, 352, 80])
74
+ XCTAssertEqual(commit([["d", 9702], ["d", 9703], ["d", 9704], ["d", 9701]], revision: 2)["ok"] as? Bool, true)
75
+ XCTAssertNil(PNLayout.nodes[9701])
76
+ XCTAssertTrue(PNLayout.compute(request).isEmpty)
77
+ }
78
+
79
+ func testReplayCannotDestroyAnAcceptedWidget() {
80
+ XCTAssertEqual(commit([["c", 9301, "View", [:]]])["ok"] as? Bool, true)
81
+ XCTAssertEqual(commit([["d", 9301]])["ok"] as? Bool, false)
82
+ XCTAssertNotNil(PNViewRegistry.shared.view(for: 9301))
83
+ XCTAssertEqual(commit([["d", 9301]], revision: 2)["ok"] as? Bool, true)
84
+ XCTAssertNil(PNViewRegistry.shared.view(for: 9301))
85
+ }
86
+ }
@@ -0,0 +1,101 @@
1
+ import XCTest
2
+ @testable import PythonNativeKit
3
+
4
+ final class PNGestureTests: XCTestCase {
5
+ override func tearDown() {
6
+ PNViewRegistry.shared.removeAll()
7
+ super.tearDown()
8
+ }
9
+
10
+ func testSpecsBecomeRecognizersWithRelationships() {
11
+ let manager = PNViewManager()
12
+ let view = manager.createView(tag: 1, props: [
13
+ "gestures": [
14
+ ["kind": "tap", "n_taps": 2, "simultaneous": [1], "wait_for": []],
15
+ ["kind": "pan", "min_distance": 10, "simultaneous": [0], "wait_for": []],
16
+ ["kind": "long_press", "min_duration_ms": 800, "simultaneous": [], "wait_for": [0]],
17
+ ["kind": "swipe", "direction": "left", "simultaneous": [], "wait_for": []],
18
+ ["kind": "pinch", "simultaneous": [], "wait_for": []],
19
+ ["kind": "rotation", "simultaneous": [], "wait_for": []],
20
+ ["kind": "fling", "direction": "down", "n_pointers": 2, "simultaneous": [], "wait_for": []],
21
+ ],
22
+ ])
23
+ let recognizers = PNViewState.existing(for: view)?.gestureRecognizers ?? []
24
+ XCTAssertEqual(recognizers.count, 7)
25
+ XCTAssertEqual((recognizers[0] as? UITapGestureRecognizer)?.numberOfTapsRequired, 2)
26
+ XCTAssertTrue(recognizers[1] is UIPanGestureRecognizer)
27
+ XCTAssertEqual((recognizers[2] as? UILongPressGestureRecognizer)?.minimumPressDuration ?? 0, 0.8, accuracy: 0.001)
28
+ XCTAssertEqual((recognizers[3] as? UISwipeGestureRecognizer)?.direction, .left)
29
+ XCTAssertTrue(recognizers[4] is UIPinchGestureRecognizer)
30
+ XCTAssertTrue(recognizers[5] is UIRotationGestureRecognizer)
31
+ XCTAssertEqual((recognizers[6] as? UISwipeGestureRecognizer)?.numberOfTouchesRequired, 2)
32
+ XCTAssertEqual((recognizers[6] as? UISwipeGestureRecognizer)?.direction, .down)
33
+
34
+ let coordinator = PNGestureCoordinator.shared
35
+ XCTAssertEqual(coordinator.index(of: recognizers[2]), 2)
36
+ XCTAssertTrue(coordinator.allowsSimultaneous(recognizers[0], recognizers[1]))
37
+ XCTAssertFalse(coordinator.allowsSimultaneous(recognizers[0], recognizers[2]))
38
+ XCTAssertFalse(coordinator.allowsSimultaneous(recognizers[3], recognizers[4]))
39
+ XCTAssertTrue(view.isUserInteractionEnabled)
40
+ XCTAssertTrue(recognizers.allSatisfy { $0.view === view && !$0.cancelsTouchesInView })
41
+ }
42
+
43
+ func testRewiringReplacesRecognizersAndUnknownKindsAreSkipped() {
44
+ let manager = PNViewManager()
45
+ let view = manager.createView(tag: 2, props: ["gestures": [["kind": "tap"]]])
46
+ XCTAssertEqual(view.gestureRecognizers?.count, 1)
47
+ manager.update(view: view, changed: ["gestures": [["kind": "nonsense"], ["kind": "pan"]]])
48
+ let recognizers = PNViewState.existing(for: view)?.gestureRecognizers ?? []
49
+ XCTAssertEqual(recognizers.count, 1)
50
+ XCTAssertTrue(recognizers[0] is UIPanGestureRecognizer)
51
+ XCTAssertEqual(PNGestureCoordinator.shared.index(of: recognizers[0]), 1, "index follows the spec position")
52
+ manager.update(view: view, changed: ["gestures": NSNull()])
53
+ XCTAssertEqual(view.gestureRecognizers?.count ?? 0, 0)
54
+ }
55
+
56
+ func testStateAndDirectionNames() {
57
+ XCTAssertEqual(PNGestureCoordinator.stateName(.began), "began")
58
+ XCTAssertEqual(PNGestureCoordinator.stateName(.changed), "changed")
59
+ XCTAssertEqual(PNGestureCoordinator.stateName(.ended), "ended")
60
+ XCTAssertEqual(PNGestureCoordinator.stateName(.cancelled), "cancelled")
61
+ XCTAssertEqual(PNGestureCoordinator.swipeDirection("up"), .up)
62
+ XCTAssertEqual(PNGestureCoordinator.swipeDirection("any"), [.left, .right, .up, .down])
63
+ }
64
+
65
+ func testAnyDirectionSwipeInstallsOneRecognizerPerDirection() {
66
+ let manager = PNViewManager()
67
+ let view = manager.createView(tag: 3, props: [
68
+ "gestures": [
69
+ ["kind": "tap", "simultaneous": [], "wait_for": [1]],
70
+ ["kind": "swipe", "direction": "any", "simultaneous": [], "wait_for": []],
71
+ ],
72
+ ])
73
+ let recognizers = PNViewState.existing(for: view)?.gestureRecognizers ?? []
74
+ XCTAssertEqual(recognizers.count, 5, "one tap plus four single-direction swipes")
75
+ let coordinator = PNGestureCoordinator.shared
76
+ let swipes = recognizers.compactMap { $0 as? UISwipeGestureRecognizer }
77
+ XCTAssertEqual(swipes.map { coordinator.direction(of: $0) }, ["left", "right", "up", "down"])
78
+ XCTAssertEqual(swipes.map { $0.direction }, [.left, .right, .up, .down])
79
+ XCTAssertTrue(swipes.allSatisfy { coordinator.index(of: $0) == 1 }, "every recognizer reports the spec index")
80
+ XCTAssertNil(coordinator.direction(of: recognizers[0]))
81
+ }
82
+
83
+ func testAnimatorTimingParameters() {
84
+ let timing = PNAnimator.timingParameters(kind: "timing", spec: ["duration_ms": 250, "easing": "linear"])
85
+ XCTAssertEqual(timing.duration, 0.25, accuracy: 0.0001)
86
+ let spring = PNAnimator.timingParameters(kind: "spring", spec: ["stiffness": 100, "damping": 10, "mass": 1, "from": 0, "to": 1])
87
+ XCTAssertGreaterThan(spring.duration, 0.15)
88
+ XCTAssertTrue(spring.parameters is UISpringTimingParameters)
89
+ XCTAssertTrue(PNAnimator.curve(for: [0.1, 0.2, 0.3, 0.4]) is UICubicTimingParameters)
90
+ }
91
+
92
+ func testAnimatorSetAppliesImmediately() {
93
+ PNTransaction.apply("[[\"c\", 50, \"View\", {}]]")
94
+ _ = PNAnimator.shared.handle(tag: 50, request: ["op": "set", "prop": "opacity", "value": 0.25])
95
+ XCTAssertEqual(PNViewRegistry.shared.view(for: 50)?.alpha ?? 0, 0.25, accuracy: 0.001)
96
+ _ = PNAnimator.shared.handle(tag: 50, request: ["op": "set", "prop": "translate_x", "value": 12])
97
+ XCTAssertEqual(PNViewRegistry.shared.view(for: 50)?.transform.tx ?? 0, 12, accuracy: 0.001)
98
+ let rejected = PNAnimator.shared.handle(tag: 50, request: ["op": "start", "id": 1, "prop": "opacity", "spec": ["kind": "mystery"]])
99
+ XCTAssertEqual((rejected as? [String: Any])?["ok"] as? Bool, false)
100
+ }
101
+ }
@@ -0,0 +1,126 @@
1
+ import XCTest
2
+ @testable import PythonNativeKit
3
+
4
+ final class PNManagerTests: XCTestCase {
5
+ override func tearDown() {
6
+ PNViewRegistry.shared.removeAll()
7
+ super.tearDown()
8
+ }
9
+
10
+ func testViewManagerAppliesCommonProps() {
11
+ let manager = PNViewManager()
12
+ let view = manager.createView(tag: 1, props: [
13
+ "background_color": "#ff0000",
14
+ "opacity": 0.5,
15
+ "border_width": 2,
16
+ "border_color": "#00ff00",
17
+ "border_radius": 8,
18
+ "test_id": "hero",
19
+ "accessibility_label": "Hero card",
20
+ ])
21
+ XCTAssertEqual(view.alpha, 0.5, accuracy: 0.001)
22
+ XCTAssertEqual(view.layer.borderWidth, 2)
23
+ XCTAssertEqual(view.layer.cornerRadius, 8)
24
+ XCTAssertEqual(view.accessibilityIdentifier, "hero")
25
+ XCTAssertEqual(view.accessibilityLabel, "Hero card")
26
+ XCTAssertEqual(PNColor.hexString(view.backgroundColor ?? .clear).lowercased(), "#ffff0000")
27
+
28
+ manager.update(view: view, changed: ["opacity": 1, "background_color": NSNull(), "display": "none"])
29
+ XCTAssertEqual(view.alpha, 1, accuracy: 0.001)
30
+ XCTAssertTrue(view.isHidden)
31
+ XCTAssertNil(PNViewState.existing(for: view)?.props["background_color"])
32
+ XCTAssertEqual(PNProps.double(PNViewState.existing(for: view)?.props["opacity"]), 1)
33
+ }
34
+
35
+ func testTransformPropBuildsAffineTransform() {
36
+ let manager = PNViewManager()
37
+ let view = manager.createView(tag: 2, props: [
38
+ "transform": [["translate_x": 10], ["translate_y": 5], ["scale": 2]],
39
+ ])
40
+ XCTAssertEqual(view.transform.tx, 10, accuracy: 0.001)
41
+ XCTAssertEqual(view.transform.ty, 5, accuracy: 0.001)
42
+ XCTAssertEqual(view.transform.a, 2, accuracy: 0.001)
43
+ XCTAssertEqual(view.transform.d, 2, accuracy: 0.001)
44
+
45
+ manager.update(view: view, changed: ["transform": [["rotate": "90deg"]]])
46
+ XCTAssertEqual(view.transform.b, 1, accuracy: 0.001)
47
+ XCTAssertEqual(view.transform.a, 0, accuracy: 0.001)
48
+
49
+ manager.update(view: view, changed: ["transform": NSNull()])
50
+ XCTAssertTrue(view.transform.isIdentity)
51
+ }
52
+
53
+ func testFrameSurvivesTransform() {
54
+ let manager = PNViewManager()
55
+ let view = manager.createView(tag: 3, props: ["transform": [["scale": 2]]])
56
+ manager.setFrame(view: view, x: 10, y: 20, w: 100, h: 50)
57
+ XCTAssertEqual(view.bounds.size, CGSize(width: 100, height: 50))
58
+ XCTAssertEqual(view.center, CGPoint(x: 60, y: 45))
59
+ }
60
+
61
+ func testTextMeasureAndTransform() {
62
+ let manager = PNTextManager()
63
+ let view = manager.createView(tag: 4, props: ["text": "hello world", "font_size": 20, "text_transform": "uppercase"])
64
+ XCTAssertEqual((view as? UILabel)?.text, "HELLO WORLD")
65
+ let unconstrained = manager.measure(view: view, maxW: .infinity, maxH: .infinity)
66
+ XCTAssertGreaterThan(unconstrained.width, 50)
67
+ XCTAssertGreaterThan(unconstrained.height, 15)
68
+ let narrow = manager.measure(view: view, maxW: 60, maxH: 1e6)
69
+ XCTAssertLessThanOrEqual(narrow.width, 60)
70
+ XCTAssertGreaterThan(narrow.height, unconstrained.height, "wrapped text grows in height")
71
+ XCTAssertEqual(PNTextManager.transform("hello big world", mode: "capitalize"), "Hello Big World")
72
+ }
73
+
74
+ func testTextSpansProduceAttributedString() {
75
+ let manager = PNTextManager()
76
+ let view = manager.createView(tag: 5, props: [
77
+ "spans": [["text": "Hi "], ["text": "there", "bold": true, "color": "#ff0000"]],
78
+ ])
79
+ let label = view as? UILabel
80
+ XCTAssertEqual(label?.attributedText?.string, "Hi there")
81
+ var range = NSRange()
82
+ let color = label?.attributedText?.attribute(.foregroundColor, at: 3, effectiveRange: &range) as? UIColor
83
+ XCTAssertNotNil(color)
84
+ XCTAssertEqual(range.location, 3)
85
+ XCTAssertEqual(range.length, 5)
86
+ }
87
+
88
+ func testVirtualListBindsRowsThroughRegistry() {
89
+ PNTransaction.apply("[[\"c\", 40, \"View\", {\"background_color\": \"#123456\"}]]")
90
+ let manager = PNVirtualListManager()
91
+ guard let table = manager.createView(tag: 41, props: ["keys": ["a", "b", "c"], "revision": 1, "row_heights": [50.0, 50.0, 50.0]]) as? UICollectionView else {
92
+ return XCTFail("expected a collection view")
93
+ }
94
+ XCTAssertEqual(table.numberOfItems(inSection: 0), 3)
95
+ let delegate = table.delegate as? UICollectionViewDelegateFlowLayout
96
+ XCTAssertEqual(delegate?.collectionView?(table, layout: table.collectionViewLayout, sizeForItemAt: IndexPath(item: 1, section: 0)).height, 50)
97
+ manager.update(view: table, changed: ["row_heights": [10.0, 20.0, 30.0], "keys": ["a", "b", "c"], "revision": 2])
98
+ XCTAssertEqual(delegate?.collectionView?(table, layout: table.collectionViewLayout, sizeForItemAt: IndexPath(item: 2, section: 0)).height, 30)
99
+ manager.destroy(view: table)
100
+ }
101
+
102
+ func testScrollPayloadShape() {
103
+ let scroll = UIScrollView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
104
+ scroll.contentSize = CGSize(width: 100, height: 800)
105
+ scroll.contentOffset = CGPoint(x: 0, y: 40)
106
+ let payload = PNScrollPayload.make(scroll)
107
+ XCTAssertEqual(payload["y"] as? Double, 40)
108
+ XCTAssertEqual(payload["extent"] as? Double, 200)
109
+ XCTAssertEqual(payload["range"] as? Double, 800)
110
+ }
111
+
112
+ func testRegistryKnowsEveryBuiltinType() {
113
+ let names = PNRegistry.shared.componentNames
114
+ for type in ["View", "Column", "Row", "Text", "Button", "TextInput", "Image", "Switch", "ProgressBar",
115
+ "ActivityIndicator", "WebView", "Spacer", "ScrollView", "SafeAreaView", "Modal", "Portal",
116
+ "Slider", "TabBar", "Pressable", "StatusBar", "KeyboardAvoidingView", "Picker", "Checkbox",
117
+ "SegmentedControl", "DatePicker", "VirtualList"] {
118
+ XCTAssertTrue(names.contains(type), "missing manager for \(type)")
119
+ }
120
+ for module in ["Host", "Device", "Alert", "Storage", "SecureStore", "Clipboard", "Share", "Linking",
121
+ "Haptics", "Battery", "NetInfo", "AppState", "Permissions", "Notifications", "Camera",
122
+ "Location", "Biometrics"] {
123
+ XCTAssertTrue(PNRegistry.shared.moduleNames.contains(module), "missing module \(module)")
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,111 @@
1
+ import XCTest
2
+ @testable import PythonNativeKit
3
+
4
+ /// A module that settles inline or later depending on the method.
5
+ final class PNTestEchoModule: PNNativeModule {
6
+ static let name = "TestEcho"
7
+ static var pending: PNPromise?
8
+
9
+ init() {}
10
+
11
+ func call(_ method: String, args: [String: Any], promise: PNPromise) {
12
+ switch method {
13
+ case "echo": promise.resolve(args["value"])
14
+ case "fail": promise.reject("nope", code: "test_code")
15
+ case "later": PNTestEchoModule.pending = promise
16
+ default: promise.reject("unknown method \(method)")
17
+ }
18
+ }
19
+ }
20
+
21
+ final class PNModuleTests: XCTestCase {
22
+ override func setUp() {
23
+ super.setUp()
24
+ PNRegistry.shared.registerModule(PNTestEchoModule.self)
25
+ }
26
+
27
+ func testSynchronousResolveProducesOkEnvelope() {
28
+ let result = PNModuleDispatcher.shared.call(module: "TestEcho", method: "echo", envelope: ["call_id": 7, "args": ["value": 42]])
29
+ XCTAssertEqual(result["ok"] as? Bool, true)
30
+ XCTAssertEqual(result["value"] as? Int, 42)
31
+ XCTAssertNil(result["pending"])
32
+ }
33
+
34
+ func testRejectProducesErrorEnvelope() {
35
+ let result = PNModuleDispatcher.shared.call(module: "TestEcho", method: "fail", envelope: ["call_id": 8, "args": [:]])
36
+ XCTAssertEqual(result["ok"] as? Bool, false)
37
+ XCTAssertEqual(result["error"] as? String, "nope")
38
+ XCTAssertEqual(result["code"] as? String, "test_code")
39
+ }
40
+
41
+ func testUnknownModuleAndMethod() {
42
+ let missing = PNModuleDispatcher.shared.call(module: "Nope", method: "x", envelope: [:])
43
+ XCTAssertEqual(missing["ok"] as? Bool, false)
44
+ XCTAssertEqual(missing["code"] as? String, "unknown_module")
45
+ let method = PNModuleDispatcher.shared.call(module: "TestEcho", method: "zzz", envelope: [:])
46
+ XCTAssertEqual(method["ok"] as? Bool, false)
47
+ }
48
+
49
+ func testAsynchronousSettlementReturnsPending() {
50
+ let result = PNModuleDispatcher.shared.call(module: "TestEcho", method: "later", envelope: ["call_id": 9, "args": [:]])
51
+ XCTAssertEqual(result["pending"] as? Bool, true)
52
+ guard let promise = PNTestEchoModule.pending else { return XCTFail("promise not captured") }
53
+ XCTAssertFalse(promise.isSettled)
54
+ XCTAssertEqual(promise.callId, 9)
55
+ promise.resolve("done")
56
+ XCTAssertTrue(promise.isSettled)
57
+ promise.resolve("again")
58
+ XCTAssertEqual(promise.result?["value"] as? String, "done", "second settlement is ignored")
59
+ }
60
+
61
+ func testEnvelopeJSONRoundTrip() {
62
+ let ok = PNJSON.encode(["ok": true, "value": ["a": 1]])
63
+ let decoded = PNJSON.decodeObject(ok)
64
+ XCTAssertEqual(decoded["ok"] as? Bool, true)
65
+ XCTAssertEqual((decoded["value"] as? [String: Any])?["a"] as? Int, 1)
66
+ XCTAssertEqual(PNJSON.decodeObject(PNJSON.encode(["pending": true]))["pending"] as? Bool, true)
67
+ XCTAssertEqual(PNJSON.encode(Double.infinity), "null", "non-finite numbers never leave Swift as JSON numbers")
68
+ XCTAssertEqual(PNJSON.resolveInfinity("inf") as? Double, Double.infinity)
69
+ XCTAssertEqual(PNJSON.encode(nil), "null")
70
+ }
71
+
72
+ func testCancellationReleasesNativeWorkAndIgnoresLateCompletion() {
73
+ _ = PNModuleDispatcher.shared.call(module: "TestEcho", method: "later", envelope: ["call_id": 99, "args": [:]])
74
+ guard let promise = PNTestEchoModule.pending else { return XCTFail("missing promise") }
75
+ var cancelled = 0
76
+ promise.onCancel { cancelled += 1 }
77
+ _ = PNModuleDispatcher.shared.call(module: "TestEcho", method: "_pn_cancel", envelope: ["args": ["call_id": 99]])
78
+ promise.cancel()
79
+ promise.resolve("late")
80
+ XCTAssertTrue(promise.isCancelled)
81
+ XCTAssertEqual(cancelled, 1)
82
+ XCTAssertNil(promise.result)
83
+ }
84
+
85
+ func testDeviceInfoShape() {
86
+ let info = DeviceModule.info()
87
+ XCTAssertEqual(info["os"] as? String, "ios")
88
+ XCTAssertNotNil(info["os_version"])
89
+ XCTAssertNotNil(info["app_dir"])
90
+ XCTAssertNotNil(info["cache_dir"])
91
+ XCTAssertNotNil(info["scale"])
92
+ }
93
+
94
+ func testStorageModuleRoundTrip() {
95
+ let storage = StorageModule()
96
+ _ = PNModuleDispatcher.shared.call(module: "Storage", method: "clear", envelope: [:])
97
+ let set = PNPromise(callId: 1, module: "Storage", method: "set")
98
+ storage.call("set", args: ["key": "k", "value": "v"], promise: set)
99
+ let get = PNPromise(callId: 2, module: "Storage", method: "get")
100
+ storage.call("get", args: ["key": "k"], promise: get)
101
+ XCTAssertEqual(get.result?["value"] as? String, "v")
102
+ let keys = PNPromise(callId: 3, module: "Storage", method: "all_keys")
103
+ storage.call("all_keys", args: [:], promise: keys)
104
+ XCTAssertEqual(keys.result?["value"] as? [String], ["k"])
105
+ let del = PNPromise(callId: 4, module: "Storage", method: "delete")
106
+ storage.call("delete", args: ["key": "k"], promise: del)
107
+ let missing = PNPromise(callId: 5, module: "Storage", method: "get")
108
+ storage.call("get", args: ["key": "k"], promise: missing)
109
+ XCTAssertTrue(missing.result?["value"] is NSNull)
110
+ }
111
+ }
@@ -0,0 +1,91 @@
1
+ import XCTest
2
+ @testable import PythonNativeKit
3
+
4
+ final class PNTransactionTests: XCTestCase {
5
+ override func tearDown() {
6
+ PNViewRegistry.shared.removeAll()
7
+ super.tearDown()
8
+ }
9
+
10
+ func testDecodesEveryOpcode() throws {
11
+ let json = """
12
+ [["c", 1, "View", {"background_color": "#ff0000"}],
13
+ ["u", 1, {"opacity": 0.5}],
14
+ ["c", 2, "Text", {"text": "hi"}],
15
+ ["i", 1, 2, 0],
16
+ ["f", 2, 1.5, 2.5, 100, 20],
17
+ ["d", 2]]
18
+ """
19
+ let ops = try PNTransaction.decode(json)
20
+ XCTAssertEqual(ops.count, 6)
21
+ XCTAssertEqual(ops[0], .create(tag: 1, type: "View", props: ["background_color": "#ff0000"]))
22
+ XCTAssertEqual(ops[1], .update(tag: 1, changed: ["opacity": 0.5]))
23
+ XCTAssertEqual(ops[3], .insert(parent: 1, child: 2, index: 0))
24
+ XCTAssertEqual(ops[4], .frame(tag: 2, x: 1.5, y: 2.5, w: 100, h: 20))
25
+ XCTAssertEqual(ops[5], .destroy(tag: 2))
26
+ }
27
+
28
+ func testInfinityStringsBecomeInfinity() throws {
29
+ let ops = try PNTransaction.decode("[[\"c\", 5, \"View\", {\"max_width\": \"inf\", \"nested\": {\"h\": \"inf\"}}]]")
30
+ guard case let .create(_, _, props) = ops[0] else { return XCTFail("expected create") }
31
+ XCTAssertEqual(props["max_width"] as? Double, Double.infinity)
32
+ XCTAssertEqual((props["nested"] as? [String: Any])?["h"] as? Double, Double.infinity)
33
+ }
34
+
35
+ func testMalformedOpsAreSkippedNotFatal() throws {
36
+ let ops = try PNTransaction.decode("[[\"c\", 1, \"View\", {}], [\"zz\", 9], [\"u\"], 42, [\"d\", 1]]")
37
+ XCTAssertEqual(ops.count, 2)
38
+ XCTAssertEqual(ops[0], .create(tag: 1, type: "View", props: [:]))
39
+ XCTAssertEqual(ops[1], .destroy(tag: 1))
40
+ }
41
+
42
+ func testNonArrayDocumentThrows() {
43
+ XCTAssertThrowsError(try PNTransaction.decode("{\"not\": \"an array\"}"))
44
+ }
45
+
46
+ func testApplyBuildsHierarchyAndIsolatesFailures() {
47
+ PNTransaction.apply("""
48
+ [["c", 10, "View", {"background_color": "#00ff00"}],
49
+ ["c", 11, "Text", {"text": "hello"}],
50
+ ["u", 999, {"opacity": 0.1}],
51
+ ["i", 10, 11, 0],
52
+ ["i", 10, 12345, 0],
53
+ ["f", 11, 4, 8, 120, 30],
54
+ ["c", 13, "NoSuchType", {}]]
55
+ """)
56
+ let parent = PNViewRegistry.shared.view(for: 10)
57
+ let child = PNViewRegistry.shared.view(for: 11)
58
+ XCTAssertNotNil(parent)
59
+ XCTAssertNotNil(child)
60
+ XCTAssertTrue(child?.superview === parent)
61
+ XCTAssertEqual(child?.frame, CGRect(x: 4, y: 8, width: 120, height: 30))
62
+ XCTAssertNotNil(PNViewRegistry.shared.view(for: 13), "unknown types get a placeholder view")
63
+ XCTAssertEqual(PNViewRegistry.shared.resolve(13)?.typeName, "NoSuchType")
64
+
65
+ PNTransaction.apply("[[\"d\", 11]]")
66
+ XCTAssertNil(PNViewRegistry.shared.view(for: 11))
67
+ XCTAssertEqual(parent?.subviews.count, 0)
68
+ }
69
+
70
+ func testInsertIsMoveAwareAndClamps() {
71
+ PNTransaction.apply("""
72
+ [["c", 20, "View", {}], ["c", 21, "View", {}], ["c", 22, "View", {}], ["c", 23, "View", {}],
73
+ ["i", 20, 21, 0], ["i", 20, 22, 1], ["i", 20, 23, 99]]
74
+ """)
75
+ let parent = PNViewRegistry.shared.view(for: 20)
76
+ XCTAssertEqual(parent?.subviews.map { PNViewState.existing(for: $0)?.tag }, [21, 22, 23])
77
+ PNTransaction.apply("[[\"i\", 20, 23, 0]]")
78
+ XCTAssertEqual(parent?.subviews.map { PNViewState.existing(for: $0)?.tag }, [23, 21, 22])
79
+ XCTAssertEqual(parent?.subviews.count, 3)
80
+ }
81
+
82
+ func testFrameClampsNonFiniteValues() {
83
+ PNTransaction.apply("[[\"c\", 30, \"View\", {}]]")
84
+ guard let record = PNViewRegistry.shared.resolve(30) else { return XCTFail("missing view") }
85
+ record.manager.setFrame(view: record.view, x: .nan, y: 5, w: .infinity, h: -3)
86
+ XCTAssertEqual(record.view.frame.origin.x, 0)
87
+ XCTAssertEqual(record.view.frame.origin.y, 5)
88
+ XCTAssertEqual(record.view.frame.size.height, 0)
89
+ XCTAssertTrue(record.view.frame.size.width.isFinite)
90
+ }
91
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Facebook, Inc. and its affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+ let package = Package(
4
+ name: "YogaCore",
5
+ products: [.library(name: "YogaCore", targets: ["YogaCore"])],
6
+ targets: [.target(name: "YogaCore", path: ".", exclude: ["yoga/CMakeLists.txt", "yoga/module.modulemap"], sources: ["yoga", "style.cpp"],
7
+ publicHeadersPath: "include", cxxSettings: [.headerSearchPath(".")])],
8
+ cxxLanguageStandard: .cxx20
9
+ )
@@ -0,0 +1,2 @@
1
+ 3.2.1
2
+ https://github.com/react/yoga/releases/tag/v3.2.1
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+ #include <yoga/Yoga.h>
3
+ #ifdef __cplusplus
4
+ extern "C" {
5
+ #endif
6
+ // Returns false for an unsupported or invalid layout property.
7
+ bool PNYogaSetStyle(YGNodeRef node, const char* key, const char* value);
8
+ #ifdef __cplusplus
9
+ }
10
+ #endif
@@ -0,0 +1,5 @@
1
+ module YogaCore {
2
+ header "yoga/Yoga.h"
3
+ header "PNStyle.h"
4
+ export *
5
+ }