Hello world¶
The smallest possible PythonNative app. You'll learn how to:
- Define a component with
@pn.component. - Manage state with
use_state. - Compose elements with
pn.Column. - Run it with
pn run.
The code¶
Save this as app/main.py:
import pythonnative as pn
@pn.component
def App():
count, set_count = pn.use_state(0)
return pn.Column(
pn.Text(f"Count: {count}", style={"font_size": 24, "bold": True}),
pn.Button("Tap me", on_click=lambda: set_count(count + 1)),
style={"spacing": 12, "padding": 16, "align_items": "stretch"},
)
What's happening¶
@pn.componentregistersAppas a function component. Hooks (likeuse_state) work because the decorator establishes a hook context for each call.pn.use_state(0)returns(value, setter). The setter triggers a re-render scheduled by the screen host.pn.Column(*children, style=...)returns a vertical container element. Both the children and the style are read on every render; the reconciler diffs them against the previous render and updates the underlyingUIView/FrameLayoutin place.pn.Textandpn.Buttonmap to native widgets via their registeredViewHandlerimplementations.- After every commit a layout pass computes
an absolute frame for every element using PythonNative's pure-Python
flexbox engine, so
spacing,padding, andalign_itemsproduce the same geometry on Android and iOS.
Run it¶
From the project root:
pn run will:
- Stage your
app/and the bundledpythonnativepackage into the appropriate native template underbuild/. - Build it (
gradle installDebugon Android,xcodebuildon iOS). - Install and launch it on a connected device or simulator.
- Stream logs back to the terminal.
For an even tighter loop while iterating, add --hot-reload:
See Hot reload guide for the details.
Next steps¶
- Build a slightly richer counter: Counter.
- Add a second screen and navigation: Navigation.
- Learn the runtime model: Mental model.