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

Uploaded Python 3

File details

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

File metadata

  • Download URL: cacao-2.0.7.tar.gz
  • Upload date:
  • Size: 49.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.7.tar.gz
Algorithm Hash digest
SHA256 5c821d179452b96980ad891ca32e506438b29237eff3698351bc5f08fef9cd6a
MD5 3b079dab64d9828b7630873be2f15de5
BLAKE2b-256 14a2aae076070ffc60b8b28411b74ba8add78ed62cc5f6b0594d9bd0f8f186ed

See more details on using hashes here.

File details

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

File metadata

  • Download URL: cacao-2.0.7-py3-none-any.whl
  • Upload date:
  • Size: 259.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.7-py3-none-any.whl
Algorithm Hash digest
SHA256 58876c7253f9783a4be97ed9df6bd9212ae256f3d0a66426c506714c62301db8
MD5 b31596181c897c1175a368832e5fe3ff
BLAKE2b-256 4b048d3c1292551c84752485d918a3037bc63479de361ff2b64686da476cf550

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