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.
- pythonnative/__init__.py +411 -0
- pythonnative/_ios_log.py +92 -0
- pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
- pythonnative/alerts.py +236 -0
- pythonnative/animated.py +1687 -0
- pythonnative/animation_graph.py +78 -0
- pythonnative/appearance.py +124 -0
- pythonnative/bootstrap.py +100 -0
- pythonnative/bridge/__init__.py +302 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +170 -0
- pythonnative/bridge/commits.py +114 -0
- pythonnative/bridge/fake.py +243 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/bridge/web.py +489 -0
- pythonnative/cli/__init__.py +7 -0
- pythonnative/cli/pn.py +1214 -0
- pythonnative/component.py +271 -0
- pythonnative/components/__init__.py +111 -0
- pythonnative/components/_base.py +166 -0
- pythonnative/components/controls.py +521 -0
- pythonnative/components/layout.py +518 -0
- pythonnative/components/lists.py +785 -0
- pythonnative/components/media.py +204 -0
- pythonnative/components/overlays.py +107 -0
- pythonnative/components/pressable.py +252 -0
- pythonnative/components/structural.py +167 -0
- pythonnative/components/text.py +291 -0
- pythonnative/devclient.py +824 -0
- pythonnative/devserver/__init__.py +34 -0
- pythonnative/devserver/server.py +718 -0
- pythonnative/devserver/static/animation_graph.js +82 -0
- pythonnative/devserver/static/bridge.js +147 -0
- pythonnative/devserver/static/colors.js +70 -0
- pythonnative/devserver/static/host.js +552 -0
- pythonnative/devserver/static/index.html +60 -0
- pythonnative/devserver/static/layout.js +85 -0
- pythonnative/devserver/static/preview.css +415 -0
- pythonnative/devserver/static/renderer.js +1994 -0
- pythonnative/devserver/static/shell.js +345 -0
- pythonnative/devserver/static/yoga/LICENSE +21 -0
- pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
- pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
- pythonnative/devserver/static/yoga/src/index.js +16 -0
- pythonnative/devserver/static/yoga/src/index.js.map +1 -0
- pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
- pythonnative/devserver/static/yoga/src/load.js +17 -0
- pythonnative/devserver/static/yoga/src/load.js.map +1 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
- pythonnative/devserver/watcher.py +267 -0
- pythonnative/devserver/ws.py +421 -0
- pythonnative/diagnostics.py +241 -0
- pythonnative/element.py +159 -0
- pythonnative/equality.py +19 -0
- pythonnative/events.py +231 -0
- pythonnative/gestures.py +1333 -0
- pythonnative/hooks.py +1621 -0
- pythonnative/hosts/__init__.py +63 -0
- pythonnative/hosts/base.py +596 -0
- pythonnative/hosts/native.py +302 -0
- pythonnative/hot_reload.py +585 -0
- pythonnative/layout.py +328 -0
- pythonnative/mutations.py +142 -0
- pythonnative/native/android/build.gradle +52 -0
- pythonnative/native/android/gradle.properties +3 -0
- pythonnative/native/android/settings.gradle +12 -0
- pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
- pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
- pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
- pythonnative/native/ios/Package.swift +23 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/native/yoga/LICENSE +21 -0
- pythonnative/native/yoga/Package.swift +9 -0
- pythonnative/native/yoga/VENDORED.md +2 -0
- pythonnative/native/yoga/include/PNStyle.h +10 -0
- pythonnative/native/yoga/include/module.modulemap +5 -0
- pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/python.cpp +16 -0
- pythonnative/native/yoga/style.cpp +272 -0
- pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
- pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
- pythonnative/native/yoga/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
- pythonnative/native/yoga/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
- pythonnative/native/yoga/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
- pythonnative/native/yoga/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
- pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
- pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
- pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
- pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
- pythonnative/native/yoga/yoga/config/Config.h +92 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
- pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
- pythonnative/native/yoga/yoga/debug/Log.h +34 -0
- pythonnative/native/yoga/yoga/enums/Align.h +47 -0
- pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
- pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
- pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
- pythonnative/native/yoga/yoga/enums/Display.h +41 -0
- pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
- pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
- pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
- pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
- pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
- pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
- pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
- pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
- pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
- pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
- pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
- pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
- pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
- pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
- pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
- pythonnative/native/yoga/yoga/event/event.cpp +87 -0
- pythonnative/native/yoga/yoga/event/event.h +130 -0
- pythonnative/native/yoga/yoga/module.modulemap +21 -0
- pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
- pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
- pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
- pythonnative/native/yoga/yoga/node/Node.h +337 -0
- pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
- pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
- pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
- pythonnative/native/yoga/yoga/style/Style.h +757 -0
- pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
- pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
- pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
- pythonnative/native_modules/__init__.py +124 -0
- pythonnative/native_modules/app_state.py +99 -0
- pythonnative/native_modules/battery.py +75 -0
- pythonnative/native_modules/biometrics.py +42 -0
- pythonnative/native_modules/camera.py +65 -0
- pythonnative/native_modules/clipboard.py +46 -0
- pythonnative/native_modules/fallback.py +324 -0
- pythonnative/native_modules/file_system.py +145 -0
- pythonnative/native_modules/haptics.py +75 -0
- pythonnative/native_modules/linking.py +123 -0
- pythonnative/native_modules/location.py +75 -0
- pythonnative/native_modules/net_info.py +112 -0
- pythonnative/native_modules/notifications.py +129 -0
- pythonnative/native_modules/permissions.py +108 -0
- pythonnative/native_modules/registry.py +526 -0
- pythonnative/native_modules/secure_store.py +52 -0
- pythonnative/native_modules/share.py +51 -0
- pythonnative/native_views/__init__.py +375 -0
- pythonnative/native_views/base.py +316 -0
- pythonnative/native_views/bridge_backend.py +277 -0
- pythonnative/navigation/__init__.py +103 -0
- pythonnative/navigation/container.py +154 -0
- pythonnative/navigation/handle.py +540 -0
- pythonnative/navigation/hooks.py +133 -0
- pythonnative/navigation/host.py +58 -0
- pythonnative/navigation/linking.py +200 -0
- pythonnative/navigation/navigators.py +659 -0
- pythonnative/navigation/screen.py +149 -0
- pythonnative/navigation/state.py +269 -0
- pythonnative/net.py +248 -0
- pythonnative/platform.py +166 -0
- pythonnative/platform_metrics.py +252 -0
- pythonnative/preview.py +287 -0
- pythonnative/profiling.py +101 -0
- pythonnative/project/__init__.py +68 -0
- pythonnative/project/android.py +557 -0
- pythonnative/project/builder.py +817 -0
- pythonnative/project/config.py +773 -0
- pythonnative/project/deps.py +719 -0
- pythonnative/project/devices.py +304 -0
- pythonnative/project/doctor.py +283 -0
- pythonnative/project/fingerprint.py +171 -0
- pythonnative/project/icons.py +247 -0
- pythonnative/project/ios.py +325 -0
- pythonnative/project/lockfile.py +100 -0
- pythonnative/project/permissions.py +361 -0
- pythonnative/project/plugins.py +519 -0
- pythonnative/project/runtime_assets.py +183 -0
- pythonnative/py.typed +0 -0
- pythonnative/query.py +153 -0
- pythonnative/reconciler/__init__.py +29 -0
- pythonnative/reconciler/boundaries.py +375 -0
- pythonnative/reconciler/children.py +88 -0
- pythonnative/reconciler/core.py +1165 -0
- pythonnative/reconciler/layout_pass.py +393 -0
- pythonnative/reconciler/vnode.py +266 -0
- pythonnative/refresh.py +55 -0
- pythonnative/runtime.py +306 -0
- pythonnative/scheduler.py +159 -0
- pythonnative/sdk/__init__.py +153 -0
- pythonnative/sdk/_components.py +427 -0
- pythonnative/sdk/builtins.py +91 -0
- pythonnative/sdk/codegen.py +149 -0
- pythonnative/sdk/module_codegen.py +184 -0
- pythonnative/sdk/schema.py +224 -0
- pythonnative/sdk/templates/contracts.kt +46 -0
- pythonnative/sdk/templates/contracts.swift +46 -0
- pythonnative/storage.py +184 -0
- pythonnative/style.py +841 -0
- pythonnative/suspense.py +183 -0
- pythonnative/templates/android_template/app/build.gradle +75 -0
- pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
- pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
- pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
- pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
- pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
- pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
- pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
- pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
- pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
- pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
- pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
- pythonnative/templates/android_template/build.gradle +10 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
- pythonnative/templates/android_template/gradle.properties +23 -0
- pythonnative/templates/android_template/gradlew +185 -0
- pythonnative/templates/android_template/gradlew.bat +89 -0
- pythonnative/templates/android_template/settings.gradle +17 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
- pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
- pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
- pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
- pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
- pythonnative/testing/__init__.py +53 -0
- pythonnative/testing/backend.py +276 -0
- pythonnative/testing/harness.py +369 -0
- pythonnative/utils.py +145 -0
- pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
- pythonnative-0.40.0.dist-info/METADATA +150 -0
- pythonnative-0.40.0.dist-info/RECORD +418 -0
- pythonnative-0.40.0.dist-info/WHEEL +5 -0
- pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
- pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
- pythonnative-0.40.0.dist-info/top_level.txt +1 -0
- pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Portable animation expressions evaluated by the native UI thread."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def serialize(root: Any) -> dict[str, Any]:
|
|
9
|
+
"""Serialize one connected animation graph in dependency order."""
|
|
10
|
+
from .animated import AnimatedInterpolation, AnimatedNode, AnimatedValue, _AnimatedDiffClamp, _AnimatedOperation
|
|
11
|
+
|
|
12
|
+
connected: dict[int, Any] = {}
|
|
13
|
+
|
|
14
|
+
def discover(node: Any) -> None:
|
|
15
|
+
if not isinstance(node, AnimatedNode) or id(node) in connected:
|
|
16
|
+
return
|
|
17
|
+
connected[id(node)] = node
|
|
18
|
+
for child in list(node._children):
|
|
19
|
+
discover(child)
|
|
20
|
+
for parent in getattr(node, "_parents", [getattr(node, "_parent", None)]):
|
|
21
|
+
discover(parent)
|
|
22
|
+
|
|
23
|
+
discover(root)
|
|
24
|
+
encoded: dict[int, dict[str, Any]] = {}
|
|
25
|
+
|
|
26
|
+
def encode(node: Any) -> Any:
|
|
27
|
+
if not isinstance(node, AnimatedNode):
|
|
28
|
+
return {"constant": float(node)}
|
|
29
|
+
identity = id(node)
|
|
30
|
+
if identity not in encoded:
|
|
31
|
+
definition: dict[str, Any] = {"id": identity}
|
|
32
|
+
if isinstance(node, AnimatedValue):
|
|
33
|
+
definition.update(kind="value", value=node.value)
|
|
34
|
+
elif isinstance(node, AnimatedInterpolation):
|
|
35
|
+
definition.update(
|
|
36
|
+
kind="interpolate",
|
|
37
|
+
inputs=[encode(node._parent)],
|
|
38
|
+
ranges=node._inputs,
|
|
39
|
+
outputs=node._outputs,
|
|
40
|
+
color=node._kind == "color",
|
|
41
|
+
left=node._left,
|
|
42
|
+
right=node._right,
|
|
43
|
+
)
|
|
44
|
+
elif isinstance(node, _AnimatedOperation):
|
|
45
|
+
definition.update(kind=node._op, inputs=[encode(parent) for parent in node._parents])
|
|
46
|
+
elif isinstance(node, _AnimatedDiffClamp):
|
|
47
|
+
definition.update(
|
|
48
|
+
kind="diff_clamp",
|
|
49
|
+
inputs=[encode(node._parent)],
|
|
50
|
+
minimum=node._min,
|
|
51
|
+
maximum=node._max,
|
|
52
|
+
previous=node._last_input,
|
|
53
|
+
value=node.value,
|
|
54
|
+
)
|
|
55
|
+
else:
|
|
56
|
+
raise TypeError(f"Unsupported animated node {type(node).__name__}")
|
|
57
|
+
encoded[identity] = definition
|
|
58
|
+
return {"node": identity}
|
|
59
|
+
|
|
60
|
+
for node in connected.values():
|
|
61
|
+
encode(node)
|
|
62
|
+
bindings = [[tag, prop, id(node)] for node in connected.values() for tag, prop in node.attachments()]
|
|
63
|
+
return {"id": min(connected), "nodes": list(encoded.values()), "bindings": bindings}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def install(node: Any, *, detached_tag: int | None = None) -> dict[str, Any] | None:
|
|
67
|
+
"""Synchronize native graph ownership when a binding is attached or removed."""
|
|
68
|
+
from .animated import _backend
|
|
69
|
+
|
|
70
|
+
backend = _backend()
|
|
71
|
+
handler = getattr(backend, "install_animation_graph", None)
|
|
72
|
+
if handler is None:
|
|
73
|
+
return None
|
|
74
|
+
graph = serialize(node)
|
|
75
|
+
tag = graph["bindings"][0][0] if graph["bindings"] else detached_tag
|
|
76
|
+
if tag is not None:
|
|
77
|
+
handler(tag, graph)
|
|
78
|
+
return graph
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""System color-scheme (light / dark mode) tracking.
|
|
2
|
+
|
|
3
|
+
The platform screen host publishes the operating system's current
|
|
4
|
+
appearance here (Android: ``Configuration.uiMode``; iOS:
|
|
5
|
+
``UITraitCollection.userInterfaceStyle``), and components read it back
|
|
6
|
+
through [`use_color_scheme`][pythonnative.use_color_scheme] or
|
|
7
|
+
[`use_theme`][pythonnative.use_theme], both of which re-render when
|
|
8
|
+
the scheme changes.
|
|
9
|
+
|
|
10
|
+
Apps can also *override* the scheme (e.g. an in-app appearance
|
|
11
|
+
setting) with [`set_color_scheme`][pythonnative.appearance.set_color_scheme];
|
|
12
|
+
the override wins over the system value until cleared with ``None``.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
>>> from pythonnative import appearance
|
|
16
|
+
>>> appearance.get_color_scheme()
|
|
17
|
+
'light'
|
|
18
|
+
>>> appearance.set_color_scheme("dark") # app-level override
|
|
19
|
+
>>> appearance.get_color_scheme()
|
|
20
|
+
'dark'
|
|
21
|
+
>>> appearance.set_color_scheme(None) # follow the system again
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import threading
|
|
27
|
+
from typing import Callable, List, Literal, Optional
|
|
28
|
+
|
|
29
|
+
ColorScheme = Literal["light", "dark"]
|
|
30
|
+
"""The two supported appearance values."""
|
|
31
|
+
|
|
32
|
+
_system_scheme: str = "light"
|
|
33
|
+
_override_scheme: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
_subscribers: List[Callable[[], None]] = []
|
|
36
|
+
_subscribers_lock = threading.Lock()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _notify_subscribers() -> None:
|
|
40
|
+
"""Invoke every registered subscriber, swallowing exceptions."""
|
|
41
|
+
with _subscribers_lock:
|
|
42
|
+
callbacks = list(_subscribers)
|
|
43
|
+
for cb in callbacks:
|
|
44
|
+
try:
|
|
45
|
+
cb()
|
|
46
|
+
except Exception:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def subscribe(callback: Callable[[], None]) -> Callable[[], None]:
|
|
51
|
+
"""Register ``callback`` to fire whenever the effective scheme changes.
|
|
52
|
+
|
|
53
|
+
Returns an unsubscribe function. Threadsafe.
|
|
54
|
+
"""
|
|
55
|
+
with _subscribers_lock:
|
|
56
|
+
_subscribers.append(callback)
|
|
57
|
+
|
|
58
|
+
def _unsub() -> None:
|
|
59
|
+
with _subscribers_lock:
|
|
60
|
+
try:
|
|
61
|
+
_subscribers.remove(callback)
|
|
62
|
+
except ValueError:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
return _unsub
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _coerce(scheme: object) -> Optional[str]:
|
|
69
|
+
if scheme in ("light", "dark"):
|
|
70
|
+
return str(scheme)
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def set_system_color_scheme(scheme: str) -> None:
|
|
75
|
+
"""Publish the operating system's current scheme.
|
|
76
|
+
|
|
77
|
+
Called by the platform screen host on create/resume and whenever
|
|
78
|
+
the system reports an appearance change. Invalid values are
|
|
79
|
+
ignored. Subscribers are only notified when the *effective* scheme
|
|
80
|
+
(after any app override) actually changes.
|
|
81
|
+
"""
|
|
82
|
+
global _system_scheme
|
|
83
|
+
coerced = _coerce(scheme)
|
|
84
|
+
if coerced is None or coerced == _system_scheme:
|
|
85
|
+
return
|
|
86
|
+
effective_before = get_color_scheme()
|
|
87
|
+
_system_scheme = coerced
|
|
88
|
+
if get_color_scheme() != effective_before:
|
|
89
|
+
_notify_subscribers()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def set_color_scheme(scheme: Optional[str]) -> None:
|
|
93
|
+
"""Set (or clear) the app-level scheme override.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
scheme: ``"light"`` or ``"dark"`` to force that appearance
|
|
97
|
+
regardless of the system setting, or ``None`` to follow
|
|
98
|
+
the system again.
|
|
99
|
+
"""
|
|
100
|
+
global _override_scheme
|
|
101
|
+
coerced = _coerce(scheme) if scheme is not None else None
|
|
102
|
+
if scheme is not None and coerced is None:
|
|
103
|
+
return
|
|
104
|
+
effective_before = get_color_scheme()
|
|
105
|
+
_override_scheme = coerced
|
|
106
|
+
if get_color_scheme() != effective_before:
|
|
107
|
+
_notify_subscribers()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_color_scheme() -> str:
|
|
111
|
+
"""Return the effective scheme: the app override if set, else the system value."""
|
|
112
|
+
return _override_scheme if _override_scheme is not None else _system_scheme
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_system_color_scheme() -> str:
|
|
116
|
+
"""Return the system-reported scheme, ignoring any app override."""
|
|
117
|
+
return _system_scheme
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def reset_color_scheme() -> None:
|
|
121
|
+
"""Reset to system ``"light"`` with no override. Intended for tests."""
|
|
122
|
+
global _system_scheme, _override_scheme
|
|
123
|
+
_system_scheme = "light"
|
|
124
|
+
_override_scheme = None
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Entry point the native app templates run right after Python starts.
|
|
2
|
+
|
|
3
|
+
Both templates execute one line of Python once the interpreter is up:
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
import pythonnative.bootstrap; pythonnative.bootstrap.start()
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
[`start`][pythonnative.bootstrap.start] connects the two halves of the
|
|
10
|
+
bridge (installing the native -> Python callback on iOS), verifies the
|
|
11
|
+
protocol version, routes ``print()`` to the console on iOS, warms the
|
|
12
|
+
asyncio runtime, and, in debug builds, starts the dev client that syncs
|
|
13
|
+
sources from ``pn start``. From then on the native runtime drives
|
|
14
|
+
everything through ``callback("host", ...)``; see ``docs/concepts/bridge.md``.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
import traceback
|
|
22
|
+
from typing import Any, Dict
|
|
23
|
+
|
|
24
|
+
__all__ = ["start", "status"]
|
|
25
|
+
|
|
26
|
+
_started: Dict[str, Any] = {}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def start(dev: bool = False, strict: bool = False) -> Dict[str, Any]:
|
|
30
|
+
"""Connect the bridge and prepare the runtime.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
dev: Enable dev mode (RedBox, validation warnings, the dev
|
|
34
|
+
client). Debug templates pass ``True``.
|
|
35
|
+
strict: Re-raise the failure after recording it. The templates
|
|
36
|
+
pass ``True`` so a broken bridge surfaces as a bootstrap
|
|
37
|
+
error screen with the full traceback.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
A status dict (``{"protocol": 2, "platform": "ios"}``) that the
|
|
41
|
+
template logs. Unless ``strict`` is set this never raises:
|
|
42
|
+
failures are printed and reported in the dict under
|
|
43
|
+
``"error"``.
|
|
44
|
+
"""
|
|
45
|
+
global _started
|
|
46
|
+
if _started and "error" not in _started:
|
|
47
|
+
return dict(_started)
|
|
48
|
+
status_: Dict[str, Any] = {"platform": None, "protocol": None}
|
|
49
|
+
try:
|
|
50
|
+
from .utils import IS_ANDROID, IS_IOS
|
|
51
|
+
|
|
52
|
+
status_["platform"] = "ios" if IS_IOS else "android" if IS_ANDROID else "off-device"
|
|
53
|
+
if IS_IOS:
|
|
54
|
+
try:
|
|
55
|
+
from . import _ios_log
|
|
56
|
+
|
|
57
|
+
_ios_log.install()
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
from .runtime import start as start_runtime
|
|
61
|
+
|
|
62
|
+
start_runtime()
|
|
63
|
+
from .sdk.schema import load_bundled_contracts
|
|
64
|
+
|
|
65
|
+
load_bundled_contracts()
|
|
66
|
+
from . import bridge
|
|
67
|
+
|
|
68
|
+
status_["protocol"] = bridge.handshake()
|
|
69
|
+
dev_mode = bool(dev or os.environ.get("PN_DEV") in ("1", "true"))
|
|
70
|
+
if dev_mode:
|
|
71
|
+
from . import diagnostics
|
|
72
|
+
|
|
73
|
+
diagnostics.set_dev_mode(True)
|
|
74
|
+
# Import the view backend eagerly: on a slow device the first
|
|
75
|
+
# commit shouldn't also pay for importing the reconciler.
|
|
76
|
+
from .native_views import get_registry
|
|
77
|
+
|
|
78
|
+
get_registry()
|
|
79
|
+
if dev_mode:
|
|
80
|
+
# Debug builds are dev clients: connect to `pn start` when
|
|
81
|
+
# the build (or a remembered connection) names a server.
|
|
82
|
+
from . import devclient
|
|
83
|
+
|
|
84
|
+
client = devclient.start_if_configured()
|
|
85
|
+
status_["dev_server"] = client.url if client is not None else None
|
|
86
|
+
except Exception as exc:
|
|
87
|
+
status_["error"] = f"{type(exc).__name__}: {exc}"
|
|
88
|
+
print(f"[pn.bootstrap] start failed: {exc!r}", file=sys.stderr)
|
|
89
|
+
traceback.print_exc()
|
|
90
|
+
_started = status_
|
|
91
|
+
if strict:
|
|
92
|
+
raise
|
|
93
|
+
return dict(status_)
|
|
94
|
+
_started = status_
|
|
95
|
+
return dict(status_)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def status() -> Dict[str, Any]:
|
|
99
|
+
"""Return the result of the last [`start`][pythonnative.bootstrap.start] (empty before it ran)."""
|
|
100
|
+
return dict(_started)
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""The native bridge: one channel between Python and Swift / Kotlin.
|
|
2
|
+
|
|
3
|
+
Everything that crosses into native code goes through a
|
|
4
|
+
[`Transport`][pythonnative.bridge.Transport] (``apply`` a transaction,
|
|
5
|
+
``measure`` a view, run a ``command``, drive an ``animate`` request, or
|
|
6
|
+
``call`` a native module), and everything native sends back arrives at
|
|
7
|
+
[`native_callback`][pythonnative.bridge.native_callback]. The protocol
|
|
8
|
+
is documented in ``docs/concepts/bridge.md``.
|
|
9
|
+
|
|
10
|
+
Under ``pn preview`` the native side is a browser page, reached through
|
|
11
|
+
[`WebTransport`][pythonnative.bridge.web.WebTransport]; the preview
|
|
12
|
+
installs it with [`set_transport`][pythonnative.bridge.set_transport]
|
|
13
|
+
before any screen mounts. In headless tests there is no transport at
|
|
14
|
+
all: native modules fall back to their Python implementations, and
|
|
15
|
+
tests that want to exercise the bridge itself install a
|
|
16
|
+
[`FakeTransport`][pythonnative.bridge.fake.FakeTransport].
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import threading
|
|
22
|
+
from typing import Callable, Optional, Protocol, Tuple
|
|
23
|
+
|
|
24
|
+
from . import codec
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"PROTOCOL_VERSION",
|
|
28
|
+
"Transport",
|
|
29
|
+
"get_transport",
|
|
30
|
+
"has_transport",
|
|
31
|
+
"handshake",
|
|
32
|
+
"native_callback",
|
|
33
|
+
"set_transport",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
from .commits import PROTOCOL_VERSION
|
|
37
|
+
|
|
38
|
+
"""Bridge protocol version this Python package speaks."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Transport(Protocol):
|
|
42
|
+
"""The Python -> native half of the bridge."""
|
|
43
|
+
|
|
44
|
+
name: str
|
|
45
|
+
|
|
46
|
+
def protocol_version(self) -> int:
|
|
47
|
+
"""Return the protocol version compiled into the native library."""
|
|
48
|
+
|
|
49
|
+
def apply(self, transaction_json: str) -> str:
|
|
50
|
+
"""Apply one serialized transaction (a JSON array of ops)."""
|
|
51
|
+
|
|
52
|
+
def measure(self, tag: int, max_width: float, max_height: float) -> Tuple[float, float]:
|
|
53
|
+
"""Return the intrinsic ``(width, height)`` of the view ``tag`` under the constraints."""
|
|
54
|
+
|
|
55
|
+
def command(self, tag: int, name: str, args_json: str) -> Optional[str]:
|
|
56
|
+
"""Run an imperative command on one view; returns its JSON result or ``None``."""
|
|
57
|
+
|
|
58
|
+
def animate(self, tag: int, request_json: str) -> Optional[str]:
|
|
59
|
+
"""Handle an animation request (``set`` / ``start`` / ``cancel``) for one view."""
|
|
60
|
+
|
|
61
|
+
def call(self, module: str, method: str, args_json: str) -> Optional[str]:
|
|
62
|
+
"""Call a native module method with a ``{"call_id", "args"}`` envelope."""
|
|
63
|
+
|
|
64
|
+
def set_callback(self, callback: Callable[[str, int, str, str], Optional[str]]) -> None:
|
|
65
|
+
"""Install ``callback`` as the native -> Python entry point."""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ======================================================================
|
|
69
|
+
# Transport selection
|
|
70
|
+
# ======================================================================
|
|
71
|
+
|
|
72
|
+
_transport: Optional[Transport] = None
|
|
73
|
+
_transport_lock = threading.Lock()
|
|
74
|
+
_explicit = False
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _create_platform_transport() -> Optional[Transport]:
|
|
78
|
+
from ..utils import IS_ANDROID, IS_IOS, IS_WEB
|
|
79
|
+
|
|
80
|
+
if IS_IOS:
|
|
81
|
+
from .ios import IOSTransport
|
|
82
|
+
|
|
83
|
+
transport: Transport = IOSTransport()
|
|
84
|
+
transport.set_callback(native_callback)
|
|
85
|
+
return transport
|
|
86
|
+
if IS_ANDROID:
|
|
87
|
+
from .android import AndroidTransport
|
|
88
|
+
|
|
89
|
+
return AndroidTransport()
|
|
90
|
+
if IS_WEB:
|
|
91
|
+
raise RuntimeError(
|
|
92
|
+
"PN_PLATFORM=web is set but no browser preview transport is installed. "
|
|
93
|
+
"Start the app with `pn preview` (or `pn start`), which installs the WebTransport."
|
|
94
|
+
)
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_transport() -> Transport:
|
|
99
|
+
"""Return the active transport, creating the platform one on first use.
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
RuntimeError: Off-device, where no native runtime exists.
|
|
103
|
+
"""
|
|
104
|
+
global _transport
|
|
105
|
+
if _transport is not None:
|
|
106
|
+
return _transport
|
|
107
|
+
with _transport_lock:
|
|
108
|
+
if _transport is None:
|
|
109
|
+
created = _create_platform_transport()
|
|
110
|
+
if created is None:
|
|
111
|
+
raise RuntimeError(
|
|
112
|
+
"No native bridge is available on this platform (running off-device). "
|
|
113
|
+
"Use `pn preview` for the browser renderer or install a FakeTransport in tests."
|
|
114
|
+
)
|
|
115
|
+
_transport = created
|
|
116
|
+
return _transport
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def has_transport() -> bool:
|
|
120
|
+
"""Whether a transport exists or can be created without raising."""
|
|
121
|
+
if _transport is not None:
|
|
122
|
+
return True
|
|
123
|
+
if _explicit:
|
|
124
|
+
return False
|
|
125
|
+
from ..utils import IS_ANDROID, IS_IOS, IS_WEB
|
|
126
|
+
|
|
127
|
+
return bool(IS_IOS or IS_ANDROID or IS_WEB)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def set_transport(transport: Optional[Transport]) -> None:
|
|
131
|
+
"""Install a transport explicitly (tests) or reset with ``None``."""
|
|
132
|
+
global _transport, _explicit
|
|
133
|
+
with _transport_lock:
|
|
134
|
+
_transport = transport
|
|
135
|
+
_explicit = transport is not None
|
|
136
|
+
if transport is not None:
|
|
137
|
+
transport.set_callback(native_callback)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def handshake() -> int:
|
|
141
|
+
"""Verify the native library speaks our protocol version.
|
|
142
|
+
|
|
143
|
+
Called by the native templates right after Python starts. Returns
|
|
144
|
+
the negotiated version.
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
RuntimeError: On a version mismatch, with a hint to rebuild.
|
|
148
|
+
"""
|
|
149
|
+
version = get_transport().protocol_version()
|
|
150
|
+
if version != PROTOCOL_VERSION:
|
|
151
|
+
raise RuntimeError(
|
|
152
|
+
f"Bridge protocol mismatch: the native runtime speaks v{version} but pythonnative "
|
|
153
|
+
f"expects v{PROTOCOL_VERSION}. Re-run 'pn build' so the staged template matches the "
|
|
154
|
+
"installed pythonnative package."
|
|
155
|
+
)
|
|
156
|
+
if getattr(get_transport(), "name", "") in {"ios", "android"}:
|
|
157
|
+
from ..sdk.schema import fingerprint
|
|
158
|
+
|
|
159
|
+
reply = codec.loads(get_transport().call("Runtime", "capabilities", codec.dumps({"id": 0, "args": {}})))
|
|
160
|
+
capabilities = reply.get("value", {}) if isinstance(reply, dict) else {}
|
|
161
|
+
if capabilities.get("schema") != fingerprint() or capabilities.get("yoga") != "3.2.1":
|
|
162
|
+
raise RuntimeError("Native component contracts changed. Rebuild the app with 'pn run'.")
|
|
163
|
+
return version
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# ======================================================================
|
|
167
|
+
# native -> Python
|
|
168
|
+
# ======================================================================
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Callback threads coalesce continuous input before the application loop drains.
|
|
172
|
+
_continuous: dict[tuple[int, str], list[str]] = {}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _deliver_continuous(tag: int, name: str, slot: list[str]) -> None:
|
|
176
|
+
if _continuous.get((tag, name)) is slot:
|
|
177
|
+
_continuous.pop((tag, name), None)
|
|
178
|
+
native_callback("event", tag, name, slot[0])
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def native_callback(kind: str, tag: int, name: str, payload: str) -> Optional[str]:
|
|
182
|
+
"""Single entry point for every native -> Python message.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
kind: ``"event"``, ``"module"``, ``"host"``, ``"animation"``,
|
|
186
|
+
or ``"pump"``.
|
|
187
|
+
tag: View tag (events), screen id (host), otherwise ``0``.
|
|
188
|
+
name: Event name, module name, or host event.
|
|
189
|
+
payload: JSON text whose shape depends on ``kind``.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
A JSON string for request-style messages (a handler's return
|
|
193
|
+
value, ``"true"`` / ``"false"`` for ``back_pressed``), else
|
|
194
|
+
``None``. Never raises: failures are reported through
|
|
195
|
+
``diagnostics`` so nothing propagates into UIKit or the
|
|
196
|
+
Android looper.
|
|
197
|
+
"""
|
|
198
|
+
from ..runtime import _on_loop_thread, get_loop
|
|
199
|
+
|
|
200
|
+
loop = get_loop()
|
|
201
|
+
if loop.is_running() and not _on_loop_thread(loop):
|
|
202
|
+
if kind == "event" and name in {"on_scroll", "on_selection_change", "on_gesture_update"}:
|
|
203
|
+
key = (tag, name)
|
|
204
|
+
slot = _continuous.get(key)
|
|
205
|
+
if slot is None:
|
|
206
|
+
slot = [payload]
|
|
207
|
+
_continuous[key] = slot
|
|
208
|
+
loop.call_soon_threadsafe(_deliver_continuous, tag, name, slot)
|
|
209
|
+
else:
|
|
210
|
+
slot[0] = payload
|
|
211
|
+
else:
|
|
212
|
+
_continuous.clear()
|
|
213
|
+
loop.call_soon_threadsafe(native_callback, kind, tag, name, payload)
|
|
214
|
+
return None
|
|
215
|
+
try:
|
|
216
|
+
if kind == "layout":
|
|
217
|
+
from ..native_views import get_registry
|
|
218
|
+
|
|
219
|
+
backend = get_registry()
|
|
220
|
+
if backend.on_layout is not None:
|
|
221
|
+
backend.on_layout(codec.loads(payload))
|
|
222
|
+
return None
|
|
223
|
+
if kind == "event":
|
|
224
|
+
return _on_event(int(tag), name, payload)
|
|
225
|
+
if kind == "module":
|
|
226
|
+
from ..native_modules.registry import dispatch_module_message
|
|
227
|
+
|
|
228
|
+
dispatch_module_message(name, codec.loads(payload) or {})
|
|
229
|
+
return None
|
|
230
|
+
if kind == "host":
|
|
231
|
+
from ..hosts.native import dispatch_host_event
|
|
232
|
+
|
|
233
|
+
return dispatch_host_event(int(tag), name, codec.loads(payload))
|
|
234
|
+
if kind == "animation":
|
|
235
|
+
from ..animated import native_animation_completed
|
|
236
|
+
|
|
237
|
+
data = codec.loads(payload) or {}
|
|
238
|
+
native_animation_completed(int(data.get("id", 0)), bool(data.get("finished", True)))
|
|
239
|
+
return None
|
|
240
|
+
print(f"[pn.bridge] unknown callback kind {kind!r}")
|
|
241
|
+
except Exception as exc:
|
|
242
|
+
from .. import diagnostics
|
|
243
|
+
|
|
244
|
+
if not diagnostics.report_error(exc, phase=f"bridge {kind}:{name}"):
|
|
245
|
+
import traceback
|
|
246
|
+
|
|
247
|
+
traceback.print_exc()
|
|
248
|
+
return None
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _on_event(tag: int, name: str, payload: str) -> Optional[str]:
|
|
252
|
+
from ..events import get_event_registry
|
|
253
|
+
|
|
254
|
+
args = codec.loads(payload)
|
|
255
|
+
from ..native_views import get_registry
|
|
256
|
+
|
|
257
|
+
backend = get_registry()
|
|
258
|
+
accept = getattr(backend, "accept_event", None)
|
|
259
|
+
if accept is not None:
|
|
260
|
+
if not accept(tag, name, args):
|
|
261
|
+
return None
|
|
262
|
+
args = args["args"]
|
|
263
|
+
if args is None:
|
|
264
|
+
args = []
|
|
265
|
+
elif not isinstance(args, list):
|
|
266
|
+
args = [args]
|
|
267
|
+
callback = get_event_registry().get(tag, name)
|
|
268
|
+
if callback is None:
|
|
269
|
+
from ..native_views import get_registry
|
|
270
|
+
|
|
271
|
+
backend = get_registry()
|
|
272
|
+
internal = getattr(backend, "handle_internal_event", None)
|
|
273
|
+
if internal is not None:
|
|
274
|
+
result = internal(tag, name, args)
|
|
275
|
+
return None if result is None else codec.dumps(codec.to_jsonable(result))
|
|
276
|
+
return None
|
|
277
|
+
try:
|
|
278
|
+
result = get_event_registry().invoke(tag, name, *args)
|
|
279
|
+
except Exception as exc:
|
|
280
|
+
from .. import diagnostics
|
|
281
|
+
|
|
282
|
+
if not diagnostics.report_error(exc, phase=f"event {name!r}"):
|
|
283
|
+
import traceback
|
|
284
|
+
|
|
285
|
+
traceback.print_exc()
|
|
286
|
+
return None
|
|
287
|
+
import inspect
|
|
288
|
+
|
|
289
|
+
if result is None or inspect.isawaitable(result):
|
|
290
|
+
return None
|
|
291
|
+
try:
|
|
292
|
+
return codec.dumps(codec.to_jsonable(result))
|
|
293
|
+
except (TypeError, ValueError):
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _reset_for_tests() -> None:
|
|
298
|
+
"""Drop the transport for test isolation."""
|
|
299
|
+
global _transport, _explicit
|
|
300
|
+
with _transport_lock:
|
|
301
|
+
_transport = None
|
|
302
|
+
_explicit = False
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Android transport: the ``com.pythonnative.runtime.PNBridge`` class via Chaquopy.
|
|
2
|
+
|
|
3
|
+
``PNBridge`` is the only Java class Python touches. Its static methods
|
|
4
|
+
mirror the C entry points used on iOS (see ``docs/concepts/bridge.md``).
|
|
5
|
+
The reverse direction (native -> Python) is installed by the template's
|
|
6
|
+
``MainActivity``, which implements ``PythonHost`` by calling
|
|
7
|
+
[`pythonnative.bridge.native_callback`][pythonnative.bridge.native_callback]
|
|
8
|
+
through Chaquopy; this transport therefore has nothing to register.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any, Callable, Optional, Tuple
|
|
14
|
+
|
|
15
|
+
__all__ = ["AndroidTransport"]
|
|
16
|
+
|
|
17
|
+
BRIDGE_CLASS = "com.pythonnative.runtime.PNBridge"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AndroidTransport:
|
|
21
|
+
"""Thin wrapper over the static ``PNBridge`` methods."""
|
|
22
|
+
|
|
23
|
+
name = "android"
|
|
24
|
+
|
|
25
|
+
def __init__(self, bridge_class: Any = None) -> None:
|
|
26
|
+
if bridge_class is None:
|
|
27
|
+
from java import jclass
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
bridge_class = jclass(BRIDGE_CLASS)
|
|
31
|
+
except Exception as exc:
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
f"{BRIDGE_CLASS} is not on the classpath. Rebuild the app with 'pn run android' or "
|
|
34
|
+
"'pn build android' so the pythonnative Gradle module is included."
|
|
35
|
+
) from exc
|
|
36
|
+
self._bridge = bridge_class
|
|
37
|
+
|
|
38
|
+
def protocol_version(self) -> int:
|
|
39
|
+
"""Return the protocol version compiled into the native library."""
|
|
40
|
+
return int(self._bridge.protocolVersion())
|
|
41
|
+
|
|
42
|
+
def apply(self, transaction_json: str) -> str:
|
|
43
|
+
"""Apply one serialized transaction (a JSON array of ops)."""
|
|
44
|
+
return str(self._bridge.apply(transaction_json))
|
|
45
|
+
|
|
46
|
+
def measure(self, tag: int, max_width: float, max_height: float) -> Tuple[float, float]:
|
|
47
|
+
"""Return the intrinsic ``(width, height)`` of the view ``tag`` under the constraints."""
|
|
48
|
+
packed = self._bridge.measure(int(tag), float(max_width), float(max_height))
|
|
49
|
+
if not packed:
|
|
50
|
+
return (0.0, 0.0)
|
|
51
|
+
text = str(packed)
|
|
52
|
+
w, _, h = text.partition(",")
|
|
53
|
+
try:
|
|
54
|
+
return (float(w), float(h))
|
|
55
|
+
except ValueError:
|
|
56
|
+
return (0.0, 0.0)
|
|
57
|
+
|
|
58
|
+
def command(self, tag: int, name: str, args_json: str) -> Optional[str]:
|
|
59
|
+
"""Run an imperative command on one view; returns its JSON result or ``None``."""
|
|
60
|
+
return _opt_str(self._bridge.command(int(tag), name, args_json))
|
|
61
|
+
|
|
62
|
+
def animate(self, tag: int, request_json: str) -> Optional[str]:
|
|
63
|
+
"""Handle an animation request (``set`` / ``start`` / ``cancel``) for one view."""
|
|
64
|
+
return _opt_str(self._bridge.animate(int(tag), request_json))
|
|
65
|
+
|
|
66
|
+
def call(self, module: str, method: str, args_json: str) -> Optional[str]:
|
|
67
|
+
"""Call a native module method with a ``{"call_id", "args"}`` envelope."""
|
|
68
|
+
return _opt_str(self._bridge.call(module, method, args_json))
|
|
69
|
+
|
|
70
|
+
def set_callback(self, callback: Callable[[str, int, str, str], Optional[str]]) -> None:
|
|
71
|
+
"""No-op: the Android template installs the host through ``PNBridge.setHost``."""
|
|
72
|
+
del callback
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _opt_str(value: Any) -> Optional[str]:
|
|
76
|
+
if value is None:
|
|
77
|
+
return None
|
|
78
|
+
return str(value)
|