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,526 @@
1
+ """Native module registry: name -> callable module, on device or off.
2
+
3
+ A *native module* is a named bag of methods implemented in Swift and
4
+ Kotlin (``Camera``, ``Storage``, ``Haptics``, ...). Python facades in
5
+ this package never touch platform APIs; they obtain a
6
+ [`NativeModule`][pythonnative.native_modules.registry.NativeModule]
7
+ through [`native_module`][pythonnative.native_modules.registry.native_module]
8
+ and call methods on it:
9
+
10
+ ```python
11
+ _clipboard = native_module("Clipboard")
12
+ _clipboard.call("set_string", text="hello")
13
+ text = _clipboard.call("get_string")
14
+ result = await _camera.call_async("take_photo")
15
+ ```
16
+
17
+ On device the module is a
18
+ [`BridgeModule`][pythonnative.native_modules.registry.BridgeModule]
19
+ that speaks the ``call(module, method, args_json)`` protocol described
20
+ in ``docs/concepts/bridge.md``. Off device (tests, ``pn preview``) the
21
+ same name resolves to a
22
+ [`PythonModule`][pythonnative.native_modules.registry.PythonModule]
23
+ wrapping a plain Python object with the same method names; the
24
+ built-in fallbacks live in ``pythonnative.native_modules.fallback`` and
25
+ third-party packages register theirs through the
26
+ ``pythonnative.modules`` entry point group or
27
+ [`register_python_module`][pythonnative.native_modules.registry.register_python_module].
28
+
29
+ Modules can also push events (``AppState`` changes, deep links,
30
+ battery updates). Facades subscribe with
31
+ [`NativeModule.add_listener`][pythonnative.native_modules.registry.NativeModule.add_listener];
32
+ native delivers through
33
+ [`dispatch_module_message`][pythonnative.native_modules.registry.dispatch_module_message]
34
+ and Python implementations through
35
+ [`emit`][pythonnative.native_modules.registry.emit].
36
+ """
37
+
38
+ from __future__ import annotations
39
+
40
+ import asyncio
41
+ import inspect
42
+ import itertools
43
+ import threading
44
+ from typing import Any, Callable, Dict, List, Optional
45
+
46
+ from ..bridge import codec
47
+
48
+ __all__ = [
49
+ "ENTRY_POINT_GROUP",
50
+ "BridgeModule",
51
+ "NativeModule",
52
+ "NativeModuleError",
53
+ "PythonModule",
54
+ "dispatch_module_message",
55
+ "emit",
56
+ "native_module",
57
+ "on_event",
58
+ "register_python_module",
59
+ "unregister_python_module",
60
+ ]
61
+
62
+ ENTRY_POINT_GROUP = "pythonnative.modules"
63
+ """Entry-point group for Python (fallback / test) implementations of native modules."""
64
+
65
+ Listener = Callable[[Any], None]
66
+
67
+
68
+ class NativeModuleError(RuntimeError):
69
+ """A native module method failed.
70
+
71
+ Attributes:
72
+ module: Module name.
73
+ method: Method name.
74
+ code: Optional machine-readable code supplied by native.
75
+ """
76
+
77
+ def __init__(self, module: str, method: str, message: str, code: Optional[str] = None) -> None:
78
+ super().__init__(f"{module}.{method}: {message}")
79
+ self.module = module
80
+ self.method = method
81
+ self.message = message
82
+ self.code = code
83
+
84
+
85
+ class NativeModule:
86
+ """Common surface of bridge-backed and Python-backed modules."""
87
+
88
+ name: str
89
+
90
+ def __init__(self, name: str) -> None:
91
+ self.name = name
92
+ self._listeners: Dict[str, List[Listener]] = {}
93
+ self._lock = threading.Lock()
94
+
95
+ def call(self, method: str, **args: Any) -> Any:
96
+ """Invoke ``method`` synchronously and return its value.
97
+
98
+ Raises:
99
+ NativeModuleError: When the native side reports a failure.
100
+ RuntimeError: When the method only completes asynchronously
101
+ (use [`call_async`][pythonnative.native_modules.registry.NativeModule.call_async]).
102
+ """
103
+ raise NotImplementedError
104
+
105
+ async def call_async(self, method: str, **args: Any) -> Any:
106
+ """Invoke ``method`` and await its result."""
107
+ raise NotImplementedError
108
+
109
+ def add_listener(self, event: str, callback: Listener) -> Callable[[], None]:
110
+ """Subscribe to ``event``; returns an unsubscribe callable."""
111
+ with self._lock:
112
+ self._listeners.setdefault(event, []).append(callback)
113
+
114
+ def _remove() -> None:
115
+ with self._lock:
116
+ bucket = self._listeners.get(event)
117
+ if bucket is None:
118
+ return
119
+ try:
120
+ bucket.remove(callback)
121
+ except ValueError:
122
+ pass
123
+ if not bucket:
124
+ self._listeners.pop(event, None)
125
+
126
+ return _remove
127
+
128
+ def listener_count(self, event: Optional[str] = None) -> int:
129
+ """Number of listeners for ``event`` (or for every event when ``None``)."""
130
+ with self._lock:
131
+ if event is None:
132
+ return sum(len(b) for b in self._listeners.values())
133
+ return len(self._listeners.get(event, ()))
134
+
135
+ def _deliver(self, event: str, payload: Any) -> None:
136
+ with self._lock:
137
+ callbacks = list(self._listeners.get(event, ()))
138
+ for callback in callbacks:
139
+ try:
140
+ callback(payload)
141
+ except Exception:
142
+ from .. import diagnostics
143
+
144
+ diagnostics.swallowed(f"native_modules.{self.name}.{event}")
145
+
146
+
147
+ # ======================================================================
148
+ # Bridge-backed modules (device)
149
+ # ======================================================================
150
+
151
+ _call_ids = itertools.count(1)
152
+ _pending: Dict[int, "asyncio.Future[Any]"] = {}
153
+ _pending_meta: Dict[int, tuple] = {}
154
+ _pending_lock = threading.Lock()
155
+
156
+
157
+ class BridgeModule(NativeModule):
158
+ """A module implemented natively; every call crosses the bridge once."""
159
+
160
+ def __init__(self, name: str, transport: Any = None) -> None:
161
+ super().__init__(name)
162
+ self._transport = transport
163
+
164
+ @property
165
+ def transport(self) -> Any:
166
+ """The transport in use (resolved lazily on first access)."""
167
+ if self._transport is None:
168
+ from ..bridge import get_transport
169
+
170
+ self._transport = get_transport()
171
+ return self._transport
172
+
173
+ def _invoke(self, method: str, args: Dict[str, Any], call_id: int) -> Any:
174
+ envelope = codec.dumps({"call_id": call_id, "args": codec.to_jsonable(args)})
175
+ raw = self.transport.call(self.name, method, envelope)
176
+ result = codec.loads(raw)
177
+ if result is None:
178
+ return {"ok": True, "value": None}
179
+ if not isinstance(result, dict):
180
+ return {"ok": True, "value": result}
181
+ return result
182
+
183
+ def call(self, method: str, **args: Any) -> Any:
184
+ """Call a native module method with a ``{"call_id", "args"}`` envelope."""
185
+ result = self._invoke(method, args, 0)
186
+ if result.get("pending"):
187
+ raise RuntimeError(f"{self.name}.{method} completes asynchronously; use call_async()")
188
+ if result.get("ok", True):
189
+ return result.get("value")
190
+ raise NativeModuleError(self.name, method, str(result.get("error", "unknown error")), result.get("code"))
191
+
192
+ async def call_async(self, method: str, **args: Any) -> Any:
193
+ """Invoke ``method`` and await its result."""
194
+ loop = asyncio.get_running_loop()
195
+ call_id = next(_call_ids)
196
+ future: asyncio.Future[Any] = loop.create_future()
197
+ with _pending_lock:
198
+ _pending[call_id] = future
199
+ _pending_meta[call_id] = (self.name, method)
200
+ try:
201
+ result = self._invoke(method, args, call_id)
202
+ except Exception:
203
+ with _pending_lock:
204
+ _pending.pop(call_id, None)
205
+ _pending_meta.pop(call_id, None)
206
+ raise
207
+ if not result.get("pending"):
208
+ with _pending_lock:
209
+ _pending.pop(call_id, None)
210
+ _pending_meta.pop(call_id, None)
211
+ if result.get("ok", True):
212
+ return result.get("value")
213
+ raise NativeModuleError(self.name, method, str(result.get("error", "unknown error")), result.get("code"))
214
+ try:
215
+ return await future
216
+ except asyncio.CancelledError:
217
+ # Native implementations can release their work through the
218
+ # promise's cancellation hook; late settlements are discarded.
219
+ try:
220
+ self._invoke("_pn_cancel", {"call_id": call_id}, 0)
221
+ except Exception:
222
+ pass
223
+ raise
224
+ finally:
225
+ with _pending_lock:
226
+ _pending.pop(call_id, None)
227
+ _pending_meta.pop(call_id, None)
228
+
229
+
230
+ def _settle(call_id: int, message: Dict[str, Any]) -> None:
231
+ with _pending_lock:
232
+ future = _pending.pop(call_id, None)
233
+ meta = _pending_meta.pop(call_id, ("?", "?"))
234
+ if future is None:
235
+ return
236
+ from ..runtime import reject_future, resolve_future
237
+
238
+ if message.get("ok", True):
239
+ resolve_future(future, message.get("value"))
240
+ else:
241
+ module, method = meta
242
+ reject_future(
243
+ future, NativeModuleError(module, method, str(message.get("error", "unknown error")), message.get("code"))
244
+ )
245
+
246
+
247
+ # ======================================================================
248
+ # Python-backed modules (fallbacks / tests)
249
+ # ======================================================================
250
+
251
+
252
+ class PythonModule(NativeModule):
253
+ """A module implemented by a plain Python object.
254
+
255
+ Methods are looked up by name on ``impl``; keyword arguments are
256
+ forwarded. A method may be a coroutine function (or return an
257
+ awaitable), in which case ``call`` raises and ``call_async`` awaits
258
+ it. The implementation can push events with
259
+ [`emit`][pythonnative.native_modules.registry.emit].
260
+ """
261
+
262
+ def __init__(self, name: str, impl: Any = None) -> None:
263
+ super().__init__(name)
264
+ self._impl = impl
265
+
266
+ @property
267
+ def impl(self) -> Any:
268
+ """The implementation object, resolved on first use.
269
+
270
+ Facades call ``native_module()`` at import time, so resolution is
271
+ deferred until the first method call; by then the package's
272
+ fallback implementation (or entry point) has had a chance to
273
+ register.
274
+
275
+ Raises:
276
+ KeyError: If no implementation is registered for the module.
277
+ """
278
+ if self._impl is None:
279
+ self._impl = _resolve_python_impl(self.name)
280
+ return self._impl
281
+
282
+ def _method(self, method: str) -> Callable[..., Any]:
283
+ fn = getattr(self.impl, method, None)
284
+ if fn is None or not callable(fn):
285
+ raise NativeModuleError(self.name, method, "unknown method", code="unknown_method")
286
+ return fn
287
+
288
+ def call(self, method: str, **args: Any) -> Any:
289
+ """Call a native module method with a ``{"call_id", "args"}`` envelope."""
290
+ fn = self._method(method)
291
+ if inspect.iscoroutinefunction(fn):
292
+ raise RuntimeError(f"{self.name}.{method} is asynchronous; use call_async()")
293
+ try:
294
+ value = fn(**args)
295
+ except NativeModuleError:
296
+ raise
297
+ except Exception as exc:
298
+ raise NativeModuleError(self.name, method, str(exc)) from exc
299
+ if inspect.isawaitable(value):
300
+ raise RuntimeError(f"{self.name}.{method} returned an awaitable; use call_async()")
301
+ return value
302
+
303
+ async def call_async(self, method: str, **args: Any) -> Any:
304
+ """Invoke ``method`` and await its result."""
305
+ fn = self._method(method)
306
+ try:
307
+ value = fn(**args)
308
+ if inspect.isawaitable(value):
309
+ value = await value
310
+ except NativeModuleError:
311
+ raise
312
+ except Exception as exc:
313
+ raise NativeModuleError(self.name, method, str(exc)) from exc
314
+ return value
315
+
316
+
317
+ # ======================================================================
318
+ # Registry
319
+ # ======================================================================
320
+
321
+ _modules: Dict[str, NativeModule] = {}
322
+ _python_impls: Dict[str, Any] = {}
323
+ _registry_lock = threading.Lock()
324
+ _discovered = False
325
+
326
+
327
+ def register_python_module(name: str, impl: Any) -> None:
328
+ """Register ``impl`` as the off-device implementation of module ``name``.
329
+
330
+ ``impl`` is an object (or a zero-arg factory returning one) whose
331
+ methods match the module's method names. Registering replaces any
332
+ earlier implementation and invalidates the cached module so the
333
+ next [`native_module`][pythonnative.native_modules.registry.native_module]
334
+ call picks it up.
335
+ """
336
+ with _registry_lock:
337
+ _python_impls[name] = impl
338
+ _modules.pop(name, None)
339
+
340
+
341
+ def unregister_python_module(name: str) -> None:
342
+ """Remove a Python implementation registered for ``name`` (tests)."""
343
+ with _registry_lock:
344
+ _python_impls.pop(name, None)
345
+ _modules.pop(name, None)
346
+
347
+
348
+ def native_module(name: str) -> NativeModule:
349
+ """Return the module registered under ``name`` for the current platform.
350
+
351
+ On iOS and Android this is always a
352
+ [`BridgeModule`][pythonnative.native_modules.registry.BridgeModule];
353
+ the native runtime decides whether the module exists when a method
354
+ is first called. Elsewhere it is the registered
355
+ [`PythonModule`][pythonnative.native_modules.registry.PythonModule].
356
+
357
+ Off device the implementation is resolved lazily, on the first
358
+ method call, so facades can call this at import time; a missing
359
+ implementation surfaces then as ``KeyError``.
360
+ """
361
+ module = _modules.get(name)
362
+ if module is not None:
363
+ return module
364
+ with _registry_lock:
365
+ module = _modules.get(name)
366
+ if module is not None:
367
+ return module
368
+ module = _create(name)
369
+ _modules[name] = module
370
+ return module
371
+
372
+
373
+ def _create(name: str) -> NativeModule:
374
+ from ..bridge import has_transport
375
+
376
+ if has_transport():
377
+ return BridgeModule(name)
378
+ return PythonModule(name)
379
+
380
+
381
+ def _resolve_python_impl(name: str) -> Any:
382
+ _discover_entry_points()
383
+ with _registry_lock:
384
+ impl = _python_impls.get(name)
385
+ if impl is None:
386
+ from . import fallback
387
+
388
+ impl = fallback.default_implementation(name)
389
+ if impl is None:
390
+ raise KeyError(
391
+ f"No native module named {name!r} is available off device; register one with register_python_module()"
392
+ )
393
+ if inspect.isclass(impl) or inspect.isfunction(impl):
394
+ impl = impl()
395
+ return impl
396
+
397
+
398
+ def _discover_entry_points() -> None:
399
+ global _discovered
400
+ if _discovered:
401
+ return
402
+ _discovered = True
403
+ try:
404
+ from importlib.metadata import entry_points
405
+ except ImportError: # pragma: no cover
406
+ return
407
+ try:
408
+ eps = entry_points()
409
+ except Exception: # pragma: no cover
410
+ return
411
+ selected: List[Any] = []
412
+ if hasattr(eps, "select"):
413
+ try:
414
+ selected = list(eps.select(group=ENTRY_POINT_GROUP))
415
+ except Exception:
416
+ selected = []
417
+ if not selected:
418
+ getter = getattr(eps, "get", None)
419
+ if getter is not None:
420
+ try:
421
+ selected = list(getter(ENTRY_POINT_GROUP, []))
422
+ except Exception:
423
+ selected = []
424
+ for ep in selected:
425
+ try:
426
+ loaded = ep.load()
427
+ except Exception as exc: # pragma: no cover - defensive
428
+ import sys
429
+
430
+ print(
431
+ f"[pythonnative.native_modules] Failed to load module entry point {ep.name!r}: {exc!r}", file=sys.stderr
432
+ )
433
+ continue
434
+ module_name = getattr(loaded, "name", None) or ep.name
435
+ if inspect.isfunction(loaded):
436
+ try:
437
+ loaded()
438
+ except Exception as exc: # pragma: no cover - defensive
439
+ import sys
440
+
441
+ print(f"[pythonnative.native_modules] entry point {ep.name!r} raised: {exc!r}", file=sys.stderr)
442
+ continue
443
+ _python_impls.setdefault(str(module_name), loaded)
444
+
445
+
446
+ # ======================================================================
447
+ # Inbound messages and events
448
+ # ======================================================================
449
+
450
+
451
+ def dispatch_module_message(module: str, message: Dict[str, Any]) -> None:
452
+ """Route a native ``callback("module", ...)`` payload.
453
+
454
+ ``{"call_id": n, "ok": ..., "value"|"error": ...}`` settles a
455
+ pending ``call_async``; ``{"event": name, "payload": ...}`` fans
456
+ out to listeners.
457
+ """
458
+ if not isinstance(message, dict):
459
+ return
460
+ if "call_id" in message:
461
+ try:
462
+ _settle(int(message["call_id"]), message)
463
+ except (TypeError, ValueError):
464
+ pass
465
+ return
466
+ event = message.get("event")
467
+ if event:
468
+ emit(module, str(event), message.get("payload"))
469
+
470
+
471
+ _hooks: Dict[tuple, List[Listener]] = {}
472
+
473
+
474
+ def on_event(module: str, event: str, callback: Listener) -> Callable[[], None]:
475
+ """Subscribe to ``module``/``event`` without resolving the module.
476
+
477
+ Facades use this at import time to route native pushes (``AppState``
478
+ ``change``, ``Linking`` ``url``, ...) into their own listener lists.
479
+ Unlike [`NativeModule.add_listener`][pythonnative.native_modules.registry.NativeModule.add_listener]
480
+ the subscription survives module re-creation and never touches the
481
+ platform. Returns an unsubscribe callable.
482
+ """
483
+ key = (module, event)
484
+ with _registry_lock:
485
+ _hooks.setdefault(key, []).append(callback)
486
+
487
+ def _remove() -> None:
488
+ with _registry_lock:
489
+ bucket = _hooks.get(key)
490
+ if bucket and callback in bucket:
491
+ bucket.remove(callback)
492
+
493
+ return _remove
494
+
495
+
496
+ def emit(module: str, event: str, payload: Any = None) -> None:
497
+ """Deliver ``event`` to every listener of ``module`` (any platform).
498
+
499
+ Python implementations use this to behave like their native
500
+ counterparts (a test can emit ``AppState`` ``change`` events, for
501
+ example).
502
+ """
503
+ with _registry_lock:
504
+ hooks = list(_hooks.get((module, event), ()))
505
+ for hook in hooks:
506
+ try:
507
+ hook(payload)
508
+ except Exception:
509
+ from .. import diagnostics
510
+
511
+ diagnostics.swallowed(f"native_modules.{module}.{event}")
512
+ target = _modules.get(module)
513
+ if target is not None:
514
+ target._deliver(event, payload)
515
+
516
+
517
+ def _reset_for_tests() -> None:
518
+ """Forget cached modules and pending calls (test isolation)."""
519
+ global _discovered
520
+ with _registry_lock:
521
+ _modules.clear()
522
+ _python_impls.clear()
523
+ _discovered = False
524
+ with _pending_lock:
525
+ _pending.clear()
526
+ _pending_meta.clear()
@@ -0,0 +1,52 @@
1
+ """Encrypted key/value storage for secrets (tokens, credentials).
2
+
3
+ [`SecureStore`][pythonnative.SecureStore] persists small string values
4
+ in the iOS Keychain and Android ``EncryptedSharedPreferences`` (the
5
+ native ``SecureStore`` module), the right place for auth tokens and
6
+ other secrets that [`AsyncStorage`][pythonnative.AsyncStorage] (plain,
7
+ unencrypted) should never hold.
8
+
9
+ Both backing stores complete on the calling thread, so every method is
10
+ synchronous. Reads return ``Optional[str]``; writes return nothing and
11
+ raise on failure. Off device the module falls back to an in-process dict
12
+ so code paths stay exercisable without a device Keychain.
13
+
14
+ Example:
15
+ ```python
16
+ import pythonnative as pn
17
+
18
+ pn.SecureStore.set_item("token", "abc123")
19
+ token = pn.SecureStore.get_item("token")
20
+ ```
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from typing import Optional
26
+
27
+ from .registry import native_module
28
+
29
+
30
+ class SecureStore:
31
+ """Encrypted secret storage (synchronous).
32
+
33
+ Raises:
34
+ NativeModuleError: If the Keychain / EncryptedSharedPreferences
35
+ operation fails (for example a Keychain entitlement problem).
36
+ """
37
+
38
+ @staticmethod
39
+ def set_item(key: str, value: str) -> None:
40
+ """Store ``value`` under ``key``, replacing any previous value."""
41
+ native_module("SecureStore").call("set_item", key=key, value=value)
42
+
43
+ @staticmethod
44
+ def get_item(key: str) -> Optional[str]:
45
+ """Return the value for ``key``, or ``None`` if absent."""
46
+ value = native_module("SecureStore").call("get_item", key=key)
47
+ return None if value is None else str(value)
48
+
49
+ @staticmethod
50
+ def delete_item(key: str) -> bool:
51
+ """Delete ``key``. Returns ``True`` if it existed, ``False`` if there was nothing to delete."""
52
+ return bool(native_module("SecureStore").call("delete_item", key=key))
@@ -0,0 +1,51 @@
1
+ """Present the system share sheet.
2
+
3
+ [`Share.share`][pythonnative.Share] is a coroutine that opens
4
+ ``UIActivityViewController`` (iOS) or an ``ACTION_SEND`` chooser
5
+ (Android) through the native ``Share`` module and resolves to ``True``
6
+ once the user completes a share or ``False`` if they dismiss it.
7
+
8
+ Example:
9
+ ```python
10
+ import pythonnative as pn
11
+
12
+ async def share_link():
13
+ await pn.Share.share(
14
+ message="Check out PythonNative!",
15
+ url="https://example.com",
16
+ )
17
+ ```
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from typing import Optional
23
+
24
+ from .registry import native_module
25
+
26
+
27
+ class Share:
28
+ """System share-sheet interface."""
29
+
30
+ @staticmethod
31
+ async def share(
32
+ *,
33
+ message: Optional[str] = None,
34
+ url: Optional[str] = None,
35
+ title: Optional[str] = None,
36
+ ) -> bool:
37
+ """Open the share sheet with ``message`` / ``url``.
38
+
39
+ Args:
40
+ message: Text body to share.
41
+ url: A URL to share (combined with ``message`` on Android).
42
+ title: Chooser title (Android) / subject (iOS mail).
43
+
44
+ Returns:
45
+ ``True`` if the user completed a share, ``False`` if they
46
+ dismissed the sheet or the platform has no share UI (tests).
47
+
48
+ Raises:
49
+ NativeModuleError: If the sheet could not be presented.
50
+ """
51
+ return bool(await native_module("Share").call_async("share", message=message, url=url, title=title))