pythonnative 0.17.1__tar.gz → 0.19.0__tar.gz
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-0.17.1/src/pythonnative.egg-info → pythonnative-0.19.0}/PKG-INFO +4 -1
- {pythonnative-0.17.1 → pythonnative-0.19.0}/README.md +3 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/pyproject.toml +4 -1
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/__init__.py +53 -2
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/cli/pn.py +107 -1
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/components.py +547 -10
- pythonnative-0.19.0/src/pythonnative/native_modules/__init__.py +79 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/app_state.py +94 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/battery.py +139 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/biometrics.py +156 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/clipboard.py +142 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/haptics.py +180 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/linking.py +179 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/net_info.py +151 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/permissions.py +200 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/secure_store.py +193 -0
- pythonnative-0.19.0/src/pythonnative/native_modules/share.py +155 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_views/__init__.py +18 -5
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_views/android.py +974 -23
- pythonnative-0.19.0/src/pythonnative/native_views/desktop.py +1489 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_views/ios.py +952 -27
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/platform.py +17 -8
- pythonnative-0.19.0/src/pythonnative/preview.py +471 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/runtime.py +26 -1
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/screen.py +184 -4
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/utils.py +38 -2
- {pythonnative-0.17.1 → pythonnative-0.19.0/src/pythonnative.egg-info}/PKG-INFO +4 -1
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative.egg-info/SOURCES.txt +15 -0
- pythonnative-0.19.0/tests/test_desktop_backend.py +363 -0
- pythonnative-0.19.0/tests/test_extended_components.py +296 -0
- pythonnative-0.19.0/tests/test_native_modules.py +268 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_screen.py +43 -0
- pythonnative-0.17.1/src/pythonnative/native_modules/__init__.py +0 -25
- {pythonnative-0.17.1 → pythonnative-0.19.0}/LICENSE +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/setup.cfg +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/_ios_log.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/alerts.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/animated.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/cli/__init__.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/element.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/hooks.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/hot_reload.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/layout.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_modules/camera.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_modules/file_system.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_modules/location.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_modules/notifications.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/native_views/base.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/navigation.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/net.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/platform_metrics.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/reconciler.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/sdk/__init__.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/sdk/_components.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/storage.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/style.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/build.gradle +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/proguard-rules.pro +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PNVirtualListView.java +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/values/colors.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/values/strings.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/values/themes.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/build.gradle +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/gradle.properties +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/gradlew +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/gradlew.bat +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/android_template/settings.gradle +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/AppDelegate.swift +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/Base.lproj/Main.storyboard +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/Info.plist +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template/ViewController.swift +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative.egg-info/dependency_links.txt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative.egg-info/entry_points.txt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative.egg-info/requires.txt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/src/pythonnative.egg-info/top_level.txt +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_alert.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_animated.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_async_hooks.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_cli.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_components.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_element.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_hooks.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_hot_reload.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_ios_log.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_layout.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_metric_hooks.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_native_views.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_navigation.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_net.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_new_components.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_platform.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_platform_metrics.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_reconciler.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_ref.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_runtime.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_sdk.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_smoke.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_storage.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_style.py +0 -0
- {pythonnative-0.17.1 → pythonnative-0.19.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonnative
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: Cross-platform native UI toolkit for Android and iOS
|
|
5
5
|
Author: Owen Carey
|
|
6
6
|
License: MIT License
|
|
@@ -97,6 +97,8 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
|
|
|
97
97
|
## Features
|
|
98
98
|
|
|
99
99
|
- **Declarative UI:** Describe *what* your UI should look like with element functions (`Text`, `Button`, `Column`, `Row`, etc.). PythonNative creates and updates native views automatically.
|
|
100
|
+
- **Rich component library:** 25+ built-in components backed by real native widgets — `TextInput`, `Image` / `ImageBackground`, `ScrollView`, `FlatList` / `SectionList`, `Modal`, `Pressable` / `TouchableOpacity`, `Switch` / `Checkbox`, `Slider`, `SegmentedControl`, `Picker`, `DatePicker`, `ProgressBar` / `ActivityIndicator`, `WebView`, and more.
|
|
101
|
+
- **Device APIs:** Cross-platform modules for `Camera`, `Location`, `FileSystem`, `Notifications`, `Clipboard`, `Share`, `Linking`, `Permissions`, `AppState`, `NetInfo`, `SecureStore`, `Battery`, `Haptics` / `Vibration`, and `Biometrics` — plus reactive `use_app_state` and `use_net_info` hooks.
|
|
100
102
|
- **Hooks and function components:** Manage state with `use_state`, side effects with `use_effect`, and navigation with `use_navigation`, all through one consistent pattern.
|
|
101
103
|
- **Typed `style` prop:** Pass all visual and layout properties through a single `style` dict, fully described by the `pn.Style` `TypedDict` and the ergonomic `pn.style(...)` helper for IDE autocomplete and static checking. Compose reusable styles with `StyleSheet`.
|
|
102
104
|
- **Cross-platform flexbox engine:** A pure-Python, Yoga-style layout engine computes frames once and applies them to native views, so `flex`, `padding`, `aspect_ratio`, and `position: "absolute"` produce the same geometry on Android and iOS.
|
|
@@ -104,6 +106,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
|
|
|
104
106
|
- **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge.
|
|
105
107
|
- **Custom-component SDK:** Wrap any platform widget as a first-class element with type-checked props via `pythonnative.sdk` (`Props`, `@native_component`, `element_factory`). Plugins distributed on PyPI auto-register through the `pythonnative.handlers` entry-point group.
|
|
106
108
|
- **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app.
|
|
109
|
+
- **Instant desktop preview:** `pn preview` renders your app in a native desktop window via Tkinter with Fast Refresh on every save — iterate on layout, state, and navigation in milliseconds without booting a simulator or device. The reconciler, hooks, layout engine, and navigation are the same code that ships to the phone.
|
|
107
110
|
- **Native-backed navigation:** Declarative `Stack`, `Tab`, and `Drawer` navigators inspired by React Navigation. The root stack drives the platform's native navigation controller (`UINavigationController` on iOS, AndroidX Navigation Component on Android), so transitions, back gestures, and the hardware back button match what users expect.
|
|
108
111
|
- **Fast Refresh hot reload:** `pn run --hot-reload` watches `app/` and patches edits into the running app on save, preserving component state across most changes.
|
|
109
112
|
- **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access.
|
|
@@ -31,6 +31,8 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
|
|
|
31
31
|
## Features
|
|
32
32
|
|
|
33
33
|
- **Declarative UI:** Describe *what* your UI should look like with element functions (`Text`, `Button`, `Column`, `Row`, etc.). PythonNative creates and updates native views automatically.
|
|
34
|
+
- **Rich component library:** 25+ built-in components backed by real native widgets — `TextInput`, `Image` / `ImageBackground`, `ScrollView`, `FlatList` / `SectionList`, `Modal`, `Pressable` / `TouchableOpacity`, `Switch` / `Checkbox`, `Slider`, `SegmentedControl`, `Picker`, `DatePicker`, `ProgressBar` / `ActivityIndicator`, `WebView`, and more.
|
|
35
|
+
- **Device APIs:** Cross-platform modules for `Camera`, `Location`, `FileSystem`, `Notifications`, `Clipboard`, `Share`, `Linking`, `Permissions`, `AppState`, `NetInfo`, `SecureStore`, `Battery`, `Haptics` / `Vibration`, and `Biometrics` — plus reactive `use_app_state` and `use_net_info` hooks.
|
|
34
36
|
- **Hooks and function components:** Manage state with `use_state`, side effects with `use_effect`, and navigation with `use_navigation`, all through one consistent pattern.
|
|
35
37
|
- **Typed `style` prop:** Pass all visual and layout properties through a single `style` dict, fully described by the `pn.Style` `TypedDict` and the ergonomic `pn.style(...)` helper for IDE autocomplete and static checking. Compose reusable styles with `StyleSheet`.
|
|
36
38
|
- **Cross-platform flexbox engine:** A pure-Python, Yoga-style layout engine computes frames once and applies them to native views, so `flex`, `padding`, `aspect_ratio`, and `position: "absolute"` produce the same geometry on Android and iOS.
|
|
@@ -38,6 +40,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
|
|
|
38
40
|
- **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge.
|
|
39
41
|
- **Custom-component SDK:** Wrap any platform widget as a first-class element with type-checked props via `pythonnative.sdk` (`Props`, `@native_component`, `element_factory`). Plugins distributed on PyPI auto-register through the `pythonnative.handlers` entry-point group.
|
|
40
42
|
- **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app.
|
|
43
|
+
- **Instant desktop preview:** `pn preview` renders your app in a native desktop window via Tkinter with Fast Refresh on every save — iterate on layout, state, and navigation in milliseconds without booting a simulator or device. The reconciler, hooks, layout engine, and navigation are the same code that ships to the phone.
|
|
41
44
|
- **Native-backed navigation:** Declarative `Stack`, `Tab`, and `Drawer` navigators inspired by React Navigation. The root stack drives the platform's native navigation controller (`UINavigationController` on iOS, AndroidX Navigation Component on Android), so transitions, back gestures, and the hardware back button match what users expect.
|
|
42
45
|
- **Fast Refresh hot reload:** `pn run --hot-reload` watches `app/` and patches edits into the running app on save, preserving component state across most changes.
|
|
43
46
|
- **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pythonnative"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.19.0"
|
|
8
8
|
description = "Cross-platform native UI toolkit for Android and iOS"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Owen Carey" }
|
|
@@ -70,6 +70,8 @@ Documentation = "https://docs.pythonnative.com/"
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
|
|
74
|
+
|
|
73
75
|
[tool.setuptools.packages.find]
|
|
74
76
|
where = ["src"]
|
|
75
77
|
|
|
@@ -116,6 +118,7 @@ ignore = ["D107", "D105", "D203", "D213"]
|
|
|
116
118
|
# docstrings would only add boilerplate that repeats the ABC.
|
|
117
119
|
"src/pythonnative/native_views/android.py" = ["D101", "D102"]
|
|
118
120
|
"src/pythonnative/native_views/ios.py" = ["D101", "D102"]
|
|
121
|
+
"src/pythonnative/native_views/desktop.py" = ["D101", "D102"]
|
|
119
122
|
|
|
120
123
|
[tool.ruff.lint.pydocstyle]
|
|
121
124
|
convention = "google"
|
|
@@ -51,7 +51,7 @@ Example:
|
|
|
51
51
|
```
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
|
-
__version__ = "0.
|
|
54
|
+
__version__ = "0.19.0"
|
|
55
55
|
|
|
56
56
|
from . import runtime, sdk
|
|
57
57
|
from .alerts import Alert
|
|
@@ -61,11 +61,17 @@ from .components import (
|
|
|
61
61
|
ActivityIndicatorProps,
|
|
62
62
|
Button,
|
|
63
63
|
ButtonProps,
|
|
64
|
+
Checkbox,
|
|
65
|
+
CheckboxProps,
|
|
64
66
|
Column,
|
|
67
|
+
DatePicker,
|
|
68
|
+
DatePickerProps,
|
|
65
69
|
ErrorBoundary,
|
|
66
70
|
FlatList,
|
|
67
71
|
Fragment,
|
|
68
72
|
Image,
|
|
73
|
+
ImageBackground,
|
|
74
|
+
ImageBackgroundProps,
|
|
69
75
|
ImageProps,
|
|
70
76
|
KeyboardAvoidingView,
|
|
71
77
|
KeyboardAvoidingViewProps,
|
|
@@ -84,6 +90,8 @@ from .components import (
|
|
|
84
90
|
ScrollView,
|
|
85
91
|
ScrollViewProps,
|
|
86
92
|
SectionList,
|
|
93
|
+
SegmentedControl,
|
|
94
|
+
SegmentedControlProps,
|
|
87
95
|
Slider,
|
|
88
96
|
SliderProps,
|
|
89
97
|
Spacer,
|
|
@@ -96,6 +104,8 @@ from .components import (
|
|
|
96
104
|
TextInput,
|
|
97
105
|
TextInputProps,
|
|
98
106
|
TextProps,
|
|
107
|
+
TouchableOpacity,
|
|
108
|
+
TouchableOpacityProps,
|
|
99
109
|
View,
|
|
100
110
|
ViewProps,
|
|
101
111
|
WebView,
|
|
@@ -126,7 +136,25 @@ from .hooks import (
|
|
|
126
136
|
use_state,
|
|
127
137
|
use_window_dimensions,
|
|
128
138
|
)
|
|
129
|
-
from .native_modules import
|
|
139
|
+
from .native_modules import (
|
|
140
|
+
AppState,
|
|
141
|
+
Battery,
|
|
142
|
+
Biometrics,
|
|
143
|
+
Camera,
|
|
144
|
+
Clipboard,
|
|
145
|
+
FileSystem,
|
|
146
|
+
Haptics,
|
|
147
|
+
Linking,
|
|
148
|
+
Location,
|
|
149
|
+
NetInfo,
|
|
150
|
+
Notifications,
|
|
151
|
+
Permissions,
|
|
152
|
+
SecureStore,
|
|
153
|
+
Share,
|
|
154
|
+
Vibration,
|
|
155
|
+
use_app_state,
|
|
156
|
+
use_net_info,
|
|
157
|
+
)
|
|
130
158
|
from .navigation import (
|
|
131
159
|
NavigationContainer,
|
|
132
160
|
create_drawer_navigator,
|
|
@@ -178,11 +206,14 @@ __all__ = [
|
|
|
178
206
|
# Components
|
|
179
207
|
"ActivityIndicator",
|
|
180
208
|
"Button",
|
|
209
|
+
"Checkbox",
|
|
181
210
|
"Column",
|
|
211
|
+
"DatePicker",
|
|
182
212
|
"ErrorBoundary",
|
|
183
213
|
"FlatList",
|
|
184
214
|
"Fragment",
|
|
185
215
|
"Image",
|
|
216
|
+
"ImageBackground",
|
|
186
217
|
"KeyboardAvoidingView",
|
|
187
218
|
"Modal",
|
|
188
219
|
"Picker",
|
|
@@ -193,17 +224,22 @@ __all__ = [
|
|
|
193
224
|
"SafeAreaView",
|
|
194
225
|
"ScrollView",
|
|
195
226
|
"SectionList",
|
|
227
|
+
"SegmentedControl",
|
|
196
228
|
"Slider",
|
|
197
229
|
"Spacer",
|
|
198
230
|
"StatusBar",
|
|
199
231
|
"Switch",
|
|
200
232
|
"Text",
|
|
201
233
|
"TextInput",
|
|
234
|
+
"TouchableOpacity",
|
|
202
235
|
"View",
|
|
203
236
|
"WebView",
|
|
204
237
|
# Built-in Props dataclasses
|
|
205
238
|
"ActivityIndicatorProps",
|
|
206
239
|
"ButtonProps",
|
|
240
|
+
"CheckboxProps",
|
|
241
|
+
"DatePickerProps",
|
|
242
|
+
"ImageBackgroundProps",
|
|
207
243
|
"ImageProps",
|
|
208
244
|
"KeyboardAvoidingViewProps",
|
|
209
245
|
"ModalProps",
|
|
@@ -212,12 +248,14 @@ __all__ = [
|
|
|
212
248
|
"ProgressBarProps",
|
|
213
249
|
"SafeAreaViewProps",
|
|
214
250
|
"ScrollViewProps",
|
|
251
|
+
"SegmentedControlProps",
|
|
215
252
|
"SliderProps",
|
|
216
253
|
"SpacerProps",
|
|
217
254
|
"StatusBarProps",
|
|
218
255
|
"SwitchProps",
|
|
219
256
|
"TextInputProps",
|
|
220
257
|
"TextProps",
|
|
258
|
+
"TouchableOpacityProps",
|
|
221
259
|
"ViewProps",
|
|
222
260
|
"WebViewProps",
|
|
223
261
|
# Core
|
|
@@ -286,10 +324,23 @@ __all__ = [
|
|
|
286
324
|
# Imperative
|
|
287
325
|
"Alert",
|
|
288
326
|
# Native modules
|
|
327
|
+
"AppState",
|
|
328
|
+
"Battery",
|
|
329
|
+
"Biometrics",
|
|
289
330
|
"Camera",
|
|
331
|
+
"Clipboard",
|
|
290
332
|
"FileSystem",
|
|
333
|
+
"Haptics",
|
|
334
|
+
"Linking",
|
|
291
335
|
"Location",
|
|
336
|
+
"NetInfo",
|
|
292
337
|
"Notifications",
|
|
338
|
+
"Permissions",
|
|
339
|
+
"SecureStore",
|
|
340
|
+
"Share",
|
|
341
|
+
"Vibration",
|
|
342
|
+
"use_app_state",
|
|
343
|
+
"use_net_info",
|
|
293
344
|
# Networking + persistence
|
|
294
345
|
"AsyncStorage",
|
|
295
346
|
"fetch",
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"""`pn` CLI: scaffold, run, and clean PythonNative projects.
|
|
2
2
|
|
|
3
3
|
The console script `pn` (declared in `pyproject.toml` under
|
|
4
|
-
`[project.scripts]`) dispatches to one of
|
|
4
|
+
`[project.scripts]`) dispatches to one of four subcommands:
|
|
5
5
|
|
|
6
6
|
- `pn init [name]`: scaffold a new project in the current directory.
|
|
7
|
+
- `pn preview [component]`: render the app in a desktop (Tkinter)
|
|
8
|
+
window with instant Fast Refresh — the fast inner dev loop, no
|
|
9
|
+
device or simulator required.
|
|
7
10
|
- `pn run android|ios`: stage code into a native template, build it,
|
|
8
11
|
install it, and stream logs back to the terminal.
|
|
9
12
|
- `pn clean`: remove the local `build/` directory.
|
|
@@ -1119,6 +1122,90 @@ def _run_hot_reload(platform: str, project_dir: str, build_dir: str, show_logs:
|
|
|
1119
1122
|
print("\n[hot-reload] Stopped.")
|
|
1120
1123
|
|
|
1121
1124
|
|
|
1125
|
+
def _entrypoint_to_module(entry_point: str) -> str:
|
|
1126
|
+
"""Convert a config ``entryPoint`` path into an importable module path.
|
|
1127
|
+
|
|
1128
|
+
``"app/main.py"`` → ``"app.main"``. Returns ``"app.main"`` for
|
|
1129
|
+
empty / unusable input so ``pn preview`` always has a sane default.
|
|
1130
|
+
"""
|
|
1131
|
+
normalized = entry_point.strip().replace("\\", "/")
|
|
1132
|
+
if normalized.endswith(".py"):
|
|
1133
|
+
normalized = normalized[:-3]
|
|
1134
|
+
normalized = normalized.strip("/").replace("/", ".")
|
|
1135
|
+
return normalized or "app.main"
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
def preview_project(args: argparse.Namespace) -> None:
|
|
1139
|
+
"""Render the project in a desktop preview window (Tkinter).
|
|
1140
|
+
|
|
1141
|
+
Sets ``PN_PLATFORM=desktop`` (so PythonNative selects the Tkinter
|
|
1142
|
+
backend) and hands off to ``pythonnative.preview.run_preview``,
|
|
1143
|
+
which opens a window, mounts the app, and Fast Refreshes on every
|
|
1144
|
+
file save until the window is closed.
|
|
1145
|
+
|
|
1146
|
+
Args:
|
|
1147
|
+
args: Parsed argparse namespace. Recognized attributes:
|
|
1148
|
+
|
|
1149
|
+
- `component` (`str`, optional): Module path like
|
|
1150
|
+
``"app.main"`` (its ``App`` is used) or a dotted
|
|
1151
|
+
``module.Component`` path. Defaults to the project's
|
|
1152
|
+
configured ``entryPoint``.
|
|
1153
|
+
- `width` / `height` (`int`): Initial window size in points.
|
|
1154
|
+
- `title` (`str`): Window title.
|
|
1155
|
+
- `no_hot_reload` (`bool`): Disable file watching.
|
|
1156
|
+
"""
|
|
1157
|
+
# The desktop backend is selected at *import time* from the
|
|
1158
|
+
# ``PN_PLATFORM`` environment variable (see ``pythonnative.utils`` and
|
|
1159
|
+
# the host selection in ``pythonnative.screen``). Because the ``pn``
|
|
1160
|
+
# console entry point lives inside the ``pythonnative`` package,
|
|
1161
|
+
# importing it already loaded the package under the default,
|
|
1162
|
+
# non-desktop platform before this handler ever runs. Re-exec a fresh
|
|
1163
|
+
# interpreter with the variable set so every module binds to the
|
|
1164
|
+
# Tkinter backend; the re-execed child sees ``PN_PLATFORM=desktop`` and
|
|
1165
|
+
# skips this branch, so there is no exec loop.
|
|
1166
|
+
if os.environ.get("PN_PLATFORM") != "desktop":
|
|
1167
|
+
try:
|
|
1168
|
+
completed = subprocess.run(
|
|
1169
|
+
[sys.executable, "-m", "pythonnative.cli.pn", *sys.argv[1:]],
|
|
1170
|
+
env={**os.environ, "PN_PLATFORM": "desktop"},
|
|
1171
|
+
)
|
|
1172
|
+
except KeyboardInterrupt:
|
|
1173
|
+
sys.exit(130)
|
|
1174
|
+
sys.exit(completed.returncode)
|
|
1175
|
+
|
|
1176
|
+
project_dir = os.getcwd()
|
|
1177
|
+
component: Optional[str] = getattr(args, "component", None)
|
|
1178
|
+
if not component:
|
|
1179
|
+
config = _read_project_config()
|
|
1180
|
+
component = _entrypoint_to_module(config.get("entryPoint", "app/main.py"))
|
|
1181
|
+
|
|
1182
|
+
try:
|
|
1183
|
+
from pythonnative.preview import run_preview
|
|
1184
|
+
except Exception as exc: # pragma: no cover - environment dependent
|
|
1185
|
+
print(f"Error: could not start the desktop preview: {exc}")
|
|
1186
|
+
print(
|
|
1187
|
+
"The desktop preview needs Tkinter (Python's standard GUI toolkit).\n"
|
|
1188
|
+
"On macOS: brew install python-tk\n"
|
|
1189
|
+
"On Debian/Ubuntu: sudo apt-get install python3-tk\n"
|
|
1190
|
+
"On Windows: reinstall Python with the 'tcl/tk' option checked."
|
|
1191
|
+
)
|
|
1192
|
+
sys.exit(1)
|
|
1193
|
+
|
|
1194
|
+
print(f"Starting PythonNative preview for {component} (Ctrl+C or close the window to stop).")
|
|
1195
|
+
try:
|
|
1196
|
+
run_preview(
|
|
1197
|
+
component,
|
|
1198
|
+
project_root=project_dir,
|
|
1199
|
+
width=getattr(args, "width", 390),
|
|
1200
|
+
height=getattr(args, "height", 844),
|
|
1201
|
+
title=getattr(args, "title", "PythonNative Preview"),
|
|
1202
|
+
hot_reload=not getattr(args, "no_hot_reload", False),
|
|
1203
|
+
)
|
|
1204
|
+
except RuntimeError as exc:
|
|
1205
|
+
print(f"Error: {exc}")
|
|
1206
|
+
sys.exit(1)
|
|
1207
|
+
|
|
1208
|
+
|
|
1122
1209
|
def clean_project(args: argparse.Namespace) -> None:
|
|
1123
1210
|
"""Remove the local `build/` directory.
|
|
1124
1211
|
|
|
@@ -1152,6 +1239,25 @@ def main() -> None:
|
|
|
1152
1239
|
parser_init.add_argument("--force", action="store_true", help="Overwrite existing files if present")
|
|
1153
1240
|
parser_init.set_defaults(func=init_project)
|
|
1154
1241
|
|
|
1242
|
+
# Create a new command 'preview' that calls preview_project
|
|
1243
|
+
parser_preview = subparsers.add_parser("preview")
|
|
1244
|
+
parser_preview.add_argument(
|
|
1245
|
+
"component",
|
|
1246
|
+
nargs="?",
|
|
1247
|
+
help="Module path (e.g. app.main) or dotted component path; defaults to the project entry point",
|
|
1248
|
+
)
|
|
1249
|
+
parser_preview.add_argument("--width", type=int, default=390, help="Initial window width in points (default: 390)")
|
|
1250
|
+
parser_preview.add_argument(
|
|
1251
|
+
"--height", type=int, default=844, help="Initial window height in points (default: 844)"
|
|
1252
|
+
)
|
|
1253
|
+
parser_preview.add_argument("--title", default="PythonNative Preview", help="Preview window title")
|
|
1254
|
+
parser_preview.add_argument(
|
|
1255
|
+
"--no-hot-reload",
|
|
1256
|
+
action="store_true",
|
|
1257
|
+
help="Disable file watching / Fast Refresh",
|
|
1258
|
+
)
|
|
1259
|
+
parser_preview.set_defaults(func=preview_project)
|
|
1260
|
+
|
|
1155
1261
|
# Create a new command 'run' that calls run_project
|
|
1156
1262
|
parser_run = subparsers.add_parser("run")
|
|
1157
1263
|
parser_run.add_argument("platform", choices=["android", "ios"])
|