You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-`pythonnative.native_modules.Notifications` — local push notifications
45
+
19
46
## Internal helpers
20
47
21
48
-`pythonnative.utils.IS_ANDROID` — platform flag with robust detection for Chaquopy/Android.
22
49
-`pythonnative.utils.get_android_context()` — returns the current Android `Activity`/`Context` when running on Android.
23
50
-`pythonnative.utils.set_android_context(ctx)` — set by `Page` on Android; you generally don't call this directly.
24
51
-`pythonnative.utils.get_android_fragment_container()` — returns the current Fragment container `ViewGroup` used for page rendering.
25
-
-`pythonnative.utils.set_android_fragment_container(viewGroup)` — set by the host `PageFragment`; you generally don't call this directly.
26
52
27
53
## Reconciler
28
54
29
-
`pythonnative.reconciler.Reconciler` — diffs element trees and applies minimal native mutations. Used internally by `Page`.
55
+
`pythonnative.reconciler.Reconciler` — diffs element trees and applies minimal native mutations. Supports key-based child reconciliation, function components, and context providers. Used internally by `Page`.
56
+
57
+
## Hot reload
58
+
59
+
`pythonnative.hot_reload.FileWatcher` — watches a directory for file changes and triggers a callback. Used by `pn run --hot-reload`.
60
+
61
+
`pythonnative.hot_reload.ModuleReloader` — reloads changed Python modules on the device and triggers page re-rendering.
Copy file name to clipboardExpand all lines: docs/concepts/architecture.md
+50-6Lines changed: 50 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,27 +5,58 @@ PythonNative combines **direct native bindings** with a **declarative reconciler
5
5
## High-level model
6
6
7
7
1.**Declarative element tree:** Your `Page.render()` method returns a tree of `Element` descriptors (similar to React elements / virtual DOM nodes).
8
-
2.**Reconciler:** On first render, the reconciler walks the tree and creates real native views via the platform backend. On subsequent renders (triggered by `set_state`), it diffs the new tree against the old one and applies the minimal set of native mutations.
9
-
3.**Direct bindings:** Under the hood, native views are created and updated through direct platform calls:
8
+
2.**Function components and hooks:** Reusable components with independent state via `@pn.component`, `use_state`, `use_effect`, etc. — inspired by React hooks but designed for Python.
9
+
3.**Reconciler:** On first render, the reconciler walks the tree and creates real native views via the platform backend. On subsequent renders (triggered by `set_state` or hook state changes), it diffs the new tree against the old one and applies the minimal set of native mutations.
10
+
4.**Key-based reconciliation:** Children can be assigned stable `key` values to preserve identity across re-renders — critical for lists and dynamic content.
11
+
5.**Direct bindings:** Under the hood, native views are created and updated through direct platform calls:
-**Android:** Chaquopy exposes Java classes (`android.widget.TextView`, `android.widget.Button`, etc.) via the JNI bridge.
12
-
4.**Thin native bootstrap:** The host app remains native (Android `Activity` or iOS `UIViewController`). It passes a live instance/pointer into Python, and Python drives the UI through the reconciler.
14
+
6.**Thin native bootstrap:** The host app remains native (Android `Activity` or iOS `UIViewController`). It passes a live instance/pointer into Python, and Python drives the UI through the reconciler.
13
15
14
16
## How it works
15
17
16
18
```
17
19
Page.render() → Element tree → Reconciler → Native views
The reconciler uses **positional diffing** (comparing children by index). When a child at a given position has the same element type, its props are updated in-place on the native view. When the type changes, the old native view is destroyed and a new one is created.
25
+
The reconciler uses **key-based diffing** (matching children by key first, then by position). When a child with the same key/type is found, its props are updated in-place on the native view. When the type changes, the old native view is destroyed and a new one is created.
26
+
27
+
## Component model
28
+
29
+
PythonNative supports two kinds of components:
30
+
31
+
### Page classes (screens)
32
+
33
+
Each screen is a `Page` subclass that bridges native lifecycle events to Python. Pages have `render()`, `set_state()`, navigation (`push`/`pop`), and lifecycle hooks (`on_create`, `on_resume`, etc.).
34
+
35
+
### Function components (reusable UI)
36
+
37
+
Decorated with `@pn.component`, these are Python functions that return `Element` trees and can use hooks for state, effects, memoisation, and context. Each call site creates an independent instance with its own hook state.
38
+
39
+
```python
40
+
@pn.component
41
+
defcounter(initial: int=0) -> pn.Element:
42
+
count, set_count = pn.use_state(initial)
43
+
return pn.Text(f"Count: {count}")
44
+
```
45
+
46
+
## Styling
47
+
48
+
-**Inline styles:** Pass props directly to components (`font_size=24`, `color="#333"`).
49
+
-**StyleSheet:** Create reusable named style dictionaries with `pn.StyleSheet.create(...)`.
50
+
-**Theming:** Use `pn.ThemeContext` with `pn.Provider` and `pn.use_context` to propagate theme values through the tree.
51
+
52
+
## Layout
53
+
54
+
All components support layout properties: `width`, `height`, `flex`, `margin`, `min_width`, `max_width`, `min_height`, `max_height`, `align_self`. Containers (`Column`, `Row`) support `spacing`, `padding`, and `alignment`.
23
55
24
56
## Comparison
25
57
26
58
-**Versus React Native:** RN uses JSX + a JavaScript bridge + Yoga layout. PythonNative uses Python + direct native calls + platform layout managers. No JS bridge, no serialisation overhead.
27
-
-**Versus NativeScript:** Similar philosophy (direct, synchronous native access), but PythonNative adds a declarative reconciler layer that NativeScript does not have by default.
28
-
-**Versus the old imperative API:** The previous PythonNative API required manual `add_view()` calls and explicit setter methods. The new declarative model handles view lifecycle automatically.
59
+
-**Versus NativeScript:** Similar philosophy (direct, synchronous native access), but PythonNative adds a declarative reconciler layer and React-like hooks that NativeScript does not have by default.
29
60
30
61
## iOS flow (Rubicon-ObjC)
31
62
@@ -39,6 +70,19 @@ The reconciler uses **positional diffing** (comparing children by index). When a
39
70
-`PageFragment` calls `on_create()` on the Python `Page`, which renders and attaches views to the fragment container.
40
71
- State changes trigger re-render; the reconciler patches Android views in-place.
41
72
73
+
## Hot reload
74
+
75
+
During development, `pn run --hot-reload` watches `app/` for file changes and pushes updated Python files to the running app, enabling near-instant UI updates without full rebuilds.
76
+
77
+
## Native API modules
78
+
79
+
PythonNative provides cross-platform modules for common device APIs:
80
+
81
+
-`pythonnative.native_modules.Camera` — photo capture and gallery
0 commit comments