Write responsive web apps in full python
npx @tessl/cli install tessl/pypi-lona@1.16.0A comprehensive Python web application framework that enables developers to build responsive, interactive web applications entirely in Python without requiring separate JavaScript development. Lona provides a unified architecture where both server-side logic and client-side interactions are handled through Python code, using a specialized protocol that communicates between a Python backend and a JavaScript browser library.
pip install lonaimport lona
from lona import App, View, Request, Route, Channel, Bucket, MATCH_ALLCommon imports for HTML and responses:
from lona.html import HTML, H1, H2, P, Div, Button, Input, Form
from lona.responses import Response, HtmlResponse, JsonResponse, RedirectResponseEvent handling:
from lona.events import CLICK, CHANGE, FOCUS, BLURfrom lona import App, View
from lona.html import HTML, H1, Button, P
# Create the app
app = App(__file__)
# Define a simple view
@app.route('/')
class IndexView(View):
def handle_request(self, request):
return HTML(
H1('Welcome to Lona'),
P('This is a simple web application built with Python!')
)
# Define an interactive view
@app.route('/interactive')
class InteractiveView(View):
def handle_request(self, request):
click_count = 0
button = Button('Click me!')
counter = P(f'Clicks: {click_count}')
html = HTML(
H1('Interactive Example'),
counter,
button
)
self.show(html)
# Handle button clicks
while True:
self.await_click(button)
click_count += 1
counter.set_text(f'Clicks: {click_count}')
# Run the application
if __name__ == '__main__':
app.run(host='localhost', port=8080)Lona's architecture eliminates the traditional frontend/backend separation by providing:
This design allows Python developers to create full-stack web applications using familiar Python patterns while automatically handling client-server communication, DOM manipulation, and real-time updates.
Essential classes and patterns for building Lona web applications, including the main App class, View base class for handling requests and interactions, and Request objects containing HTTP data.
class App:
def __init__(self, script_path: str): ...
def route(self, raw_pattern: str | int, name: str = '', interactive: bool = True,
http_pass_through: bool = False, frontend_view=None): ...
def run(self, host: str = 'localhost', port: int = 8080, **kwargs): ...
class View:
def handle_request(self, request: 'Request'): ...
def show(self, html=None, template: str = None, template_string: str = None,
title: str = None, template_context: dict = None): ...
def await_click(self, *nodes, timeout=None): ...
def await_change(self, *nodes, timeout=None): ...
def send_str(self, string: str, broadcast: bool = False,
filter_connections=None, wait: bool = True): ...
def fire_view_event(self, name: str, data=None): ...
def subscribe(self, topic: str, handler, implicit_show: bool = True): ...
def ping(self) -> str: ...
class Request:
GET: dict
POST: dict
method: str
url: str
user: object
id: str
interactive: bool
server: 'Server'
route: 'Route'
match_info: dictComprehensive HTML element system with 60+ node classes covering all HTML5 elements, plus utilities for HTML parsing and document building. All HTML elements support event handling and real-time updates.
def HTML(*args, **kwargs) -> 'Node': ...
class Node:
def __init__(self, *args, **kwargs): ...
def set_text(self, text: str): ...
def append(self, *nodes): ...
# Document structure
class Html(Node): ...
class Head(Node): ...
class Body(Node): ...
class Title(Node): ...
# Common elements
class H1(Node): ...
class P(Node): ...
class Div(Node): ...
class Button(Node): ...
class Input(Node): ...Various response classes for different content types and HTTP behaviors, including HTML responses, JSON responses, template responses, file downloads, and redirects.
class Response:
def __init__(self, content: str = '', status: int = 200, headers: dict = None): ...
class HtmlResponse(Response):
def __init__(self, html, status: int = 200, headers: dict = None): ...
class JsonResponse(Response):
def __init__(self, json_data, status: int = 200, headers: dict = None): ...
class RedirectResponse(Response):
def __init__(self, redirect_url: str): ...
class FileResponse(Response):
def __init__(self, path: str, content_type: str = None, as_attachment: bool = False): ...Event system for handling user interactions including clicks, form changes, focus events, and custom events. Supports both synchronous and asynchronous event handling patterns.
# Event constants
CLICK: int
CHANGE: int
FOCUS: int
BLUR: int
class InputEvent:
def __init__(self, event_type, node, data: dict = None): ...
# View event methods
def await_input_event(self, *nodes, timeout=None) -> 'InputEvent': ...
def await_click(self, *nodes, timeout=None) -> 'InputEvent': ...
def await_change(self, *nodes, timeout=None) -> 'InputEvent': ...
def fire_view_event(self, name: str, data=None): ...Pub/sub messaging system for communication between views, background tasks, and external services. Supports topic-based messaging with message expiry and local/broadcast modes.
class Channel:
def __init__(self, topic: str): ...
def subscribe(self, handler): ...
def unsubscribe(self): ...
def send(self, message_data=None, expiry=None, local: bool = False): ...
class Message:
topic: str
data: object
timestamp: floatSecure file upload and download system using bucket containers with configurable limits, automatic URL generation, and integration with view lifecycle.
class Bucket:
def __init__(self, request, max_files: int = None, max_size: int = None,
index: bool = True, on_add=None, on_delete=None): ...
def get_path(self, file_name: str = '') -> str: ...
def get_url(self, file_name: str = '') -> str: ...
def get_file_names(self) -> list: ...
def get_size(self) -> int: ...
def get_add_url(self) -> str: ...
def get_delete_url(self, file_name: str) -> str: ...URL routing system with pattern matching, named routes, and support for both interactive and non-interactive views. Includes route decorators and programmatic route registration.
class Route:
def __init__(self, raw_pattern: str, view, name: str = '',
interactive: bool = True, http_pass_through: bool = False): ...
# Route matching constant (value = 1)
MATCH_ALL: int
# App routing methods
def route(self, raw_pattern: str | int, name: str = '', interactive: bool = True,
http_pass_through: bool = False, frontend_view=None): ...
def add_route(self, route: 'Route'): ...Static file management system for CSS, JavaScript, images, and other assets with automatic URL generation, dependency ordering, and development/production optimization.
class StaticFile:
def __init__(self, name: str, path: str = '', string: str = ''): ...
class StyleSheet(StaticFile): ...
class Script(StaticFile): ...
# Sort order constants
class SORT_ORDER:
FRAMEWORK: int
LIBRARY: int
APPLICATION: intException and error handling classes for view lifecycle management, HTTP errors, and custom error responses with built-in error view support.
# View control exceptions
class StopReason(Exception): ...
class UserAbort(StopReason): ...
class ServerStop(StopReason): ...
# HTTP error classes
class ForbiddenError(Exception): ...
class NotFoundError(Exception): ...
class ClientError(Exception): ...# Package version information
VERSION: tuple # Version tuple (major, minor, patch)
VERSION_STRING: str # Version as string (e.g., "1.16.2")
# Route matching
MATCH_ALL: int = 1 # Matches any URL pattern# Core type definitions used across capabilities
from typing import Union, Optional, Dict, List, Callable, Any
NodeContent = Union[str, int, float, 'Node']
HTMLContent = Union[NodeContent, List[NodeContent]]
EventHandler = Callable[['InputEvent'], None]
ChannelHandler = Callable[['Message'], None]
ViewHandler = Callable[['Request'], Any]
MiddlewareHandler = Callable[['Request'], 'Request']