Newpyxpo 0.1.0a5 is on PyPI

Make any app.
Write it in Python.

pyxpo is an open-source framework for truly native iOS, Android, Mac and Windows apps, and for the web. React-style components, hooks and file-based routing, running on real CPython on the device.

$pip install pyxpo
  • iOS 13+
  • Android 7+ (API 24)
  • macOS and Windows
  • Web
  • CPython 3.13.7
  • MIT licensed
app/(tabs)/index.py
from pyxpo import FlatList, Pressable, StyleSheet, Text, View, useState

HABITS = [("Morning run", 12), ("Read 20 pages", 5),
          ("Drink water", 30), ("Meditate", 3)]

def Today():
    done, setDone = useState({"Morning run"})

    def row(p):
        name, streak = p["item"]
        on = name in done
        return Pressable(
            View(style=[styles.check, on and styles.checked]),
            View(
                Text(name, style=[styles.name, on and styles.faded]),
                Text("%d day streak" % streak, style=styles.muted),
                style=styles.info,
            ),
            onPress=lambda: setDone(lambda d: d ^ {name}),
            style=styles.row,
        )

    return View(
        Text("Today", style=styles.title),
        Text("%d of %d done" % (len(done), len(HABITS)), style=styles.muted),
        FlatList(data=HABITS, renderItem=row, keyExtractor=lambda h, i: h[0]),
        style=styles.screen,
    )

styles = StyleSheet.create(
    screen=dict(flex=1, padding=16, gap=8, backgroundColor="#f2f2f7"),
    title=dict(fontSize=30, fontWeight="bold"),
    row=dict(flexDirection="row", alignItems="center", gap=10,
             padding=12, borderRadius=14, backgroundColor="#fff"),
    check=dict(width=22, height=22, borderRadius=11,
               borderWidth=2, borderColor="#3776ab"),
    checked=dict(backgroundColor="#3776ab"),
    info=dict(flex=1, gap=2),
    name=dict(fontSize=15, fontWeight="600"),
    faded=dict(opacity=0.45),
    muted=dict(fontSize=12, color="#8a909b"),
)

default = Today
9:41

Today

1 of 4 done

iOS · UIKit
9:41

Today

1 of 4 done

Android · Views

Live preview: tap a habit on either phone. One Python file, two native apps.

5 platforms
iOS, Android, Mac, Windows and web
CPython 3.13.7
running on the device
24 modules
camera, files, storage and more
MIT
open source license
framework

Everything an app needs, in Python.

If you have used React Native or Expo, you already know the shape of pyxpo. The same ideas, written as plain Python functions.

workflow

From pip install to app binary.

One CLI covers the whole loop. Everything runs on your machine.

terminal
pip install pyxpo
pyxpo create demo && cd demo
pyxpo doctor        # checks Xcode, Android SDK and Gradle
native modules

Device features are one pip install away.

Each native feature is its own package. Add it to your project and list it in modules; only the modules you list are compiled into your app.

Browse all packages
terminal
pip install pyxpo-image-picker
app/index.py
from pyxpo import Button, Image, View, useState
from pyxpo_image_picker import ImagePicker

def Index():
    uri, setUri = useState(None)

    async def pick():
        res = await ImagePicker.launchImageLibraryAsync()
        if not res["canceled"]:
            setUri(res["assets"][0]["uri"])

    return View(
        Button(title="Pick a photo", onPress=pick),
        uri and Image(source={"uri": uri}, style={"width": 240, "height": 240}),
    )

default = Index
performance

Native speed. Python simplicity.

No web view and no transpiling. Your code runs in CPython on its own thread, and only the changes cross to the native UI.

Python threadYour components
  • hooks
  • reconciler
  • diff
C bridge1 batched message{"op":"update","id":7, "props":{"text":"2 of 4 done"}}
UI threadNative views
  • UIView
  • android.view.View
  • native layout

One bridge crossing per commit

State changes are batched and diffed, then sent as one message. Not one native call per widget.

UI thread stays free

Python runs on its own thread. Scrolling, layout and touch handling stay on the native UI thread.

Only what changed

The reconciler matches elements by type and key and sends only the props that differ.

Animations on the native driver

Animated timing and spring run natively by default, so they stay smooth while Python is busy.

Real native widgets

UIKit and Android views with flexbox layout computed natively. No web view, no canvas.

Fast startup, lean builds

The standard library ships precompiled, and release APKs use R8 minify and shrink.

pythonic

Familiar API. Python style.

Every React Native name works, and so does its snake_case twin. There is no JSX: children are just call arguments, and styles are dicts.

  • useState or use_state, onPress or on_press
  • StyleSheet.create with keyword arguments, or a function of the theme
  • async def handlers for camera, files and network calls
  • ErrorBoundary keeps one broken screen from crashing the app
app/counter.py
from pyxpo import Pressable, StyleSheet, Text, View, component, use_state

styles = StyleSheet.create(
    title=dict(fontSize=24, fontWeight="bold"),
    box=dict(padding=16, borderRadius=12, backgroundColor="#ffd43b"),
)

@component
def Counter():
    count, set_count = use_state(0)
    return View(
        Text("Hello from Python", style=styles.title),
        Pressable(
            Text(f"Tapped {count} times"),
            on_press=lambda: set_count(count + 1),
            style=styles.box,
        ),
    )
editor

Your editor knows pyxpo.

The VS Code extension fills in what Pylance cannot see: style keys, component props, colors and your app config.

  • Completion for style keys, their values and component props
  • Auto-import: pick View and from pyxpo import View is added
  • Color swatches, a color picker and checks for unknown style keys
  • [tool.pyxpo] completion and run commands for iOS, Android, desktop and web
pyxpoPython 3.13
why python

Bring the language you already use.

pyxpo is not a Python flavour of JavaScript. It is CPython, so the tools and libraries you know come with you.

01

The standard library on the phone

json, sqlite3, datetime, re, pathlib, asyncio and the rest run on the device, because the app ships a real CPython.

02

Your PyPI packages

Pure-Python packages work as they are. pyxpo add-lib checks whether a package has wheels for iOS and Android before you add it.

03

One language for app and backend

Share models, validation and business logic with your Python server instead of writing it twice.

04

Testing with pytest

Render components in memory and test modules without a device, using the test helpers that ship with pyxpo.

faq

Questions, answered.

Something missing? Open an issue on GitHub.

Is pyxpo ready for production?

Not yet. The current release is 0.1.0a5, an alpha. The API follows React Native and Expo closely, but it can still change between releases.

Does it use a web view?

Not on phones or desktop. Components render to real UIKit views on iOS and Mac, Android views on Android and XAML controls on Windows, and your Python runs in CPython inside the app. The web target is the one exception: there the app renders to the DOM and Python runs on Pyodide in the page.

Which platforms can I build for?

iOS, Android, Mac (through Mac Catalyst), Windows (WinUI 3) and the web, from one project. A browser preview needs no toolchain at all and is the fastest loop for screen work.

Can I use packages from PyPI?

Pure-Python packages work. Packages with compiled code need wheels built for iOS and Android. Run pyxpo add-lib to check a package first.

What do I need on my computer?

Python, plus Xcode for iOS and Mac builds, the Android SDK for Android builds and Visual Studio for Windows builds. The web target and the browser preview need only Python. pyxpo doctor checks your setup and tells you what is missing.

Can I write my own native module?

Yes. A module is a pip package with Python code, a small JSON manifest and optional Swift and Kotlin sources. The official packages are built the same way.

Build your first app today.

Free and open source. Install it from PyPI and have a screen running in a few minutes.