This release is a pre-release and may not be stable for production use.
Pyxpo
React-Native-style Python framework: declarative components + hooks -> reconciler -> batched JSON ops -> native widgets. See DESIGN.md (architecture) and PLAN.md (roadmap). Android and iOS are both supported.
Install
pip install pyxpo
pyxpo create demo && cd demo
pyxpo doctor # check Xcode / Android SDK / Gradle
pyxpo run android # or: pyxpo run ios
The first mobile build downloads the prebuilt CPython runtime (about 20-60 MB per target) into ~/.cache/pyxpo.
Develop pyxpo itself
tools/dev_install.sh # .venv with core + every module package in packages/, all editable
.venv/bin/pyxpo create demo && cd demo && ../.venv/bin/pyxpo run desktop # type 1 + Enter to press the button, q to quit
.venv/bin/pytest
A project is an app/ folder of routes, like Expo Router:
app/
_layout.py # Stack / Tabs / Drawer / Slot around the routes below
index.py # "/"
details/[id].py # "/details/7" -> useLocalSearchParams()["id"]
+not-found.py # unmatched URLs
# app/index.py
from pyxpo import Button, Text, View, useState
from pyxpo.router import Link
def Index():
n, setN = useState(0)
return View(Text("Count: ", n), Button(title="Add", onPress=lambda: setN(n + 1)),
Link("Details", href="/details/%d" % n))
default = Index
Hooks: use_state, use_effect, use_ref, use_memo, use_callback, use_context, use_async. Lists need key=.
pyxpo add-lib <pkg> checks mobile wheel availability (note: full tensorflow/torch cannot run on mobile).
Native modules
Features beyond the core are optional native modules, each its own pip package (like Expo's expo-image-picker).
Only the modules an app lists are compiled into it.
| Package | Import | modules entry |
|---|---|---|
pyxpo-file-system |
from pyxpo_file_system import File, Directory, Paths |
file-system |
pyxpo-image-manipulator |
from pyxpo_image_manipulator import ImageManipulator |
image-manipulator |
pyxpo-image-picker |
from pyxpo_image_picker import ImagePicker |
image-picker |
pyxpo-media-library |
from pyxpo_media_library import MediaLibrary |
media-library |
pyxpo-secure-store |
import pyxpo_secure_store as SecureStore |
secure-store |
pyxpo-sharing |
from pyxpo_sharing import Share |
sharing |
pyxpo-storage |
from pyxpo_storage import storage |
storage |
pip install pyxpo-image-picker
[tool.pyxpo]
modules = ["image-picker"]
Their sources live in packages/; see each package's README. Third-party modules are pip packages that register a
pyxpo.modules entry point the same way.
React Native style API
Every RN spelling is an alias; the snake_case API keeps working. No JSX (not valid Python), so children are call arguments.
from pyxpo import StyleSheet, View, Text, Pressable, FlatList, SectionList, useState, useEffect, component
styles = StyleSheet.create( # or StyleSheet.create({"title": {...}})
title=dict(fontSize=24, fontWeight="bold", marginBottom=12),
)
@component
def App():
count, setCount = useState(0)
useEffect(lambda: print("count", count), [count])
return View(
Text("Hello", style=styles.title),
Pressable(Text("+"), onPress=lambda: setCount(count + 1),
style=lambda state: {"opacity": 0.5 if state.pressed else 1}),
FlatList(data=[1, 2], renderItem=lambda p: Text(p["item"]), keyExtractor=lambda i, _: i),
)
- Style keys and props accept camelCase (
backgroundColor,onPress,numberOfLines,placeholderTextColor,testID). Giving both spellings of one prop raisesTypeError. User components accept a camelCase key when its snake_case form is a parameter. - Hooks:
useState,useEffect,useLayoutEffect,useReducer,useRef,useMemo,useCallback,useContext,useId,useImperativeHandle,useSyncExternalStore,useTransition,useDeferredValue. Effects are exception-safe: one failing effect or cleanup does not stop the others, errors go toErrorBoundary(on_error=...)orapp.on_error. Child effects run before parent effects. Effects must be sync functions (anasync defeffect runs as a task and warns). ErrorBoundary(*children, fallback=lambda error, reset: ...).FlatListrenderItemwith one parameter gets{"item", "index"}; with two it gets(item, index).SectionList(sections=[{"title", "data"}], renderItem, renderSectionHeader)(no sticky headers yet).- Modules:
Platform.OS,Dimensions.addEventListener("change", fn)(returns an object with.remove()),BackHandler.addEventListener("hardwareBackPress", fn),Keyboard.addListener("keyboardDidShow", fn),Linking.openURL,Alert.alert(title, msg, [{"text", "onPress"}]). - RN style values that have no native equivalent (
borderStyle,tintColor,resizeMode, ...) log a warning and are ignored.Pressablehit_slopanddelay_long_pressare accepted but not applied natively yet. - Example:
examples/rn_style.
Routing (pyxpo.router, Expo Router)
- Files under
app/are routes:index,[id](dynamic),[...rest](catch-all),(group)/(no URL segment),_layout.py(navigator),+not-found.py. A route module exportsdefault(or has a single@component). - Layouts:
Stack,Tabs,Drawer,Slot; configure withStack.Screen(name=..., options={...})orscreenOptions. Options follow react-navigation (title,headerShown,headerRight,tabBarIcon, ...). A layout may exportunstable_settings = {"initialRouteName": ...}. router.push/navigate/replace/back/dismiss/dismissAll/setParams,<Link href=...>,<Redirect href=...>; hooksuseRouter,useLocalSearchParams,useGlobalSearchParams,usePathname,useSegments,useNavigation,useIsFocused,useFocusEffect. Theme:ThemeProvider,DefaultTheme,DarkTheme,useTheme.- Android hardware back, the stack edge-swipe and the drawer all go through one navigation store. iOS Swift controls and the native stack are not ported yet.
Metadata
Release files for pyxpo 0.1.0a2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyxpo-0.1.0a2.tar.gz | 292.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyxpo-0.1.0a2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 639.8 kB
Release files / pyxpo-0.1.0a2.tar.gz
| Download URL | pyxpo-0.1.0a2.tar.gz |
|---|---|
| Size | 292.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e2a67a5cf336916c8f3423a6383394eb70b10f7c0e9e1a10eed23f702d3b6262
|
|
BLAKE2b-256 checksum How to use checksums |
7988193fbb700e8e7ee9ae0fc54b7212f2a07c52bfc4029c6dec30ed95ccb7a0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logRelease files / pyxpo-0.1.0a2-py3-none-any.whl
| Download URL | pyxpo-0.1.0a2-py3-none-any.whl |
|---|---|
| Size | 347.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f849553e8918f2e499cdd226f9a3fdf145b3deccea6b02b518360d1e9a1a837c
|
|
BLAKE2b-256 checksum How to use checksums |
e48dab6df19a3278cd83f19ad4957dfe1019dc77e60445c24d0ab4f12361a552
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency log