Skip to main content

High-performance reactive web framework for Python. Build dashboards, internal tools, and data apps with a Streamlit-like API but 10x faster.

Project description

image

Cacao

PyPI Version Downloads Python Versions License Build GitHub Stars


High-performance reactive web framework for Python. Build dashboards, internal tools, and data apps with a simple API — 10x faster than Streamlit with true WebSocket reactivity.

v2.0 - Complete rewrite with signal-based reactivity, session-scoped state, and a Streamlit-like API that doesn't re-run your entire script.

Quick Start

pip install cacao

Hello World (4 lines)

import cacao as c

c.title("Hello, Cacao!")
c.text("Welcome to the simplest Python web framework")

Interactive Counter

import cacao as c

c.config(title="Counter")

count = c.signal(0, name="count")

@c.on("increment")
async def increment(session, event):
    count.set(session, count.get(session) + 1)

@c.on("decrement")
async def decrement(session, event):
    count.set(session, count.get(session) - 1)

c.title("Counter")

with c.card():
    c.metric("Count", count)
    with c.row():
        c.button("-", on_click="decrement", variant="secondary")
        c.button("+", on_click="increment")

Dashboard with Charts

import cacao as c

c.config(title="Sales Dashboard", theme="dark")

sales = c.sample_sales_data()

c.title("Sales Dashboard")

with c.row():
    c.metric("Revenue", "$45,231", trend="+20.1%", trend_direction="up")
    c.metric("Orders", "1,247", trend="+12.5%", trend_direction="up")
    c.metric("Customers", "842", trend="+5.3%", trend_direction="up")

with c.row():
    with c.col(span=8):
        with c.card("Revenue Trend"):
            c.line(sales, x="date", y="revenue", area=True)
    with c.col(span=4):
        with c.card("By Category"):
            c.pie(sales[:5], values="revenue", names="category", donut=True)

with c.card("Recent Transactions"):
    c.table(sales[:10], columns=["date", "category", "revenue", "orders"])

Run with:

cacao run dashboard.py

Why Cacao?

Feature Cacao Streamlit
Reactivity Signal-based (only changed values update) Full script re-run on every interaction
State Session-scoped by design st.session_state bolt-on
Updates WebSocket streaming (instant) HTTP polling (laggy)
Multi-user Isolated sessions built-in Shared state issues
API Context managers + decorators Magic globals

Core Concepts

Signals (Reactive State)

count = c.signal(0, name="count")

# Get value for a session
current = count.get(session)

# Set value (auto-syncs to client)
count.set(session, current + 1)

Event Handlers

@c.on("submit")
async def handle_submit(session, event):
    print(event.get("value"))

Layout Components

with c.row():           # Horizontal layout
    with c.col(span=8): # 8/12 width column
        c.text("Main content")
    with c.col(span=4): # 4/12 width column
        c.text("Sidebar")

with c.card("Title"):   # Card container
    c.metric("Value", 100)

with c.tabs():          # Tabbed content
    with c.tab("tab1", "First"):
        c.text("Tab 1 content")
    with c.tab("tab2", "Second"):
        c.text("Tab 2 content")

Form Components

c.button("Click me", on_click="submit")
c.input("Name", signal=name_signal)
c.select("Category", ["A", "B", "C"])
c.checkbox("Agree", signal=agree_signal)
c.slider("Volume", min=0, max=100)

Charts

c.line(data, x="date", y="value")
c.bar(data, x="category", y="count")
c.pie(data, values="amount", names="label")
c.area(data, x="date", y="value")
c.scatter(data, x="x", y="y")
c.gauge(value=75, max_value=100)

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         PYTHON SERVER                            │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌───────────────┐   │
│  │ Signals  │  │ Sessions │  │  Events  │  │ WebSocket/HTTP│   │
│  │ (state)  │──│ (per-    │──│ (typed   │──│    Server     │   │
│  │          │  │  client) │  │  async)  │  │               │   │
│  └──────────┘  └──────────┘  └──────────┘  └───────┬───────┘   │
└────────────────────────────────────────────────────┼───────────┘
                                                     │ JSON
                                                     │ WebSocket
┌────────────────────────────────────────────────────┼───────────┐
│                      REACT CLIENT                   │           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────┴──────┐    │
│  │  Hooks   │  │Components│  │  Event   │  │   State     │    │
│  │useCacao()│──│ (your UI)│──│Dispatcher│──│   Store     │    │
│  └──────────┘  └──────────┘  └──────────┘  └─────────────┘    │
└─────────────────────────────────────────────────────────────────┘

Project Structure

cacao/
├── __init__.py          # Simple API exports
├── simple.py            # Streamlit-like API
├── server/              # Core server
│   ├── app.py           # App class
│   ├── signal.py        # Signal, Computed
│   ├── session.py       # Session management
│   ├── events.py        # Event handling
│   ├── server.py        # WebSocket server
│   ├── ui.py            # UI components
│   ├── chart.py         # Chart components
│   └── data.py          # Data utilities
├── cli/                 # CLI commands
└── examples/            # Example apps

CLI

# Run an app with hot reload
cacao run app.py

# Run on custom port
cacao run app.py --port 3000

# Create a new project
cacao create my-dashboard

# Build a static site (no server required)
cacao build app.py

# Build for GitHub Pages subdirectory
cacao build app.py --base-path /my-repo

Static Builds

Cacao can generate static sites that run entirely in the browser — no Python server required. Perfect for GitHub Pages, Netlify, or any static hosting.

cacao build app.py

This creates a dist/ folder with:

  • index.html - Your app
  • cacao.js - Runtime with built-in handlers
  • cacao.css - Styles

Built-in handlers for common operations work automatically:

  • Encoders: Base64, URL, HTML entities, JWT decode
  • Generators: UUID, passwords, Lorem Ipsum
  • Converters: JSON/YAML, case conversion, number bases
  • Text: Statistics, regex testing
  • Crypto: Hash generation, HMAC

Deploy to GitHub Pages:

# .github/workflows/deploy.yml
- run: pip install cacao
- run: cacao build app.py --base-path /${{ github.event.repository.name }}

See cacao-tools for a full static site example.

Examples

See the examples/ directory:

  • examples/simple/hello.py - Minimal app
  • examples/simple/counter.py - Interactive counter
  • examples/simple/metrics.py - KPI dashboard
  • examples/simple/dashboard.py - Full dashboard with charts

Contributing

Contributions are welcome! Please read our contributing guidelines for details.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cacao-2.0.10.tar.gz (57.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cacao-2.0.10-py3-none-any.whl (326.2 kB view details)

Uploaded Python 3

File details

Details for the file cacao-2.0.10.tar.gz.

File metadata

  • Download URL: cacao-2.0.10.tar.gz
  • Upload date:
  • Size: 57.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cacao-2.0.10.tar.gz
Algorithm Hash digest
SHA256 8e411c2338946212660f07a217258b34132a7a590fa6327c647f88533295f8a2
MD5 f25b7cfc729b9ddf2b920d806d10dbb0
BLAKE2b-256 6fa10f776841fa37ab11b1f6f5a8d2b2a1766244a7e3f22007602cca94cb5cd6

See more details on using hashes here.

File details

Details for the file cacao-2.0.10-py3-none-any.whl.

File metadata

  • Download URL: cacao-2.0.10-py3-none-any.whl
  • Upload date:
  • Size: 326.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cacao-2.0.10-py3-none-any.whl
Algorithm Hash digest
SHA256 e85e518b0f422e62fbcab30b361b3f0790f87ec2fc203d7c24410ada1fdd4a12
MD5 44364f1cff0c4076f76e36afecb56e41
BLAKE2b-256 5badc6fb71abcb0ebe010fcd2dc2945489f0fa4b93c21eb48a635621c756f68e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page