CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-fasthtml

The fastest way to create HTML apps - a next-generation Python web framework for building fast, scalable web applications with minimal code

Pending
Overview
Eval results
Files

development-tools.mddocs/

Development Tools

Development server with live reload, Jupyter notebook integration, testing utilities, deployment tools, and development workflow enhancements.

Capabilities

Development Server and Live Reload

Enhanced development server with hot reload capabilities for rapid development iteration.

class FastHTMLWithLiveReload:
    """
    FastHTML app with live reload functionality.
    
    Automatically reloads the browser when source files change,
    enabling rapid development workflow.
    """
    
    def __init__(self, app, watch_dirs=None, watch_extensions=None):
        """
        Initialize live reload server.
        
        Args:
            app: FastHTML application instance
            watch_dirs: Directories to watch for changes
            watch_extensions: File extensions to monitor
        """

Jupyter Notebook Integration

Comprehensive Jupyter notebook support for interactive development and prototyping.

def nb_serve(
    appname=None,
    app='app',
    host='127.0.0.1',
    port=None,
    reload=True,
    reload_includes=None,
    reload_excludes=None
):
    """
    Start Jupyter-compatible server.
    
    Launches development server optimized for Jupyter notebook
    workflows with proper port management and reload handling.
    
    Args:
        appname: Application module name
        app: Application instance or attribute name
        host: Host to bind server to
        port: Port to bind server to (auto-selected if None)
        reload: Enable hot reload
        reload_includes: Additional file patterns to watch
        reload_excludes: File patterns to exclude from watching
    """

def nb_serve_async(
    appname=None,
    app='app',
    host='127.0.0.1',
    port=None,
    reload=True
):
    """
    Async version of nb_serve for Jupyter environments.
    
    Args:
        appname: Application module name
        app: Application instance
        host: Host to bind to
        port: Port to use
        reload: Enable reload functionality
        
    Returns:
        Async server instance
    """

def show(ft):
    """
    Display FastHTML elements in Jupyter notebooks.
    
    Renders FastHTML elements as HTML output in Jupyter
    notebook cells for interactive development.
    
    Args:
        ft: FastHTML element to display
        
    Returns:
        Rendered HTML for Jupyter display
    """

def render_ft(ft) -> str:
    """
    Render FastHTML element to HTML string.
    
    Converts FastHTML elements to HTML string format
    for display or processing.
    
    Args:
        ft: FastHTML element to render
        
    Returns:
        str: HTML string representation
    """

def HTMX(path="/", host='localhost', app=None, port=8000, height="auto", link=False, iframe=True):
    """
    HTMX app display for Jupyter notebooks.
    
    Sets up HTMX functionality in Jupyter environment with iframe
    display, server connectivity, and interactive features.
    
    Args:
        path: App path to display
        host: Server host address
        app: FastHTML application instance
        port: Server port number
        height: Iframe height
        link: Show clickable link
        iframe: Display in iframe
        
    Returns:
        HTMX configuration and display elements
    """

Testing and HTTP Client

HTTP client for testing FastHTML applications and API endpoints.

class Client:
    """
    HTTP client for testing FastHTML apps.
    
    Provides testing interface for FastHTML applications
    with support for all HTTP methods and session management.
    """
    
    def __init__(self, app):
        """
        Initialize test client.
        
        Args:
            app: FastHTML application to test
        """
    
    def get(self, url: str, **kwargs):
        """Send GET request to application."""
    
    def post(self, url: str, data=None, json=None, **kwargs):
        """Send POST request to application."""
    
    def put(self, url: str, data=None, json=None, **kwargs):
        """Send PUT request to application."""
    
    def delete(self, url: str, **kwargs):
        """Send DELETE request to application."""
    
    def patch(self, url: str, data=None, json=None, **kwargs):
        """Send PATCH request to application."""
    
    def head(self, url: str, **kwargs):
        """Send HEAD request to application."""
    
    def options(self, url: str, **kwargs):
        """Send OPTIONS request to application."""

def ws_client(app, nm='', host='localhost', port=8000, ws_connect='/ws', frame=True, link=True, **kwargs):
    """
    WebSocket client for Jupyter environments.
    
    Creates WebSocket client for testing and interacting with
    WebSocket endpoints in FastHTML applications from Jupyter.
    
    Args:
        app: FastHTML application with WebSocket routes
        nm: Client name identifier
        host: WebSocket server host
        port: WebSocket server port
        ws_connect: WebSocket connection endpoint
        frame: Display in frame
        link: Show connection link
        **kwargs: Additional client configuration
        
    Returns:
        WebSocket client interface
    """

Port Management Utilities

Utilities for managing development server ports and availability.

def is_port_free(port: int, host: str = '127.0.0.1') -> bool:
    """
    Check if port is available.
    
    Tests whether a specific port is free and available
    for binding a development server.
    
    Args:
        port: Port number to check
        host: Host address to check
        
    Returns:
        bool: True if port is available
    """

def wait_port_free(port: int, host: str = '127.0.0.1', max_wait: int = 3):
    """
    Wait for port to become free.
    
    Waits for a port to become available, useful for
    sequential server startup and testing workflows.
    
    Args:
        port: Port number to wait for
        host: Host address to check
        max_wait: Maximum time to wait in seconds
    """

Development Server Management

Advanced server management classes for production and development environments.

class JupyUvi:
    """
    Jupyter uvicorn server manager.
    
    Manages uvicorn server lifecycle in Jupyter environments
    with automatic startup, shutdown, and configuration.
    """
    
    def __init__(self, app, log_level: str = "error", host: str = '0.0.0.0', port: int = 8000, start: bool = True, **kwargs):
        """
        Initialize Jupyter uvicorn server.
        
        Args:
            app: FastHTML application to serve
            log_level: Logging level for server
            host: Host address to bind to
            port: Port number to bind to
            start: Whether to start server immediately
            **kwargs: Additional uvicorn configuration
        """
        
    def start(self):
        """Start the uvicorn server."""
        
    def start_async(self):
        """Start server asynchronously."""
        
    def stop(self):
        """Stop the uvicorn server."""

class JupyUviAsync:
    """
    Async version of Jupyter uvicorn server manager.
    
    Provides asynchronous server management for integration
    with async workflows and event loops.
    """
    
    def __init__(self, app, log_level: str = "error", host: str = '0.0.0.0', port: int = 8000, **kwargs):
        """
        Initialize async Jupyter uvicorn server.
        
        Args:
            app: FastHTML application to serve
            log_level: Logging level for server
            host: Host address to bind to  
            port: Port number to bind to
            **kwargs: Additional uvicorn configuration
        """
        
    async def start(self):
        """Start server asynchronously."""
        
    async def stop(self):
        """Stop server asynchronously."""

Deployment Tools

Command-line deployment tools for cloud platforms.

def railway_link() -> str:
    """
    Link to Railway deployment.
    
    Generates Railway deployment link for current
    FastHTML application.
    
    Returns:
        str: Railway deployment URL
    """

def railway_deploy(project_name: str = None):
    """
    Deploy to Railway platform.
    
    Deploys FastHTML application to Railway cloud
    platform with automatic configuration.
    
    Args:
        project_name: Name for Railway project
        
    Returns:
        Deployment status and URL
    """

Usage Examples

Basic Development Setup

from fasthtml.common import *

# Create app with development features
app, rt = fast_app(
    debug=True,
    live=True,  # Enable live reload
    reload=True
)

@rt('/')
def homepage():
    return Titled("Development Mode",
        Div(
            H1("FastHTML Development"),
            P("This app has live reload enabled."),
            P("Changes to this file will automatically refresh the page."),
            Button("Test Button", hx_get="/test", hx_target="#result"),
            Div(id="result")
        )
    )

@rt('/test')
def test_endpoint():
    from datetime import datetime
    return P(f"Test endpoint called at {datetime.now()}")

# Start development server
if __name__ == '__main__':
    serve(reload=True, port=8000)

Jupyter Notebook Integration

# In Jupyter notebook cell
from fasthtml.common import *

# Create app for notebook development
app, rt = fast_app()

@rt('/')
def notebook_demo():
    return Div(
        H1("Jupyter Integration Demo"),
        P("This content is rendered directly in the notebook."),
        Form(
            Input(type="text", name="message", placeholder="Enter message"),
            Button("Submit", hx_post="/echo", hx_target="#output")
        ),
        Div(id="output")
    )

@rt('/echo', methods=['POST'])
def echo_message(message: str):
    return P(f"You said: {message}", style="color: green;")

# Display in notebook
show(notebook_demo())

# Start server for interactive development
nb_serve(port=8001)

Testing FastHTML Applications

from fasthtml.common import *
import pytest

# Create test app
app, rt = fast_app()

@rt('/')
def homepage():
    return Div("Welcome to FastHTML")

@rt('/api/users')
def list_users():
    return {"users": ["alice", "bob", "charlie"]}

@rt('/api/users', methods=['POST'])
def create_user(name: str, email: str):
    # Simulate user creation
    user_id = 123
    return {"id": user_id, "name": name, "email": email}, 201

@rt('/api/users/{user_id}')
def get_user(user_id: int):
    if user_id == 123:
        return {"id": 123, "name": "Test User", "email": "test@example.com"}
    else:
        return {"error": "User not found"}, 404

# Test functions
def test_homepage():
    client = Client(app)
    response = client.get('/')
    
    assert response.status_code == 200
    assert "Welcome to FastHTML" in response.text

def test_list_users():
    client = Client(app)
    response = client.get('/api/users')
    
    assert response.status_code == 200
    data = response.json()
    assert "users" in data
    assert len(data["users"]) == 3

def test_create_user():
    client = Client(app)
    response = client.post('/api/users', data={
        'name': 'John Doe',
        'email': 'john@example.com'
    })
    
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "John Doe"
    assert data["email"] == "john@example.com"
    assert "id" in data

def test_get_user_found():
    client = Client(app)
    response = client.get('/api/users/123')
    
    assert response.status_code == 200
    data = response.json()
    assert data["id"] == 123
    assert data["name"] == "Test User"

def test_get_user_not_found():
    client = Client(app)
    response = client.get('/api/users/999')
    
    assert response.status_code == 404
    data = response.json()
    assert "error" in data

# Run tests
if __name__ == '__main__':
    test_homepage()
    test_list_users()
    test_create_user()
    test_get_user_found()
    test_get_user_not_found()
    print("All tests passed!")

Advanced Testing with Fixtures

from fasthtml.common import *
import pytest
import tempfile
import os

# Test app with database
def create_test_app():
    # Use temporary database for testing
    db_path = tempfile.mktemp(suffix='.db')
    app, rt = fast_app(db=db_path)
    
    # Create test routes
    @rt('/')
    def homepage():
        return Titled("Test App", P("Homepage"))
    
    @rt('/users')
    def list_users():
        users = app.db.users.select().all() if hasattr(app.db, 'users') else []
        return {"users": [dict(u) for u in users]}
    
    @rt('/users', methods=['POST'])
    def create_user(name: str, email: str):
        # Create users table if it doesn't exist
        if not hasattr(app.db, 'users'):
            app.db.users.create({'name': str, 'email': str}, pk='id')
        
        user_id = app.db.users.insert({'name': name, 'email': email}).last_pk
        return {"id": user_id, "name": name, "email": email}
    
    return app, db_path

@pytest.fixture
def app_client():
    """Create app and client for testing."""
    app, db_path = create_test_app()
    client = Client(app)
    
    yield client
    
    # Cleanup
    if os.path.exists(db_path):
        os.remove(db_path)

def test_homepage_with_fixture(app_client):
    response = app_client.get('/')
    assert response.status_code == 200
    assert "Test App" in response.text

def test_user_crud_operations(app_client):
    # Test empty user list
    response = app_client.get('/users')
    assert response.status_code == 200
    assert response.json()["users"] == []
    
    # Create a user
    response = app_client.post('/users', data={
        'name': 'Alice Johnson',
        'email': 'alice@example.com'
    })
    assert response.status_code == 200
    user_data = response.json()
    assert user_data["name"] == "Alice Johnson"
    assert user_data["email"] == "alice@example.com"
    user_id = user_data["id"]
    
    # Verify user was created
    response = app_client.get('/users')
    assert response.status_code == 200
    users = response.json()["users"]
    assert len(users) == 1
    assert users[0]["name"] == "Alice Johnson"

Development with Live Reload

from fasthtml.common import *
import os

# Enable live reload in development
app, rt = fast_app(
    debug=True,
    live=True
)

@rt('/')
def development_page():
    # Show current file modification time for debugging
    current_file = __file__
    mod_time = os.path.getmtime(current_file) if os.path.exists(current_file) else 0
    
    return Titled("Live Reload Demo",
        Container(
            H1("Development with Live Reload"),
            P("This page will automatically refresh when you save changes."),
            P(f"File last modified: {mod_time}"),
            
            # Development info
            Details(
                Summary("Development Info"),
                Ul(
                    Li(f"Debug mode: {app.debug}"),
                    Li(f"Current file: {current_file}"),
                    Li("Try editing this file and saving - the page will reload!")
                )
            ),
            
            # Test different components
            Card(
                Header(H3("Live Development")),
                P("Add new content here and see it appear immediately."),
                Footer(
                    Button("Test Button", hx_get="/test-reload"),
                    Div(id="test-output")
                )
            )
        )
    )

@rt('/test-reload')
def test_reload():
    from datetime import datetime
    return P(f"Reloaded at {datetime.now()}", style="color: green;")

# Custom development middleware for debugging
def debug_middleware(request, call_next):
    import time
    start_time = time.time()
    
    response = call_next(request)
    
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    
    return response

# Add middleware in development
if app.debug:
    app.middleware('http')(debug_middleware)

# Start with live reload
if __name__ == '__main__':
    serve(
        reload=True,
        reload_includes=['*.py', '*.html', '*.css', '*.js'],
        port=8000
    )

Port Management and Server Control

from fasthtml.common import *
import asyncio

app, rt = fast_app()

@rt('/')
def homepage():
    return Titled("Port Management Demo",
        P("Server running with automatic port selection")
    )

def find_free_port(start_port=8000, max_attempts=100):
    """Find a free port starting from start_port."""
    for port in range(start_port, start_port + max_attempts):
        if is_port_free(port):
            return port
    raise RuntimeError(f"No free port found in range {start_port}-{start_port + max_attempts}")

def start_development_server():
    """Start server with automatic port selection."""
    try:
        port = find_free_port(8000)
        print(f"Starting server on port {port}")
        serve(port=port, reload=True)
    except RuntimeError as e:
        print(f"Error starting server: {e}")

async def start_async_server():
    """Start server asynchronously."""
    port = find_free_port(8000)
    
    # Wait for any existing server to shut down
    if not is_port_free(port):
        print(f"Waiting for port {port} to become free...")
        try:
            wait_port_free(port, timeout=10)
        except TimeoutError:
            port = find_free_port(port + 1)
    
    print(f"Starting async server on port {port}")
    server = JupyUviAsync(app, port=port)
    await server.start()
    return server

if __name__ == '__main__':
    # Choose startup method
    import sys
    if '--async' in sys.argv:
        asyncio.run(start_async_server())
    else:
        start_development_server()

Deployment Preparation

from fasthtml.common import *
import os

# Production-ready app configuration
app, rt = fast_app(
    debug=False,  # Disable debug in production
    secret_key=os.getenv('SECRET_KEY', 'fallback-secret-key'),
    session_cookie='secure_session',
    sess_https_only=True,  # HTTPS only in production
    pico=True,
    htmx=True
)

@rt('/')
def production_homepage():
    return Titled("FastHTML Production App",
        Container(
            H1("Production Ready"),
            P("This app is configured for production deployment."),
            Card(
                Header(H3("Features")),
                Ul(
                    Li("Secure session management"),
                    Li("HTTPS-only cookies"),
                    Li("Environment-based configuration"),
                    Li("Production optimizations")
                )
            )
        )
    )

@rt('/health')
def health_check():
    """Health check endpoint for load balancers."""
    return {"status": "healthy", "service": "fasthtml-app"}

# Deployment configuration
def get_deployment_config():
    return {
        'host': os.getenv('HOST', '0.0.0.0'),
        'port': int(os.getenv('PORT', 8000)),
        'workers': int(os.getenv('WORKERS', 1)),
        'reload': os.getenv('RELOAD', 'false').lower() == 'true',
        'log_level': os.getenv('LOG_LEVEL', 'info'),
    }

if __name__ == '__main__':
    config = get_deployment_config()
    
    # For Railway deployment
    if os.getenv('RAILWAY_ENVIRONMENT'):
        print("Deploying to Railway...")
        railway_deploy()
    else:
        # Local or other deployment
        serve(**config)

Install with Tessl CLI

npx tessl i tessl/pypi-python-fasthtml

docs

application-routing.md

authentication.md

css-styling.md

development-tools.md

form-handling.md

html-components.md

htmx-integration.md

index.md

javascript-integration.md

notifications.md

svg-components.md

tile.json