Native views¶
The boundary between PythonNative's element tree and concrete native
widgets. Each commit's diff is expressed as a flat list of
mutation ops referencing integer tags, applied through a
single
apply_mutations
call on a NativeViewRegistry.
On device that registry is the
BridgeBackend,
which forwards the transaction to Swift and Kotlin component managers
over the native bridge. The browser preview uses the same
backend with a WebSocket transport to the page. In tests it dispatches
to Python ViewHandler
objects (an in-memory fake).
The view backend the reconciler commits to.
The reconciler talks to exactly one object, obtained from
get_registry, through a
small protocol: apply_mutations (one ordered batch of
create/update/insert/destroy/frame ops per commit, see
pythonnative.mutations), resolve_view, measure_intrinsic,
command, and the animation hooks. Two implementations exist:
BridgeBackend(iOS, Android, and the browser preview): serializes each commit and hands it to the native runtime through the bridge; the Swift and Kotlin component managers, or the preview page's DOM applier, own every platform view. Python holds no native objects.NativeViewRegistry(tests and SDK handler introspection): maps element type names to PythonViewHandlerimplementations and owns the tag table itself.
Platform selection happens lazily on first use, so this package
imports on any platform. Tests install a mock with
set_registry.
Modules:
| Name | Description |
|---|---|
base |
Shared base classes and utilities for native-view handlers. |
bridge_backend |
Revisioned native view backend. |
Classes:
| Name | Description |
|---|---|
ViewRecord |
One live native view tracked by the tag table. |
NativeViewRegistry |
Map element type names to handlers and tags to live native views. |
Functions:
| Name | Description |
|---|---|
get_registry |
Return the process-wide view backend, creating it on first use. |
refresh_registry |
Re-run SDK handler installation against the existing backend. |
set_registry |
Install a custom backend (primarily for testing). |
ViewRecord
¶
ViewRecord(
tag: int,
type_name: str,
view: Any,
handler: ViewHandler,
)
One live native view tracked by the tag table.
NativeViewRegistry
¶
Map element type names to handlers and tags to live native views.
The reconciler depends only on this protocol: apply_mutations,
resolve_view, measure_intrinsic, and command.
Implementations may host real platform handlers (Android/iOS/
browser) or mocks for tests.
Methods:
| Name | Description |
|---|---|
register |
Register |
handler_for |
Return the handler registered for |
resolve_view |
Return the native view registered under |
record_for |
Return the full |
live_view_count |
Number of views currently tracked (test/diagnostic helper). |
apply_mutations |
Apply one commit transaction. |
measure_intrinsic |
Return the natural |
command |
Execute an imperative command against the view for |
set_animated_property |
Apply one Python-driven animation frame to the view for |
start_animation |
Start a natively-driven animation on the view for |
cancel_animation |
Cancel a natively-driven animation; returns the presentation value if known. |
register
¶
register(type_name: str, handler: ViewHandler) -> None
Register handler to service elements of type type_name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_name
|
str
|
The element type name (e.g., |
required |
handler
|
ViewHandler
|
A |
required |
handler_for
¶
handler_for(type_name: str) -> Optional[ViewHandler]
Return the handler registered for type_name, if any.
live_view_count
¶
live_view_count() -> int
Number of views currently tracked (test/diagnostic helper).
apply_mutations
¶
Apply one commit transaction.
Ops are applied strictly in order. Failures are isolated per op: a handler exception is logged (rate-limited) and the remaining ops still apply, so one bad prop can't desync the whole native tree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ops
|
Sequence[Mutation]
|
Ordered mutations emitted by the reconciler. |
required |
measure_intrinsic
¶
Return the natural (width, height) of a content-sized view.
Used by the layout engine for leaves whose intrinsic size depends on their content (text, buttons, images).
command
¶
Execute an imperative command against the view for tag.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
int
|
Target view tag. |
required |
name
|
str
|
Command name (handler-specific, e.g.
|
required |
args
|
Optional[Dict[str, Any]]
|
Optional command arguments. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The handler's command result, or |
Any
|
unknown. |
set_animated_property
¶
Apply one Python-driven animation frame to the view for tag.
start_animation
¶
get_registry
¶
get_registry() -> Any
refresh_registry
¶
refresh_registry() -> Any
Re-run SDK handler installation against the existing backend.
Call this after registering a new component at runtime if the
registry has already been instantiated. This is mostly useful in
REPL sessions and tests; the normal flow is "register, then call
get_registry" and the
handlers come along automatically.
set_registry
¶
set_registry(registry: Any) -> None
Install a custom backend (primarily for testing).
Replaces the lazy singleton so subsequent
get_registry calls
return registry. Pass a mock to drive the reconciler from
unit tests without touching real native APIs. Pass None to
reset the singleton; the next get_registry call will then
rebuild it from scratch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
registry
|
Any
|
The replacement backend, or |
required |
Mutation ops¶
The op types themselves are documented in Mutation ops.
Event routing¶
The registry and its dispatch entry point are documented in Events.
Base classes¶
Shared base classes and utilities for native-view handlers.
Provides the ViewHandler
protocol implemented by Android and iOS handlers, plus the
parse_color_int
helper shared across platforms.
Yoga owns sizing and positioning. Mobile renderers run its C++ core beside
their widgets; headless backends use the host binding in
pythonnative.layout. Handlers receive computed frames via
set_frame and
optionally expose an intrinsic-size hook via
measure_intrinsic
for content-sized leaves (text, buttons, images).
Classes:
| Name | Description |
|---|---|
ViewHandler |
Protocol implemented by every native-view handler. |
Functions:
| Name | Description |
|---|---|
parse_color_int |
Parse a color value into a signed 32-bit ARGB int. |
transform_text |
Apply a |
transform_spans |
Return |
shadow_offset_xy |
Coerce a |
Attributes:
| Name | Type | Description |
|---|---|---|
TEXT_SHADOW_STYLE_KEYS |
Style keys that together describe a text shadow. |
TEXT_SHADOW_STYLE_KEYS
module-attribute
¶
Style keys that together describe a text shadow.
ViewHandler
¶
Protocol implemented by every native-view handler.
A ViewHandler knows how to create, update, re-parent, and destroy
native views of one element type. The reconciler never calls a
handler directly; it emits a batch of mutation ops
(pythonnative.mutations) that the
NativeViewRegistry
applies by dispatching to handlers. Handlers never need to know
about Element or VNode.
Event contract: props delivered to
create /
update
contain no Python callables. The set of event names wired on
the element arrives under the _pn_events key (see
event_names); handlers wire
platform listeners once at create time and forward firings through
dispatch_event using the
tag passed to create.
Subclasses must override create and update. Container
handlers override the child-management methods; leaf handlers can
leave them as no-ops. Handlers whose intrinsic size depends on
content (text, buttons, images) override
measure_intrinsic.
Methods:
| Name | Description |
|---|---|
create |
Create a fresh native view and apply initial visual props. |
update |
Apply only the visual props that changed since the last render. |
insert_child |
Ensure |
remove_child |
Remove |
destroy |
Release platform resources owned by |
set_frame |
Position and size |
measure_intrinsic |
Return the natural |
command |
Execute an imperative command (e.g. |
set_animated_property |
Apply one frame of a Python-driven animation immediately. |
start_animation |
Start a natively-driven animation, if the platform supports it. |
cancel_animation |
Cancel a natively-driven animation. |
create
¶
Create a fresh native view and apply initial visual props.
Layout-related props (width, height, flex, padding,
etc.) are consumed by the layout engine and applied via
set_frame,
so handlers should ignore them here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
int
|
The reconciler-assigned identity for this view. Used when dispatching events back into Python. |
required |
props
|
Dict[str, Any]
|
Initial props dict (callable-free; event names under
|
required |
Returns:
| Type | Description |
|---|---|
Any
|
The platform-native view object. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
Subclasses must override. |
update
¶
Apply only the visual props that changed since the last render.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
native_view
|
Any
|
The platform-native view to mutate. |
required |
changed_props
|
Dict[str, Any]
|
Props whose values changed (a value of
|
required |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
Subclasses must override. |
insert_child
¶
Ensure child sits at index among parent's children.
Must be move-aware: when child is already attached to
parent, reposition it instead of attaching twice. Handlers
should clamp index to the current child count. No-op for
leaf handlers.
remove_child
¶
Remove child from parent without destroying it. No-op for leaf handlers.
destroy
¶
destroy(native_view: Any) -> None
Release platform resources owned by native_view.
Called exactly once when the reconciler unmounts the view. The default is a no-op; override to detach listeners, cancel in-flight work, or destroy widgets that the platform doesn't garbage-collect.
set_frame
¶
Position and size native_view relative to its parent.
Coordinates are in points and relative to the parent's content
origin. Default no-op so handlers that don't need explicit
positioning (e.g., Modal) can opt out.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
native_view
|
Any
|
The platform-native view. |
required |
x
|
float
|
X-coordinate (points) of the view's top-left corner relative to its parent's content origin. |
required |
y
|
float
|
Y-coordinate (points) of the view's top-left corner. |
required |
width
|
float
|
View width in points. |
required |
height
|
float
|
View height in points. |
required |
measure_intrinsic
¶
Return the natural (width, height) of a content-sized view.
Used by the layout engine for leaves whose size depends on
their content (text, buttons, images). Either max_width or
max_height may be math.inf to indicate no constraint.
The default implementation returns (0, 0); override for
leaves whose size depends on their content. Container handlers
leave this alone; the engine sizes containers by laying out
their children.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
native_view
|
Any
|
The platform-native view to measure. |
required |
max_width
|
float
|
Maximum width in points (or |
required |
max_height
|
float
|
Maximum height in points (or |
required |
Returns:
| Type | Description |
|---|---|
Tuple[float, float]
|
|
command
¶
Execute an imperative command (e.g. "scroll_to_offset").
Commands are the escape hatch for one-shot imperative actions that don't fit declarative props: scrolling, focusing, flashing indicators. Unknown commands should be ignored.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
native_view
|
Any
|
The platform-native view. |
required |
name
|
str
|
Command name. |
required |
args
|
Dict[str, Any]
|
Command arguments. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
An optional command-specific result. |
set_animated_property
¶
Apply one frame of a Python-driven animation immediately.
This is the fallback path used by
animations the platform cannot drive natively. prop_name
is one of opacity, background_color, translate_x,
translate_y, scale, scale_x, scale_y,
rotate.
start_animation
¶
Start a natively-driven animation, if the platform supports it.
spec describes the animation::
{"kind": "timing", "from": 0.0, "to": 1.0,
"duration_ms": 300.0, "easing": "ease_in_out"}
{"kind": "spring", "from": ..., "to": ...,
"stiffness": 100.0, "damping": 10.0, "mass": 1.0,
"initial_velocity": 0.0}
Implementations must invoke
pythonnative.animated.native_animation_completed(anim_id, finished)
when the animation completes or is cancelled.
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
tells the caller to fall back to the Python ticker (the |
bool
|
default). |
parse_color_int
¶
Parse a color value into a signed 32-bit ARGB int.
Accepts "#RRGGBB", "#AARRGGBB", or a raw integer. Java APIs
such as setBackgroundColor expect a signed 32-bit int, so values
with a high alpha byte (e.g., 0xFF......) must be converted to
their negative two's-complement equivalent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
color
|
Union[str, int]
|
Hex string (with or without leading |
required |
Returns:
| Type | Description |
|---|---|
int
|
Signed 32-bit ARGB int suitable for Android's color APIs. |
transform_text
¶
Apply a text_transform style value to text.
Runs in Python before the string is handed to the native label, so
the displayed text and the intrinsic measurement agree on every
backend. "capitalize" upper-cases the first character of each
whitespace-separated word and leaves the rest untouched (matching
CSS / React Native rather than str.title(), which would
lower-case the remainder). Unknown modes and "none" return the
text unchanged.
transform_spans
¶
Return spans with transform_text applied to each span's text.
Rich text is flattened into one native string, so a run-by-run
transform matches what a single-string transform would produce for
uppercase / lowercase. capitalize is evaluated per span,
which is also how CSS treats inline boxes.
On-device backend¶
Revisioned native view backend.
Each commit is validated, sent as a protocol-3 envelope, and acknowledged before Python updates its native tag index. Rejected commits poison the surface until it is remounted. Native events carry application, revision, sequence, and text edit identities. NativeViewRef holds a live native tag rather than a UI object.
Classes:
| Name | Description |
|---|---|
NativeViewRef |
Opaque handle to a native view living on the other side of the bridge. |
BridgeBackend |
Registry protocol implementation that forwards to the native runtime. |
NativeViewRef
¶
Opaque handle to a native view living on the other side of the bridge.
Attributes:
| Name | Type | Description |
|---|---|---|
tag |
The reconciler-assigned tag; pass it to
|
|
type_name |
The element type ( |
BridgeBackend
¶
BridgeBackend(transport: Any = None)
Registry protocol implementation that forwards to the native runtime.
Methods:
| Name | Description |
|---|---|
prepare_layout |
Include geometry in the next native commit when a viewport is known. |
compute_layout |
Compute native Yoga layout in one request, returning changed frames. |
accept_layout |
Accept geometry only for this surface's current committed revision. |
register |
Record a Python handler for diagnostics only. |
handler_for |
Return the diagnostic Python handler registered for |
resolve_view |
Return the handle for |
type_of |
Return the element type registered for |
live_view_count |
Number of views currently alive on the native side. |
python_props |
Props held Python-side for |
apply_mutations |
Serialize |
accept_event |
Reject events from destroyed views, earlier applications, and replayed input. |
measure_intrinsic |
Ask native for the natural size of |
command |
Run an imperative command on one view; returns its JSON result or |
set_animated_property |
Write one animated property value without animating (a Python-driven frame). |
install_animation_graph |
Install native expression nodes and view bindings in one crossing. |
start_animation |
Start a native-driven animation; returns whether native accepted it. |
cancel_animation |
Cancel a native animation and return its presentation value, if known. |
reset |
Forget a disconnected surface before the host remounts its tree. |
Attributes:
| Name | Type | Description |
|---|---|---|
transport |
Any
|
The transport in use (resolved lazily on first access). |
native_layout |
bool
|
Whether layout runs beside the renderer's native widgets. |
native_layout
property
¶
native_layout: bool
Whether layout runs beside the renderer's native widgets.
prepare_layout
¶
Include geometry in the next native commit when a viewport is known.
compute_layout
¶
Compute native Yoga layout in one request, returning changed frames.
accept_layout
¶
accept_layout(payload: Any) -> None
Accept geometry only for this surface's current committed revision.
register
¶
Record a Python handler for diagnostics only.
On device, rendering is native; a Python ViewHandler can't
create platform views. The registration is kept so
handler_for can answer introspection questions and so the
SDK's install step doesn't fail, but it is never invoked.
handler_for
¶
Return the diagnostic Python handler registered for type_name.
resolve_view
¶
resolve_view(tag: int) -> Optional[NativeViewRef]
Return the handle for tag (None if the view is gone).
python_props
¶
Props held Python-side for tag (callables never sent to native).
apply_mutations
¶
Serialize ops and apply them natively in one crossing.
accept_event
¶
Reject events from destroyed views, earlier applications, and replayed input.
measure_intrinsic
¶
Ask native for the natural size of tag under the constraints.
command
¶
Run an imperative command on one view; returns its JSON result or None.
set_animated_property
¶
Write one animated property value without animating (a Python-driven frame).
install_animation_graph
¶
Install native expression nodes and view bindings in one crossing.
start_animation
¶
Start a native-driven animation; returns whether native accepted it.
cancel_animation
¶
Cancel a native animation and return its presentation value, if known.
Component managers
The native implementations live in the templates:
PythonNativeKit/Sources/PythonNativeKit/Components (Swift) and
pythonnative/src/main/java/com/pythonnative/runtime/components
(Kotlin). Their hooks are described in
Native views (concept).
Next steps¶
- Read the high-level model in Native views (concept).
- Read the wire protocol in Bridge.
- See how the reconciler drives handlers in Reconciler.
- Read the op vocabulary handlers apply in Mutation ops.
- Read the callback registry handlers dispatch into in Events.
- Read the values handlers size themselves against in Platform metrics.