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.9.tar.gz (50.7 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.9-py3-none-any.whl (261.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: cacao-2.0.9.tar.gz
  • Upload date:
  • Size: 50.7 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.9.tar.gz
Algorithm Hash digest
SHA256 e6b224e83dc9a86858af0039e18c86edcb2e2bf5ea0fe050f188745d01c1f1bc
MD5 e9ec51d74847c7cfe1e7e708f823a37d
BLAKE2b-256 a320e381ebc098673a062c67f5ab628c7834cbe6073aed246aec05eec1d0d993

See more details on using hashes here.

File details

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

File metadata

  • Download URL: cacao-2.0.9-py3-none-any.whl
  • Upload date:
  • Size: 261.7 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.9-py3-none-any.whl
Algorithm Hash digest
SHA256 712f5058627609afc616f3f765dd5ccdddbd64ae3babce0f0f07db8e5b07e3ab
MD5 48ce4c898992e12f043fd378799a6313
BLAKE2b-256 7b01f61bda26c51d8b6cb695c40f966b50f79d61ab19f4fb9e7ef9da3b6c7c8f

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