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,375 @@
|
|
|
1
|
+
"""``ErrorBoundary`` and ``Suspense`` handling for the reconciler.
|
|
2
|
+
|
|
3
|
+
Both boundaries are transparent wrappers whose children are swapped
|
|
4
|
+
for a fallback subtree when something goes wrong beneath them:
|
|
5
|
+
|
|
6
|
+
- an **error boundary** catches exceptions raised while rendering its
|
|
7
|
+
subtree, mounts its ``fallback`` (optionally receiving the error and
|
|
8
|
+
a ``reset`` callable), and rebuilds the content when ``reset`` runs;
|
|
9
|
+
- a **Suspense** boundary catches [`Suspend`][pythonnative.suspense.Suspend]
|
|
10
|
+
signals (an ``async`` body or a [`use_resource`][pythonnative.use_resource]
|
|
11
|
+
read that isn't ready), shows its ``fallback``, and retries the
|
|
12
|
+
content once the awaited work completes. Hook states of components
|
|
13
|
+
that had already rendered are preserved across the retry so cached
|
|
14
|
+
resources aren't refetched.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import inspect
|
|
20
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple
|
|
21
|
+
|
|
22
|
+
from .. import diagnostics
|
|
23
|
+
from ..element import Element
|
|
24
|
+
from ..hooks import HookState
|
|
25
|
+
from ..suspense import Suspend
|
|
26
|
+
from .vnode import VNode, normalize_children
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from ..scheduler import TransitionQueue
|
|
30
|
+
|
|
31
|
+
HydrationMap = Dict[Tuple[int, Any], List[HookState]]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BoundaryMixin:
|
|
35
|
+
"""Error-boundary and Suspense behavior mixed into the reconciler."""
|
|
36
|
+
|
|
37
|
+
# Attributes provided by the concrete reconciler.
|
|
38
|
+
_dirty_boundaries: Dict[int, VNode]
|
|
39
|
+
_dirty_suspense: Dict[int, VNode]
|
|
40
|
+
_hydration: Optional[HydrationMap]
|
|
41
|
+
_suspense_salvage: Optional[HydrationMap]
|
|
42
|
+
transitions: "TransitionQueue"
|
|
43
|
+
|
|
44
|
+
# Methods provided by the concrete reconciler.
|
|
45
|
+
def _create_child_list(self, elements: List[Element]) -> List[VNode]: ... # pragma: no cover
|
|
46
|
+
|
|
47
|
+
def _reconcile_child_list(self, old: List[VNode], new: List[Element]) -> List[VNode]: ... # pragma: no cover
|
|
48
|
+
|
|
49
|
+
def _destroy_tree(self, node: VNode, salvage: Optional[HydrationMap] = None) -> None: ... # pragma: no cover
|
|
50
|
+
|
|
51
|
+
def _refresh_identity(self, node: VNode) -> None: ... # pragma: no cover
|
|
52
|
+
|
|
53
|
+
def request_render(self) -> None: # pragma: no cover
|
|
54
|
+
"""Ask for another render pass (provided by the concrete reconciler)."""
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
# ------------------------------------------------------------------
|
|
58
|
+
# Error boundaries
|
|
59
|
+
# ------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
def _create_error_boundary(self, element: Element) -> VNode:
|
|
62
|
+
node = VNode(element, [])
|
|
63
|
+
try:
|
|
64
|
+
children = self._create_child_list(normalize_children(element.children, owner="ErrorBoundary"))
|
|
65
|
+
except Exception as exc:
|
|
66
|
+
self._activate_boundary(node, exc)
|
|
67
|
+
return node
|
|
68
|
+
for child in children:
|
|
69
|
+
child.parent = node
|
|
70
|
+
node.children = children
|
|
71
|
+
self._refresh_identity(node)
|
|
72
|
+
return node
|
|
73
|
+
|
|
74
|
+
def _reconcile_error_boundary(self, old: VNode, new_el: Element) -> VNode:
|
|
75
|
+
old.element = new_el
|
|
76
|
+
if old.error is not None:
|
|
77
|
+
# Fallback is showing; keep showing it (rebuilt against the
|
|
78
|
+
# latest fallback prop) until reset() clears the error.
|
|
79
|
+
fallback_els = self._error_fallback_elements(old, old.error)
|
|
80
|
+
old.children = self._reconcile_child_list(old.children, fallback_els)
|
|
81
|
+
for child in old.children:
|
|
82
|
+
child.parent = old
|
|
83
|
+
self._refresh_identity(old)
|
|
84
|
+
return old
|
|
85
|
+
try:
|
|
86
|
+
children = self._reconcile_child_list(
|
|
87
|
+
old.children, normalize_children(new_el.children, owner="ErrorBoundary")
|
|
88
|
+
)
|
|
89
|
+
old.children = children
|
|
90
|
+
for child in children:
|
|
91
|
+
child.parent = old
|
|
92
|
+
self._refresh_identity(old)
|
|
93
|
+
except Exception as exc:
|
|
94
|
+
self._activate_boundary(old, exc)
|
|
95
|
+
return old
|
|
96
|
+
|
|
97
|
+
def _activate_boundary(self, node: VNode, exc: BaseException) -> None:
|
|
98
|
+
"""Destroy a boundary's failed subtree and mount its fallback.
|
|
99
|
+
|
|
100
|
+
Calls the ``on_error`` prop (if any), records the error on the
|
|
101
|
+
node, and replaces the children with the rendered fallback.
|
|
102
|
+
Re-raises when the boundary has no fallback, letting an outer
|
|
103
|
+
boundary (or the screen host) take over.
|
|
104
|
+
"""
|
|
105
|
+
props = node.element.props
|
|
106
|
+
on_error = props.get("on_error")
|
|
107
|
+
if callable(on_error):
|
|
108
|
+
try:
|
|
109
|
+
on_error(exc)
|
|
110
|
+
except Exception as cb_exc:
|
|
111
|
+
diagnostics.warn(f"ErrorBoundary on_error callback raised {cb_exc!r}")
|
|
112
|
+
if props.get("fallback") is None:
|
|
113
|
+
raise exc
|
|
114
|
+
for child in node.children:
|
|
115
|
+
self._destroy_tree(child)
|
|
116
|
+
node.children = []
|
|
117
|
+
node.error = exc
|
|
118
|
+
children = self._create_child_list(self._error_fallback_elements(node, exc))
|
|
119
|
+
for child in children:
|
|
120
|
+
child.parent = node
|
|
121
|
+
node.children = children
|
|
122
|
+
self._refresh_identity(node)
|
|
123
|
+
|
|
124
|
+
def _error_fallback_elements(self, node: VNode, exc: BaseException) -> List[Element]:
|
|
125
|
+
"""Render a boundary's fallback prop into a normalized child list."""
|
|
126
|
+
fallback = node.element.props.get("fallback")
|
|
127
|
+
if fallback is None:
|
|
128
|
+
return []
|
|
129
|
+
result: Any = fallback
|
|
130
|
+
if callable(fallback) and not isinstance(fallback, Element):
|
|
131
|
+
arity = _positional_arity(fallback)
|
|
132
|
+
if arity >= 2:
|
|
133
|
+
result = fallback(exc, self._make_boundary_reset(node))
|
|
134
|
+
elif arity == 1:
|
|
135
|
+
result = fallback(exc)
|
|
136
|
+
else:
|
|
137
|
+
result = fallback()
|
|
138
|
+
return normalize_children(result, owner="ErrorBoundary.fallback")
|
|
139
|
+
|
|
140
|
+
def _make_boundary_reset(self, node: VNode) -> Callable[[], None]:
|
|
141
|
+
"""Return the ``reset`` callable handed to a boundary's fallback."""
|
|
142
|
+
|
|
143
|
+
def reset() -> None:
|
|
144
|
+
if not node.mounted or node.error is None:
|
|
145
|
+
return
|
|
146
|
+
node.error = None
|
|
147
|
+
self._dirty_boundaries[id(node)] = node
|
|
148
|
+
from ..scheduler import schedule_trigger
|
|
149
|
+
|
|
150
|
+
schedule_trigger(self.request_render)
|
|
151
|
+
|
|
152
|
+
return reset
|
|
153
|
+
|
|
154
|
+
# ------------------------------------------------------------------
|
|
155
|
+
# Suspense boundaries
|
|
156
|
+
# ------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
def _create_suspense(self, element: Element) -> VNode:
|
|
159
|
+
if element.props.get("fallback") is None:
|
|
160
|
+
return self._create_wrapper(element, "Suspense")
|
|
161
|
+
node = VNode(element, [])
|
|
162
|
+
self._attempt_suspense_content(node)
|
|
163
|
+
return node
|
|
164
|
+
|
|
165
|
+
def _reconcile_suspense(self, old: VNode, new_el: Element) -> VNode:
|
|
166
|
+
previous = old.element
|
|
167
|
+
old.element = new_el
|
|
168
|
+
if old.suspense_showing_fallback and previous.children != new_el.children:
|
|
169
|
+
if old.suspense_hydration:
|
|
170
|
+
self._dispose_hydration(old.suspense_hydration)
|
|
171
|
+
old.suspense_hydration = None
|
|
172
|
+
old.suspense_waits = None
|
|
173
|
+
self._attempt_suspense_content(old)
|
|
174
|
+
return old
|
|
175
|
+
if old.suspense_showing_fallback:
|
|
176
|
+
# Fallback showing; keep it in sync with the latest fallback
|
|
177
|
+
# prop. Content retries are driven by waitable completions,
|
|
178
|
+
# not by parent re-renders.
|
|
179
|
+
old.children = self._reconcile_child_list(old.children, self._suspense_fallback_elements(old))
|
|
180
|
+
for child in old.children:
|
|
181
|
+
child.parent = old
|
|
182
|
+
self._refresh_identity(old)
|
|
183
|
+
return old
|
|
184
|
+
try:
|
|
185
|
+
children = self._reconcile_child_list(old.children, normalize_children(new_el.children, owner="Suspense"))
|
|
186
|
+
old.children = children
|
|
187
|
+
for child in children:
|
|
188
|
+
child.parent = old
|
|
189
|
+
self._refresh_identity(old)
|
|
190
|
+
except Suspend as signal:
|
|
191
|
+
self._teardown_suspense_content(old)
|
|
192
|
+
self._suspend_boundary(old, signal)
|
|
193
|
+
return old
|
|
194
|
+
|
|
195
|
+
def _attempt_suspense_content(self, node: VNode) -> None:
|
|
196
|
+
"""Build a boundary's content from scratch (initial mount or retry).
|
|
197
|
+
|
|
198
|
+
Components re-adopt hook states preserved from the previous
|
|
199
|
+
attempt (the hydration map), so cached resources resolve
|
|
200
|
+
instead of refetching. On success any still-showing fallback
|
|
201
|
+
is swapped out for the content; on suspension the fallback
|
|
202
|
+
mounts (or stays) and a retry is wired to the pending work.
|
|
203
|
+
"""
|
|
204
|
+
hydration: HydrationMap = node.suspense_hydration or {}
|
|
205
|
+
node.suspense_hydration = None
|
|
206
|
+
saved_hydration = self._hydration
|
|
207
|
+
saved_salvage = self._suspense_salvage
|
|
208
|
+
self._hydration = hydration
|
|
209
|
+
self._suspense_salvage = None
|
|
210
|
+
try:
|
|
211
|
+
children = self._create_child_list(normalize_children(node.element.children, owner="Suspense"))
|
|
212
|
+
except Suspend as signal:
|
|
213
|
+
# Unclaimed hook states from the previous attempt stay
|
|
214
|
+
# preserved for the next retry; salvaged sibling states are
|
|
215
|
+
# folded in by _suspend_boundary.
|
|
216
|
+
merged = {key: states for key, states in hydration.items() if states}
|
|
217
|
+
node.suspense_hydration = merged or None
|
|
218
|
+
self._suspend_boundary(node, signal)
|
|
219
|
+
return
|
|
220
|
+
finally:
|
|
221
|
+
self._hydration = saved_hydration
|
|
222
|
+
self._suspense_salvage = saved_salvage
|
|
223
|
+
|
|
224
|
+
self._dispose_hydration(hydration)
|
|
225
|
+
for child in node.children:
|
|
226
|
+
self._destroy_tree(child)
|
|
227
|
+
for child in children:
|
|
228
|
+
child.parent = node
|
|
229
|
+
node.children = children
|
|
230
|
+
node.suspense_showing_fallback = False
|
|
231
|
+
node.suspense_waits = None
|
|
232
|
+
self._refresh_identity(node)
|
|
233
|
+
|
|
234
|
+
def _teardown_suspense_content(self, node: VNode) -> None:
|
|
235
|
+
"""Destroy a boundary's live content, salvaging its hook states.
|
|
236
|
+
|
|
237
|
+
Used when an *update* under the boundary suspends: the content
|
|
238
|
+
components' hook states move into the boundary's hydration map,
|
|
239
|
+
so when the retry re-mounts them their state, caches, and
|
|
240
|
+
effect bookkeeping carry over (the fallback round-trip doesn't
|
|
241
|
+
reset the subtree).
|
|
242
|
+
"""
|
|
243
|
+
salvage: HydrationMap = {}
|
|
244
|
+
for child in node.children:
|
|
245
|
+
self._destroy_tree(child, salvage=salvage)
|
|
246
|
+
node.children = []
|
|
247
|
+
node.suspense_showing_fallback = False
|
|
248
|
+
if salvage:
|
|
249
|
+
hydration = node.suspense_hydration
|
|
250
|
+
if hydration is None:
|
|
251
|
+
hydration = node.suspense_hydration = {}
|
|
252
|
+
for key, states in salvage.items():
|
|
253
|
+
hydration.setdefault(key, []).extend(states)
|
|
254
|
+
|
|
255
|
+
def _suspend_boundary(self, node: VNode, signal: Suspend) -> None:
|
|
256
|
+
"""Show a boundary's fallback and schedule a retry for ``signal``.
|
|
257
|
+
|
|
258
|
+
A boundary without a fallback is transparent: the suspension
|
|
259
|
+
propagates to the next Suspense ancestor (mirroring how an
|
|
260
|
+
ErrorBoundary without a fallback re-raises).
|
|
261
|
+
"""
|
|
262
|
+
if node.element.props.get("fallback") is None:
|
|
263
|
+
raise signal
|
|
264
|
+
|
|
265
|
+
# Fold in hook states salvaged while the Suspend unwound
|
|
266
|
+
# (already-rendered siblings of the suspender), plus the
|
|
267
|
+
# suspender's own state carried on the signal.
|
|
268
|
+
salvage = self._suspense_salvage
|
|
269
|
+
self._suspense_salvage = None
|
|
270
|
+
if salvage or (signal.hook_state is not None and signal.key is not None):
|
|
271
|
+
hydration = node.suspense_hydration
|
|
272
|
+
if hydration is None:
|
|
273
|
+
hydration = node.suspense_hydration = {}
|
|
274
|
+
if salvage:
|
|
275
|
+
for key, states in salvage.items():
|
|
276
|
+
hydration.setdefault(key, []).extend(states)
|
|
277
|
+
if signal.hook_state is not None and signal.key is not None:
|
|
278
|
+
bucket = hydration.setdefault(signal.key, [])
|
|
279
|
+
if signal.hook_state not in bucket:
|
|
280
|
+
bucket.append(signal.hook_state)
|
|
281
|
+
|
|
282
|
+
if not node.suspense_showing_fallback:
|
|
283
|
+
children = self._create_child_list(self._suspense_fallback_elements(node))
|
|
284
|
+
for child in children:
|
|
285
|
+
child.parent = node
|
|
286
|
+
node.children = children
|
|
287
|
+
node.suspense_showing_fallback = True
|
|
288
|
+
self._refresh_identity(node)
|
|
289
|
+
|
|
290
|
+
self._watch_waitable(node, signal.waitable)
|
|
291
|
+
|
|
292
|
+
@staticmethod
|
|
293
|
+
def _suspense_fallback_elements(node: VNode) -> List[Element]:
|
|
294
|
+
fallback = node.element.props.get("fallback")
|
|
295
|
+
if fallback is None:
|
|
296
|
+
return []
|
|
297
|
+
result: Any = fallback
|
|
298
|
+
if callable(fallback) and not isinstance(fallback, Element):
|
|
299
|
+
result = fallback()
|
|
300
|
+
return normalize_children(result, owner="Suspense.fallback")
|
|
301
|
+
|
|
302
|
+
def _watch_waitable(self, node: VNode, waitable: Any) -> None:
|
|
303
|
+
"""Queue a content retry for ``node`` when ``waitable`` completes."""
|
|
304
|
+
waits = node.suspense_waits
|
|
305
|
+
if waits is None:
|
|
306
|
+
waits = node.suspense_waits = set()
|
|
307
|
+
marker = id(waitable)
|
|
308
|
+
if marker in waits:
|
|
309
|
+
return
|
|
310
|
+
waits.add(marker)
|
|
311
|
+
|
|
312
|
+
def _on_done(_w: Any = None) -> None:
|
|
313
|
+
live_waits = node.suspense_waits
|
|
314
|
+
if live_waits is not None:
|
|
315
|
+
live_waits.discard(marker)
|
|
316
|
+
if not node.mounted or not node.suspense_showing_fallback:
|
|
317
|
+
return
|
|
318
|
+
self._dirty_suspense[id(node)] = node
|
|
319
|
+
from ..scheduler import schedule_trigger
|
|
320
|
+
|
|
321
|
+
schedule_trigger(self.request_render)
|
|
322
|
+
|
|
323
|
+
waitable.add_done_callback(_on_done)
|
|
324
|
+
|
|
325
|
+
def _take_hydrated_hook_state(self, element: Element) -> Optional[HookState]:
|
|
326
|
+
"""Pop a preserved hook state matching ``element`` from the hydration map."""
|
|
327
|
+
hydration = self._hydration
|
|
328
|
+
if not hydration:
|
|
329
|
+
return None
|
|
330
|
+
bucket = hydration.get((id(element.type), element.key))
|
|
331
|
+
if not bucket:
|
|
332
|
+
return None
|
|
333
|
+
return bucket.pop(0)
|
|
334
|
+
|
|
335
|
+
@staticmethod
|
|
336
|
+
def _dispose_hydration(hydration: HydrationMap) -> None:
|
|
337
|
+
"""Clean up preserved hook states that no component reclaimed."""
|
|
338
|
+
for states in hydration.values():
|
|
339
|
+
for hook_state in states:
|
|
340
|
+
try:
|
|
341
|
+
hook_state.cleanup_all_effects()
|
|
342
|
+
except Exception as exc:
|
|
343
|
+
diagnostics.warn(f"Error disposing a suspended component's state: {exc!r}")
|
|
344
|
+
hydration.clear()
|
|
345
|
+
|
|
346
|
+
def _discard_salvage(self) -> None:
|
|
347
|
+
"""Dispose hook states salvaged during a Suspend that no boundary caught."""
|
|
348
|
+
salvage = self._suspense_salvage
|
|
349
|
+
self._suspense_salvage = None
|
|
350
|
+
if salvage:
|
|
351
|
+
self._dispose_hydration(salvage)
|
|
352
|
+
|
|
353
|
+
@staticmethod
|
|
354
|
+
def _missing_suspense_error(signal: Suspend) -> RuntimeError:
|
|
355
|
+
who = signal.label or "A component"
|
|
356
|
+
return RuntimeError(
|
|
357
|
+
f"{who} suspended while rendering, but no Suspense ancestor provides a "
|
|
358
|
+
"fallback. Wrap the async part of the tree in pn.Suspense(..., "
|
|
359
|
+
"fallback=...) to declare its loading state."
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _positional_arity(fn: Callable[..., Any]) -> int:
|
|
364
|
+
"""Count positional parameters ``fn`` accepts (2+ means unbounded is fine)."""
|
|
365
|
+
try:
|
|
366
|
+
sig = inspect.signature(fn)
|
|
367
|
+
except (TypeError, ValueError):
|
|
368
|
+
return 1
|
|
369
|
+
count = 0
|
|
370
|
+
for p in sig.parameters.values():
|
|
371
|
+
if p.kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD):
|
|
372
|
+
count += 1
|
|
373
|
+
elif p.kind == inspect.Parameter.VAR_POSITIONAL:
|
|
374
|
+
return 2
|
|
375
|
+
return count
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Pure planning of native child-list moves.
|
|
2
|
+
|
|
3
|
+
Given the tags a native container currently holds and the tags it
|
|
4
|
+
should hold after a pass, [`plan_child_moves`][pythonnative.reconciler.children.plan_child_moves]
|
|
5
|
+
returns the minimal sequence of ``(tag, index)`` insertions (with
|
|
6
|
+
move-aware ``insert_child`` semantics: a child already attached is
|
|
7
|
+
re-positioned) that transforms one into the other.
|
|
8
|
+
|
|
9
|
+
The algorithm keeps the longest increasing subsequence of surviving
|
|
10
|
+
children in place and moves only the rest, processing right to left so
|
|
11
|
+
every moved child is inserted directly before an already-settled
|
|
12
|
+
neighbor. That yields ``n - len(LIS)`` operations, the optimum for a
|
|
13
|
+
move-aware insert primitive.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from bisect import bisect_left
|
|
19
|
+
from typing import Dict, List, Optional, Sequence, Tuple
|
|
20
|
+
|
|
21
|
+
__all__ = ["longest_increasing_subsequence", "plan_child_moves"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def longest_increasing_subsequence(values: Sequence[int]) -> List[int]:
|
|
25
|
+
"""Return the indices (into ``values``) of one longest strictly increasing subsequence."""
|
|
26
|
+
if not values:
|
|
27
|
+
return []
|
|
28
|
+
tails: List[int] = [] # values
|
|
29
|
+
tails_idx: List[int] = [] # index into values of each tail
|
|
30
|
+
prev: List[int] = [-1] * len(values)
|
|
31
|
+
for i, v in enumerate(values):
|
|
32
|
+
pos = bisect_left(tails, v)
|
|
33
|
+
if pos == len(tails):
|
|
34
|
+
tails.append(v)
|
|
35
|
+
tails_idx.append(i)
|
|
36
|
+
else:
|
|
37
|
+
tails[pos] = v
|
|
38
|
+
tails_idx[pos] = i
|
|
39
|
+
prev[i] = tails_idx[pos - 1] if pos > 0 else -1
|
|
40
|
+
out: List[int] = []
|
|
41
|
+
cursor = tails_idx[-1]
|
|
42
|
+
while cursor != -1:
|
|
43
|
+
out.append(cursor)
|
|
44
|
+
cursor = prev[cursor]
|
|
45
|
+
out.reverse()
|
|
46
|
+
return out
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def plan_child_moves(before: Sequence[int], after: Sequence[int]) -> List[Tuple[int, int]]:
|
|
50
|
+
"""Compute ``(tag, index)`` insert ops turning ``before`` into ``after``.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
before: Tags currently attached to the container, in order.
|
|
54
|
+
Tags absent from ``after`` are assumed to be detached
|
|
55
|
+
already (the reconciler destroys them first) and must not
|
|
56
|
+
appear here.
|
|
57
|
+
after: Desired child tags, in order. Tags absent from
|
|
58
|
+
``before`` are fresh children.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Ordered insert operations. Applying each as "detach ``tag`` if
|
|
62
|
+
attached, then insert at ``index``" reproduces ``after``.
|
|
63
|
+
"""
|
|
64
|
+
if list(before) == list(after):
|
|
65
|
+
return []
|
|
66
|
+
position_after: Dict[int, int] = {tag: i for i, tag in enumerate(after)}
|
|
67
|
+
# Surviving children in their current order, mapped to their target
|
|
68
|
+
# positions; the LIS of that sequence is the set we never touch.
|
|
69
|
+
surviving_targets = [position_after[tag] for tag in before if tag in position_after]
|
|
70
|
+
keep_positions = set(surviving_targets[i] for i in longest_increasing_subsequence(surviving_targets))
|
|
71
|
+
|
|
72
|
+
sim: List[int] = list(before)
|
|
73
|
+
ops: List[Tuple[int, int]] = []
|
|
74
|
+
anchor: Optional[int] = None
|
|
75
|
+
for i in range(len(after) - 1, -1, -1):
|
|
76
|
+
tag = after[i]
|
|
77
|
+
if i in keep_positions:
|
|
78
|
+
anchor = tag
|
|
79
|
+
continue
|
|
80
|
+
try:
|
|
81
|
+
sim.remove(tag)
|
|
82
|
+
except ValueError:
|
|
83
|
+
pass
|
|
84
|
+
index = sim.index(anchor) if anchor is not None else len(sim)
|
|
85
|
+
sim.insert(index, tag)
|
|
86
|
+
ops.append((tag, index))
|
|
87
|
+
anchor = tag
|
|
88
|
+
return ops
|