CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-shiny

A web development framework for Python that enables building fast, beautiful, and interactive web applications using reactive programming principles.

Pending
Overview
Eval results
Files

express.mddocs/

Express Mode

Express mode provides a simplified API for building Shiny applications with automatic UI collection and streamlined syntax. It eliminates the need for explicit UI structure and server function definition, making it ideal for rapid prototyping and simple applications.

# Required imports for this module
from shiny.express import app_opts, wrap_express_app, is_express_app, expressify, output_args
from shiny.express import input, output, ui, render
from shiny import App, Inputs, Outputs, Session
from typing import Callable, Literal, Mapping
from htmltools import Tag, TagList, TagChild
from pathlib import Path

Capabilities

Express Core Objects

Dynamic objects that provide session-dependent access to inputs, outputs, and session functionality.

# Express mode core objects (session-dependent)
input: Inputs
    """
    Dynamic input accessor that provides reactive access to user inputs.
    Equivalent to the input parameter in core mode server functions.
    """

output: Outputs
    """
    Dynamic output accessor for assigning rendered content.
    Equivalent to the output parameter in core mode server functions.
    """

session: Session
    """
    Dynamic session accessor for session management and client communication.
    Equivalent to the session parameter in core mode server functions.
    """

render: ModuleType
    """
    Rendering functions for creating reactive outputs.
    Same as shiny.render module but optimized for Express mode.
    """

Usage Examples

# Express mode application
from shiny.express import input, output, ui, render

# Direct UI definition (automatically collected)
ui.h1("Express Shiny App")
ui.input_slider("n", "Number of observations:", 0, 100, 20)

# Direct output rendering (automatically assigned)
@render.text
def txt():
    return f"The value of n is {input.n()}"

# Access session directly
@render.text  
def session_info():
    return f"Session ID: {id(session)}"

# Multiple outputs
@render.plot
def histogram():
    import matplotlib.pyplot as plt
    import numpy as np
    
    np.random.seed(19680801)
    data = np.random.randn(input.n())
    
    plt.hist(data, bins=30)
    plt.title(f"Histogram of {input.n()} observations")
    return plt.gcf()

@render.table
def summary():
    import pandas as pd
    import numpy as np
    
    np.random.seed(19680801)
    data = np.random.randn(input.n())
    
    return pd.DataFrame({
        "Statistic": ["Mean", "Std", "Min", "Max"],
        "Value": [data.mean(), data.std(), data.min(), data.max()]
    })

Express Configuration

Functions for configuring Express mode applications.

def app_opts(
    *,
    static_assets: str | Path | Mapping[str, str | Path] | None = None,
    bookmark_store: Literal["url", "server", "disable"] | None = None,
    debug: bool | None = None,
) -> None:
    """
    Configure express app options.
    
    Args:
        static_assets: Path to static assets directory or mapping.
        bookmark_store: Bookmark storage strategy.
        debug: Enable debug mode.
    """

def wrap_express_app(file: Path) -> App:
    """
    Wrap an express app file for deployment.
    
    Args:
        file: Path to the express app Python file.
        
    Returns:
        App instance suitable for deployment.
    """

def is_express_app(app: str, app_dir: str | None) -> bool:
    """
    Check if the specified app is an express mode app.
    
    Args:
        app: The app filename to check.
        app_dir: Directory containing the app file.
        
    Returns:
        True if it's an express mode app, False otherwise.
    """

def expressify(fn: Callable[..., T]) -> Callable[..., T]:
    """
    Decorator for making functions work with Express mode's automatic display system.
    
    Args:
        fn: Function to make compatible with Express mode.
        
    Returns:
        Decorated function that works in Express mode.
    """

def output_args(**kwargs: object) -> Callable[[Callable[..., T]], Callable[..., T]]:
    """
    Decorator for setting default UI arguments for rendering functions.
    
    Args:
        **kwargs: Default arguments to apply to the output UI.
        
    Returns:
        Decorator function.
    """

Usage Examples

# Configure express app
from shiny.express import app_opts, ui, render, input

app_opts(
    title="My Express App",
    debug=True
)

ui.h1("Configured Express App")
ui.input_text("name", "Enter name:")

@render.text
def greeting():
    return f"Hello, {input.name()}!"

# Wrap for deployment (in separate deployment script)
from shiny.express import wrap_express_app

app = wrap_express_app("my_express_app.py")

# Check if in express mode
from shiny.express import is_express_app

if is_express_app():
    print("Running in Express mode")
else:
    print("Running in Core mode")

# Function-based express app
from shiny.express import expressify

def my_app():
    from shiny.express import ui, render, input
    
    ui.h1("Function-based App")
    ui.input_slider("x", "Value:", 1, 10, 5)
    
    @render.text
    def result():
        return f"Value squared: {input.x() ** 2}"

app = expressify(my_app)

Express UI Components

All UI components from the main shiny.ui module, plus Express-specific additions and context manager versions.

def page_opts(**kwargs: object) -> None:
    """
    Configure page-level options for express apps.
    
    Args:
        **kwargs: Page configuration options including:
            - title: Page title
            - lang: Page language
            - theme: UI theme
    """

class hold:
    """
    Context manager to hold UI element rendering until explicitly released.
    """
    def __enter__(self) -> None:
        """Enter hold context."""
    
    def __exit__(self, *args: object) -> None:
        """Exit hold context and render held elements."""

Context Manager Layouts

Express mode provides context manager versions of layout components for intuitive nested syntax:

# Context manager versions of layout components
sidebar(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
layout_sidebar(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
card(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
accordion(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
nav_panel(title: str, *args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
navset_tab(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
layout_columns(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]

Usage Examples

# Express UI with context managers
from shiny.express import ui, render, input

# Configure page
ui.page_opts(title="Express Layout Demo")

ui.h1("Express Layout Example")

# Sidebar layout with context manager
with ui.layout_sidebar():
    with ui.sidebar():
        ui.h3("Controls")
        ui.input_select("dataset", "Dataset:", ["mtcars", "iris", "diamonds"])
        ui.input_slider("n_rows", "Rows to show:", 5, 50, 10)
        ui.input_checkbox("show_summary", "Show summary", False)
    
    # Main content area
    ui.h2("Data View")
    
    # Cards with context manager
    with ui.card():
        ui.card_header("Dataset Preview")
        
        @render.data_frame
        def data_preview():
            # Implementation here
            pass
    
    with ui.card():
        ui.card_header("Visualization")
        
        @render.plot
        def data_plot():
            # Implementation here
            pass

# Navigation with context manager
with ui.navset_tab():
    with ui.nav_panel("Data"):
        ui.h3("Data Management")
        ui.input_file("upload", "Upload CSV")
    
    with ui.nav_panel("Analysis"):
        ui.h3("Statistical Analysis")
        
        with ui.layout_columns():
            with ui.card():
                ui.card_header("Options")
                ui.input_checkbox_group(
                    "analyses", 
                    "Select analyses:",
                    ["correlation", "regression", "clustering"]
                )
            
            with ui.card():
                ui.card_header("Results")
                
                @render.text
                def analysis_results():
                    return f"Selected: {input.analyses()}"

# Hold UI rendering
with ui.hold():
    # These elements won't render until the context exits
    ui.h3("Batch Rendered Elements")
    ui.p("This content is rendered together")
    
    for i in range(3):
        ui.p(f"Item {i + 1}")

Express Modules

Module system adapted for Express mode applications.

module: object
    """
    Module system for Express apps with decorators and utilities.
    
    Provides:
    - @module.ui decorator for module UI functions
    - @module.server decorator for module server functions
    - current_namespace() function
    - resolve_id() function
    """

Usage Examples

# Express module definition
from shiny.express import module, ui, render, input

# Module UI function
@module.ui
def counter_ui():
    ui.h3("Counter Module")
    ui.input_action_button("increment", "Increment")
    ui.input_action_button("reset", "Reset")
    ui.output_text("count")

# Module server function
@module.server
def counter_server(input, output, session):
    count = reactive.value(0)
    
    @reactive.effect
    @reactive.event(input.increment)
    def _():
        count.set(count.get() + 1)
    
    @reactive.effect
    @reactive.event(input.reset)
    def _():
        count.set(0)
    
    @output
    @render.text
    def count():
        return f"Count: {count()}"

# Use module in main app
from shiny.express import ui

ui.h1("App with Modules")

# Include multiple instances of the module
counter_ui("counter1")
counter_server("counter1")

ui.hr()

counter_ui("counter2") 
counter_server("counter2")

Express Chat and Markdown

Express-compatible versions of interactive components.

class Chat:
    """
    Express-compatible chat interface.
    
    Provides real-time chat functionality optimized for Express mode
    with automatic UI integration and simplified message handling.
    """
    def __init__(
        self,
        id: str,
        messages: list[ChatMessage] | None = None,
        **kwargs: object
    ): ...
    
    def send_message(self, message: str, user: str = "assistant") -> None:
        """Send a message to the chat."""
    
    def clear_messages(self) -> None:
        """Clear all chat messages."""

class MarkdownStream:
    """
    Express-compatible markdown streaming component.
    
    Provides streaming markdown rendering with real-time updates
    optimized for Express mode applications.
    """
    def __init__(self, id: str, **kwargs: object): ...
    
    def write(self, content: str) -> None:
        """Write content to the markdown stream."""
    
    def clear(self) -> None:
        """Clear the markdown stream."""

Usage Examples

# Express chat application
from shiny.express import ui, render, input, Chat

ui.h1("Express Chat Demo")

# Create chat interface
chat = Chat(
    id="main_chat",
    messages=[
        {"user": "assistant", "message": "Hello! How can I help you?"},
    ]
)

ui.input_text("user_message", "Type your message:", placeholder="Enter message...")
ui.input_action_button("send", "Send")

@reactive.effect
@reactive.event(input.send)
def handle_message():
    message = input.user_message()
    if message.strip():
        # Add user message
        chat.send_message(message, user="user")
        
        # Simple echo response
        response = f"You said: {message}"
        chat.send_message(response, user="assistant")
        
        # Clear input (would need session.send_input_message in real app)

# Streaming markdown example
from shiny.express import MarkdownStream

ui.h2("Streaming Content")

markdown_stream = MarkdownStream("content_stream")

ui.input_action_button("start_stream", "Start Streaming")
ui.input_action_button("clear_stream", "Clear")

@reactive.effect
@reactive.event(input.start_stream)
def start_streaming():
    import asyncio
    
    async def stream_content():
        content_pieces = [
            "# Streaming Demo\n\n",
            "This content is being **streamed** in real-time.\n\n",
            "- First item\n",
            "- Second item\n", 
            "- Third item\n\n",
            "## Code Example\n\n",
            "```python\n",
            "def hello():\n",
            "    print('Hello, World!')\n",
            "```\n\n",
            "Streaming complete! 🎉"
        ]
        
        for piece in content_pieces:
            markdown_stream.write(piece)
            await asyncio.sleep(0.5)
    
    asyncio.create_task(stream_content())

@reactive.effect
@reactive.event(input.clear_stream)
def clear_content():
    markdown_stream.clear()

Express vs Core Mode Comparison

Core Mode Application

from shiny import App, ui, render, Inputs, Outputs, Session

# Explicit UI definition
app_ui = ui.page_fluid(
    ui.h1("Core Mode App"),
    ui.input_slider("n", "Number:", 1, 10, 5),
    ui.output_text("result")
)

# Explicit server function
def server(input: Inputs, output: Outputs, session: Session):
    @output
    @render.text
    def result():
        return f"Value: {input.n()}"

# Explicit app creation
app = App(app_ui, server)

Express Mode Application

from shiny.express import ui, render, input

# Direct UI definition (automatically collected)
ui.h1("Express Mode App")
ui.input_slider("n", "Number:", 1, 10, 5)

# Direct output rendering (automatically assigned)
@render.text
def result():
    return f"Value: {input.n()}"

# App automatically created from collected UI and outputs

Express Mode Best Practices

  1. Use for Rapid Prototyping: Express mode is ideal for quick demos and simple applications
  2. Context Managers: Take advantage of context manager syntax for cleaner nested layouts
  3. Gradual Migration: Start with Express mode and migrate to Core mode as complexity grows
  4. Module Organization: Use Express modules to organize complex applications
  5. Debugging: Use is_express_app() to write code that works in both modes
# Adaptive code for both modes
from shiny.express import is_express_app

if is_express_app():
    from shiny.express import input, output, session
else:
    # In core mode, these come from server function parameters
    pass

# Function that works in both modes
def get_user_greeting():
    if is_express_app():
        from shiny.express import input
        return f"Hello, {input.username()}!"
    else:
        # Core mode would need input parameter passed in
        raise RuntimeError("Must be called from within server function")

Install with Tessl CLI

npx tessl i tessl/pypi-shiny

docs

app.md

express.md

index.md

reactive.md

render.md

session.md

types.md

ui.md

tile.json