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

feat(cli)!: add dev server, dev clients, and browser preview by owenthcarey · Pull Request #74 · pythonnative/pythonnative · GitHub

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

Filter by extension

Filter by extension .css  (1) .gradle  (1) .html  (1) .js  (5) .kt  (3) .md  (35) .py  (70) .swift  (3) .toml  (1) .xml  (1) .yml  (1) All 11 file types selected
Only manifest files
Deleted 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
9 changes: 6 additions & 3 deletions 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 @@ -151,16 +151,19 @@ Recommended scopes (choose the smallest, most accurate unit; prefer module/direc
- `gestures`: gesture descriptors and the pure-Python recognition arbiter (`gestures.py`)
- `hooks`: hooks and contexts (`hooks.py`)
- `hosts`: screen hosts, lifecycle forwarding, and render scheduling (`hosts/`)
- `hot_reload`: file watcher and module reloader (`hot_reload.py`)
- `devserver`: dev server, file watcher, and WebSocket implementation (`devserver/`)
- `devclient`: on-device dev client that syncs sources and Fast Refreshes (`devclient.py`)
- `hot_reload`: module reloader and Fast Refresh (`hot_reload.py`)
- `layout`: pure-Python flexbox engine (`layout.py`)
- `mutations`: batched mutation ops between reconciler and native backends (`mutations.py`)
- `native_modules`: native module registry, Python facades, and desktop implementations (`native_modules/`)
- `native_views`: view registry protocol, bridge backend, and desktop handlers (`native_views/`)
- `native_modules`: native module registry, Python facades, and Python fallbacks (`native_modules/`)
- `native_views`: view registry protocol and bridge backend (`native_views/`)
- `navigation`: navigation state, container, navigators, hooks, and linking (`navigation/`)
- `net`: awaitable HTTP client (`net.py`)
- `package`: `src/pythonnative/__init__.py` exports and package boundary
- `platform`: `Platform.OS`/`Platform.select` and version detection (`platform.py`)
- `platform_metrics`: platform-reported metrics like safe-area insets and bar heights (`platform_metrics.py`)
- `preview`: `pn start` / `pn preview` session and the browser preview page (`preview.py`, `devserver/static/`)
- `project`: `pythonnative.toml` config, template configurators, plugin staging, and the builder (`project/`)
- `reconciler`: virtual view tree diffing, boundaries, and the layout pass (`reconciler/`)
- `runtime`: framework-wide asyncio loop and thread-safe future helpers (`runtime.py`)
Expand Down
20 changes: 15 additions & 5 deletions 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 @@ -35,20 +35,20 @@ PythonNative is a cross-platform toolkit for building native Android and iOS app
- **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.
- **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.
- **Developer feedback that finds your bugs:** In dev mode (`pn start`, `pn preview`, debug builds from `pn run`, 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 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.
- **Native gesture system:** Attach `Tap`, `LongPress`, `Pan`, `Swipe`, `Fling`, `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. Compose them with `Race`, `Exclusive`, and `Simultaneous` for cross-gesture arbitration (single vs. double tap, drag vs. long press).
- **Native gesture system:** Attach `Tap`, `LongPress`, `Pan`, `Swipe`, `Fling`, `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 in the browser preview. Compose them with `Race`, `Exclusive`, and `Simultaneous` for cross-gesture arbitration (single vs. double tap, drag vs. long press).
- **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.
- **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.
- **Metro-style dev loop:** `pn start` runs one dev server that serves the browser preview and every connected debug build. Save a file and each client Fast Refreshes in place, keeping component state; their `print` output and tracebacks stream back into the same terminal. `pn run android` / `pn run ios` bakes the server URL into a debug build and rebuilds the native project only when a native input actually changed, so relaunching after a Python edit takes seconds, not minutes.
- **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.
- **Browser preview:** `pn preview` renders your app in a browser tab inside a phone frame (pick a device, rotate, toggle dark mode) with Fast Refresh on every save. The page is a bridge peer exactly like the Swift and Kotlin runtimes, so the reconciler, hooks, layout engine, navigation, and screen host are the same code that ships to the phone; only the leaf widgets are DOM elements.
- **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.
- **Dev client:** Build a shell app once with `pn run ios --dev-client` and point it at any project's dev server from a connect screen, the way Expo Go does; physical phones on the same Wi-Fi get the same Fast Refresh as simulators.
- **Bundled templates:** Android Gradle and iOS Xcode templates are included, so scaffolding requires no network access.

## Quick Start
Expand Down Expand Up @@ -80,6 +80,16 @@ def App():
)
```

### Develop

```bash
pn init my-app && cd my-app
pn preview # dev server + browser preview with Fast Refresh
pn run ios # in another terminal: debug build that connects to the same server
pn run android
pn build ios # standalone release artifacts
```

## Documentation

Visit [pythonnative.com](https://pythonnative.com/) for the full documentation, including getting started guides, platform-specific instructions for Android and iOS, API reference, and working examples.
Expand Down
30 changes: 21 additions & 9 deletions 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 @@ -23,17 +23,29 @@ the documented behavior never drifts from the code.
`--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
[Desktop preview guide](../guides/desktop-preview.md).
- `pn start [entry]`: run the dev server. It watches `app/`, syncs
every save to each connected debug build with Fast Refresh, relays
their logs, and serves the browser preview page. Flags: `--port`
(default 8765), `--host` (default `0.0.0.0`), `--open` to also open
the browser preview. See the
[Development workflow](../guides/dev-workflow.md).
- `pn preview [entry]`: `pn start` plus opening the browser preview in
your default browser. Flags: `--port`, `--host`, `--no-open`. See the
[Browser preview guide](../guides/browser-preview.md).
- `pn devices [android|ios]`: list connected devices, emulators, and
simulators with the identifiers `--device` accepts. Flag: `--json` to
print a JSON array to stdout for scripting; the "no devices" hints go
to stderr instead, and an empty list prints `[]` and exits 0.
- `pn run android|ios`: build and run on a connected device or
simulator. Flags: `--device` (target a specific device by identifier
or name), `--prepare-only`, `--hot-reload`, `--no-logs`.
- `pn run android|ios`: build, install, and launch a debug build that
connects to the running dev server. The native toolchain runs only
when a native input changed (config, template, `pythonnative`
itself, native plugins); otherwise the previous artifact is
reinstalled. Flags: `--device` (target a specific device by
identifier or name), `--prepare-only`, `--no-logs`, `--rebuild`
(force the toolchain), `--dev-server URL` (override the server URL
baked into the app), `--port` (where `pn start` listens),
`--dev-client` (build a shell app with a connect screen that loads
any project from a dev server).
- `pn logs android|ios`: stream logs from the running app without
rebuilding. Flag: `--device` (target a specific device by identifier
or name, same as `pn run`). Physical iOS devices aren't supported for
Expand All @@ -57,5 +69,5 @@ the documented behavior never drifts from the code.
## Next steps

- See the [Getting started](../getting-started.md) walkthrough.
- Read about [Hot reload](../guides/hot-reload.md) when you turn on
`--hot-reload`.
- Read the [Development workflow](../guides/dev-workflow.md) for how
`pn start` and `pn run` work together.
84 changes: 84 additions & 0 deletions docs/api/devserver.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
@@ -0,0 +1,84 @@
# Dev server and dev client

The development loop is a server process (`pn start`) and any number of
clients: the browser preview and debug builds on simulators, emulators,
and devices. See the [Development workflow](../guides/dev-workflow.md)
guide for how they fit together; this page documents the modules.

## `pythonnative.devserver`

::: pythonnative.devserver
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

### Server

::: pythonnative.devserver.server
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

### File watcher and source snapshots

::: pythonnative.devserver.watcher
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

### WebSocket

::: pythonnative.devserver.ws
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

## `pythonnative.devclient`

::: pythonnative.devclient
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

## `pythonnative.preview`

::: pythonnative.preview
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

## `pythonnative.bridge.web`

::: pythonnative.bridge.web
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

## `pythonnative.project.fingerprint`

::: pythonnative.project.fingerprint
options:
show_root_heading: false
show_root_toc_entry: false
members_order: source
filters: ["!^_"]

## Next steps

- [Fast Refresh](../guides/hot-reload.md) and the
[hot reload API](hot_reload.md) for the device-side reload.
- [Browser preview](../guides/browser-preview.md).
5 changes: 3 additions & 2 deletions docs/api/diagnostics.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 @@ -6,8 +6,9 @@ props and styles, the [`HookOrderError`][pythonnative.HookOrderError]
raised on conditional hooks, and the RedBox overlay that surfaces
uncaught errors from renders, effects, and event handlers.

Dev mode is enabled automatically by `pn preview` and by `pn run
--hot-reload`, or explicitly with the `PN_DEV=1` environment variable.
Dev mode is enabled automatically by `pn start` / `pn preview` and in
the debug builds `pn run` produces, or explicitly with the `PN_DEV=1`
environment variable.
In production builds every check in this module is skipped, so
shipping apps pay no overhead.

Expand Down
13 changes: 4 additions & 9 deletions docs/api/hosts.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 @@ -12,8 +12,10 @@ templates create a host through the `Host` native module's `create`
event and never need to be edited by app code; one
[`NativeScreenHost`][pythonnative.hosts.native.NativeScreenHost] class
serves both platforms because every platform-specific step goes over
the [bridge](../concepts/bridge.md). The desktop preview uses
[`DesktopScreenHost`][pythonnative.hosts.desktop.DesktopScreenHost].
the [bridge](../concepts/bridge.md). The browser preview uses the same
class: its page is a bridge peer that speaks the `Host` module protocol
over a WebSocket (see
[`WebTransport`][pythonnative.bridge.web.WebTransport]).

::: pythonnative.hosts
options:
Expand All @@ -40,13 +42,6 @@ the [bridge](../concepts/bridge.md). The desktop preview uses
members_order: source
filters: ["!^_"]

::: pythonnative.hosts.desktop
options:
show_root_heading: false
show_root_toc_entry: false
members: ["DesktopScreenHost"]
filters: ["!^_"]

## Next steps

- Understand the render queue in [Lifecycle](../concepts/lifecycle.md).
Expand Down
13 changes: 8 additions & 5 deletions docs/api/hot_reload.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,9 +1,11 @@
# Hot reload

Hot-reload comes in two cooperating pieces: a host-side file watcher
that pushes changed `.py` files to the device, and a device-side
module reloader that swaps the new code in and re-renders the active
page. Both are wired up automatically by `pn run --hot-reload`.
Fast Refresh comes in two cooperating pieces: the
[dev server](devserver.md) that watches `app/` and pushes changed files
to every connected client, and this device-side module reloader that
swaps the new code in and refreshes every mounted screen. Debug builds
launched with `pn run` while `pn start` is running are wired up
automatically.

::: pythonnative.hot_reload
options:
Expand All @@ -14,4 +16,5 @@ page. Both are wired up automatically by `pn run --hot-reload`.

## Next steps

- See the workflow in [Hot reload guide](../guides/hot-reload.md).
- See the workflow in the [Fast Refresh guide](../guides/hot-reload.md).
- The other half: [Dev server and dev client](devserver.md).
2 changes: 1 addition & 1 deletion docs/api/native_modules.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 @@ -26,7 +26,7 @@ and the [Async + data guide](../guides/async.md).

## Desktop implementations

::: pythonnative.native_modules.desktop
::: pythonnative.native_modules.fallback
options:
show_root_heading: false
show_root_toc_entry: false
Expand Down
7 changes: 4 additions & 3 deletions docs/api/native_views.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 @@ -9,9 +9,10 @@ call on a [`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry].
On device that registry is the
[`BridgeBackend`][pythonnative.native_views.bridge_backend.BridgeBackend],
which forwards the transaction to Swift and Kotlin component managers
over the [native bridge](bridge.md). Off device it dispatches to Python
[`ViewHandler`][pythonnative.native_views.base.ViewHandler] objects
(Tkinter for `pn preview`, a fake for tests).
over the [native bridge](bridge.md). The browser preview uses the same
backend with a WebSocket transport to the page. In tests it dispatches
to Python [`ViewHandler`][pythonnative.native_views.base.ViewHandler]
objects (an in-memory fake).

::: pythonnative.native_views
options:
Expand Down
6 changes: 3 additions & 3 deletions docs/api/platform.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,12 +16,12 @@ branches throughout the codebase.

| Attribute | Values |
|---|---|
| `Platform.OS` | `"ios"`, `"android"`, `"desktop"`, or `"test"` |
| `Platform.OS` | `"ios"`, `"android"`, `"web"`, or `"test"` |
| `Platform.Version` | Best-effort OS version string |
| `Platform.is_ios` / `Platform.is_android` / `Platform.is_desktop` / `Platform.is_test` | Booleans |
| `Platform.is_ios` / `Platform.is_android` / `Platform.is_web` / `Platform.is_test` | Booleans |
| `Platform.select(spec, default=None)` | Pick a value matching the current platform |

- `"desktop"` means the `pn preview` Tkinter backend.
- `"web"` means the `pn preview` browser preview.

## See also

Expand Down
Loading
Loading

Back | FazBrowse Home | New Git URL