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,427 @@
|
|
|
1
|
+
"""Custom native-component registration.
|
|
2
|
+
|
|
3
|
+
Implements the [`@native_component`][pythonnative.sdk.native_component]
|
|
4
|
+
decorator and supporting helpers that let third-party packages contribute
|
|
5
|
+
new element types to the reconciler.
|
|
6
|
+
|
|
7
|
+
On device a custom component is rendered by a Swift
|
|
8
|
+
``PNComponentManager`` and a Kotlin ``ComponentManager`` registered
|
|
9
|
+
under the same type name by the package's native plugin (see
|
|
10
|
+
``docs/guides/custom-components.md``). The Python side only needs to
|
|
11
|
+
know the element name and, optionally, its typed props and a
|
|
12
|
+
[`ViewHandler`][pythonnative.sdk.ViewHandler] that renders a stand-in
|
|
13
|
+
in unit tests (the browser preview draws unknown types as labeled
|
|
14
|
+
placeholders). Registration is therefore a three-part agreement:
|
|
15
|
+
|
|
16
|
+
1. A typed, immutable [`Props`][pythonnative.sdk.Props] dataclass
|
|
17
|
+
declaring the component's public surface.
|
|
18
|
+
2. An element factory built with
|
|
19
|
+
[`element_factory`][pythonnative.sdk.element_factory].
|
|
20
|
+
3. Optionally, a test [`ViewHandler`][pythonnative.sdk.ViewHandler]
|
|
21
|
+
so the component also renders under the Python test backend.
|
|
22
|
+
|
|
23
|
+
The registry is process-wide. The view backend calls
|
|
24
|
+
[`install_into_registry`][pythonnative.sdk.install_into_registry] on
|
|
25
|
+
first use; that helper performs entry-point discovery (importing any
|
|
26
|
+
modules registered under
|
|
27
|
+
[`ENTRY_POINT_GROUP`][pythonnative.sdk.ENTRY_POINT_GROUP]) and copies
|
|
28
|
+
every test handler into the registry.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
```python
|
|
32
|
+
from dataclasses import dataclass
|
|
33
|
+
import pythonnative as pn
|
|
34
|
+
from pythonnative.sdk import Props, ViewHandler, element_factory, native_component
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class BadgeProps(Props):
|
|
39
|
+
text: str = ""
|
|
40
|
+
color: str = "#FF3B30"
|
|
41
|
+
style: pn.StyleProp = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@native_component("Badge", props=BadgeProps)
|
|
45
|
+
class BadgePreviewHandler(ViewHandler):
|
|
46
|
+
def create(self, tag, props):
|
|
47
|
+
... # stand-in used by the Python test backend
|
|
48
|
+
|
|
49
|
+
def update(self, view, changed):
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
Badge = element_factory("Badge")
|
|
54
|
+
```
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
from dataclasses import dataclass, fields, is_dataclass
|
|
58
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar
|
|
59
|
+
|
|
60
|
+
from ..element import Element
|
|
61
|
+
from ..native_views.base import ViewHandler
|
|
62
|
+
|
|
63
|
+
ENTRY_POINT_GROUP = "pythonnative.handlers"
|
|
64
|
+
"""Entry-point group used by PyPI packages to register native handlers.
|
|
65
|
+
|
|
66
|
+
Packages declare entries like:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[project.entry-points."pythonnative.handlers"]
|
|
70
|
+
my_blur = "my_pkg.blur:register"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
PythonNative imports the referenced module the first time the
|
|
74
|
+
[`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry] is
|
|
75
|
+
materialized; the decorators inside that module populate the registry
|
|
76
|
+
during import.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass(frozen=True)
|
|
81
|
+
class Props:
|
|
82
|
+
"""Optional base class for typed prop dataclasses.
|
|
83
|
+
|
|
84
|
+
Subclassing is not strictly required (any
|
|
85
|
+
``@dataclass(frozen=True)`` works), but inheriting from
|
|
86
|
+
``Props`` gives third-party components a clear, searchable marker
|
|
87
|
+
in their public API and a stable place to add framework-wide
|
|
88
|
+
behavior in the future.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
```python
|
|
92
|
+
from dataclasses import dataclass
|
|
93
|
+
from pythonnative.sdk import Props
|
|
94
|
+
|
|
95
|
+
@dataclass(frozen=True)
|
|
96
|
+
class BadgeProps(Props):
|
|
97
|
+
text: str = ""
|
|
98
|
+
color: str = "#FF3B30"
|
|
99
|
+
```
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---------------------------------------------------------------------- #
|
|
104
|
+
# Internal registry
|
|
105
|
+
# ---------------------------------------------------------------------- #
|
|
106
|
+
|
|
107
|
+
# name -> (props_type or None, test handler or None)
|
|
108
|
+
_REGISTRY: Dict[str, Tuple[Optional[type], Optional[ViewHandler]]] = {}
|
|
109
|
+
|
|
110
|
+
# Caches `_install_into_registry` runs to avoid repeated entry-point
|
|
111
|
+
# discovery once the registry has been populated for a given platform.
|
|
112
|
+
_DISCOVERED: bool = False
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
H = TypeVar("H", bound=ViewHandler)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def native_component(
|
|
119
|
+
name: str,
|
|
120
|
+
*,
|
|
121
|
+
props: Optional[type] = None,
|
|
122
|
+
) -> Callable[[Type[H]], Type[H]]:
|
|
123
|
+
"""Decorator that registers a test [`ViewHandler`][pythonnative.sdk.ViewHandler] under ``name``.
|
|
124
|
+
|
|
125
|
+
The handler class is instantiated immediately and stored in the
|
|
126
|
+
process-wide registry as the component's off-device renderer. The
|
|
127
|
+
on-device renderers are the Swift and Kotlin component managers the
|
|
128
|
+
package's native plugin registers under the same ``name``.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
name: Element type name (e.g., ``"Badge"``). Used by the
|
|
132
|
+
reconciler and by native component managers at lookup time.
|
|
133
|
+
props: Optional dataclass type describing the component's
|
|
134
|
+
typed props. When supplied, the
|
|
135
|
+
[`element_factory`][pythonnative.sdk.element_factory] helper
|
|
136
|
+
uses this type to validate kwargs and produce frozen prop
|
|
137
|
+
instances.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
A decorator that, when applied to a
|
|
141
|
+
[`ViewHandler`][pythonnative.sdk.ViewHandler] subclass, registers
|
|
142
|
+
it and returns the class unchanged.
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
TypeError: If the decorated object is not a class subclassing
|
|
146
|
+
``ViewHandler``.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def decorator(handler_cls: Type[H]) -> Type[H]:
|
|
150
|
+
if not isinstance(handler_cls, type) or not issubclass(handler_cls, ViewHandler):
|
|
151
|
+
raise TypeError(f"@native_component({name!r}) must decorate a ViewHandler subclass; got {handler_cls!r}")
|
|
152
|
+
register_component(name=name, props=props, handler=handler_cls())
|
|
153
|
+
return handler_cls
|
|
154
|
+
|
|
155
|
+
return decorator
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def register_component(
|
|
159
|
+
*,
|
|
160
|
+
name: str,
|
|
161
|
+
props: Optional[type] = None,
|
|
162
|
+
handler: Optional[ViewHandler] = None,
|
|
163
|
+
) -> None:
|
|
164
|
+
"""Register a custom native component imperatively.
|
|
165
|
+
|
|
166
|
+
Declares ``name`` as an element type so
|
|
167
|
+
[`element_factory`][pythonnative.sdk.element_factory] can build it.
|
|
168
|
+
``handler`` is the optional test renderer; native
|
|
169
|
+
rendering always comes from the platform component managers.
|
|
170
|
+
Subsequent calls for the same ``name`` merge: a later ``props`` or
|
|
171
|
+
``handler`` replaces the earlier one, ``None`` leaves it alone.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
name: Element type name.
|
|
175
|
+
props: Optional dataclass type describing the typed props.
|
|
176
|
+
handler: Optional [`ViewHandler`][pythonnative.sdk.ViewHandler]
|
|
177
|
+
instance used off device.
|
|
178
|
+
|
|
179
|
+
Raises:
|
|
180
|
+
TypeError: If ``handler`` is not a ``ViewHandler`` instance, or
|
|
181
|
+
if ``props`` is not a dataclass type.
|
|
182
|
+
"""
|
|
183
|
+
if props is not None and not (isinstance(props, type) and is_dataclass(props)):
|
|
184
|
+
raise TypeError(f"register_component({name!r}): props must be a @dataclass type, got {props!r}")
|
|
185
|
+
if handler is not None and not isinstance(handler, ViewHandler):
|
|
186
|
+
raise TypeError(f"register_component({name!r}): handler must be a ViewHandler instance")
|
|
187
|
+
|
|
188
|
+
if props is not None:
|
|
189
|
+
from .schema import ComponentSchema, register_schema
|
|
190
|
+
|
|
191
|
+
register_schema(ComponentSchema.from_dataclass(name, props))
|
|
192
|
+
existing = _REGISTRY.get(name)
|
|
193
|
+
if existing is None:
|
|
194
|
+
_REGISTRY[name] = (props, handler)
|
|
195
|
+
return
|
|
196
|
+
existing_props, existing_handler = existing
|
|
197
|
+
_REGISTRY[name] = (
|
|
198
|
+
props if props is not None else existing_props,
|
|
199
|
+
handler if handler is not None else existing_handler,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def unregister_component(name: str) -> None:
|
|
204
|
+
"""Remove a previously-registered component (primarily for tests).
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
name: The element type name to unregister.
|
|
208
|
+
"""
|
|
209
|
+
_REGISTRY.pop(name, None)
|
|
210
|
+
from .schema import COMPONENTS
|
|
211
|
+
|
|
212
|
+
COMPONENTS.pop(name, None)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def list_components() -> List[str]:
|
|
216
|
+
"""Return the names of every registered custom component.
|
|
217
|
+
|
|
218
|
+
Useful for diagnostics and tests.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
Sorted list of names registered via
|
|
222
|
+
[`@native_component`][pythonnative.sdk.native_component] or
|
|
223
|
+
[`register_component`][pythonnative.sdk.register_component].
|
|
224
|
+
"""
|
|
225
|
+
return sorted(_REGISTRY)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def get_props_type(name: str) -> Optional[type]:
|
|
229
|
+
"""Return the registered props dataclass for ``name`` (or ``None``)."""
|
|
230
|
+
entry = _REGISTRY.get(name)
|
|
231
|
+
return entry[0] if entry is not None else None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def get_test_handler(name: str) -> Optional[ViewHandler]:
|
|
235
|
+
"""Return the registered off-device handler for ``name`` (or ``None``)."""
|
|
236
|
+
entry = _REGISTRY.get(name)
|
|
237
|
+
return entry[1] if entry is not None else None
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def install_into_registry(registry: Any) -> None:
|
|
241
|
+
"""Copy registered test handlers into a view registry.
|
|
242
|
+
|
|
243
|
+
Called once by the registry on first use. Triggers entry-point
|
|
244
|
+
discovery on the first call so PyPI-installed components register
|
|
245
|
+
themselves before the registry snapshot is taken.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
registry: A
|
|
249
|
+
[`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry]
|
|
250
|
+
(or duck-compatible object) with a ``register(name, handler)``
|
|
251
|
+
method.
|
|
252
|
+
"""
|
|
253
|
+
_discover_entry_points()
|
|
254
|
+
for name, (_props_type, handler) in _REGISTRY.items():
|
|
255
|
+
if handler is not None:
|
|
256
|
+
registry.register(name, handler)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _discover_entry_points() -> None:
|
|
260
|
+
"""Import every module registered under ``ENTRY_POINT_GROUP``.
|
|
261
|
+
|
|
262
|
+
Idempotent and safe to call repeatedly; the actual discovery only
|
|
263
|
+
runs once per process. Exceptions raised by individual entry points
|
|
264
|
+
are swallowed (with the offending name printed to stderr) so a
|
|
265
|
+
single broken plugin never prevents the rest of the process from
|
|
266
|
+
rendering.
|
|
267
|
+
"""
|
|
268
|
+
global _DISCOVERED
|
|
269
|
+
if _DISCOVERED:
|
|
270
|
+
return
|
|
271
|
+
_DISCOVERED = True
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
from importlib.metadata import entry_points
|
|
275
|
+
except ImportError:
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
eps = entry_points()
|
|
280
|
+
except Exception:
|
|
281
|
+
return
|
|
282
|
+
|
|
283
|
+
# importlib.metadata's API changed across Python versions; both
|
|
284
|
+
# ``select`` and direct ``.get`` are normalized here.
|
|
285
|
+
selected: List[Any] = []
|
|
286
|
+
if hasattr(eps, "select"):
|
|
287
|
+
try:
|
|
288
|
+
selected = list(eps.select(group=ENTRY_POINT_GROUP))
|
|
289
|
+
except Exception:
|
|
290
|
+
selected = []
|
|
291
|
+
if not selected:
|
|
292
|
+
try:
|
|
293
|
+
getter = getattr(eps, "get", None)
|
|
294
|
+
if getter is not None:
|
|
295
|
+
selected = list(getter(ENTRY_POINT_GROUP, []))
|
|
296
|
+
except Exception:
|
|
297
|
+
selected = []
|
|
298
|
+
|
|
299
|
+
for ep in selected:
|
|
300
|
+
name = getattr(ep, "name", "?")
|
|
301
|
+
try:
|
|
302
|
+
ep.load()
|
|
303
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
304
|
+
import sys
|
|
305
|
+
|
|
306
|
+
print(
|
|
307
|
+
f"[pythonnative.sdk] Failed to load handler entry point {name!r}: {exc!r}",
|
|
308
|
+
file=sys.stderr,
|
|
309
|
+
flush=True,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _reset_discovery_state_for_tests() -> None:
|
|
314
|
+
"""Reset the entry-point discovery flag (for tests only)."""
|
|
315
|
+
global _DISCOVERED
|
|
316
|
+
_DISCOVERED = False
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# ---------------------------------------------------------------------- #
|
|
320
|
+
# Element factories
|
|
321
|
+
# ---------------------------------------------------------------------- #
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _props_to_dict(value: Any) -> Dict[str, Any]:
|
|
325
|
+
"""Convert a typed props dataclass to a flat dict of non-None fields."""
|
|
326
|
+
if isinstance(value, dict):
|
|
327
|
+
return {k: v for k, v in value.items() if v is not None}
|
|
328
|
+
if is_dataclass(value):
|
|
329
|
+
out: Dict[str, Any] = {}
|
|
330
|
+
for f in fields(value):
|
|
331
|
+
field_value = getattr(value, f.name)
|
|
332
|
+
if field_value is not None:
|
|
333
|
+
out[f.name] = field_value
|
|
334
|
+
return out
|
|
335
|
+
raise TypeError(f"Expected a dataclass instance or dict, got {type(value).__name__!r}")
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def element_factory(name: str) -> Callable[..., Element]:
|
|
339
|
+
"""Return a callable that builds [`Element`][pythonnative.Element] instances of type ``name``.
|
|
340
|
+
|
|
341
|
+
The returned factory accepts:
|
|
342
|
+
|
|
343
|
+
- Children as positional arguments (any number).
|
|
344
|
+
- ``key=`` (optional, keyword-only) for keyed reconciliation.
|
|
345
|
+
- Either ``props=`` (a dataclass instance) or per-field keyword
|
|
346
|
+
arguments matching the registered props dataclass.
|
|
347
|
+
|
|
348
|
+
If no ``props`` dataclass was registered for ``name``, kwargs flow
|
|
349
|
+
through unmodified, useful when iterating before locking down a
|
|
350
|
+
prop schema.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
name: An element type name previously registered via
|
|
354
|
+
[`@native_component`][pythonnative.sdk.native_component] or
|
|
355
|
+
[`register_component`][pythonnative.sdk.register_component].
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
A callable producing fresh
|
|
359
|
+
[`Element`][pythonnative.Element] instances of type ``name``.
|
|
360
|
+
|
|
361
|
+
Raises:
|
|
362
|
+
KeyError: If ``name`` is not registered.
|
|
363
|
+
|
|
364
|
+
Example:
|
|
365
|
+
```python
|
|
366
|
+
Badge = element_factory("Badge")
|
|
367
|
+
Badge(text="3", color="#0A84FF")
|
|
368
|
+
Badge(props=BadgeProps(text="3"))
|
|
369
|
+
```
|
|
370
|
+
"""
|
|
371
|
+
if name not in _REGISTRY:
|
|
372
|
+
raise KeyError(
|
|
373
|
+
f"No component registered under name {name!r}. Use @native_component or register_component first."
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
def factory(*children: Element, key: Optional[str] = None, props: Any = None, **kwargs: Any) -> Element:
|
|
377
|
+
props_type = get_props_type(name)
|
|
378
|
+
if props is not None:
|
|
379
|
+
if kwargs:
|
|
380
|
+
raise TypeError("Pass either props=... or keyword props, not both")
|
|
381
|
+
props_dict = _props_to_dict(props)
|
|
382
|
+
elif props_type is not None:
|
|
383
|
+
try:
|
|
384
|
+
instance = props_type(**kwargs)
|
|
385
|
+
except TypeError as exc:
|
|
386
|
+
raise TypeError(f"Invalid props for {name!r}: {exc}") from exc
|
|
387
|
+
props_dict = _props_to_dict(instance)
|
|
388
|
+
else:
|
|
389
|
+
props_dict = dict(kwargs)
|
|
390
|
+
if props_type is not None:
|
|
391
|
+
from .schema import ComponentSchema
|
|
392
|
+
|
|
393
|
+
ComponentSchema.from_dataclass(name, props_type).validate(props_dict)
|
|
394
|
+
# Style props pass through resolve_style at the boundary so list
|
|
395
|
+
# forms / None get flattened identically to built-in factories.
|
|
396
|
+
from ..style import resolve_style as _resolve
|
|
397
|
+
|
|
398
|
+
style_value = props_dict.pop("style", None)
|
|
399
|
+
style_dict = _resolve(style_value)
|
|
400
|
+
merged: Dict[str, Any] = {**style_dict, **props_dict}
|
|
401
|
+
return Element(name, merged, list(children), key=key)
|
|
402
|
+
|
|
403
|
+
import inspect
|
|
404
|
+
|
|
405
|
+
props_type = get_props_type(name)
|
|
406
|
+
if props_type is not None:
|
|
407
|
+
factory.__signature__ = inspect.signature(props_type)
|
|
408
|
+
from .schema import ComponentSchema, register_schema
|
|
409
|
+
|
|
410
|
+
register_schema(ComponentSchema.from_dataclass(name, props_type))
|
|
411
|
+
factory.__name__ = name
|
|
412
|
+
factory.__doc__ = f"Construct an Element of type {name!r}."
|
|
413
|
+
return factory
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
__all__ = [
|
|
417
|
+
"ENTRY_POINT_GROUP",
|
|
418
|
+
"Props",
|
|
419
|
+
"element_factory",
|
|
420
|
+
"get_test_handler",
|
|
421
|
+
"get_props_type",
|
|
422
|
+
"install_into_registry",
|
|
423
|
+
"list_components",
|
|
424
|
+
"native_component",
|
|
425
|
+
"register_component",
|
|
426
|
+
"unregister_component",
|
|
427
|
+
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Native contracts derived from the annotated built-in Python factories."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
import inspect
|
|
7
|
+
import typing
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
|
|
10
|
+
from ..style import Style
|
|
11
|
+
from .schema import COMPONENTS, ComponentSchema, NativeField, register_schema, type_schema
|
|
12
|
+
|
|
13
|
+
# These types own native child layout or physical child presentation.
|
|
14
|
+
CONTAINERS = frozenset(
|
|
15
|
+
{"View", "Column", "Row", "ScrollView", "Screen", "ScreenStack", "Modal", "Portal", "VirtualList"}
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def install(factories: dict[str, Any]) -> None:
|
|
20
|
+
"""Compile ordinary Python annotations into the shared native contract."""
|
|
21
|
+
style_fields = {name: type_schema(annotation) for name, annotation in typing.get_type_hints(Style).items()}
|
|
22
|
+
for name, factory in factories.items():
|
|
23
|
+
if not inspect.isfunction(factory) or not name[:1].isupper() or name.startswith("_"):
|
|
24
|
+
continue
|
|
25
|
+
signature = inspect.signature(factory)
|
|
26
|
+
hints = typing.get_type_hints(factory)
|
|
27
|
+
fields: list[Any] = []
|
|
28
|
+
for key, parameter in signature.parameters.items():
|
|
29
|
+
if key in {"style", "ref", "key"} or parameter.kind in {parameter.VAR_POSITIONAL, parameter.VAR_KEYWORD}:
|
|
30
|
+
continue
|
|
31
|
+
annotation = hints.get(key, Any)
|
|
32
|
+
default = parameter.default
|
|
33
|
+
fields.append(
|
|
34
|
+
(key, annotation)
|
|
35
|
+
if default is inspect.Parameter.empty
|
|
36
|
+
else (key, annotation, dataclasses.field(default=default))
|
|
37
|
+
)
|
|
38
|
+
props_type = dataclasses.make_dataclass(f"{name}Props", fields, frozen=True, kw_only=True)
|
|
39
|
+
schema = ComponentSchema.from_dataclass(
|
|
40
|
+
name, props_type, measurement="container" if name in CONTAINERS else "intrinsic"
|
|
41
|
+
)
|
|
42
|
+
wire = dict(style_fields) | schema.props
|
|
43
|
+
wire.update(ref={}, on_layout=type_schema(Callable[..., Any]))
|
|
44
|
+
for key in wire:
|
|
45
|
+
wire[key] = dict(wire[key])
|
|
46
|
+
wire[key]["native"] = dataclasses.asdict(
|
|
47
|
+
NativeField(
|
|
48
|
+
invalidates_layout=key in style_fields or key in {"text", "value", "title", "source", "spans"},
|
|
49
|
+
recreate=key in {"multiline"},
|
|
50
|
+
animated=key
|
|
51
|
+
in {
|
|
52
|
+
"opacity",
|
|
53
|
+
"background_color",
|
|
54
|
+
"color",
|
|
55
|
+
"rotate",
|
|
56
|
+
"translate_x",
|
|
57
|
+
"translate_y",
|
|
58
|
+
"scale",
|
|
59
|
+
"scale_x",
|
|
60
|
+
"scale_y",
|
|
61
|
+
},
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
if name == "Text":
|
|
65
|
+
wire.update(text={"type": "string"}, spans={"type": "array"})
|
|
66
|
+
register_schema(dataclasses.replace(schema, props=wire, required=()))
|
|
67
|
+
base = COMPONENTS["View"]
|
|
68
|
+
for name, extra in {
|
|
69
|
+
"Screen": {"route_key": {"type": "string"}, "title": {"type": "string"}, "active": {"type": "boolean"}},
|
|
70
|
+
"ScreenStack": {"on_native_back": {"type": "event"}},
|
|
71
|
+
"VirtualList": {
|
|
72
|
+
"keys": {"type": "array"},
|
|
73
|
+
"revision": {"type": "integer"},
|
|
74
|
+
"count": {"type": "integer"},
|
|
75
|
+
"estimated_item_size": {"type": "number"},
|
|
76
|
+
"on_bind_row": {"type": "event"},
|
|
77
|
+
},
|
|
78
|
+
}.items():
|
|
79
|
+
register_schema(ComponentSchema(name, base.props | extra, measurement="container"))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def validate_props(name: str, props: dict[str, Any]) -> None:
|
|
83
|
+
"""Check known built-in arguments while preserving composed internal props."""
|
|
84
|
+
schema = COMPONENTS.get(name)
|
|
85
|
+
if schema is None:
|
|
86
|
+
return
|
|
87
|
+
for key, value in props.items():
|
|
88
|
+
if value is not None and key in schema.props:
|
|
89
|
+
from .schema import validate
|
|
90
|
+
|
|
91
|
+
validate(value, schema.props[key], f"{name}.{key}")
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Generate component props decoders and portable native metadata."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from ..bridge.codec import to_jsonable
|
|
10
|
+
from .schema import COMPONENTS, fingerprint, manifest
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def generate(destination: str | Path) -> list[Path]:
|
|
14
|
+
"""Write deterministic Swift, Kotlin, Python, and browser schema artifacts."""
|
|
15
|
+
destination = Path(destination)
|
|
16
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
spec = manifest()
|
|
18
|
+
encoded = json.dumps(spec, indent=2, sort_keys=True, default=str) + "\n"
|
|
19
|
+
swift = ["import Foundation", "", "// Generated from Python schemas. Regenerate instead of editing."]
|
|
20
|
+
kotlin = [
|
|
21
|
+
"package com.pythonnative.generated",
|
|
22
|
+
"",
|
|
23
|
+
"import org.json.JSONObject",
|
|
24
|
+
"",
|
|
25
|
+
"// Generated from Python schemas.",
|
|
26
|
+
]
|
|
27
|
+
python = [
|
|
28
|
+
'"""Generated native component factories."""',
|
|
29
|
+
"from typing import Any",
|
|
30
|
+
"from pythonnative.element import Element",
|
|
31
|
+
"from pythonnative.sdk.schema import COMPONENTS",
|
|
32
|
+
"",
|
|
33
|
+
]
|
|
34
|
+
docs = ["# Native contracts", "", f"Runtime fingerprint: `{fingerprint()}`.", ""]
|
|
35
|
+
names = {
|
|
36
|
+
"string": ("String", "String", "str"),
|
|
37
|
+
"boolean": ("Bool", "Boolean", "bool"),
|
|
38
|
+
"integer": ("Int", "Int", "int"),
|
|
39
|
+
"number": ("Double", "Double", "float"),
|
|
40
|
+
}
|
|
41
|
+
for name, component in sorted(COMPONENTS.items()):
|
|
42
|
+
if not name.isidentifier():
|
|
43
|
+
raise ValueError(f"Invalid native component name {name!r}")
|
|
44
|
+
swift.extend(
|
|
45
|
+
[
|
|
46
|
+
f"public struct {name}Props {{",
|
|
47
|
+
" public let values: [String: Any]",
|
|
48
|
+
" public init(_ values: [String: Any]) throws {",
|
|
49
|
+
" self.values = values",
|
|
50
|
+
]
|
|
51
|
+
)
|
|
52
|
+
kotlin.extend([f"data class {name}Props(val values: JSONObject) {{", " init {"])
|
|
53
|
+
parameters = []
|
|
54
|
+
values = []
|
|
55
|
+
for key, field in component.props.items():
|
|
56
|
+
if not key.isidentifier():
|
|
57
|
+
raise ValueError(f"Invalid property name {key!r}")
|
|
58
|
+
kind = field.get("type")
|
|
59
|
+
swift_type, kotlin_type, python_type = names.get(kind, ("Any", "Any", "Any"))
|
|
60
|
+
if key in component.required:
|
|
61
|
+
swift.append(
|
|
62
|
+
f' guard values["{key}"] is {swift_type} else {{ '
|
|
63
|
+
f'throw NativeDecodeError.invalid("{name}.{key}") }}'
|
|
64
|
+
)
|
|
65
|
+
kotlin.append(
|
|
66
|
+
f' require(values.has("{key}") && !values.isNull("{key}")) {{ "Missing {name}.{key}" }}'
|
|
67
|
+
)
|
|
68
|
+
default = component.defaults.get(key)
|
|
69
|
+
if hasattr(default, "value"):
|
|
70
|
+
default = default.value
|
|
71
|
+
if default is None and python_type != "Any":
|
|
72
|
+
python_type += " | None"
|
|
73
|
+
parameters.append(f"{key}: {python_type}" + (f" = {default!r}" if key not in component.required else ""))
|
|
74
|
+
values.append(f'"{key}": {key}')
|
|
75
|
+
swift.append(" }")
|
|
76
|
+
kotlin.append(" }")
|
|
77
|
+
for key, field in component.props.items():
|
|
78
|
+
kind = field.get("type")
|
|
79
|
+
st, kt, _ = names.get(kind, ("Any", "Any", "Any"))
|
|
80
|
+
expression = f'values["{key}"]' + (f" as? {st}" if st != "Any" else "")
|
|
81
|
+
swift.append(f" public var {key}: {st}? {{ {expression} }}")
|
|
82
|
+
accessor = {"string": "getString", "boolean": "getBoolean", "integer": "getInt", "number": "getDouble"}.get(
|
|
83
|
+
kind, "get"
|
|
84
|
+
)
|
|
85
|
+
kotlin.append(
|
|
86
|
+
f' val {key}: {kt}? get() = if (values.isNull("{key}")) null else values.{accessor}("{key}")'
|
|
87
|
+
)
|
|
88
|
+
swift.extend(["}", ""])
|
|
89
|
+
kotlin.extend(["}", ""])
|
|
90
|
+
python.extend(
|
|
91
|
+
[
|
|
92
|
+
f"def {name}(*children: Element, "
|
|
93
|
+
+ ", ".join(parameters + ["key: str | None = None"])
|
|
94
|
+
+ ") -> Element:",
|
|
95
|
+
f' """Create a validated {name} native element."""',
|
|
96
|
+
" props = {" + ", ".join(values) + "}",
|
|
97
|
+
f' COMPONENTS["{name}"].validate(props)',
|
|
98
|
+
f' return Element("{name}", props, list(children), key=key)',
|
|
99
|
+
"",
|
|
100
|
+
]
|
|
101
|
+
)
|
|
102
|
+
docs.extend(
|
|
103
|
+
[
|
|
104
|
+
f"## {name}",
|
|
105
|
+
"",
|
|
106
|
+
f"Measurement: {component.measurement}.",
|
|
107
|
+
"",
|
|
108
|
+
"| Property | Type | Required |",
|
|
109
|
+
"| --- | --- | --- |",
|
|
110
|
+
]
|
|
111
|
+
)
|
|
112
|
+
docs.extend(
|
|
113
|
+
f"| `{key}` | `{field.get('type', 'union')}` | {key in component.required} |"
|
|
114
|
+
for key, field in component.props.items()
|
|
115
|
+
)
|
|
116
|
+
docs.append("")
|
|
117
|
+
swift.extend(["public enum NativeDecodeError: Error { case invalid(String) }", ""])
|
|
118
|
+
outputs: dict[str, Any] = {
|
|
119
|
+
"schema.json": encoded,
|
|
120
|
+
"schema.js": "export default " + encoded.strip() + ";\n",
|
|
121
|
+
"NativeProps.swift": "\n".join(swift),
|
|
122
|
+
"NativeProps.kt": "\n".join(kotlin),
|
|
123
|
+
"components.py": "\n".join(python),
|
|
124
|
+
"README.md": "\n".join(docs),
|
|
125
|
+
}
|
|
126
|
+
compact = json.dumps(to_jsonable(spec), separators=(",", ":"), sort_keys=True)
|
|
127
|
+
templates = Path(__file__).with_name("templates")
|
|
128
|
+
for extension in ("swift", "kt"):
|
|
129
|
+
template = (templates / f"contracts.{extension}").read_text(encoding="utf-8")
|
|
130
|
+
# Escaped Swift strings and Kotlin raw strings have different interpolation rules.
|
|
131
|
+
data = (
|
|
132
|
+
compact.replace("\\", "\\\\")
|
|
133
|
+
if extension == "swift"
|
|
134
|
+
else ",\n".join(
|
|
135
|
+
'"""' + compact[i : i + 8000].replace("$", "${'$'}") + '"""' for i in range(0, len(compact), 8000)
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
outputs[f"PNContracts.{extension}"] = template.replace("{{fingerprint}}", fingerprint()).replace(
|
|
139
|
+
"{{specification}}", data
|
|
140
|
+
)
|
|
141
|
+
from .module_codegen import generate_modules
|
|
142
|
+
|
|
143
|
+
outputs.update(generate_modules())
|
|
144
|
+
paths = []
|
|
145
|
+
for name, contents in outputs.items():
|
|
146
|
+
path = destination / name
|
|
147
|
+
path.write_text(contents, encoding="utf-8")
|
|
148
|
+
paths.append(path)
|
|
149
|
+
return paths
|