Build resilient widgets for private, distributed systems
The main class for creating file-backed widgets that automatically update in real-time. Widgets spawn local HTTP servers that watch files and serve live updates to the browser.
import syft_widget as sw
class MyWidget(sw.DynamicWidget):
def get_endpoints(self):
@self.endpoint("/api/data")
def get_data():
return {"value": "Hello World", "time": time.time()}
def get_template(self):
return '''
<div>
<h1>{value}</h1>
<span data-field="time">{time}</span>
</div>
'''
widget = MyWidget()
widget # Display in Jupyter
Initialize a new DynamicWidget instance. Creates the widget configuration and optionally starts a backend server to handle live updates.
widget_title | str, optional | Title for the widget (defaults to class name) |
server_name | str, optional | Unique server identifier (derived from title if not provided) |
start_infra | bool | Whether to start the server automatically (default: True) |
width | str | Widget width CSS value (default: "100%") |
height | str | Widget height CSS value (default: "60px") |
update_interval | int | Milliseconds between updates (default: 1000) |
dependencies | list[str], optional | Python packages to install in server environment |
force_new_server | bool | Replace existing server with same name (default: False) |
expiration_seconds | int | Server auto-cleanup time (default: 86400 = 24 hours) |
# Basic widget
widget = MyWidget()
# Custom configuration
widget = MyWidget(
widget_title="Dashboard",
height="400px",
update_interval=500, # Update every 500ms
dependencies=["pandas", "numpy"],
expiration_seconds=3600 # Clean up after 1 hour
)
Define the API endpoints for your widget. Use the @self.endpoint decorator to register functions that will be called to fetch data. This method must be overridden in subclasses.
No parameters |
None (registers endpoints via decorator) |
def get_endpoints(self):
@self.endpoint("/api/status")
def get_status():
return {"status": "running", "uptime": 3600}
@self.endpoint("/api/data")
def get_data():
# Read from files, databases, etc.
with open("data.json") as f:
return json.load(f)
Return the HTML template for your widget. Use {variable} placeholders for initial render and data-field="variable" attributes on elements for live updates.
No parameters |
str | HTML template string with placeholders |
def get_template(self):
return '''
<div class="widget-container">
<h2>System Status</h2>
<div>CPU: <span data-field="cpu">{cpu}</span>%</div>
<div>Memory: <span data-field="memory">{memory}</span>%</div>
<div>Updated: <span data-field="timestamp">{timestamp}</span></div>
</div>
'''
Decorator to register an endpoint function. Must be used inside get_endpoints(). The decorated function should return a dictionary of data.
path | str | URL path for the endpoint (e.g., "/api/data") |
def get_endpoints(self):
@self.endpoint("/api/metrics")
def get_metrics():
# This function will be called every update_interval
return {
"users": count_users(),
"requests": get_request_count(),
"errors": check_errors()
}
Access the underlying syft-serve server object. This provides access to server status, logs, and control methods.
Server or None | The syft-serve server handle if available |
# Access server logs
if widget.server:
print(widget.server.stdout.tail(20))
print(f"Status: {widget.server.status}")
print(f"URL: {widget.server.url}")
The unique identifier for this widget's server. Used to reuse servers across widget recreations.
str | Server name identifier |
The interval in milliseconds between automatic updates. Set during initialization.
int | Update interval in milliseconds |
Override to provide custom CSS styles for your widget. These styles are applied to all themes.
str | CSS styles as a string |
def _get_widget_styles(self):
return """
.widget-container {
padding: 20px;
border-radius: 8px;
font-family: monospace;
}
.metric {
font-size: 24px;
font-weight: bold;
}
"""
Override to provide CSS styles specific to light theme.
def _get_css_light(self):
return """
.widget-container {
background: #f0f0f0;
color: #333;
border: 1px solid #ddd;
}
"""
Override to provide CSS styles specific to dark theme.
def _get_css_dark(self):
return """
.widget-container {
background: #1e1e1e;
color: #e0e0e0;
border: 1px solid #444;
}
"""
Access logs through the widget's server property. Useful for debugging and monitoring.
# Get recent logs
if widget.server:
# Last 20 lines of stdout
print(widget.server.stdout.tail(20))
# Check for errors
errors = widget.server.stderr.tail(20)
if errors:
print("Errors found:", errors)
# Follow logs in real-time
for line in widget.server.stdout.follow():
print(line)
if "error" in line.lower():
break
Control the widget's server lifecycle through syft-serve integration.
import syft_serve as ss
# List all servers
ss.servers
# Access specific widget's server
server = ss.servers['my_widget_server']
# Terminate the server
server.terminate()
# Or terminate all servers
ss.servers.terminate_all()