Skip to main content

Flash - async port of the Dash framework

Project description

Flash

Quart async Patch of Dash.

Flash is a async patch of the Plotly Dash library, building on Quart as backend instead of Flask. It is very inspired by the already existing dash-async repo, but covering all features up to Dash 2.18.2

Quarts async capabilities are directly baked into the standard library, making it easy to inject into existing projects.

Flash makes it possible to run true async callbacks and layout functions while running sync functions in a separate thread (asyncio.run_in_executor).

With dash-extensions you can create native websocket components and handle serverside events - making your application realtime compatible.

Installation

pip install dash-flash

Table of Contents

Motivation

One of the biggest pain points in Dash was handling database requests, which often required:

  • Adding multiple callbacks to fetch a "lazy" component
  • Rendering the real component only when the lazy component's ID appears
  • Creating complex pattern matching callbacks for each component's data

Dash Flash addresses these challenges by:

  • Ensuring I/O bound tasks don't block each other
  • Better state management via the URL due to async layout functions
  • Native websocket and HTTP/2 support

Future improvements may include:

  • native Websocket component which spawns and manages the websocket itself
  • LazyLoad component like dash-grocery, this will also increase responsiveness and overall better UI feeling
  • shared callbacks / channel callbacks like dash-devices offered. Will most likly be implemented with redis PubSub
  • ?? new routing system based on blueprints enabling parallel routes ??

A Notice

  • Background callbacks must run synchronously
  • For Dash testing, use dash_duo_mp instead of dash_duo
  • currently not tested in prod, will soon on a basic K8s cluster running in a Docker container

Known Issues

  • not all tests pass - detailed look in TEST_LOGS.md
    • 10 integration tests
    • 2 unit tests

Usage

modules that need to be imported from flash

from flash import (
    Flash,
    get_app,
    register_page,
    page_registry,
    ctx,
    set_props,
    callback,
    clientse_callback,
    no_update,
    page_container,
)

Modules that can be imported from flash but also from dash - seeking your feedback here, would you preffer to keep them separate or just import from flash?

from flash import (
    Input,  
    Output, 
    State, 
    ClientsideFunction,
    MATCH,
    ALL, 
    ALLSMALLER, 
    get_asset_url,
    get_relative_path,
    strip_relative_path,
)
  1. Gather async functions in callback:
from flash import Flash, callback, Input, Output, html
from dash import _dash_renderer

import time 
import asyncio


_dash_renderer._set_react_version("18.2.0")

external_scripts = ["https://unpkg.com/dash.nprogress@latest/dist/dash.nprogress.js"]

app = Flash(__name__, external_scripts=external_scripts)


class ids:
    sync_btn_id = "sync-btn-id" 
    async_btn_id = "async-btn-id"
    sync_output = "sync-output"
    async_output = "async-output"


app.layout = html.Div(
    [
        html.Button("Sync", id=ids.sync_btn_id),
        html.Button("Async", id=ids.async_btn_id),
        html.Div(id=ids.sync_output)
        html.Div(id=ids.async_output)
    ]
)


def long_running(sleep):
    time.sleep(sleep)

async def long_running_async(sleep):
    await asyncio.sleep(sleep)


@callback(
    Output(ids.sync_output, "children"),
    Input(ids.sync_btn_id, "n_clicks"),
    prevent_initial_call=True
)

def update_sync(_):
    start_time = time.perf_counter()
    long_running(1)
    long_running(0.7)
    long_running(.5)
    duration = time.perf_counter() - start_time
    return duration


@callback(
    Output(ids.async_output, "children"),
    Input(ids.async_btn_id, "n_clicks"),
    prevent_initial_call=True,
)

async def update_async(_):
    start_time = time.perf_counter()
    await asyncio.gather(
        long_running_async(1),
        long_running_async(0.7),
        long_running_async(.5) 
    )
    duration = time.perf_counter() - start_time
    return duration


if __name__ == "__main__":
    app.run(debug=True)
  1. websocket support with dash-extensions - (inspired by dash-async)
import asyncio
import random

from flash import Flash, Output, Input
from dash import html, dcc
from dash_extensions import WebSocket
from quart import websocket, json


app = Dash(__name__)


class ids:
    websocket_id = "ws"
    graph_id = "graph"


layout = html.Div([
    WebSocket(id=ids.websocket_id, url="ws://127.0.0.1:8050/test-ws"), 
    dcc.Graph(id=ids.graph_id)
])


clientside_callback(
    """
    function(msg) {
        if (msg) {
            const data = JSON.parse(msg.data);
            return {data: [{y: data, type: "scatter"}]};
        } else {
            return window.dash_clientside.no_update;
        }
    }
    """,
    Output(ids.graph_id, "figure"),
    [Input(ids.websocket_id, "message")],
)


@app.server.websocket("/test-ws")
async def ws():
    while True:
        output = json.dumps([random.randint(200, 1000) for _ in range(6)])
        await websocket.send(output)
        await asyncio.sleep(1)


if __name__ == "__main__":
    app.run(debug=True)

TODO

  • add Serverside Event example

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

dash_flash-0.1.0b2.tar.gz (42.0 kB view details)

Uploaded Source

Built Distribution

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

dash_flash-0.1.0b2-py3-none-any.whl (43.2 kB view details)

Uploaded Python 3

File details

Details for the file dash_flash-0.1.0b2.tar.gz.

File metadata

  • Download URL: dash_flash-0.1.0b2.tar.gz
  • Upload date:
  • Size: 42.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.12.7 Darwin/23.6.0

File hashes

Hashes for dash_flash-0.1.0b2.tar.gz
Algorithm Hash digest
SHA256 c05a670981fc576bd744b93c6ca1bfae8a46f2fef09a7b4f3d8710af9f8a80a4
MD5 756f95b785d234005dceff64bd4c959a
BLAKE2b-256 6ee07d31983155e4a395e5b6670a0dd8e2312db7022f65ca2c8d99a2bad11aac

See more details on using hashes here.

File details

Details for the file dash_flash-0.1.0b2-py3-none-any.whl.

File metadata

  • Download URL: dash_flash-0.1.0b2-py3-none-any.whl
  • Upload date:
  • Size: 43.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.12.7 Darwin/23.6.0

File hashes

Hashes for dash_flash-0.1.0b2-py3-none-any.whl
Algorithm Hash digest
SHA256 0af705764595485a60b2d3d70768eefd3c259d030c3e05e2da86eacaa61a30da
MD5 8acbf5276b550c7cd96082dca9cfc54b
BLAKE2b-256 ed73d422f599d0cae9078886ae7e6e7be09b2e829e24c99b1ccf25609c9fcb6e

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