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

feat!: implement RFC 0002 core parity and correctness · pythonnative/pythonnative@c588d11 · GitHub

feat!: implement RFC 0002 core parity and correctness · pythonnative/pythonnative@c588d11 · GitHub
Skip to content

Navigation Menu

Commit c588d11

Browse files
committed
feat!: implement RFC 0002 core parity and correctness
Implement RFC 0002 (rfcs/0002-core-parity-and-correctness.md) across Python, Swift, Kotlin, and the browser preview. Runtime correctness - Route use_effect and use_layout_effect errors to the nearest ErrorBoundary; post-commit Python errors no longer retire the surface. - Keep Suspense siblings mounted (hidden) when a new descendant suspends. - Step async components eagerly so resolved awaits render inline. - Batch state updates automatically on every host; one render-storm policy (50 passes, RuntimeError through the boundary and RedBox). - Dev warnings for unkeyed lists, setters after unmount or during render, in-place mutations, and changing dependency lengths. Components, style, and accessibility - Pressable disabled/delay_long_press/android_ripple and PressState; ScrollView horizontal, content_container_style, insets, throttle, drag and momentum events, snapping, keyboard persistence; Text ellipsize_mode, selectable, allow_font_scaling, pressable spans; TextInput selection, key presses, content size, keyboard appearance; Image load lifecycle, fade, headers; Modal on_request_close; StatusBar translucent/animated; FlatList/SectionList inverted, separators, initial index, sticky section headers. - Typed event records (LayoutEvent, ScrollEvent, SelectionEvent, KeyPressEvent, ContentSizeEvent) and typed imperative handles (ViewHandle, TextInputHandle, ScrollViewHandle, WebViewHandle). - border_style, inset shorthands, 3D transforms, DynamicColor on every renderer; pn.style typed with Unpack[Style]. - accessibility_value/actions/important_for_accessibility on every view. Device APIs - AccessibilityInfo, Keyboard, Dimensions, PixelRatio, Device, Localization modules with hooks; iOS keyboard height; Android camera full-resolution capture, location permission prompt; SecureStore raises on failure. Navigation - Navigator screen_options, Group, create_navigation_ref, pop_to, before_remove on every removal with an iOS guarded-back path, NavigationTheme with dark mode, tab bar styling, tab_bar_visible, freeze_on_blur, presentation and animation variants on iOS and Android, Android slide transitions, back arrow, inset-aware toolbar, large titles, and predictive back. The browser preview's native stacks draw navigation bars. Animation and gestures - React Native's decay model everywhere, composed iOS transform channels, Easing namespace with bezier passthrough, AnimationResult, a clear error for non-animatable props; gesture enabled flags, Pan offsets, max_pointers, min_velocity, and absolute coordinates. Found on the simulator and emulator - Events a view emits while its own commit applies carry that commit's identity, so a new Image's on_load_start arrives. - Pressable spans are bounded by their glyphs; Android Text labels with on_press are clickable. - Horizontal ScrollView content lays out in a row on every renderer. - WebViewHandle.eval_js settles with the page's answer through an async WebViews module. - iOS Pan gestures with activation offsets begin; iOS single-line fields report Enter; TextInputHandle.clear() reports on_change everywhere. - A reopened Modal shows its content on iOS and Android; one iOS sheet pull-down is one on_request_close; on_dismiss fires on every renderer when visible turns false; overlay backdrop taps request close. Testing, tooling, and docs - Role, placeholder, and display-value queries, find_by_*, within, wait_for, a fake clock, and a pytest plugin. - pn start names missing requirements with an exact install command. - Regenerated native contracts, 115 e2e demos and Maestro flows, updated guides and API reference. Removals - The Python view-handler layer (NativeViewRegistry, ViewHandler, register_component, native_component, get_registry), scroll_axis, positional Context.Provider values, dict event payloads, Ref._pn_tag and _pn_frame, free-form easing strings, the eval_js view command, the unused requests dependency, duplicate equality helpers, and dead host hooks. BREAKING CHANGE: Context.Provider takes value as a keyword; ScrollView uses horizontal instead of scroll_axis; on_layout, on_scroll, and on_selection_change deliver dataclasses; Pressable style callables receive PressState; refs on built-in elements hold typed handles; sdk register_component and native_component are replaced by define_component; pythonnative.native_views.get_registry is replaced by get_backend; Animated.decay uses React Native's model; SecureStore.set_item and delete_item raise on failure; a Modal no longer closes itself on a back press or backdrop tap and calls on_request_close instead.
1 parent 9daa7ff commit c588d11

377 files changed

Lines changed: 28351 additions & 5856 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CONTRIBUTING.md‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ Unsolicited pull requests for issues that are already assigned or already have a
6363

6464
- `src/pythonnative/`: installable library and CLI
6565
- Core Python modules, UI components, and utilities
66+
- `components/`: element factories and the typed event records (`components/events.py`)
67+
- `handles.py`: typed imperative handles published on `ref.current`
68+
- `journal.py`: the undo journal a failed render pass rolls back through
69+
- `native_views/`: the thin backend accessor (`get_backend` / `set_backend`) and the bridge backend that serializes commits
70+
- `native_modules/`: device module facades and their Python fallbacks
71+
- `navigation/`: navigators, container, hooks, linking, theme, and the navigation ref
72+
- `testing/`: the headless testing library and the shipped pytest plugin (`testing/pytest_plugin.py`)
6673
- `bridge/`: JSON codec and per-platform transports into the native rendering core
6774
- `cli/`: `pn` command
6875
- `project/`: config loading, template configuration, native plugin staging, and the builder behind `pn`
@@ -198,16 +205,18 @@ Recommended scopes (choose the smallest, most accurate unit; prefer module/direc
198205
- `element`: Element descriptor class (`element.py`)
199206
- `events`: tag-based event routing between native views and Python callbacks (`events.py`)
200207
- `gestures`: gesture descriptors and the pure-Python recognition arbiter (`gestures.py`)
208+
- `handles`: typed imperative handles published on refs (`handles.py`)
201209
- `hooks`: hooks and contexts (`hooks.py`)
202210
- `hosts`: screen hosts, lifecycle forwarding, and render scheduling (`hosts/`)
203211
- `devserver`: dev server, file watcher, and WebSocket implementation (`devserver/`)
204212
- `devclient`: on-device dev client that syncs sources and Fast Refreshes (`devclient.py`)
205213
- `hot_reload`: module reloader and Fast Refresh (`hot_reload.py`)
214+
- `journal`: render undo journal (`journal.py`)
206215
- `layout`: Yoga layout integration and the host binding (`layout.py`, `native/yoga/`)
207216
- `mutations`: batched mutation ops between reconciler and native backends (`mutations.py`)
208217
- `native_modules`: native module registry, Python facades, and Python fallbacks (`native_modules/`)
209-
- `native_views`: view registry protocol and bridge backend (`native_views/`)
210-
- `navigation`: navigation state, container, navigators, hooks, and linking (`navigation/`)
218+
- `native_views`: view backend accessor and bridge backend (`native_views/`)
219+
- `navigation`: navigation state, container, navigators, hooks, linking, theme, and ref (`navigation/`)
211220
- `net`: awaitable HTTP client (`net.py`)
212221
- `package`: `src/pythonnative/__init__.py` exports and package boundary
213222
- `platform`: `Platform.OS`/`Platform.select` and version detection (`platform.py`)
@@ -220,7 +229,7 @@ Recommended scopes (choose the smallest, most accurate unit; prefer module/direc
220229
- `storage`: AsyncStorage key/value persistence and `use_persisted_state` (`storage.py`)
221230
- `scheduler`: render batching and transition queues (`scheduler.py`)
222231
- `style`: StyleSheet and theming (`style.py`)
223-
- `testing`: public test utilities (`testing/`)
232+
- `testing`: public test utilities and the pytest plugin (`testing/`)
224233
- `utils`: shared utilities (`utils.py`)
225234

226235
- Other scopes:
@@ -328,7 +337,7 @@ Co-authored-by: Name <email>
328337
- PR title: Conventional Commits format (CI-enforced by `pr-lint.yml`).
329338
- Tests: added/updated; `uv run pytest` passes.
330339
- Lint/format: `uv run ruff check .` and `uv run black --check src examples tests` pass.
331-
- Docs: update `README.md` if behavior changes.
340+
- Docs: update `README.md` and the affected pages under `docs/` if behavior changes; `uv run --group docs mkdocs build --strict` must pass.
332341
- Templates: update `src/pythonnative/templates/` if generator output changes.
333342
- Generated contracts and example schemas are regenerated and reviewed when changed; vendored dependencies retain their licenses and provenance.
334343
- No local build outputs, caches, credentials, or machine-specific files are committed.
@@ -431,10 +440,14 @@ For tight iteration, run a single category instead of the full pass:
431440

432441
```bash
433442
uv run ./scripts/run-e2e.sh android hooks
434-
uv run ./scripts/run-e2e.sh ios components
443+
uv run ./scripts/run-e2e.sh ios navigation
435444
```
436445

437-
Available categories: `components`, `hooks`, `navigation`, `layout`, `styling`, `animations`, `misc`.
446+
Each category is one file under `tests/e2e/suites/` (`hooks.yaml`, `navigation.yaml`, `gestures.yaml`, and so on; large areas are split into lettered parts such as `components-a.yaml`). List the directory for the current set:
447+
448+
```bash
449+
ls tests/e2e/suites
450+
```
438451

439452
A coverage checker, `scripts/check-e2e-coverage.py`, gates CI: every name in `pythonnative.__all__` must be covered by a demo + flow, or listed in `INTENTIONAL_EXEMPTIONS` with a justification.
440453

@@ -443,7 +456,7 @@ When you add a new public symbol you must also:
443456
1. Add a demo screen under `examples/e2e-suite/app/screens/<category>/`.
444457
2. Append a `DemoEntry` in `examples/e2e-suite/app/registry.py`.
445458
3. Add a Maestro flow at `tests/e2e/flows/<category>/<name>.yaml`.
446-
4. Append the flow to the top-level `tests/e2e/android.yaml`, `tests/e2e/ios.yaml`, and the matching `tests/e2e/suites/<category>.yaml`.
459+
4. Append the flow to the top-level `tests/e2e/android.yaml`, `tests/e2e/ios.yaml`, and the matching `tests/e2e/suites/<category>.yaml` (or the lettered part it belongs to).
447460
5. Confirm `uv run python scripts/check-e2e-coverage.py` exits 0.
448461

449462
`tests/e2e/AGENTS.md` is the deeper reference (label conventions, failure triage, naming rules); AI agents should read it before touching the suite. The `e2e.yml` workflow runs the suite automatically on pushes to `main` and PRs.

‎README.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
3030

3131
## Features
3232

33-
- **Declarative components and hooks:** Describe native UI with Python functions, immutable elements, and typed styles. State, effects, context, and suspense boundaries follow one logical application tree across screens, overlays, and mounted list rows.
33+
- **Declarative components and hooks:** Describe native UI with Python functions, immutable elements, and typed styles. State, effects, context, and suspense boundaries follow one logical application tree across screens, overlays, and mounted list rows. State updates batch automatically, effect errors reach the nearest error boundary, and event callbacks receive typed records instead of dicts.
34+
- **React Native's core surface:** `Pressable`, `ScrollView`, `Text`, `TextInput`, `Image`, `Modal`, `FlatList`, and `SectionList` carry the props a React Native developer expects (disabled state and ripples, content insets and snapping, ellipsize modes and pressable spans, controlled selection and key events, sticky headers and inverted lists), plus typed imperative handles on `ref.current` and the full accessibility prop set.
3435
- **Native widgets and layout:** Swift and Kotlin component managers own UIKit and Android widgets. The shared Yoga C++ engine computes layout beside the controls, using platform measurements for text and intrinsic sizes.
3536
- **Standard asyncio:** Components, effects, event handlers, and tasks run on a dedicated Python application thread. Native UI threads handle widgets, scrolling, and animation frames. Component-owned tasks are canceled on unmount.
3637
- **Incremental reconciliation:** State changes update affected component subtrees. Versioned bridge commits validate operations and acknowledge revisions; events and controlled text inputs carry identities that prevent stale updates.
37-
- **Native lists and navigation:** UIKit collection views and Android recycler views recycle cells for fixed or variable row sizes, grids, sections, and horizontal lists. Native navigation containers present logical screen roots while providers and component state remain in the shared Python tree.
38-
- **Animation and gestures:** Serialized animation graphs support timing, springs, decay, arithmetic, interpolation, and native scroll and gesture bindings. Swift and Kotlin recognize mobile gestures and update supported animation bindings without Python work on every frame.
38+
- **Native lists and navigation:** UIKit collection views and Android recycler views recycle cells for fixed or variable row sizes, grids, sections, and horizontal lists. Native navigation containers present logical screen roots at every nesting level while providers and component state remain in the shared Python tree; navigators take screen options, groups, themes, tab-bar styles, and a navigation ref usable outside components.
39+
- **Animation and gestures:** Serialized animation graphs support timing with named or bezier easing, springs, React Native's decay model, arithmetic, interpolation, and native scroll and gesture bindings. Swift and Kotlin recognize mobile gestures with Gesture Handler-style activation offsets and update supported animation bindings without Python work on every frame.
3940
- **Assets and graphics:** Drop images, fonts, and SVGs under `app/assets/` and reference them by path. Density variants, bundled fonts, a vector `Icon` set, `Svg` drawing, gradients, and blur render natively on both platforms and in the browser preview.
40-
- **Device APIs:** Python facades expose camera, location, notifications, storage, permissions, and other native services. Test permissions and platform behavior on your deployment targets.
41-
- **Native extension SDK:** Python dataclasses and protocols define contracts; `pn codegen` generates props and module adapters for Swift and Kotlin. Plugins package native sources and resources, and builds verify matching contracts at startup.
41+
- **Device APIs:** Python facades expose camera, location, notifications, storage, permissions, keyboard, dimensions and pixel ratio, device info, localization, accessibility settings, and other native services, with a Python fallback for headless tests. Test permissions and platform behavior on your deployment targets.
42+
- **Native extension SDK:** Python dataclasses and protocols define contracts; `define_component` returns a typed element factory and `pn codegen` generates props and module adapters for Swift and Kotlin. Plugins package native sources and resources, and builds verify matching contracts at startup.
43+
- **Testing library:** `pythonnative.testing` renders components headlessly with Testing Library-style queries (`get_by_role`, `get_by_placeholder_text`, `within`, `find_by_*`), a virtual clock for timers, and a pytest plugin that resets the runtime between tests.
4244
- **Development tools:** `pn start` serves the browser preview and connected mobile dev clients. Fast Refresh preserves compatible component state, while diagnostics report errors and invalid hook usage. Changes to native inputs trigger a rebuild.
4345
- **Browser preview:** `pn preview` runs your Python application against a browser renderer with DOM widgets, Yoga WebAssembly layout, and JavaScript animation graphs. It supports iteration on application logic and UI; fonts, platform controls, and device APIs require mobile testing.
4446
- **App packaging and dependency locks:** `pn run` and `pn build` stage bundled app templates, native libraries, and Python sources. Target-specific wheel locks record dependency versions and hashes for mobile builds. Binary dependencies need compatible mobile wheels; `pn deps` reports target resolution.

‎docs/api/animated.md‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ Python reconciliation on each frame. Unattached values, Python listeners,
1010
callable easing functions, and backends that decline native animation use
1111
the Python ticker.
1212

13+
A few types frame the surface:
14+
15+
- [`Easing`][pythonnative.animated.Easing] is a namespace of
16+
serializable [`EasingSpec`][pythonnative.animated.EasingSpec] curves
17+
(`Easing.ease_out`, `Easing.bezier(...)`) accepted by
18+
`Animated.timing(easing=...)`; a misspelled easing name raises
19+
`ValueError` instead of falling back.
20+
- `await handle` and `handle.start(callback)` deliver an
21+
[`AnimationResult`][pythonnative.animated.AnimationResult] whose
22+
`finished` flag tells a stopped or superseded animation from one that
23+
ran to completion.
24+
- [`ANIMATABLE_PROPS`][pythonnative.animated.ANIMATABLE_PROPS] lists
25+
the style keys an animated node may drive; binding a layout key such
26+
as `width` raises `ValueError` at element construction.
27+
- `Animated.decay` uses React Native's model on every platform:
28+
velocity in points per millisecond decays as
29+
`v0 * deceleration ** t`, with `deceleration` defaulting to `0.998`.
30+
1331
::: pythonnative.animated
1432
options:
1533
show_root_heading: false
@@ -21,6 +39,7 @@ the Python ticker.
2139
## See also
2240

2341
- The [Animations guide](../guides/animations.md) walks through
24-
fade-ins, springs, sequences, and gesture-driven animations.
42+
fade-ins, springs, sequences, easing, decay, and gesture-driven
43+
animations.
2544
- [`use_ref`][pythonnative.use_ref] explains the `ref` semantics that
2645
back `Animated.View`.

0 commit comments

Comments
 (0)

Footer

© 2026 GitHub, Inc.

Back | FazBrowse Home | New Git URL