| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,7 +11,7 @@ jobs: | |||
| 11 | 11 | runs-on: ubuntu-latest | |
| 12 | 12 | strategy: | |
| 13 | 13 | matrix: | |
| 14 | - python-version: ['3.10', '3.11', '3.12'] | ||
| 14 | + python-version: ['3.13', '3.14'] | ||
| 15 | 15 | ||
| 16 | 16 | steps: | |
| 17 | 17 | - name: Checkout | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,7 +17,7 @@ jobs: | |||
| 17 | 17 | - uses: astral-sh/setup-uv@v10.0.1 | |
| 18 | 18 | with: | |
| 19 | 19 | enable-cache: true | |
| 20 | - python-version: '3.11' | ||
| 20 | + python-version: '3.13' | ||
| 21 | 21 | # `uv sync` installs the project itself, which mkdocstrings needs in | |
| 22 | 22 | # order to import and introspect it. | |
| 23 | 23 | - name: Install docs deps | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,7 +18,7 @@ jobs: | |||
| 18 | 18 | - name: Set up Python | |
| 19 | 19 | uses: actions/setup-python@v5 | |
| 20 | 20 | with: | |
| 21 | - python-version: '3.11' | ||
| 21 | + python-version: '3.13' | ||
| 22 | 22 | - name: Check E2E coverage of pythonnative.__all__ | |
| 23 | 23 | run: python scripts/check-e2e-coverage.py | |
| 24 | 24 | ||
@@ -64,14 +64,21 @@ jobs: | |||
| 64 | 64 | uses: astral-sh/setup-uv@v10.0.1 | |
| 65 | 65 | with: | |
| 66 | 66 | enable-cache: true | |
| 67 | - python-version: '3.11' | ||
| 67 | + python-version: '3.13' | ||
| 68 | 68 | ||
| 69 | 69 | - name: Set up Java 17 | |
| 70 | 70 | uses: actions/setup-java@v4 | |
| 71 | 71 | with: | |
| 72 | 72 | distribution: 'temurin' | |
| 73 | 73 | java-version: '17' | |
| 74 | 74 | ||
| 75 | + # Restores ~/.gradle (wrapper distribution and dependency caches) | ||
| 76 | + # so the staged project's ./gradlew doesn't download Gradle from | ||
| 77 | + # services.gradle.org on every shard; a reset connection there | ||
| 78 | + # fails the build before Maestro even starts. | ||
| 79 | + - name: Set up Gradle | ||
| 80 | + uses: gradle/actions/setup-gradle@v4 | ||
| 81 | + | ||
| 75 | 82 | - name: Install PythonNative | |
| 76 | 83 | run: uv sync --locked | |
| 77 | 84 | ||
@@ -168,7 +175,7 @@ jobs: | |||
| 168 | 175 | uses: astral-sh/setup-uv@v10.0.1 | |
| 169 | 176 | with: | |
| 170 | 177 | enable-cache: true | |
| 171 | - python-version: '3.11' | ||
| 178 | + python-version: '3.13' | ||
| 172 | 179 | ||
| 173 | 180 | - name: Install PythonNative | |
| 174 | 181 | run: uv sync --locked | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,65 @@ | |||
| 1 | + name: Packages | ||
| 2 | + | ||
| 3 | + # PyPI package compatibility matrix. Resolves tests/packages/matrix.toml | ||
| 4 | + # for every device target against the live indexes (PyPI, BeeWare, | ||
| 5 | + # Chaquopy) and fails when a package's availability disagrees with the | ||
| 6 | + # manifest, so an index change that breaks or fixes a package shows up | ||
| 7 | + # here rather than in a user's build. | ||
| 8 | + # | ||
| 9 | + # Runs weekly (the indexes change without us), on manual dispatch, and | ||
| 10 | + # on any change to the resolver, the manifest, or the guide's table. | ||
| 11 | + | ||
| 12 | + on: | ||
| 13 | + schedule: | ||
| 14 | + - cron: '17 6 * * 1' | ||
| 15 | + workflow_dispatch: | ||
| 16 | + push: | ||
| 17 | + branches: [main] | ||
| 18 | + paths: | ||
| 19 | + - 'src/pythonnative/project/deps.py' | ||
| 20 | + - 'tests/packages/**' | ||
| 21 | + - 'scripts/package-matrix.py' | ||
| 22 | + - '.github/workflows/packages.yml' | ||
| 23 | + pull_request: | ||
| 24 | + paths: | ||
| 25 | + - 'src/pythonnative/project/deps.py' | ||
| 26 | + - 'tests/packages/**' | ||
| 27 | + - 'scripts/package-matrix.py' | ||
| 28 | + - '.github/workflows/packages.yml' | ||
| 29 | + | ||
| 30 | + jobs: | ||
| 31 | + matrix: | ||
| 32 | + runs-on: ubuntu-latest | ||
| 33 | + timeout-minutes: 20 | ||
| 34 | + steps: | ||
| 35 | + - name: Checkout | ||
| 36 | + uses: actions/checkout@v4 | ||
| 37 | + | ||
| 38 | + - name: Set up uv | ||
| 39 | + uses: astral-sh/setup-uv@v10.0.1 | ||
| 40 | + with: | ||
| 41 | + enable-cache: true | ||
| 42 | + python-version: '3.13' | ||
| 43 | + | ||
| 44 | + - name: Install dependencies | ||
| 45 | + run: uv sync --locked --group dev | ||
| 46 | + | ||
| 47 | + - name: Resolve the matrix | ||
| 48 | + env: | ||
| 49 | + PN_PACKAGE_MATRIX: '1' | ||
| 50 | + run: uv run pytest tests/packages -q -m network | ||
| 51 | + | ||
| 52 | + # The Markdown table the guide embeds; download it from the run | ||
| 53 | + # page and paste it into docs/guides/pypi-packages.md when it | ||
| 54 | + # changes. | ||
| 55 | + - name: Render the Markdown table | ||
| 56 | + if: always() | ||
| 57 | + run: uv run scripts/package-matrix.py > package-matrix.md | ||
| 58 | + | ||
| 59 | + - name: Upload the table | ||
| 60 | + if: always() | ||
| 61 | + uses: actions/upload-artifact@v4 | ||
| 62 | + with: | ||
| 63 | + name: package-matrix | ||
| 64 | + path: package-matrix.md | ||
| 65 | + retention-days: 30 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,7 +26,7 @@ jobs: | |||
| 26 | 26 | uses: astral-sh/setup-uv@v10.0.1 | |
| 27 | 27 | with: | |
| 28 | 28 | enable-cache: true | |
| 29 | - python-version: '3.12' | ||
| 29 | + python-version: '3.13' | ||
| 30 | 30 | ||
| 31 | 31 | # TEMPORARY: inlined replacement for the | |
| 32 | 32 | # python-semantic-release/python-semantic-release@v9 action. That | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,7 +4,7 @@ Thanks for your interest in contributing. This repository contains the PythonNat | |||
| 4 | 4 | ||
| 5 | 5 | ## Quick start | |
| 6 | 6 | ||
| 7 | - Development uses Python ≥ 3.10 and [uv](https://docs.astral.sh/uv/) as the | ||
| 7 | + Development uses Python ≥ 3.13 (the same versions the apps embed) and [uv](https://docs.astral.sh/uv/) as the | ||
| 8 | 8 | only prerequisite. `uv sync` creates and updates `.venv` itself, so there's no | |
| 9 | 9 | virtual environment to make and nothing to activate. | |
| 10 | 10 | ||
@@ -370,6 +370,7 @@ When you add a new public symbol you must also: | |||
| 370 | 370 | ||
| 371 | 371 | - **CI** (`ci.yml`): runs formatter, linter, type checker, and tests on every push and PR. | |
| 372 | 372 | - **E2E** (`e2e.yml`): builds the hello-world example on Android (Linux emulator) and iOS (macOS simulator), then runs Maestro flows. Triggers on pushes to `main`, PRs, and manual dispatch. | |
| 373 | + - **Packages** (`packages.yml`): resolves the PyPI compatibility matrix in `tests/packages/matrix.toml` against the live indexes with `scripts/package-matrix.py --check`, weekly and on changes to the resolver or manifest, and uploads the rendered Markdown table for `docs/guides/pypi-packages.md`. | ||
| 373 | 374 | - **PR Lint** (`pr-lint.yml`): validates the PR title against Conventional Commits format (protects squash merges) and checks individual commit messages via commitlint (protects rebase merges). Recommended: add the **PR title** job as a required status check in branch-protection settings. | |
| 374 | 375 | - **Release** (`release.yml`): runs on merge to `main`; computes version, generates changelog, tags, creates GitHub Release, and (when `DRAFT_RELEASE` is `"false"`) publishes to PyPI. | |
| 375 | 376 | - **Docs** (`docs.yml`): builds the MkDocs site in strict mode on every push and pull request, and deploys to GitHub Pages on push to `main`. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -36,7 +36,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app | |||
| 36 | 36 | - **Hooks and function components:** Manage state with `use_state`, side effects with `use_effect` / `use_layout_effect`, refs and imperative handles with `use_ref` / `use_imperative_handle`, and navigation with `use_navigation`, all through one consistent pattern. Components can return a single element, a list of siblings, or `None`, and `Fragment`, `Portal`, and reactive `Provider` context work the way they do in React. | |
| 37 | 37 | - **Async-first rendering:** One `asyncio` event loop runs the whole framework on the platform's main thread. Components can be `async def` and `await` data directly in the body; `Suspense` boundaries show declarative loading states while they wait. `use_resource` fetches during render, `use_effect` accepts coroutine callbacks (cancelled automatically on unmount), `lazy` code-splits components, and `use_transition` / `use_deferred_value` keep the UI responsive during expensive updates. | |
| 38 | 38 | - **Developer feedback that finds your bugs:** In dev mode (`pn preview`, hot reload, or `PN_DEV=1`), uncaught errors from renders, effects, and event handlers show a full-screen RedBox with the traceback; unknown style keys and duplicate list keys print "did you mean" warnings; and conditional hooks raise a `HookOrderError` at the source instead of silently cross-wiring state. | |
| 39 | - - **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`. | ||
| 39 | + - **Typed `style` prop and theme:** 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`, and read design tokens from a typed, immutable `pn.Theme` via `use_theme()` that follows light and dark mode by default. | ||
| 40 | 40 | - **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. | |
| 41 | 41 | - **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. | |
| 42 | 42 | - **Native-driven animations:** The `Animated` API (timing / spring / decay / loop / stagger, 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. `interpolate`, arithmetic operators on animated nodes, `Animated.event` scroll binding, and `diff_clamp` cover the scroll-driven patterns (collapsing headers, parallax) that define native feel. | |
@@ -45,6 +45,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app | |||
| 45 | 45 | - **Native rendering core:** each commit is one serialized transaction applied by Swift and Kotlin component managers, the same shape as React Native's Fabric. Device APIs are native modules registered by name (TurboModules-style), callable from thin Python facades. | |
| 46 | 46 | - **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. | |
| 47 | 47 | - **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app. | |
| 48 | + - **PyPI packages, binary wheels included:** List requirements in `pythonnative.toml` and the CLI resolves them for the *device* (iOS wheels via PEP 730 and BeeWare's index, Android wheels via PEP 738 and Chaquopy), bundling numpy, Pillow, cryptography, and friends alongside pure-Python packages. `pn deps` reports what each target resolves to before you build, and a weekly-checked compatibility matrix keeps the docs honest. | ||
| 48 | 49 | - **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. | |
| 49 | 50 | - **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; `use_back_handler` intercepts the back action when a screen needs to. | |
| 50 | 51 | - **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. | |
@@ -54,6 +55,8 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app | |||
| 54 | 55 | ||
| 55 | 56 | ### Installation | |
| 56 | 57 | ||
| 58 | + Requires Python 3.13 or newer. | ||
| 59 | + | ||
| 57 | 60 | ```bash | |
| 58 | 61 | pip install pythonnative | |
| 59 | 62 | ``` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,7 +16,7 @@ def SchemeAwareBadge(): | |||
| 16 | 16 | theme = pn.use_theme() # built-in theme for the scheme | |
| 17 | 17 | return pn.Text( | |
| 18 | 18 | f"Currently {scheme}", | |
| 19 | - style={"color": theme["text_color"]}, | ||
| 19 | + style={"color": theme.text_color}, | ||
| 20 | 20 | ) | |
| 21 | 21 | ``` | |
| 22 | 22 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,7 +13,16 @@ the documented behavior never drifts from the code. | |||
| 13 | 13 | Flag: `--force` to overwrite existing files or scaffold into a | |
| 14 | 14 | non-empty directory. See [Configuration](../guides/configuration.md). | |
| 15 | 15 | - `pn doctor [android|ios]`: diagnose the local toolchain and validate | |
| 16 | - `pythonnative.toml`. Exits non-zero when something will block a build. | ||
| 16 | + `pythonnative.toml`, including that a `python3.X` matching | ||
| 17 | + `[app].python_version` is available for package resolution. Exits | ||
| 18 | + non-zero when something will block a build. | ||
| 19 | + - `pn deps [android|ios]`: resolve `[requirements].packages` for every | ||
| 20 | + device target (iOS device, iOS Simulator, and each Android ABI) | ||
| 21 | + without installing anything, and report the wheel each package would | ||
| 22 | + use, flagging binary wheels, their index, and downgrades. Flags: | ||
| 23 | + `--json` for a machine-readable report, `--python` to pick the | ||
| 24 | + interpreter that runs pip. Exits non-zero when any target can't be | ||
| 25 | + satisfied. See [PyPI packages](../guides/pypi-packages.md). | ||
| 17 | 26 | - `pn preview [component]`: render the app in a desktop (Tkinter) window | |
| 18 | 27 | with Fast Refresh, the fastest way to iterate on UI. Flags: | |
| 19 | 28 | `--width`, `--height`, `--title`, `--no-hot-reload`. See the | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -185,7 +185,7 @@ pn.ScrollView( | |||
| 185 | 185 | - `content_container_style`: style for the inner content wrapper (padding, | |
| 186 | 186 | alignment, spacing), distinct from `style` (the scroll frame) | |
| 187 | 187 | - `keyboard_dismiss_mode`: `"none"`, `"on_drag"`, or `"interactive"` | |
| 188 | - - `refresh_control`: pull-to-refresh spec (see [`RefreshControl`](#refreshcontrol)) | ||
| 188 | + - `refresh_control`: pull-to-refresh element (see [`RefreshControl`](#refreshcontrol)) | ||
| 189 | 189 | ||
| 190 | 190 | ## TextInput | |
| 191 | 191 | ||
@@ -429,7 +429,7 @@ pn.ScrollView(child, refresh_control=pn.RefreshControl( | |||
| 429 | 429 | refreshing=loading, on_refresh=reload, tint_color="#007AFF")) | |
| 430 | 430 | ``` | |
| 431 | 431 | ||
| 432 | - Pull-to-refresh spec (a plain dict) passed to a `ScrollView` or `FlatList`. | ||
| 432 | + Pull-to-refresh control, an element of type `"RefreshControl"`, passed as the `refresh_control=` prop of a `ScrollView`, `FlatList`, or `SectionList`. The scroll container attaches it to its native scroll view rather than rendering it as a child, and raises `TypeError` for anything that isn't a `RefreshControl`. | ||
| 433 | 433 | ||
| 434 | 434 | - `refreshing`: drive the spinner from state | |
| 435 | 435 | - `on_refresh`: callback `() -> None` when pulled past threshold | |
@@ -487,4 +487,4 @@ pn.FlatList(data=items, render_item=render_fn, key_extractor=key_fn, | |||
| 487 | 487 | - `on_end_reached`: callback `() -> None` near the end (virtualized) | |
| 488 | 488 | - `on_end_reached_threshold`: fraction-of-viewport trigger distance | |
| 489 | 489 | - `content_container_style`: style for the inner content wrapper | |
| 490 | - - `refresh_control`: pull-to-refresh spec (see [`RefreshControl`](#refreshcontrol)) | ||
| 490 | + - `refresh_control`: pull-to-refresh element (see [`RefreshControl`](#refreshcontrol)) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments