Skip to content

Events

Event callbacks live in a process-wide registry keyed by a view's integer tag and the event name. The Reconciler writes to it during a commit; platform handlers read from it when a native widget fires.

Tag-based event routing between native views and Python callbacks.

Before the batched-commit overhaul, every event prop (on_press, on_change, …) was wired by storing the Python callable on (or next to) the native view, and every re-render re-pushed fresh closures across the bridge. This module replaces that with a single dispatch channel:

  • The reconciler strips callable props out of the payload sent to native handlers and registers them here, keyed by (tag, name).
  • Handlers wire their platform listener once at view creation; the listener calls dispatch_event with the view's tag and the event name.
  • Re-renders only mutate this Python-side registry; no native call is made when just a callback identity changes.

The set of event names present on an element is forwarded to handlers under the EVENTS_PROP key (a frozenset), so handlers that wire expensive listeners (scroll delegates, gesture recognizers) can do so conditionally. Dispatching an event nobody listens to is a cheap dict miss.

Classes:

Name Description
EventRegistry

Process-wide map of (tag, event name) -> Python callback.

Functions:

Name Description
get_event_registry

Return the process-wide EventRegistry.

dispatch_event

Dispatch an event from a native view into Python.

extract_events

Split props into native-safe props and Python event callbacks.

event_names

Return the event-name set a handler should consult for props.

Attributes:

Name Type Description
EVENTS_PROP

Prop key carrying the frozenset of event names wired on an element.

GESTURES_PROP

Prop key carrying gesture descriptors (see pythonnative.gestures).

EVENTS_PROP module-attribute

EVENTS_PROP = '_pn_events'

Prop key carrying the frozenset of event names wired on an element.

GESTURES_PROP module-attribute

GESTURES_PROP = 'gestures'

Prop key carrying gesture descriptors (see pythonnative.gestures).

EventRegistry

EventRegistry()

Process-wide map of (tag, event name) -> Python callback.

Thread-safe: native backends may dispatch from the platform UI thread while the reconciler updates registrations from the render thread.

Methods:

Name Description
set_events

Replace every registration for tag with events.

clear

Drop every registration for tag (called on view destroy).

get

Return the callback for (tag, name), or None.

has

Return whether a callback is registered for (tag, name).

dispatch

Invoke the callback for (tag, name) with args.

reset

Drop every registration (test helper).

set_events

set_events(
    tag: int, events: Dict[str, Callable[..., Any]]
) -> None

Replace every registration for tag with events.

clear

clear(tag: int) -> None

Drop every registration for tag (called on view destroy).

get

get(tag: int, name: str) -> Optional[Callable[..., Any]]

Return the callback for (tag, name), or None.

has

has(tag: int, name: str) -> bool

Return whether a callback is registered for (tag, name).

dispatch

dispatch(tag: int, name: str, *args: Any) -> bool

Invoke the callback for (tag, name) with args.

Returns:

Type Description
bool

True when a callback existed and was invoked (even if

bool

it raised: exceptions never propagate into the platform's

bool

UI thread; in dev mode they are routed to the RedBox via

bool
bool

otherwise the traceback is printed), False when nothing

bool

is registered.

reset

reset() -> None

Drop every registration (test helper).

get_event_registry

get_event_registry() -> EventRegistry

Return the process-wide EventRegistry.

dispatch_event

dispatch_event(tag: int, name: str, *args: Any) -> bool

Dispatch an event from a native view into Python.

This is the single entry point platform handlers call when a native listener fires.

Parameters:

Name Type Description Default
tag int

The view's reconciler-assigned tag.

required
name str

Event name, the original prop name ("on_press", "on_change", …) or a gesture channel ("gesture:0").

required
*args Any

Positional arguments forwarded to the user callback, preserving each prop's documented signature.

()

Returns:

Type Description
bool

Whether a callback was registered for (tag, name).

extract_events

extract_events(
    props: Dict[str, Any],
) -> Tuple[Dict[str, Any], Dict[str, Callable[..., Any]]]

Split props into native-safe props and Python event callbacks.

Rules:

  • Top-level callables named on_* become events under their prop name and are removed from the native payload.
  • refresh_control dicts have their nested on_refresh hoisted to the "on_refresh" event; the remaining keys (refreshing, tint_color) stay in the payload.
  • gestures lists of gesture descriptors are serialized to plain dicts (handlers wire recognizers from them) while their callbacks are folded into per-gesture "gesture:<i>" routers.
  • The resulting payload carries _pn_events (a frozenset of the event names present), so handlers can wire listeners conditionally and the prop differ can detect listener addition/removal without comparing closures.

Parameters:

Name Type Description Default
props Dict[str, Any]

Raw element props (already stripped of reconciler-owned keys).

required

Returns:

Type Description
Dict[str, Any]

(clean_props, events) where clean_props contains no

Dict[str, Callable[..., Any]]

callables and events maps event names to callbacks.

event_names

event_names(props: Dict[str, Any]) -> FrozenSet[str]

Return the event-name set a handler should consult for props.

Next steps

  • See what carries the remaining, non-callable props in Mutation ops.
  • See how handlers wire a platform listener once, at creation, in Native views.
  • Read the other Python-side store the native layer reads on demand in Platform metrics.
  • Follow a full commit end to end in Reconciliation.