A Client-Side Browser-Based Python Playground.
Client Side Python is a browser-based Python playground powered by Pyodide.
All Python code runs entirely inside your browser tab (WebAssembly, no backend), so your code never leaves your machine.
This makes it useful for:
- Quickly trying out small Python snippets
- Demonstrating Python basics in a classroom or workshop
- Experimenting with simple numeric or scripting tasks in a safe sandbox
- Showing how WebAssembly + Pyodide can bring “real” Python to the browser
-
Fully client-side execution
- Uses Pyodide to run CPython in WebAssembly.
- No server, no database, no authentication required by default.
-
Simple code editor + console
- Text area for Python code.
- Console area that shows
stdoutandstderr. - Buttons: Run, Stop, Clear, Load Sample, Copy Output.
-
Soft “Stop” mechanism
- Execution is wrapped with a soft cancel token.
- When you press Stop, the current run is logically cancelled so that late results are ignored instead of breaking the UI.
-
Responsive web UI
- Built with Expo / React Native Web and Material UI components.
- Layout adapts to different viewport sizes (desktop / tablet).
-
Deterministic CI via Docker
- Jest tests run in a Docker container using
docker-compose.test.yml. - GitHub Actions workflows are provided for CI and Docker-based testing.
- Jest tests run in a Docker container using
-
Automatic deployment to GitHub Pages
- GitHub Actions workflow builds the Expo web bundle and publishes it to GitHub Pages for the
mainbranch.
- GitHub Actions workflow builds the Expo web bundle and publishes it to GitHub Pages for the
On first load, the app:
- Fetches Pyodide from a CDN.
- Initializes the Pyodide runtime and exposes
runPythonAsync. - Attaches custom handlers for
stdoutandstderrso that Python output is streamed into the in-page console. - Uses a simple execution token to implement a soft Stop:
- Each run increments an internal
execId. - If a run finishes with an outdated
execId, its output is discarded. - This prevents stale results from older runs from polluting the console.
- Each run increments an internal
All of this happens in the browser, without any backend API calls.
# set environment variables:
export REACT_NATIVE_PACKAGER_HOSTNAME=${YOUR_HOST}
# Build the image
docker compose build
# Run the container
docker compose updocker compose \
-f docker-compose.test.yml up \
--build --exit-code-from \
frontend_test - Apache License 2.0
