FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat(project,cli)!: resolve PyPI deps per target, and tighten API by owenthcarey · Pull Request #73 · pythonnative/pythonnative · GitHub

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .gradle  (2) .ini  (2) .kt  (1) .lock  (1) .md  (23) .pbxproj  (1) .properties  (1) .py  (59) .swift  (2) .toml  (4) .yaml  (4) .yml  (6) All 12 file types selected
Only manifest files
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
python-version: ['3.13', '3.14']

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: '3.11'
python-version: '3.13'
# `uv sync` installs the project itself, which mkdocstrings needs in
# order to import and introspect it.
- name: Install docs deps
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/e2e.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.13'
- name: Check E2E coverage of pythonnative.__all__
run: python scripts/check-e2e-coverage.py

Expand Down Expand Up @@ -64,14 +64,21 @@ jobs:
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: '3.11'
python-version: '3.13'

- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

# Restores ~/.gradle (wrapper distribution and dependency caches)
# so the staged project's ./gradlew doesn't download Gradle from
# services.gradle.org on every shard; a reset connection there
# fails the build before Maestro even starts.
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4

- name: Install PythonNative
run: uv sync --locked

Expand Down Expand Up @@ -168,7 +175,7 @@ jobs:
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: '3.11'
python-version: '3.13'

- name: Install PythonNative
run: uv sync --locked
Expand Down
65 changes: 65 additions & 0 deletions .github/workflows/packages.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Packages

# PyPI package compatibility matrix. Resolves tests/packages/matrix.toml
# for every device target against the live indexes (PyPI, BeeWare,
# Chaquopy) and fails when a package's availability disagrees with the
# manifest, so an index change that breaks or fixes a package shows up
# here rather than in a user's build.
#
# Runs weekly (the indexes change without us), on manual dispatch, and
# on any change to the resolver, the manifest, or the guide's table.

on:
schedule:
- cron: '17 6 * * 1'
workflow_dispatch:
push:
branches: [main]
paths:
- 'src/pythonnative/project/deps.py'
- 'tests/packages/**'
- 'scripts/package-matrix.py'
- '.github/workflows/packages.yml'
pull_request:
paths:
- 'src/pythonnative/project/deps.py'
- 'tests/packages/**'
- 'scripts/package-matrix.py'
- '.github/workflows/packages.yml'

jobs:
matrix:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: '3.13'

- name: Install dependencies
run: uv sync --locked --group dev

- name: Resolve the matrix
env:
PN_PACKAGE_MATRIX: '1'
run: uv run pytest tests/packages -q -m network

# The Markdown table the guide embeds; download it from the run
# page and paste it into docs/guides/pypi-packages.md when it
# changes.
- name: Render the Markdown table
if: always()
run: uv run scripts/package-matrix.py > package-matrix.md

- name: Upload the table
if: always()
uses: actions/upload-artifact@v4
with:
name: package-matrix
path: package-matrix.md
retention-days: 30
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: '3.12'
python-version: '3.13'

# TEMPORARY: inlined replacement for the
# python-semantic-release/python-semantic-release@v9 action. That
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Thanks for your interest in contributing. This repository contains the PythonNat

## Quick start

Development uses Python ≥ 3.10 and [uv](https://docs.astral.sh/uv/) as the
Development uses Python ≥ 3.13 (the same versions the apps embed) and [uv](https://docs.astral.sh/uv/) as the
only prerequisite. `uv sync` creates and updates `.venv` itself, so there's no
virtual environment to make and nothing to activate.

Expand Down Expand Up @@ -370,6 +370,7 @@ When you add a new public symbol you must also:

- **CI** (`ci.yml`): runs formatter, linter, type checker, and tests on every push and PR.
- **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.
- **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`.
- **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.
- **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.
- **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`.
Expand Down
5 changes: 4 additions & 1 deletion README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
- **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.
- **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.
- **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.
- **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`.
- **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.
- **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.
- **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.
- **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.
Expand All @@ -45,6 +45,7 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
- **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.
- **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.
- **CLI scaffolding:** `pn init` creates a ready-to-run project; `pn run android` and `pn run ios` build and launch your app.
- **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.
- **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.
- **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.
- **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.
Expand All @@ -54,6 +55,8 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app

### Installation

Requires Python 3.13 or newer.

```bash
pip install pythonnative
```
Expand Down
2 changes: 1 addition & 1 deletion docs/api/appearance.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def SchemeAwareBadge():
theme = pn.use_theme() # built-in theme for the scheme
return pn.Text(
f"Currently {scheme}",
style={"color": theme["text_color"]},
style={"color": theme.text_color},
)
```

Expand Down
11 changes: 10 additions & 1 deletion docs/api/cli.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ the documented behavior never drifts from the code.
Flag: `--force` to overwrite existing files or scaffold into a
non-empty directory. See [Configuration](../guides/configuration.md).
- `pn doctor [android|ios]`: diagnose the local toolchain and validate
`pythonnative.toml`. Exits non-zero when something will block a build.
`pythonnative.toml`, including that a `python3.X` matching
`[app].python_version` is available for package resolution. Exits
non-zero when something will block a build.
- `pn deps [android|ios]`: resolve `[requirements].packages` for every
device target (iOS device, iOS Simulator, and each Android ABI)
without installing anything, and report the wheel each package would
use, flagging binary wheels, their index, and downgrades. Flags:
`--json` for a machine-readable report, `--python` to pick the
interpreter that runs pip. Exits non-zero when any target can't be
satisfied. See [PyPI packages](../guides/pypi-packages.md).
- `pn preview [component]`: render the app in a desktop (Tkinter) window
with Fast Refresh, the fastest way to iterate on UI. Flags:
`--width`, `--height`, `--title`, `--no-hot-reload`. See the
Expand Down
6 changes: 3 additions & 3 deletions docs/api/component-properties.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ pn.ScrollView(
- `content_container_style`: style for the inner content wrapper (padding,
alignment, spacing), distinct from `style` (the scroll frame)
- `keyboard_dismiss_mode`: `"none"`, `"on_drag"`, or `"interactive"`
- `refresh_control`: pull-to-refresh spec (see [`RefreshControl`](#refreshcontrol))
- `refresh_control`: pull-to-refresh element (see [`RefreshControl`](#refreshcontrol))

## TextInput

Expand Down Expand Up @@ -429,7 +429,7 @@ pn.ScrollView(child, refresh_control=pn.RefreshControl(
refreshing=loading, on_refresh=reload, tint_color="#007AFF"))
```

Pull-to-refresh spec (a plain dict) passed to a `ScrollView` or `FlatList`.
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`.

- `refreshing`: drive the spinner from state
- `on_refresh`: callback `() -> None` when pulled past threshold
Expand Down Expand Up @@ -487,4 +487,4 @@ pn.FlatList(data=items, render_item=render_fn, key_extractor=key_fn,
- `on_end_reached`: callback `() -> None` near the end (virtualized)
- `on_end_reached_threshold`: fraction-of-viewport trigger distance
- `content_container_style`: style for the inner content wrapper
- `refresh_control`: pull-to-refresh spec (see [`RefreshControl`](#refreshcontrol))
- `refresh_control`: pull-to-refresh element (see [`RefreshControl`](#refreshcontrol))
2 changes: 1 addition & 1 deletion docs/api/pythonnative.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The reference is split per module so each page stays scannable:
| Platform | [Platform](platform.md) | [`Platform`][pythonnative.Platform] |
| Navigation | [Navigation](navigation.md) | [`NavigationContainer`][pythonnative.NavigationContainer], [`create_stack_navigator`][pythonnative.create_stack_navigator], [`create_tab_navigator`][pythonnative.create_tab_navigator], [`create_drawer_navigator`][pythonnative.create_drawer_navigator], [`Navigation`][pythonnative.Navigation], [`use_navigation`][pythonnative.use_navigation], [`use_route`][pythonnative.use_route], [`use_is_focused`][pythonnative.use_is_focused], [`LinkingConfig`][pythonnative.LinkingConfig] |
| Testing | [Testing](testing.md) | [`render`][pythonnative.testing.render], [`render_hook`][pythonnative.testing.render_hook], [`FakeBackend`][pythonnative.testing.FakeBackend], [`FakeHost`][pythonnative.testing.FakeHost] |
| Styling | [Style](style.md) | [`StyleSheet`][pythonnative.StyleSheet], [`Style`][pythonnative.style.Style], [`StyleProp`][pythonnative.style.StyleProp], [`style`][pythonnative.style.style], [`ThemeContext`][pythonnative.style.ThemeContext], [`use_theme`][pythonnative.use_theme] |
| Styling | [Style](style.md) | [`StyleSheet`][pythonnative.StyleSheet], [`Style`][pythonnative.style.Style], [`StyleProp`][pythonnative.style.StyleProp], [`style`][pythonnative.style.style], [`Theme`][pythonnative.Theme], [`ThemeContext`][pythonnative.style.ThemeContext], [`use_theme`][pythonnative.use_theme] |
| Appearance | [Appearance](appearance.md) | [`use_color_scheme`][pythonnative.use_color_scheme], `appearance.set_color_scheme`, `appearance.get_color_scheme` |
| Images | [Images](images.md) | `images.fetch`, `images.clear_cache` |
| Element descriptor | [Element](element.md) | [`Element`][pythonnative.Element] |
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/components.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ pn.Column(
- [`KeyboardAvoidingView(*children, behavior)`][pythonnative.KeyboardAvoidingView]:
shift content up when the software keyboard appears.
- [`RefreshControl(refreshing, on_refresh)`][pythonnative.RefreshControl]:
pull-to-refresh spec for `ScrollView` and `FlatList` (passed via
the `refresh_control=` prop).
pull-to-refresh control for `ScrollView`, `FlatList`, and
`SectionList` (passed via the `refresh_control=` prop).
- [`Picker(value, items, on_change, placeholder)`][pythonnative.Picker]:
select / dropdown widget backed by an action sheet.

Expand Down
13 changes: 11 additions & 2 deletions docs/concepts/hooks.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,19 @@ pn.Animated.timing(opacity, to=1.0, duration=300).start()
Read a value from the nearest `Provider` ancestor:

```python
theme = pn.use_context(pn.ThemeContext)
color = theme["primary_color"]
Locale = pn.create_context("en")


@pn.component
def Greeting():
locale = pn.use_context(Locale)
return pn.Text("Hello" if locale == "en" else "Hola")
```

For theming specifically, prefer [`use_theme`][pythonnative.use_theme],
which returns a typed [`Theme`][pythonnative.Theme] and falls back to
the built-in light or dark theme when no provider is mounted.

### Async hooks

Data fetching and priority scheduling have dedicated hooks, covered in
Expand Down
12 changes: 6 additions & 6 deletions docs/examples.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,25 @@ def SignUp():
)
```

### Theming via context
### Theming

```python
ThemeContext = pn.create_context({"primary": "#0a84ff", "bg": "#fff"})
BRAND = pn.DEFAULT_LIGHT_THEME.replace(primary_color="#0a84ff")


@pn.component
def Header():
theme = pn.use_context(ThemeContext)
theme = pn.use_theme() # follows light/dark mode unless a provider pins one
return pn.Text(
"Hello",
style={"color": theme["primary"], "font_size": 28, "bold": True},
style={"color": theme.primary_color, "font_size": theme.font_size_title, "bold": True},
)


@pn.component
def App():
return ThemeContext.Provider(
{"primary": "#222", "bg": "#fafafa"},
return pn.ThemeContext.Provider(
BRAND,
pn.Column(Header(), style={"padding": 16}),
)
```
Expand Down
9 changes: 8 additions & 1 deletion docs/getting-started.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Getting Started

PythonNative requires Python 3.13 or newer on your development
machine: the same interpreter version your app embeds, so packages
resolve identically on both.

```bash
pip install pythonnative
pn --help
Expand Down Expand Up @@ -163,7 +167,10 @@ pn run ios --hot-reload

The first run still builds and launches the native app. After that,
edits under `app/` are copied into the running app's writable source
overlay and the active page refreshes without a full rebuild.
overlay and the active page refreshes without a full rebuild. This
works on Android devices and emulators and on the iOS Simulator;
physical iPhones don't support hot reload yet (see the
[Hot reload guide](guides/hot-reload.md)).

PythonNative prefers a **Fast Refresh** path: each
[`@pn.component`][pythonnative.component.component] function is matched by
Expand Down
Loading
Loading

Back | FazBrowse Home | New Git URL