Workspace¶
The Workspace class manages static and dynamic file serving with support for multiple
search paths (overlay), similar to how $PATH works for executables.
Overview¶
When assets are spread across multiple directories, Workspace provides a unified interface to serve them all:
from vuer import Vuer, Workspace
# Multiple search paths - first match wins (like $PATH)
workspace = Workspace("./assets", "/data/robots", "./fallback")
app = Vuer(workspace=workspace)
API Summary¶
Method |
Description |
|---|---|
|
Create workspace with overlay paths |
|
Access paths (read-only tuple) |
|
Find file in overlay |
|
Expose overlay at URL route |
|
Mount single directory |
|
Link callable to URL path |
Usage Examples¶
Basic Usage¶
from vuer import Vuer, Workspace
# Single path (simplest)
app = Vuer(workspace="./assets")
# Multiple paths - searched in order, first match wins
app = Vuer(workspace=["./local", "/shared/assets", "/data"])
# Explicit Workspace object
workspace = Workspace("./primary", "./fallback")
app = Vuer(workspace=workspace)
Overlay Behavior¶
The overlay works like $PATH - paths are searched in order:
workspace = Workspace("./local", "/shared", "/data")
# Request for /static/robot.urdf searches:
# 1. ./local/robot.urdf
# 2. /shared/robot.urdf
# 3. /data/robot.urdf
# Returns first match found
# Find a file programmatically
path = workspace.find("models/robot.urdf")
if path:
print(f"Found at: {path}")
Additional Mounts¶
Mount extra directories outside the overlay:
@app.spawn(start=True)
async def main(session):
# Mount uploads directory
app.workspace.mount("./uploads", to="/uploads")
# Mount exports at a different route
app.workspace.mount("/var/exports", to="/exports")
Dynamic Links¶
Serve dynamic content with functions:
from vuer import Vuer, Workspace
from vuer.workspace import jpg, png
@app.spawn(start=True)
async def main(session):
# JSON response (no request param needed)
app.workspace.link(lambda: {"status": "ok", "count": 42}, "/api/status")
# Serve in-memory images
app.workspace.link(lambda: jpg(camera.frame), "/live/frame.jpg")
app.workspace.link(lambda: png(depth_map), "/depth.png")
# With request param for query args
app.workspace.link(lambda r: render(r.query.get("id")), "/render.jpg")
# Async handler
async def get_data(request):
data = await fetch_from_db()
return {"data": data}
app.workspace.link(get_data, "/api/data")
# POST handler
app.workspace.link(handle_submit, "/api/submit", method="POST")
Custom MIME Types¶
Add custom MIME types for auto-detection in link() and static file serving:
from vuer.workspace import MIME_TYPES
# Add custom extensions
MIME_TYPES[".npy"] = "application/x-npy"
MIME_TYPES[".npz"] = "application/x-npz"
MIME_TYPES[".h5"] = "application/x-hdf5"
Future Workspace Types¶
The Workspace interface is designed for extensibility:
Workspace- Local filesystem (current)DashWorkspace- ML-Dash experiments (future)McapWorkspace- MCAP recordings (future)S3Workspace- S3 buckets (future)
All workspace types will share the same interface (overlay(), mount(), link()).