| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,8 +30,8 @@ jobs: | |||
| 30 | 30 | # sustained Maestro driving and start reporting "device offline" / | |
| 31 | 31 | # "device not found" mid-run (the emulator VM, not the app, dies). | |
| 32 | 32 | # The full 60-flow suite reliably crosses that threshold around the | |
| 33 | - # ~35th flow. Sharding the run into a few balanced groups — each on | ||
| 34 | - # its own freshly booted emulator — keeps every session well under | ||
| 33 | + # ~35th flow. Sharding the run into a few balanced groups, each on | ||
| 34 | + # its own freshly booted emulator, keeps every session well under | ||
| 35 | 35 | # the limit, and parallelizes the Android pass as a bonus. Groups are | |
| 36 | 36 | # sized so none exceeds ~15 flows; ``components`` (28 flows after the | |
| 37 | 37 | # gesture/animated additions) crossed the ceiling at ~flow 26, so it | |
@@ -105,7 +105,7 @@ jobs: | |||
| 105 | 105 | runs-on: macos-latest | |
| 106 | 106 | timeout-minutes: 40 | |
| 107 | 107 | # iOS simulators are stable for the full suite (unlike the Android | |
| 108 | - # emulator — see the e2e-android note), so this split is purely a | ||
| 108 | + # emulator; see the e2e-android note), so this split is purely a | ||
| 109 | 109 | # speed optimization: the iOS Maestro run is ~22 minutes and is the | |
| 110 | 110 | # critical path for the whole E2E workflow. Sharding it across three | |
| 111 | 111 | # simulators (same balanced groups as Android) runs them in parallel | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,24 +32,24 @@ cd examples/hello-world && pn run android | |||
| 32 | 32 | ||
| 33 | 33 | ## Project layout (high‑level) | |
| 34 | 34 | ||
| 35 | - - `src/pythonnative/` – installable library and CLI | ||
| 36 | - - `pythonnative/` – core cross‑platform UI components and utilities | ||
| 37 | - - `cli/` – `pn` command | ||
| 38 | - - `tests/` – unit tests for the library, plus the Maestro E2E suite | ||
| 39 | - - `e2e/` – the comprehensive E2E suite (see [E2E tests](#e2e-tests-maestro) below and `tests/e2e/AGENTS.md`) | ||
| 40 | - - `templates/` – Android/iOS project templates and zips | ||
| 41 | - - `examples/` – runnable example apps | ||
| 42 | - - `hello-world/` – minimal marketing demo | ||
| 43 | - - `e2e-suite/` – comprehensive feature catalog that drives the Maestro E2E suite | ||
| 44 | - - `scripts/` – helper scripts (`check.sh`, `run-e2e.sh`, `check-e2e-coverage.py`) | ||
| 45 | - - `README.md`, `pyproject.toml` – repo docs and packaging | ||
| 35 | + - `src/pythonnative/`: installable library and CLI | ||
| 36 | + - `pythonnative/`: core cross‑platform UI components and utilities | ||
| 37 | + - `cli/`: `pn` command | ||
| 38 | + - `tests/`: unit tests for the library, plus the Maestro E2E suite | ||
| 39 | + - `e2e/`: the comprehensive E2E suite (see [E2E tests](#e2e-tests-maestro) below and `tests/e2e/AGENTS.md`) | ||
| 40 | + - `templates/`: Android/iOS project templates and zips | ||
| 41 | + - `examples/`: runnable example apps | ||
| 42 | + - `hello-world/`: minimal marketing demo | ||
| 43 | + - `e2e-suite/`: comprehensive feature catalog that drives the Maestro E2E suite | ||
| 44 | + - `scripts/`: helper scripts (`check.sh`, `run-e2e.sh`, `check-e2e-coverage.py`) | ||
| 45 | + - `README.md`, `pyproject.toml`: repo docs and packaging | ||
| 46 | 46 | ||
| 47 | 47 | ## Coding guidelines | |
| 48 | 48 | ||
| 49 | 49 | - Style: Black; lint: Ruff; typing where useful. Keep APIs stable. | |
| 50 | 50 | - Prefer explicit, descriptive names; keep platform abstractions clean. | |
| 51 | 51 | - Add/extend tests under `tests/` for new behavior. | |
| 52 | - - Do not commit generated artifacts or large binaries; templates live under `templates/`. | ||
| 52 | + - Don't commit generated artifacts or large binaries; templates live under `templates/`. | ||
| 53 | 53 | - Docstrings: Google style throughout. Ruff is configured with the Google | |
| 54 | 54 | convention (`pydocstyle.convention = "google"`) and enforces the `D` rule | |
| 55 | 55 | set on `src/pythonnative/`. See the | |
@@ -84,57 +84,57 @@ This project uses Conventional Commits. Use the form: | |||
| 84 | 84 | ||
| 85 | 85 | Accepted types (standard): | |
| 86 | 86 | ||
| 87 | - - `build` – build system or external dependencies (e.g., requirements, packaging) | ||
| 88 | - - `chore` – maintenance (no library behavior change) | ||
| 89 | - - `ci` – continuous integration configuration (workflows, pipelines) | ||
| 90 | - - `docs` – documentation only | ||
| 91 | - - `feat` – user‑facing feature or capability | ||
| 92 | - - `fix` – bug fix | ||
| 93 | - - `perf` – performance improvements | ||
| 94 | - - `refactor` – code change that neither fixes a bug nor adds a feature | ||
| 95 | - - `revert` – revert of a previous commit | ||
| 96 | - - `style` – formatting/whitespace (no code behavior) | ||
| 97 | - - `test` – add/adjust tests only | ||
| 87 | + - `build`: build system or external dependencies (e.g., requirements, packaging) | ||
| 88 | + - `chore`: maintenance (no library behavior change) | ||
| 89 | + - `ci`: continuous integration configuration (workflows, pipelines) | ||
| 90 | + - `docs`: documentation only | ||
| 91 | + - `feat`: user‑facing feature or capability | ||
| 92 | + - `fix`: bug fix | ||
| 93 | + - `perf`: performance improvements | ||
| 94 | + - `refactor`: code change that neither fixes a bug nor adds a feature | ||
| 95 | + - `revert`: revert of a previous commit | ||
| 96 | + - `style`: formatting/whitespace (no code behavior) | ||
| 97 | + - `test`: add/adjust tests only | ||
| 98 | 98 | ||
| 99 | 99 | Recommended scopes (choose the smallest, most accurate unit; prefer module/directory names): | |
| 100 | 100 | ||
| 101 | 101 | - Module/directory scopes: | |
| 102 | - - `alerts` – imperative Alert/Picker helpers (`alerts.py`) | ||
| 103 | - - `animated` – Animated namespace and animation primitives (`animated.py`) | ||
| 104 | - - `cli` – CLI tool and `pn` command (`src/pythonnative/cli/`) | ||
| 105 | - - `components` – declarative element-creating functions (`components.py`) | ||
| 106 | - - `element` – Element descriptor class (`element.py`) | ||
| 107 | - - `events` – tag-based event routing between native views and Python callbacks (`events.py`) | ||
| 108 | - - `gestures` – gesture descriptors and the pure-Python recognition arbiter (`gestures.py`) | ||
| 109 | - - `hooks` – function components and hooks (`hooks.py`) | ||
| 110 | - - `hot_reload` – file watcher and module reloader (`hot_reload.py`) | ||
| 111 | - - `layout` – pure-Python flexbox engine (`layout.py`) | ||
| 112 | - - `mutations` – batched mutation ops between reconciler and native backends (`mutations.py`) | ||
| 113 | - - `native_modules` – native API modules for device capabilities (`native_modules/`) | ||
| 114 | - - `native_views` – platform-specific native view creation and updates (`native_views/`) | ||
| 115 | - - `navigation` – navigation containers and stack/tab/drawer navigators (`navigation.py`) | ||
| 116 | - - `net` – awaitable HTTP client (`net.py`) | ||
| 117 | - - `package` – `src/pythonnative/__init__.py` exports and package boundary | ||
| 118 | - - `platform` – `Platform.OS`/`Platform.select` and version detection (`platform.py`) | ||
| 119 | - - `platform_metrics` – platform-reported metrics like safe-area insets and bar heights (`platform_metrics.py`) | ||
| 120 | - - `reconciler` – virtual view tree diffing and reconciliation (`reconciler.py`) | ||
| 121 | - - `runtime` – framework-wide asyncio loop and thread-safe future helpers (`runtime.py`) | ||
| 122 | - - `screen` – screen host, native lifecycle bridge, and render scheduling (`screen.py`) | ||
| 123 | - - `sdk` – public extension SDK for custom native components (`sdk/`) | ||
| 124 | - - `storage` – AsyncStorage key/value persistence and `use_persisted_state` (`storage.py`) | ||
| 125 | - - `style` – StyleSheet and theming (`style.py`) | ||
| 126 | - - `utils` – shared utilities (`utils.py`) | ||
| 102 | + - `alerts`: imperative Alert/Picker helpers (`alerts.py`) | ||
| 103 | + - `animated`: Animated namespace and animation primitives (`animated.py`) | ||
| 104 | + - `cli`: CLI tool and `pn` command (`src/pythonnative/cli/`) | ||
| 105 | + - `components`: declarative element-creating functions (`components.py`) | ||
| 106 | + - `element`: Element descriptor class (`element.py`) | ||
| 107 | + - `events`: tag-based event routing between native views and Python callbacks (`events.py`) | ||
| 108 | + - `gestures`: gesture descriptors and the pure-Python recognition arbiter (`gestures.py`) | ||
| 109 | + - `hooks`: function components and hooks (`hooks.py`) | ||
| 110 | + - `hot_reload`: file watcher and module reloader (`hot_reload.py`) | ||
| 111 | + - `layout`: pure-Python flexbox engine (`layout.py`) | ||
| 112 | + - `mutations`: batched mutation ops between reconciler and native backends (`mutations.py`) | ||
| 113 | + - `native_modules`: native API modules for device capabilities (`native_modules/`) | ||
| 114 | + - `native_views`: platform-specific native view creation and updates (`native_views/`) | ||
| 115 | + - `navigation`: navigation containers and stack/tab/drawer navigators (`navigation.py`) | ||
| 116 | + - `net`: awaitable HTTP client (`net.py`) | ||
| 117 | + - `package`: `src/pythonnative/__init__.py` exports and package boundary | ||
| 118 | + - `platform`: `Platform.OS`/`Platform.select` and version detection (`platform.py`) | ||
| 119 | + - `platform_metrics`: platform-reported metrics like safe-area insets and bar heights (`platform_metrics.py`) | ||
| 120 | + - `reconciler`: virtual view tree diffing and reconciliation (`reconciler.py`) | ||
| 121 | + - `runtime`: framework-wide asyncio loop and thread-safe future helpers (`runtime.py`) | ||
| 122 | + - `screen`: screen host, native lifecycle bridge, and render scheduling (`screen.py`) | ||
| 123 | + - `sdk`: public extension SDK for custom native components (`sdk/`) | ||
| 124 | + - `storage`: AsyncStorage key/value persistence and `use_persisted_state` (`storage.py`) | ||
| 125 | + - `style`: StyleSheet and theming (`style.py`) | ||
| 126 | + - `utils`: shared utilities (`utils.py`) | ||
| 127 | 127 | ||
| 128 | 128 | - Other scopes: | |
| 129 | - - `deps` – dependency updates and version pins | ||
| 130 | - - `examples` – example apps under `examples/` | ||
| 131 | - - `mkdocs` – documentation site (MkDocs/Material) configuration and content under `docs/` | ||
| 132 | - - `pyproject` – `pyproject.toml` packaging/build metadata | ||
| 133 | - - `repo` – repository metadata and top‑level files (`README.md`, `CONTRIBUTING.md`, `.gitignore`, licenses) | ||
| 134 | - - `scripts` – developer scripts under `scripts/` (e.g., `check.sh`) | ||
| 135 | - - `templates` – Android/iOS project templates under `src/pythonnative/templates/` | ||
| 136 | - - `tests` – unit/integration/E2E tests under `tests/` | ||
| 137 | - - `workflows` – CI pipelines under `.github/workflows/` | ||
| 129 | + - `deps`: dependency updates and version pins | ||
| 130 | + - `examples`: example apps under `examples/` | ||
| 131 | + - `mkdocs`: documentation site (MkDocs/Material) configuration and content under `docs/` | ||
| 132 | + - `pyproject`: `pyproject.toml` packaging/build metadata | ||
| 133 | + - `repo`: repository metadata and top‑level files (`README.md`, `CONTRIBUTING.md`, `.gitignore`, licenses) | ||
| 134 | + - `scripts`: developer scripts under `scripts/` (e.g., `check.sh`) | ||
| 135 | + - `templates`: Android/iOS project templates under `src/pythonnative/templates/` | ||
| 136 | + - `tests`: unit/integration/E2E tests under `tests/` | ||
| 137 | + - `workflows`: CI pipelines under `.github/workflows/` | ||
| 138 | 138 | ||
| 139 | 139 | Note: Avoid redundant type==scope pairs (e.g., `docs(docs)`). Prefer a module scope (e.g., `docs(core)`) or `docs(repo)` for top‑level updates. | |
| 140 | 140 | ||
@@ -194,7 +194,7 @@ feat(templates,cli): add ios template and wire pn init | |||
| 194 | 194 | - Imperative mood; no trailing period; ≤ 72 chars; `!` for breaking changes. | |
| 195 | 195 | - PR description: include brief sections: What, Why, How (brief), Testing, Risks/Impact, Docs/Follow‑ups. | |
| 196 | 196 | - Link issues with keywords (e.g., `Closes #123`). | |
| 197 | - - Merging: prefer “Squash and merge” with “Pull request title and description”. | ||
| 197 | + - Merging: prefer "Squash and merge" with "Pull request title and description". | ||
| 198 | 198 | - Keep PRs focused; avoid unrelated changes in the same PR. | |
| 199 | 199 | ||
| 200 | 200 | Recommended PR template: | |
@@ -244,7 +244,7 @@ Co-authored-by: Name <email> | |||
| 244 | 244 | - **Draft / published toggle**: the `DRAFT_RELEASE` variable at the top of `.github/workflows/release.yml` controls release mode. Set to `"true"` (the default) for draft GitHub Releases with PyPI publishing skipped; flip to `"false"` to publish releases and upload to PyPI immediately. | |
| 245 | 245 | - Commit types that trigger a release: `feat` (minor), `fix` and `perf` (patch), `BREAKING CHANGE` (major). All other types (`build`, `chore`, `ci`, `docs`, `refactor`, `revert`, `style`, `test`) are recorded in the changelog but do **not** trigger a release on their own. | |
| 246 | 246 | - Tag format: `v`-prefixed (e.g., `v0.4.0`). | |
| 247 | - - Manual version bumps are no longer needed — just merge PRs with valid Conventional Commit titles. For ad-hoc runs, use the workflow's **Run workflow** button (`workflow_dispatch`). | ||
| 247 | + - Manual version bumps are no longer needed: just merge PRs with valid Conventional Commit titles. For ad-hoc runs, use the workflow's **Run workflow** button (`workflow_dispatch`). | ||
| 248 | 248 | ||
| 249 | 249 | ### Branch naming (suggested) | |
| 250 | 250 | ||
@@ -277,7 +277,7 @@ fix/cli-regression | |||
| 277 | 277 | ||
| 278 | 278 | End-to-end tests use [Maestro](https://maestro.dev/) to drive the dedicated `examples/e2e-suite` app on real emulators and simulators. That app contains one screen per public symbol in `pythonnative.__all__`; every flow under `tests/e2e/flows/<category>/` exercises one symbol. | |
| 279 | 279 | ||
| 280 | - The dedicated `examples/hello-world` app is left in place as a small marketing demo; it is **not** the E2E target. | ||
| 280 | + The dedicated `examples/hello-world` app is left in place as a small marketing demo; it's **not** the E2E target. | ||
| 281 | 281 | ||
| 282 | 282 | ```bash | |
| 283 | 283 | # Install Maestro (one-time) | |
@@ -333,4 +333,4 @@ When you add a new public symbol you must also: | |||
| 333 | 333 | ||
| 334 | 334 | ## License | |
| 335 | 335 | ||
| 336 | - By contributing, you agree that your contributions are licensed under the repository’s MIT License. | ||
| 336 | + By contributing, you agree that your contributions are licensed under the repository's MIT License. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -31,19 +31,19 @@ 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 | + - **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. | ||
| 36 | 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. | |
| 37 | 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`. | |
| 38 | 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. | |
| 39 | - - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation. Each commit lands as **one batched transaction** of mutation ops, and event callbacks are routed through a tag-based registry so re-renders that only change closures cost zero native calls. State updates re-render **locally** — only the component whose state changed (and its subtree) re-runs, and unchanged leaves reuse cached intrinsic measurements — so deep UIs stay responsive instead of re-rendering the whole app from the root on every tap. | ||
| 39 | + - **Virtual view tree + reconciler:** Element trees are diffed and patched with minimal native mutations, similar to React's reconciliation. Each commit lands as **one batched transaction** of mutation ops, and event callbacks are routed through a tag-based registry so re-renders that only change closures cost zero native calls. State updates re-render **locally**: only the component whose state changed (and its subtree) re-runs, and unchanged leaves reuse cached intrinsic measurements, so deep UIs stay responsive instead of re-rendering the whole app from the root on every tap. | ||
| 40 | 40 | - **Native-driven animations:** The `Animated` API (timing / spring / decay, awaitable or fire-and-forget) hands animations to Core Animation and `ViewPropertyAnimator` whenever possible, so no Python code runs per frame; a pure-Python ticker covers the rest. | |
| 41 | - - **Native gesture system:** Attach `Tap`, `LongPress`, `Pan`, `Swipe`, `Pinch`, and `Rotation` recognizers to any view via the `gestures=` prop — backed by `UIGestureRecognizer` on iOS and a unit-testable pure-Python arbiter on Android and desktop. | ||
| 42 | - - **Virtualized lists:** `FlatList` / `SectionList` window their rows in Python over the platform scroll view — uniform, exact, or measured variable heights, grids, headers/footers, infinite scroll, and an imperative scroll controller, identical on every platform. | ||
| 41 | + - **Native gesture system:** Attach `Tap`, `LongPress`, `Pan`, `Swipe`, `Pinch`, and `Rotation` recognizers to any view via the `gestures=` prop, backed by `UIGestureRecognizer` on iOS and a unit-testable pure-Python arbiter on Android and desktop. | ||
| 42 | + - **Virtualized lists:** `FlatList` / `SectionList` window their rows in Python over the platform scroll view: uniform, exact, or measured variable heights, grids, headers/footers, infinite scroll, and an imperative scroll controller, identical on every platform. | ||
| 43 | 43 | - **Direct native bindings:** Python calls platform APIs directly through Chaquopy and rubicon-objc, with no JavaScript bridge. | |
| 44 | 44 | - **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. | |
| 45 | 45 | - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app. | |
| 46 | - - **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. | ||
| 46 | + - **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. | ||
| 47 | 47 | - **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. | |
| 48 | 48 | - **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. | |
| 49 | 49 | - **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,7 +29,7 @@ There are three entry points: | |||
| 29 | 29 | returns the selected label. | |
| 30 | 30 | - **Pickers**: the built-in | |
| 31 | 31 | [`Picker`][pythonnative.components.Picker] component is | |
| 32 | - implemented on top of action sheets — use it for select/dropdown | ||
| 32 | + implemented on top of action sheets; use it for select/dropdown | ||
| 33 | 33 | widgets. | |
| 34 | 34 | ||
| 35 | 35 | ## Testing | |
| Back | FazBrowse Home | New Git URL |
0 commit comments