Skip to main content

PyPI Python Pydash and Chaquopy runtimes MIT license Latest release Material Design 3 Downloads

Pydrud

Build Python UIs with a Flutter-inspired widget API.
Run host-side with the toolchain-free Pydash preview, or compile a real Android APK with Chaquopy.

Congratulations, Android users — Pydash is officially live!
Download the preview client from the Pydash releases page. iOS is coming soon.


Pydrud is a declarative UI framework for building native Android apps in Python — a Flutter-inspired, radically simpler alternative to writing Java or Kotlin, with Material Design 3 (Material You) built in. It is a Python GUI framework for Android: write the interface once as a Python widget tree, and a generated renderer turns it into native Android Views at runtime. There is no XML layout and no Java to write, and the widget, theme and styling layers stay platform-neutral, so the same screen code renders through any adapter.

Pydrud ships with a platform-neutral widget tree, a keyed diff engine, and a versioned render protocol. The same screen code drives the host preview and the native Android renderer.

It ships the Material 3 design system end to end: HCT-generated colour with all 36 semantic roles, the M3 type scale, shape and elevation systems, the component catalogue from buttons to side sheets, and the M3 motion tokens — all of it expressed once in Python and translated by the renderer.

Search terms this project answers to: Python Android UI framework · declarative Python UI · Material Design 3 in Python · Material You Python · Chaquopy app · native Android Views from Python · Flutter alternative for Python · build an Android app without Java · PSS stylesheets.

Quick start

pip install pydrud                       # install the framework
pydrud create my_app --org com.example   # scaffold a project (Pydash runtime)
cd my_app
pydrud dev                               # run host Python, print a preview QR/URI

For an installable Android app, add the native platform and run it:

pydrud init android        # standalone app with embedded Python (Chaquopy)
pydrud run                 # build, install and launch on a device/emulator

The generated APK boots your Python on device and runs fully offline. Pass --runtime chaquopy to pydrud create to scaffold the Android project directly.

Runtimes

Runtime What runs where Build requirements Select with
Pydash (default) Python and state stay on the host; a preview renderer receives widget snapshots/patches and returns events. No APK. Host Python only — no Android SDK, NDK, Gradle or ADB. pydrud create <name> or --runtime pydash
Android standalone (Chaquopy) CPython is bundled in the generated project; widgets render as native Android Views, fully offline. Android SDK/NDK, JDK, Gradle; a device/emulator to install. pydrud init android, or pydrud create <name> --runtime chaquopy

An Android target can also be built with no embedded interpreter:

Backend On the device Use it when
chaquopy (default) CPython bundled; runs fully offline You want a self-contained, publishable APK
host No interpreter — the app dials out to Python on your machine You want your real Python app without embedding a runtime
none A pure renderer with no runtime You only need the native shell / protocol
pydrud init android --backend host|none|chaquopy
pydrud dev --bridge            # serve the host bridge (runs `adb reverse` for you)

All three share the same widget tree, keyed diff and protocol-v2 render transactions; only the transport differs.

Platform-neutral by design

Android is the only renderer Pydrud ships — there is no iOS, Linux, Windows or web backend to configure or maintain — but the UI layer itself is renderer-agnostic, so the same screen code is portable:

  • One widget vocabulary. pydrud/widgets/ imports nothing from pydrud/platforms/android/, the generated Java templates or android.*.
  • One wire format. A plain JSON node dict (type, key, style, props, children, events) with no Android types in it.
  • Renderer facts as data. A RendererProfile supplies platform-specific style facts to the PSS parser/resolver, so neither ever imports a platform adapter implicitly.
  • Capability negotiation. A renderer advertises the widgets and services it supports, and unsupported widgets are substituted with documented fallbacks instead of being dropped.

Adding a platform later means adding one adapter under pydrud/platforms/ plus its transport — not forking the design system. See docs/ARCHITECTURE.md.

Installation

pip install pydrud                       # from PyPI
git clone https://github.com/MurShidM01/Pydrud.git
cd Pydrud && pip install -e ".[dev]"     # from source

Behind a proxy, export http_proxy / https_proxy before pydrud build; the values are forwarded to Gradle automatically.

What you get

Area Description
Declarative UI 130+ widgets and presets: layout, Material 3 components, form fields, chips, charts, media, gestures and animations
Reactive state State<T> re-renders the tree on change; Store / Computed / ReactiveList for app-level state
Styling Inline styles plus platform-neutral .pss stylesheets with the full CSS authoring surface (see below)
Design system Theme + Tokens — colours, radii, sizes, depth, motion and type in Python; light/dark and Material You
Responsive Live window metrics (size, insets, text scale, orientation) drive breakpoints, percent units and adaptive widgets
Rendering A transport-neutral widget tree and protocol-v2 transactions; Chaquopy renders native Android Views
CLI toolchain Runtime-aware create / init / dev / sync / analyze / doctor / pip, plus Android run / build / watch / icons / keygen / permissions / capabilities
Data layer SQLite Database, Model ORM with migrations, and a TTL Cache
Native services Dialogs, storage, files, share, notifications, location, haptics, camera, sensors, biometrics and more
Async by default Thread pool, timers and a non-blocking HTTP client, so the UI never freezes
Testable pydrud.testing.AppTester runs your whole app in CI without a device or emulator

Examples

Two complete apps live in examples/:

Example Demonstrates
todo_app.py Store state, keyed lists, swipe-to-delete, search + segmented filtering, persistence, a confirm dialog
weather_app.py The non-blocking HTTP client, pull-to-refresh, permissions + GPS, a Chart, skeleton loading states, bottom navigation

Run either headless with python examples/todo_app.py --tree, or drop it into a project as src/app/main.py.

PSS stylesheets

Pydrud Style Sheets (PSS) keep presentation out of Python while using the same platform-neutral vocabulary. Files named *.pss under src/ are discovered automatically and re-resolved without re-running Python modules.

:root { --brand: #FF4F46E5; }

.card {
    background: var(--brand);
    border-radius: 16;
    padding: 24;                       /* all four sides */
    shadow: { color: #40000000; offsetY: 8; blur: 24 };
    font: { size: 16, weight: 600 };
}

@media (max-width: 360px) {
    .card { padding: 16; }
}

@keyframes pulse {
    from { transform: scale(1); opacity: 1; }
    to   { transform: scale(1.4); opacity: .4; }
}
.badge { animation: pulse 1.2s ease-in-out infinite; }
.badge:active { transform: scale(.92); }

Supported today: custom properties (--x / var() with fallback, inherited), the universal selector *, structural and state pseudo-classes (:first-child, :nth-child(), :not(), :active, :hover, :focus, …), @media queries, @keyframes + the animation shorthand, transition, and the CSS value language — clamp(), calc(), min()/max(), env(safe-area-inset-*) and the viewport units, resolved against the live window. CSS long-hands fold into Pydrud composites (font-size → font.size, padding-top → padding.top, background → bg, transform: scale() → scale), and web-only declarations are accepted then ignored with one warning, so a stylesheet copied from the web drops in nearly verbatim.

$token references resolve against the active palette — bg: $surface, color: $text, border-radius: $radius_card — so one stylesheet follows light/dark mode and re-tints after Theme.seed().

See docs/PSS_STYLESHEETS.md for the selector, cascade, value, diagnostics and reload contract, and docs/examples/heartbeat-css-parity.pss for a full stylesheet translated from a web prototype.

Widget catalogue

The API is Flutter-shaped. Every widget serialises to a platform-neutral node; the renderer decides how to draw it.

Layout

Widget Description
Container, Padding, SizedBox, Center, Spacer Boxes, padding and fixed/centred space
Row, Column, Flex Linear layouts (Flex is either axis by direction)
Stack, Positioned Overlapping and absolutely-placed children
Scaffold, AppBar, FloatingActionButton Page chrome and the Material action button
ListView, GridView, PageView, Carousel, SingleChildScrollView, Wrap Scrolling and paging
Card, Divider, Drawer, Tabs, BottomNavigationBar, NavigationRail Surfaces and navigation
AdaptiveLayout, LayoutBuilder, ResponsiveBuilder, ResponsiveGrid, SafeArea, ShowWhen Responsive composition

Controls

Widget Description
Text, Heading, Title, Subtitle, Label, Caption, Link, RichText Typography
Button, TextButton, ElevatedButton, IconButton, SegmentedButton Actions
TextField, NumberField, PasswordField, SearchBar, Form, FormField Input and validation
Checkbox, Switch, Radio, Slider, RangeSlider, Dropdown, Stepper, Rating Selection
Chip, Badge, Avatar, Banner, Tooltip, PopupMenu, ListTile, ExpansionTile Material 3 components
ProgressBar, CircularProgress, Skeleton, EmptyState, ErrorState, LoadingState Feedback and placeholders
AlertDialog, ModalBottomSheet Declarative modals — add to the tree to show, drop to dismiss
Chart, Canvas, Image, SvgPicture, WebView, VideoPlayer, MapView, NativeView Media, painting and escape hatches

pydrud docs --serve generates a searchable HTML reference for every widget, prop and service.

Events, state and async

widget.on_click(callback)          # any widget — callback(data)
widget.on_change(callback)         # inputs, sliders, page views
widget.on("select", callback)      # any named event

from pydrud import State, Store, Computed
count = State(0)
Text(lambda: f"{count.value}")     # rebuilds when count changes
page.run_task(heavy_work)          # thread pool; `async def` also works
page.every(1.0, tick)              # repeating timer
page.http.get("/posts").then(render).catch(show_error)

CLI reference

Every command uses the same branded terminal UI (auto-disabled when output is redirected; override with NO_COLOR / PYDRUD_COLOR). pydrud analyze --json stays plain JSON.

Command Description
pydrud create <name> Scaffold a Pydash project (no Android toolchain)
pydrud create <name> --runtime chaquopy Scaffold the standalone Android APK project
pydrud init android [--backend …] Add the Android platform to an existing project
pydrud dev [--bridge] [--host] [--port] Run host Python and serve the preview / device bridge
pydrud build [--debug|--release] Build an APK (Android platform only)
pydrud run [--debug|--release] Build, install and launch on a device
pydrud watch Android Hot Reload runner
pydrud devices List connected Android devices
pydrud analyze [--path src] [--json] Static analysis of Python UI code and PSS stylesheets
pydrud sync Refresh the generated Android layer
pydrud clean Clean Android build artifacts
pydrud doctor Check host and Android toolchain requirements
pydrud pip add|remove|list|search|sync Manage project packages
pydrud permissions add|remove <name> Update YAML and the Android manifest
pydrud capabilities add|remove <name> Enable Android feature bundles
pydrud icons [--source logo.png] Generate launcher icons
pydrud keygen Create the Play Store upload keystore
pydrud docs [--serve] Offline HTML API reference
pydrud inspect [--tree] [--watch] Inspect the widget tree or Android bridge traffic

Android project configuration

Applies once a project has the Android platform. pydrud.yaml is the source of truth for generated Android files — change it and run pydrud sync.

app_name: "Taskflow"
package: "com.example.taskflow"
runtime: "chaquopy"
version_code: 2
version_name: "1.1.0"
min_sdk: 24
target_sdk: 36
compile_sdk: 36
scheme: "taskflow"
permissions: ["CAMERA"]
capabilities: ["haptics", "notifications"]
camera: false
python_version: "3.11"
protocol_version: 2
Key Purpose
runtime chaquopy, host or none
capabilities Feature bundles (camera, microphone, location, contacts, notifications, haptics, …). pydrud capabilities list --all describes each
permissions Individual Android permissions (dangerous ones still need a runtime request)
camera Bundle the CameraX + ML Kit stack (~10 MB). Off by default; pydrud permissions add camera enables it. Without it, CameraPreview renders its fallback and camera calls explain the fix

Runtime dangerous permissions always require page.permissions.request(...) and explicit user consent — Pydrud never fakes or bypasses the Android prompt.

Architecture

Both runtimes share the transport-neutral widget tree, keyed diff engine and protocol-v2 transactions:

Pydash (pydrud dev)
  host Python App  ── token-authenticated preview handshake ──► renderer
        source, state and handlers stay on the host

Chaquopy (pydrud run / APK)
  embedded Python App ── local NDJSON bridge ──► generated BridgeService
                                                 └─ native Android Views
  1. App(target=main) builds a widget tree; PSS rules resolve on the Python side.
  2. page.update() computes keyed patches from the last renderer-confirmed tree.
  3. Python sends one RenderTransaction (full snapshot or patch batch) with a strictly increasing revision.
  4. The renderer applies it atomically and ACKs; a NACK triggers a full resync.
  5. Events travel back through the same bridge to Python callbacks.

Source layout

No file in the repository exceeds 1,000 lines.

Package Contents
pydrud/widgets/ Widget library: basic, layout, forms, advanced, canvas, gestures, animation, conditional, responsive, presets, plus material/ and theme/
pydrud/runtime/ App, Page and the bridge event loop, split into focused mixins
pydrud/core/ Platform-neutral engine: diff/RenderTransaction, state, bridge/protocol, responsive, watcher, and styles/ (the PSS engine)
pydrud/services/ http and native/ platform services
pydrud/commands/ The CLI (project/, builder, analyzer, doctor, docs, …)
pydrud/android/templates/ Jinja2 templates for the generated Android project

Native renderer (Chaquopy)

A thin ViewFactory orchestrator plus cohesive collaborators:

Class Responsibility
ViewFactory Orchestrator — view/node maps, public API, collaborator wiring
BuiltinViews createView dispatch and built-in widget factories
ViewStyler applyStyle, borders, gradients, typography, dimensions
LayoutEngine Linear/grid layout params, spacing, child attach/removal
TreePatcher applyPatch / updateProps
EventBinder Click/change binding, popup menus, touch feedback
ViewAnimator Entrance animations, keyframes, transitions
ImageLoader · NativeViewFactory Image pipeline · user NativeView classes
MaterialViews + MaterialNavigationViews Material 3 components
BridgeService · PydrudTheme TCP/NDJSON server · generated design system

Requirements

Host workflow (default)

Python 3.10+ and the Pydrud package. pydrud dev needs no Java, Android SDK, NDK, Gradle or ADB.

Android APK workflow

Tool Default Notes
Python 3.11 Used by the Chaquopy build/runtime configuration
Java (JDK) 17+ Checked by pydrud doctor
Android SDK API 36 compile/target Set ANDROID_HOME or ANDROID_SDK_ROOT
Android NDK 28.2.13676358 Generated project default
Android Gradle Plugin 8.13.2 Generated project default
Gradle 8.14.4 Wrapper generated with the project
Chaquopy 17.0.0 Embedded Python runtime (MIT since 12.0.1)

Projects target Android API 24+ and default to arm64-v8a, armeabi-v7a and x86_64. ADB is needed for pydrud run, not for pydrud dev or the tests.

Setting up the Android SDK

Windows (PowerShell):

[System.Environment]::SetEnvironmentVariable('ANDROID_HOME', 'C:\Android\Sdk', 'User')
[System.Environment]::SetEnvironmentVariable('ANDROID_SDK_ROOT', 'C:\Android\Sdk', 'User')

Linux / macOS:

export ANDROID_HOME=$HOME/Android/Sdk
export ANDROID_SDK_ROOT=$HOME/Android/Sdk

Restart your terminal and run pydrud doctor to verify.

Development

pip install -e ".[dev]"
python -m pytest tests/ -v
ruff check .                 # the same lint CI runs

The suite covers widget/state/protocol unit tests, keyed-diff and PSS parsing/resolution, scaffold generation for both project shapes, generated Java template parsing, and end-to-end runtime tests via pydrud.testing — all without a device or emulator.

tests/test_neutrality.py additionally proves the UI layer is renderer-neutral: every module under pydrud/widgets/ is imported in a fresh interpreter and asserted to reach no Android adapter and no pyjnius, so the portability claim above cannot regress unnoticed.

Roadmap

Version Focus
v2.1.4 Per-ABI APKs rebuilt with a product flavor dimension (Chaquopy rejects splits.abi); pydrud build collects the flavor APKs
v2.1.3 pydrud build discovers per-ABI APKs (prints them all, returns the universal one); --output copies every split
v2.1.2 Opt-in per-ABI APK splits (abi_splits) — one APK per ABI plus a universal APK for smaller downloads
v2.1.1 PSS as a full CSS-style language, declarative @keyframes/transition/:active, pluggable runtime backends, Heartbeat starter, content blur, animated theming
v2.1.0 create/init android CLI, pluggable runtime backends, PSS engine, Heartbeat starter, runtime-aware tooling
2.1.5 Material 3 Complete: HCT colour, 36 roles, the M3 component catalogue, M3 typography/shape/motion — Android renderers, platform-neutral UI layer
Next Material Symbols + dynamic colour, expressive motion (springs), container transform, predictive back
Later Further M3 Expressive work, then additional platform backends on top of the neutral UI layer

See CHANGELOG.md for the complete itemised history.

Contributing

  1. Fork the repository.
  2. Create a branch: git checkout -b feature/amazing-feature.
  3. Commit your changes and push the branch.
  4. Open a Pull Request.

License

MIT © Pydrud Contributors. See LICENSE for details.


Pydrud — Pythonic. Portable. Simple.

Metadata

Release files for pydrud 2.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydrud 2.1.5
File Size Uploaded Provenance Actions
pydrud-2.1.5.tar.gz 1.1 MB Without provenance Details for pydrud-2.1.5.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pydrud 2.1.5
File Interpreter ABI Platform Actions
pydrud-2.1.5-py3-none-any.whl Python 3 none any Details for pydrud-2.1.5-py3-none-any.whl

Total release size: 2.0 MB

Release files / pydrud-2.1.5.tar.gz

Download URL pydrud-2.1.5.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
cbe1098a11e8b719948376104f2c63a5c210475c4ba132269d93c3f26db3e02e
BLAKE2b-256 checksum
How to use checksums
b961dd0eac23a51451fe36075e04c1b8f49ff074661df7a481c0e709dbfba9b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / pydrud-2.1.5-py3-none-any.whl

Download URL pydrud-2.1.5-py3-none-any.whl
Size 932.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
88f8675a98ec38cdb351d5c26be8090a1a4433c0776b029eca268340cd0223ff
BLAKE2b-256 checksum
How to use checksums
fab0d4f0705434898274fdc80e2aca50c4ad9d645c586ec84708b191af46621e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for pydrud 2.1.5

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page