Core functionality for managing WebAssembly workers that execute Python code through Pyodide integration. The WorkerProxy class provides a complete interface for initializing, communicating with, and managing web workers.
The main class for managing WebAssembly workers and Python code execution. Extends EventTarget for event-driven communication.
/**
* Main class for managing WebAssembly workers and Python code execution
* Extends EventTarget for event-driven communication patterns
*/
class WorkerProxy extends EventTarget {
/**
* Create a new WorkerProxy instance
* @param options - Configuration options for the worker
*/
constructor(options: WorkerProxyOptions);
/** The underlying worker instance (either dedicated or shared) */
readonly worker: globalThis.Worker | globalThis.SharedWorker;
/** Message target for communication with the worker */
readonly postMessageTarget: globalThis.Worker | MessagePort;
/**
* Execute Python code in the worker
* @param code - Python code string to execute
* @returns Promise that resolves when execution completes
*/
runPythonCode(code: string): Promise<void>;
/**
* Execute a Python file in the worker
* @param path - Path to the Python file to execute
* @returns Promise that resolves when execution completes
*/
runPythonFile(path: string): Promise<void>;
/**
* Send a message to the worker and wait for a response
* @param msg - Message to send to the worker
* @returns Promise that resolves with the worker's response
*/
postMessageAsync<T>(msg: InMessage): Promise<T>;
/**
* Initialize an ASGI connection for HTTP request handling
* @param scope - ASGI scope object containing request metadata
* @returns MessagePort for bidirectional communication
*/
requestAsgi(scope: Record<string, unknown>): MessagePort;
/**
* Make an HTTP request through the worker
* @param request - HTTP request object with method, path, headers, and body
* @returns Promise that resolves with the HTTP response
*/
httpRequest(request: HttpRequest): Promise<HttpResponse>;
/**
* Write a file to the worker's filesystem
* @param path - File path in the worker filesystem
* @param data - File data as string or binary data
* @param opts - Optional file writing options
* @returns Promise that resolves when file is written
*/
writeFile(path: string, data: string | ArrayBufferView, opts?: Record<string, unknown>): Promise<void>;
/**
* Rename a file in the worker's filesystem
* @param oldPath - Current file path
* @param newPath - New file path
* @returns Promise that resolves when file is renamed
*/
renameFile(oldPath: string, newPath: string): Promise<void>;
/**
* Delete a file from the worker's filesystem
* @param path - Path to the file to delete
* @returns Promise that resolves when file is deleted
*/
unlink(path: string): Promise<void>;
/**
* Install Python packages in the worker environment
* @param requirements - Array of package names to install
* @returns Promise that resolves when packages are installed
*/
install(requirements: string[]): Promise<void>;
/**
* Get code completions for Python code
* @param request - Code completion request with code, line, and column
* @returns Promise that resolves with completion suggestions
*/
getCodeCompletions(request: CodeCompletionRequest): Promise<CodeCompletionResponse>;
/**
* Terminate the worker and clean up resources
*/
terminate(): void;
}
/**
* Configuration options for WorkerProxy constructor
*/
interface WorkerProxyOptions {
/** URL to the Gradio wheel file for installation */
gradioWheelUrl: string;
/** URL to the Gradio client wheel file for installation */
gradioClientWheelUrl: string;
/** Files to make available in the worker filesystem */
files: Record<string, EmscriptenFile | EmscriptenFileUrl>;
/** Python packages to install during initialization */
requirements: string[];
/** Whether to use SharedWorker instead of DedicatedWorker */
sharedWorkerMode: boolean;
}Usage Examples:
import { WorkerProxy } from "@gradio/wasm";
// Create a worker with configuration
const worker = new WorkerProxy({
gradioWheelUrl: "https://example.com/gradio-4.0.0-py3-none-any.whl",
gradioClientWheelUrl: "https://example.com/gradio_client-1.0.0-py3-none-any.whl",
files: {
"data.json": {
data: JSON.stringify({ users: ["Alice", "Bob"] }),
opts: { encoding: "utf8" }
}
},
requirements: ["numpy", "pandas", "matplotlib"],
sharedWorkerMode: false
});
// Listen for initialization events
worker.addEventListener("initialization-completed", () => {
console.log("Worker initialized successfully");
});
worker.addEventListener("initialization-error", (event) => {
console.error("Worker initialization failed:", event.data);
});
// Execute Python code
await worker.runPythonCode(`
import json
import numpy as np
# Load data from virtual filesystem
with open('data.json', 'r') as f:
data = json.load(f)
print(f"Loaded {len(data['users'])} users")
# Use installed packages
arr = np.array([1, 2, 3, 4, 5])
print(f"NumPy array mean: {np.mean(arr)}")
`);
// Make HTTP requests through the worker
const response = await worker.httpRequest({
method: "POST",
path: "/api/predict",
query_string: "version=1",
headers: { "Content-Type": "application/json" },
body: new TextEncoder().encode(JSON.stringify({ input: "test" }))
});
console.log("Response status:", response.status);
console.log("Response body:", new TextDecoder().decode(response.body));
// Clean up
worker.terminate();WorkerProxy emits various events during its lifecycle and operation:
// Event types emitted by WorkerProxy
interface WorkerEvents {
/** Fired when worker initialization is completed successfully */
"initialization-completed": CustomEvent<void>;
/** Fired when worker initialization fails */
"initialization-error": CustomEvent<{ error: string }>;
/** Fired when worker reports progress updates */
"progress-update": CustomEvent<{ message: string; progress?: number }>;
/** Fired when Python modules are automatically loaded */
"modules-auto-loaded": CustomEvent<{ modules: string[] }>;
/** Fired when Python code writes to stdout */
"stdout": CustomEvent<{ data: string }>;
/** Fired when Python code writes to stderr */
"stderr": CustomEvent<{ data: string }>;
/** Fired when Python code execution encounters an error */
"python-error": CustomEvent<{ error: string; traceback: string }>;
}Event Handling Example:
import { WorkerProxy } from "@gradio/wasm";
const worker = new WorkerProxy(options);
// Handle all output events
worker.addEventListener("stdout", (event) => {
console.log("Python stdout:", event.data);
});
worker.addEventListener("stderr", (event) => {
console.warn("Python stderr:", event.data);
});
worker.addEventListener("python-error", (event) => {
console.error("Python error:", event.error);
console.error("Traceback:", event.traceback);
});
worker.addEventListener("progress-update", (event) => {
console.log("Progress:", event.message);
if (event.progress !== undefined) {
console.log(`Progress: ${event.progress}%`);
}
});Types for file handling in the worker environment:
/**
* File with inline data content
*/
interface EmscriptenFile {
/** File content as string or binary data */
data: string | ArrayBufferView;
/** Optional file system options */
opts?: Record<string, unknown>;
}
/**
* File with remote URL content
*/
interface EmscriptenFileUrl {
/** URL to fetch file content from */
url: string;
/** Optional file system options */
opts?: Record<string, unknown>;
}Internal message types used for worker communication:
/**
* Union type of all input messages sent to the worker
*/
type InMessage =
| InMessageInitEnv
| InMessageInitApp
| InMessageRunPythonCode
| InMessageRunPythonFile
| InMessageAsgiRequest
| InMessageFileWrite
| InMessageFileRename
| InMessageFileUnlink
| InMessageInstall
| InMessageCodeCompletion;
/**
* Initialize environment message
*/
interface InMessageInitEnv {
type: "init-env";
config: {
gradioWheelUrl: string;
gradioClientWheelUrl: string;
files: Record<string, EmscriptenFile | EmscriptenFileUrl>;
requirements: string[];
};
}
/**
* Run Python code message
*/
interface InMessageRunPythonCode {
type: "run-python-code";
code: string;
}
/**
* Run Python file message
*/
interface InMessageRunPythonFile {
type: "run-python-file";
path: string;
}