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 |
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
Style type, the
@native_component /
register_component
registration helpers, the
element_factory helper for
producing strongly-typed element constructors, the
ViewHandler protocol for off-device
stand-ins, and the native module registry
(native_module,
register_python_module).
A custom native component is three things:
- A typed, frozen
Propsdataclass listing the public properties the component accepts. - A Swift
PNComponentManagerand a KotlinComponentManagerregistered under the component's name by the package's native plugin (pn_plugin.jsonnext toios/andandroid/source folders; seedocs/guides/custom-components.md). - A registration call in Python
(
register_component, or the@native_componentdecorator when you also supply a testViewHandlerfor the Python backend) that declares the element name and binds its props type.
Once registered, the component appears alongside the built-ins: the reconciler, layout engine, and Fast Refresh treat it identically.
A native module (device API without a view) follows the same split: a
Swift / Kotlin class registered by name in the plugin, a Python facade
that calls native_module(name).call(...), and optionally a Python
implementation registered with register_python_module for the
browser preview and tests.
PyPI packages can ship both without users importing them explicitly
by declaring entry points in the pythonnative.handlers (Python
side) and pythonnative.plugins (native source) groups; pn build
compiles the native sources into the app.
Example
from dataclasses import dataclass
import pythonnative as pn
from pythonnative.sdk import Props, element_factory, register_component
@dataclass(frozen=True)
class BadgeProps(Props):
text: str = ""
color: str = "#FF3B30"
style: pn.StyleProp = None
register_component(name="Badge", props=BadgeProps)
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 test |
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 test handlers into a view registry. |
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: tuple[str, ...] = ("ios", "android")
) -> Callable[[Type[H]], Type[H]]
Decorator that registers a test ViewHandler under name.
The handler class is instantiated immediately and stored in the
process-wide registry as the component's off-device renderer. The
on-device renderers are the Swift and Kotlin component managers the
package's native plugin registers under the same 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
|
tuple[str, ...]
|
Platforms with an actual renderer for this component. |
('ios', 'android')
|
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
|
register_component
¶
register_component(
*,
name: str,
props: Optional[type] = None,
handler: Optional[ViewHandler] = None,
platforms: tuple[str, ...] = ("ios", "android")
) -> None
Register a custom native component imperatively.
Declares name as an element type so
element_factory can build it.
handler is the optional test renderer; native
rendering always comes from the platform component managers.
Subsequent calls for the same name merge: a later props or
handler replaces the earlier one, None leaves it alone.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Element type name. |
required |
props
|
Optional[type]
|
Optional dataclass type describing the typed props. |
None
|
handler
|
Optional[ViewHandler]
|
Optional |
None
|
platforms
|
tuple[str, ...]
|
Platforms with an actual renderer. Browser placeholders don't count as native support. |
('ios', 'android')
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
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
¶
install_into_registry(registry: Any) -> None
Copy registered test handlers into a view registry.
Called once by the registry on first use. Triggers entry-point discovery on the first call so PyPI-installed components register themselves before the registry snapshot is taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
registry
|
Any
|
A
|
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.