Pyodide WASM Integration
Purpose and Scope
This document details the client-side Python execution system powered by Pyodide WebAssembly. The system enables timetable generation logic to run entirely in the browser without requiring a backend server. This page covers Pyodide initialization, Python module loading, function invocation, and type conversion between JavaScript and Python.
For information about the Python timetable generation algorithms themselves, see Python Processing Pipeline. For how schedule generation is orchestrated at the application level, see Schedule Generation.
System Overview
The Pyodide integration consists of three main components:
| Component | Location | Purpose |
|---|---|---|
| Initialization Layer | src/utils/pyodide.ts23-58 | Loads Pyodide runtime from CDN and initializes Python environment |
| Python Modules | public/_creator.py public/modules/BE62_creator.py public/modules/BE128_creator.py | Contains timetable parsing and generation logic |
| Function Bridge | src/utils/pyodide.ts91-109 | Converts JavaScript data to Python objects and calls Python functions |
Pyodide Instance Management
The system maintains a single global Pyodide instance to avoid repeated loading overhead. The instance lifecycle is managed through module-level variables in src/utils/pyodide.ts6-10:
let pyodideInstance: PyodideInterface | null = null;
let pyodideLoading = false;
let pyodideLoaded = false;
let pyodideError: Error | null = null;
let listeners: (() => void)[] = [];
Sources: src/utils/pyodide.ts1-82
Initialization Flow

Initialization Steps
-
Check Existing State src/utils/pyodide.ts24-35
- Returns cached
pyodideInstanceif already loaded - Waits for completion if loading is in progress
- Prevents duplicate initialization
- Returns cached
-
Load Pyodide Runtime src/utils/pyodide.ts39-44
- Dynamic import from
'pyodide'package - Loads WASM runtime from
https://cdn.jsdelivr.net/pyodide/v0.27.0/full/ - Uses
fullStdLib: falseto reduce download size (~10MB vs ~50MB)
- Dynamic import from
-
Fetch Python Module src/utils/pyodide.ts15-21 src/utils/pyodide.ts45
- Fetches
/_creator.pyfrom public directory - Module URL defined in src/utils/pyodide.ts13:
const pythonModuleURL = '/_creator.py'
- Fetches
-
Execute Python Code src/utils/pyodide.ts46
- Calls
pyodideInstance.runPython(pythonCode) - Functions become available in
pyodide.globals - Includes functions:
time_table_creator,time_table_creator_v2,bca_creator,bca_creator_year1,banado128,bando128_year1,compare_timetables
- Calls
Sources: src/utils/pyodide.ts23-58 src/utils/pyodide.ts15-21
Python Module Architecture
The Python timetable generation logic is organized across multiple modules:

Function Selection Logic
The application dynamically selects which Python function to call based on campus and year parameters in src/App.tsx115-152:
| Campus | Year | Function Name | Location |
|---|---|---|---|
| 62 | 1 | time_table_creator |
public/_creator.py423-531 |
| 62 | 2-4 | time_table_creator_v2 |
public/_creator.py949-1015 |
| 128 | 1 | bando128_year1 |
public/_creator.py817-883 |
| 128 | 2-4 | banado128 |
public/_creator.py739-815 |
| BCA | 1 | bca_creator_year1 |
public/_creator.py1018-1084 |
| BCA | 2-3 | bca_creator |
public/_creator.py1087-1153 |
Sources: src/App.tsx115-152 public/_creator.py423-531 public/_creator.py739-883 public/_creator.py949-1153
Function Invocation Pipeline

Type Conversion Layer
The callPythonFunction in src/utils/pyodide.ts91-109 handles bidirectional type conversion:
JavaScript to Python src/utils/pyodide.ts99-102:
const pyTimeTable = pyodide.toPy(args.time_table_json);
const pySubjects = pyodide.toPy(args.subject_json);
const pyBatch = pyodide.toPy(args.batch);
const pyElectives = pyodide.toPy(args.electives_subject_codes);
Python to JavaScript src/utils/pyodide.ts104:
return result.toJs();
Function Arguments Interface
The TypeScript interface defines the expected structure in src/utils/pyodide.ts84-89:
interface PythonFunctionArgs {
time_table_json: YourTietable,
subject_json: Subject[],
batch: string,
electives_subject_codes: string[]
}
Sources: src/utils/pyodide.ts91-109 src/utils/pyodide.ts84-89 src/App.tsx115-152
Status Tracking System
The Pyodide integration provides a React hook for tracking initialization status:

Status Hook Implementation
The usePyodideStatus hook in src/utils/pyodide.ts64-82 provides reactive status updates:
export function usePyodideStatus() {
const [status, setStatus] = useState<{
loading: boolean;
loaded: boolean;
error: Error | null;
}>({ loading: pyodideLoading, loaded: pyodideLoaded, error: pyodideError });
useEffect(() => {
const cb = () => {
setStatus({ loading: pyodideLoading, loaded: pyodideLoaded, error: pyodideError });
};
listeners.push(cb);
return () => {
listeners = listeners.filter((l) => l !== cb);
};
}, []);
return status;
}
Usage in Application
Initialization Trigger src/App.tsx111-113:
React.useEffect(() => {
initializePyodide();
}, []);
Conditional Loading src/App.tsx183-185:
if (!pyodideLoaded) {
await initializePyodide();
}
Status Check src/App.tsx102:
const { loaded: pyodideLoaded } = usePyodideStatus();
Sources: src/utils/pyodide.ts64-82 src/App.tsx102 src/App.tsx111-113 src/App.tsx183-185
Error Handling
The system implements multiple error handling strategies:
Initialization Errors
Errors during Pyodide loading are captured and stored in src/utils/pyodide.ts52-57:
catch (err) {
pyodideError = err as Error;
pyodideLoading = false;
notifyListeners();
throw err;
}
Function Invocation Errors
Errors during Python function calls are logged and re-thrown in src/utils/pyodide.ts105-108:
catch (error) {
console.error('Error calling Python function:', error);
throw error;
}
Function Validation
The system validates Python function existence before invocation in src/utils/pyodide.ts94-98:
const pythonFunction = pyodide.globals.get(functionName);
if (!pythonFunction || typeof pythonFunction !== 'function') {
console.error('Available globals:', Object.keys(pyodide.globals.toJs()));
throw new Error(`Function ${functionName} is not a valid Python function`);
}
Sources: src/utils/pyodide.ts52-57 src/utils/pyodide.ts94-98 src/utils/pyodide.ts105-108
Performance Considerations
Cold Start Performance
| Phase | Duration | Description |
|---|---|---|
| CDN Download | ~3-5 seconds | Downloads ~10MB Pyodide WASM runtime |
| WASM Compilation | ~1-2 seconds | Browser compiles WebAssembly modules |
| Python Module Load | ~100-200ms | Fetches and executes _creator.py |
| First Execution | ~500ms-1s | Initial Python function execution |
| Subsequent Executions | ~50-150ms | Cached and optimized |
Optimization Strategies
-
Reduced Standard Library src/utils/pyodide.ts43
- Sets
fullStdLib: falseto minimize download size - Only essential packages loaded
- Sets
-
Global Instance Caching src/utils/pyodide.ts6
- Single
pyodideInstancereused across all function calls - Eliminates repeated initialization overhead
- Single
-
Listener Pattern src/utils/pyodide.ts60-62
- Notifies React components of status changes
- Prevents polling or repeated checks
-
Double Execution Workaround src/App.tsx194-204
- First execution may be slower; runs twice initially
- Ensures proper WASM optimization
Sources: src/utils/pyodide.ts6 src/utils/pyodide.ts41-44 src/utils/pyodide.ts60-62 src/App.tsx194-204
Integration Points
Main Application Flow

External Module Loading
The system can be extended to load additional Python modules. Currently, only _creator.py is loaded, but the architecture in src/utils/pyodide.ts15-21 supports fetching multiple modules:
async function fetchPythonCode(url: string): Promise<string> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch Python module from ${url}: ${response.statusText}`);
}
return response.text();
}
Sources: src/App.tsx154-229 src/App.tsx115-152 src/utils/pyodide.ts91-109 src/utils/pyodide.ts15-21
Summary
The Pyodide WASM integration provides a serverless architecture by executing Python timetable generation logic directly in the browser. Key characteristics:
- Single Global Instance: Cached
pyodideInstanceeliminates repeated initialization - Dynamic Function Selection: Routes to appropriate Python function based on campus/year
- Type Safety: TypeScript interfaces define function arguments and ensure type correctness
- Reactive Status:
usePyodideStatushook enables UI to respond to loading states - Optimized Loading:
fullStdLib: falsereduces initial payload size
This architecture eliminates the need for a backend server while maintaining full Python compatibility for complex timetable parsing and generation algorithms.
Sources: src/utils/pyodide.ts1-109 src/App.tsx102-229 public/_creator.py