SDK¶
pythonnative.sdk is the public extension API for adding new native
widgets and device modules to PythonNative. It re-exports the
Element descriptor, the typed style
primitives, and the native module registry 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 |
UNSET, UnsetType |
Mutation ops |
Style, StyleProp, Color, Dimension, EdgeInsets, EdgeValue, FlexDirection, JustifyContent, Overflow, Position, TransformSpec, style |
Style |
NativeModule, NativeModuleError, PythonModule, native_module, register_python_module, emit |
Native modules |
parse_color_int |
Native views |
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
define_component helper that
declares a custom native component and returns its typed element
factory, element_factory for
rebuilding that factory elsewhere, 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-native-components.md). - A
define_component(name, props)call in Python that declares the element name, binds its props type, and returns the element factory.
Once defined, the component appears alongside the built-ins: the
reconciler, layout engine, commit validator, contract generator, and
Fast Refresh treat it identically. The browser preview draws it as a
labeled placeholder; headless tests render it into the
FakeBackend like any element.
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, define_component
@dataclass(frozen=True)
class BadgeProps(Props):
text: str = ""
color: str = "#FF3B30"
style: pn.StyleProp = None
Badge = define_component("Badge", BadgeProps)
@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 |
|---|---|
define_component |
Declare a custom native component and return its typed element factory. |
element_factory |
Return a callable that builds |
unregister_component |
Remove a previously defined component (primarily for tests). |
list_components |
Return the names of every defined custom component, sorted. |
get_props_type |
Return the props dataclass defined for |
Attributes:
| Name | Type | Description |
|---|---|---|
ENTRY_POINT_GROUP |
Entry-point group used by PyPI packages to define native components. |
ENTRY_POINT_GROUP
module-attribute
¶
Entry-point group used by PyPI packages to define native components.
Packages declare entries like:
PythonNative imports the referenced module the first time the view
backend is created; the define_component calls inside that module
register the package's components 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
define_component
¶
define_component(
name: str,
props: type,
*,
platforms: tuple[str, ...] = ("ios", "android"),
measurement: str = "intrinsic"
) -> Callable[..., Element]
Declare a custom native component and return its typed element factory.
Registers props as the component's schema (so the contract
generator emits it, the commit validator checks it, and the factory
validates keyword arguments against it) and returns the
element_factory for name.
Defining the same name again replaces the earlier schema.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Element type name ( |
required |
props
|
type
|
A |
required |
platforms
|
tuple[str, ...]
|
Platforms with an actual renderer. Browser placeholders don't count as native support. |
('ios', 'android')
|
measurement
|
str
|
How the renderer core sizes the view when it has
no children: |
'intrinsic'
|
Returns:
| Type | Description |
|---|---|
Callable[..., Element]
|
A callable producing |
Callable[..., Element]
|
of type |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
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 defined props dataclass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
An element type name previously declared with
|
required |
Returns:
| Type | Description |
|---|---|
Callable[..., Element]
|
A callable producing fresh |
Callable[..., Element]
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
unregister_component
¶
unregister_component(name: str) -> None
Remove a previously defined component (primarily for tests).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The element type name to forget. |
required |
list_components
¶
Return the names of every defined custom component, sorted.
Contract schemas¶
define_component registers the props dataclass as a
ComponentSchema; native
modules declare a ModuleSchema
from a Protocol. Field-level options such as layout invalidation and
platform support are declared with
NativeField. pn codegen
compiles the registered schemas into Swift and Kotlin; see
Generated native contracts.
Python definitions for native props, events, commands, and modules.
Classes:
| Name | Description |
|---|---|
ComponentSchema |
The portable contract shared by every renderer and the component SDK. |
ModuleSchema |
Typed native module methods, arguments, results, and async behavior. |
NativeField |
Native behavior attached with |
Functions:
| Name | Description |
|---|---|
register_schema |
Register the contract used to generate and validate a native extension. |
ComponentSchema
dataclass
¶
ComponentSchema(
name: str,
props: dict[str, dict[str, Any]],
required: tuple[str, ...] = (),
defaults: dict[str, Any] = dict(),
measurement: str = "intrinsic",
commands: dict[str, Any] = dict(),
platforms: tuple[str, ...] = ("ios", "android", "web"),
flatten: bool = False,
adopt_flattened: bool = False,
detach_children: bool = False,
clip: bool = False,
portal: bool = False,
)
The portable contract shared by every renderer and the component SDK.
Methods:
| Name | Description |
|---|---|
from_dataclass |
Describe a native widget with a frozen Python props dataclass. |
validate |
Validate a construction or a partial update against this contract. |
validate_event |
Validate a typed callback payload before application code receives it. |
decode_event |
Reconstruct declared payload records after validating an event. |
Attributes:
| Name | Type | Description |
|---|---|---|
measurement |
str
|
How the renderer core sizes the component as a leaf: |
flatten |
bool
|
Whether the core may leave the view unmounted when it only affects layout. |
adopt_flattened |
bool
|
Whether the view may receive the children of a flattened child. |
detach_children |
bool
|
Whether children lay out as independent roots (lists, modals, stacks). |
clip |
bool
|
Whether layout clips overflow and lets the view shrink by default (scrolling containers). |
portal |
bool
|
Whether the view lays out against its own container instead of its parent. |
measurement
class-attribute
instance-attribute
¶
measurement: str = 'intrinsic'
How the renderer core sizes the component as a leaf: "container"
(never measured), "intrinsic" (a widget measured on the UI thread),
"native" (a plugin's thread-safe measurement), or one the core
computes for built-ins ("text", "image", "svg", "fill").
flatten
class-attribute
instance-attribute
¶
flatten: bool = False
Whether the core may leave the view unmounted when it only affects layout.
adopt_flattened
class-attribute
instance-attribute
¶
adopt_flattened: bool = False
Whether the view may receive the children of a flattened child.
detach_children
class-attribute
instance-attribute
¶
detach_children: bool = False
Whether children lay out as independent roots (lists, modals, stacks).
clip
class-attribute
instance-attribute
¶
clip: bool = False
Whether layout clips overflow and lets the view shrink by default (scrolling containers).
portal
class-attribute
instance-attribute
¶
portal: bool = False
Whether the view lays out against its own container instead of its parent.
from_dataclass
classmethod
¶
from_dataclass(
name: str,
props: type,
*,
measurement: str = "intrinsic",
platforms: tuple[str, ...] = ("ios", "android")
) -> ComponentSchema
Describe a native widget with a frozen Python props dataclass.
validate
¶
Validate a construction or a partial update against this contract.
validate_event
¶
Validate a typed callback payload before application code receives it.
ModuleSchema
dataclass
¶
ModuleSchema(
name: str,
methods: dict[str, dict[str, Any]],
events: dict[str, dict[str, Any]] = dict(),
)
Typed native module methods, arguments, results, and async behavior.
Methods:
| Name | Description |
|---|---|
from_protocol |
Read annotated methods from a Python protocol or interface class. |
validate_call |
Validate and normalize a method invocation before crossing a bridge. |
decode_event |
Validate and restore the declared Python payload of a module event. |
validate_result |
Reject a native result that doesn't satisfy its declared return type. |
from_protocol
classmethod
¶
from_protocol(
name: str,
protocol: type,
*,
events: Mapping[str, Any] | None = None
) -> ModuleSchema
Read annotated methods from a Python protocol or interface class.
validate_call
¶
Validate and normalize a method invocation before crossing a bridge.
decode_event
¶
Validate and restore the declared Python payload of a module event.
NativeField
dataclass
¶
NativeField(
invalidates_layout: bool = False,
recreate: bool = False,
animated: bool = False,
platforms: tuple[str, ...] = ("ios", "android", "web"),
description: str = "",
python_only: bool = False,
flatten: bool = False,
)
register_schema
¶
register_schema(
schema: ComponentSchema | ModuleSchema,
) -> None
Register the contract used to generate and validate a native extension.
Entry-point discovery¶
Third-party packages can define components automatically by exposing
an entry point in the pythonnative.handlers group (the value of
ENTRY_POINT_GROUP). The view
backend loads every registered entry point exactly once, before the
first native commit is validated. 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 module pointed at by the entry point should perform whatever
imports are needed to run its
define_component calls.
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 backend that commits custom elements alongside the built-ins.