SDK¶
pythonnative.sdk is the public extension API for adding new native
widgets to PythonNative. It re-exports the
Element descriptor, the
ViewHandler protocol,
and the typed style primitives so plugin authors only need a single
import path. The reference here documents the symbols that are
unique to the SDK module — the re-exports are documented on their
canonical pages and linked below.
The full walkthrough lives in Custom native components; this page is the symbol-level reference.
Re-exports¶
The following names are re-exported from pythonnative.sdk for
convenience and are documented on their canonical pages:
| Symbol | Defined in |
|---|---|
Element |
Element |
ViewHandler |
Native views |
Style, StyleProp, Color, Dimension, EdgeInsets, EdgeValue, FlexDirection, JustifyContent, Overflow, Position, TransformSpec, style |
Style |
parse_color_int, resolve_padding |
pythonnative.native_views.base |
Custom-component primitives¶
Public extension surface for PythonNative.
The pythonnative.sdk package collects the stable extension
contract that third-party packages rely on: the
ViewHandler protocol, the
Style type, the
@native_component registration
decorator, and an
element_factory helper for
producing strongly-typed element constructors.
A custom native component is three things:
- A typed, frozen
Propsdataclass listing the public properties the component accepts. - One or more
ViewHandlersubclasses (one per target platform) implementing creation, update, and child management for the underlying native widget. - A registration call (the
@native_componentdecorator, orregister_componentfor imperative use) that binds the props type and handler into the process-wide registry.
Once registered, the component appears alongside the built-ins: the reconciler, layout engine, and Fast Refresh treat it identically.
PyPI packages can ship handlers without users importing them
explicitly by declaring an entry point in the
pythonnative.handlers group; PythonNative discovers and imports
those modules the first time the registry is asked for a handler.
Example
from dataclasses import dataclass
import pythonnative as pn
from pythonnative.sdk import (
Props,
ViewHandler,
element_factory,
native_component,
)
@dataclass(frozen=True)
class BadgeProps(Props):
text: str = ""
color: str = "#FF3B30"
style: pn.StyleProp = None
@native_component("Badge", props=BadgeProps, platforms=("ios",))
class IOSBadgeHandler(ViewHandler):
def create(self, props):
...
def update(self, view, changed):
...
Badge = element_factory("Badge")
@pn.component
def App():
return pn.Column(
Badge(text="3", color="#0A84FF"),
pn.Text("Inbox"),
)
Classes:
| Name | Description |
|---|---|
Props |
Optional base class for typed prop dataclasses. |
Functions:
| Name | Description |
|---|---|
native_component |
Decorator that registers a |
register_component |
Register a custom native component imperatively. |
unregister_component |
Remove a previously-registered component (primarily for tests). |
element_factory |
Return a callable that builds |
install_into_registry |
Copy registered handlers into a |
list_components |
Return the names of every registered custom component. |
get_props_type |
Return the registered props dataclass for |
Attributes:
| Name | Type | Description |
|---|---|---|
ENTRY_POINT_GROUP |
Entry-point group used by PyPI packages to register native handlers. |
ENTRY_POINT_GROUP
module-attribute
¶
Entry-point group used by PyPI packages to register native handlers.
Packages declare entries like:
PythonNative imports the referenced module the first time the
NativeViewRegistry is
materialized; the decorators inside that module populate the registry
during import.
Props
dataclass
¶
Optional base class for typed prop dataclasses.
Subclassing is not strictly required (any
@dataclass(frozen=True) works), but inheriting from
Props gives third-party components a clear, searchable marker
in their public API and a stable place to add framework-wide
behavior in the future.
Example
native_component
¶
native_component(name: str, *, props: Optional[type] = None, platforms: Optional[Tuple[str, ...]] = None) -> Callable[[Type[H]], Type[H]]
Decorator that registers a ViewHandler under name.
The handler class is instantiated immediately and stored in the
process-wide registry. Decorate the same name once per platform
when shipping platform-specific implementations; the decorator
accumulates entries in a {platform: handler} mapping per name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Element type name (e.g., |
required |
props
|
Optional[type]
|
Optional dataclass type describing the component's
typed props. When supplied, the
|
None
|
platforms
|
Optional[Tuple[str, ...]]
|
Tuple of platform identifiers
( |
None
|
Returns:
| Type | Description |
|---|---|
Callable[[Type[H]], Type[H]]
|
A decorator that, when applied to a |
Callable[[Type[H]], Type[H]]
|
|
Callable[[Type[H]], Type[H]]
|
it and returns the class unchanged. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the decorated object is not a class subclassing
|
Example
from dataclasses import dataclass
from pythonnative.sdk import Props, ViewHandler, native_component
@dataclass(frozen=True)
class BadgeProps(Props):
text: str = ""
color: str = "#FF3B30"
@native_component("Badge", props=BadgeProps, platforms=("ios",))
class IOSBadgeHandler(ViewHandler):
def create(self, props):
...
register_component
¶
register_component(*, name: str, props: Optional[type] = None, handlers: Dict[str, ViewHandler]) -> None
Register a custom native component imperatively.
Equivalent to applying @native_component
one or more times, but useful when constructing handlers
programmatically (e.g., parameterized handler instances). Subsequent
calls for the same name merge their handlers into the
existing entry, replacing any previously-registered handler for the
same platform.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Element type name. |
required |
props
|
Optional[type]
|
Optional dataclass type describing the typed props. |
None
|
handlers
|
Dict[str, ViewHandler]
|
|
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If any handler is not a
|
unregister_component
¶
unregister_component(name: str) -> None
Remove a previously-registered component (primarily for tests).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The element type name to unregister. |
required |
element_factory
¶
Return a callable that builds Element instances of type name.
The returned factory accepts:
- Children as positional arguments (any number).
key=(optional, keyword-only) for keyed reconciliation.- Either
props=(a dataclass instance) or per-field keyword arguments matching the registered props dataclass.
If no props dataclass was registered for name, kwargs flow
through unmodified — useful when iterating before locking down a
prop schema.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
An element type name previously registered via
|
required |
Returns:
| Type | Description |
|---|---|
Callable[..., Element]
|
A callable producing fresh |
Callable[..., Element]
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
install_into_registry
¶
Copy registered handlers into a NativeViewRegistry.
Called once by the registry on first use. Triggers entry-point discovery on the first call so PyPI-installed handlers register themselves before the registry snapshot is taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
registry
|
Any
|
A
|
required |
platform_name
|
str
|
The active platform identifier
( |
required |
Entry-point discovery¶
Third-party packages can register handlers automatically by exposing
an entry point in the pythonnative.handlers group (the value of
ENTRY_POINT_GROUP). The first
call to get_registry()
loads every registered entry point exactly once. A misbehaving plugin
raises an exception that is caught and logged; it never breaks
PythonNative startup.
# In your plugin's pyproject.toml
[project.entry-points."pythonnative.handlers"]
my_widget = "my_pkg:register"
The function pointed at by the entry point should perform whatever
imports are needed to call
@native_component or
register_component.
Next steps¶
- Custom native components guide
walks through a complete
Badgewidget across iOS and Android. - Native views (concept) describes the reconciler boundary the SDK plugs into.
- Native views API documents the runtime registry the SDK installs handlers onto.