Deployment: pycodepractice.lukemao.site
PyCodePractice is a full-stack, LeetCode-style online Python coding platform designed for learning, practice, and performance analysis.
The platform allows users to solve coding challenges through a browser-based editor, submit code, receive feedback on time and memory usage, and compare their submissions through a public leaderboard. Each submission is executed securely in a sandboxed Docker container with enforced time and memory limits.
To support learning, PyCodePractice includes an integrated AI tutor powered by OpenAI’s GPT-4o mini model. The tutor guides users through step-by-step hints without giving away full solutions, encouraging logical thinking and independent problem solving.
Admins can create, test, and upload new coding problems using a structured offline template workflow. The backend features analytics for monitoring user activity, submission trends, and per-problem execution statistics. All core services — code execution, forum, user management, and AI messaging — are containerized using Docker and orchestrated via Docker Compose.
Admin:
- login, logout
- create, update, delete problems
- deactivate / activate user accounts
- see analytics on the submission, AI tutor usage, and time and memory usage of each problem
- view & edit admin profile
User:
- login, logout, register
- view problems, submit solutions
- view submission ranking
- view all submissions
- post comments on problem forums
- talk to AI tutor (gpt-4o mini model)
- view & edit profile
- view submission frequency plots
-
Git clone or download the code zip from Github Link
-
Open
Docker Desktop
. -
Run docker compose in the root folder.
# build a python:3.10-slim-time image with the time module, this is for the backend sandbox docker build -t python:3.10-slim-time ./backend/examples/sandbox # build the frontend under the development mode cd frontend npm install npm run build:dev # go back to the root folder cd .. # run the docker compose docker-compose up --build --force-recreate
-
Create the
.env
file with theOPENAI_API_KEY
variable in thebackend
folder. This key is used to access the OpenAIGPT-4o-mini
model. You can get the key from the OpenAI API platform.# open a terminal and go to the backend folder cd backend echo "OPENAI_API_KEY=your_openai_api_key" > .env
This
.env
file is excluded from the git tracking. So you need to create it manually.Note: In order to use the github actions, you also need to create a repository secret called
OPENAI_API_KEY
in the repo settings. You can do this by going to the repo settings -> secrets and variables -> actions -> new repository secret. The same api key can be used for both local and github actions. -
Check the
Docker Desktop
, wait until 2 services are up.Then open the browser and go to http://localhost:80.
-
Some existing user accounts:
Username Email Password Role Admin Admin@mail.com Abcd1234! Admin Tom Tom@mail.com Abcd1234! User Alice Alice@mail.com Abcd1234! User John John@mail.com Abcd1234! User Emily Emily@mail.com Abcd1234! User
The folder ./materials has provided 2 sets of new challenge materials. The admin can upload the materials.
-
Git clone the repository to local:
https://github.com/luke-mao/pycodepractice.git
-
At the root folder, open a terminal and install the dependencies for the commitlint and husky. These are for the commit message hook and linting.
npm install npx husky
-
Open
Docker Desktop
and make sure it is running during the development. The backend start file will also check whether theDocker
is running. -
Go to the backend folder, and install the dependencies. The backend will be running on http://localhost:9000. And hte backend docs is available at http://localhost:9000/docs.
cd backend docker build -t python:3.10-slim-time sandbox-example pip install -r requirements.txt python app.py # if using mac pip3 install -r requirements.txt python3 app.py
-
Go to the frontend folder, and install the dependencies for the frontend. By using
npm run dev
, the frontend will be running on http://localhost:5173.cd frontend npm install npm run dev
Keep the two terminals running to keep the backend and frontend running.
Tests have been written for the backend. Please follow the instructions in backend/README.md of the section Running Tests
to run the tests. Please ensure that you reset the database before and after running the tests.
The frontend sends the user's code submission to the backend for execution. We will first perform a syntax check and a function signature check before storing and executing the code.
Our platform includes a secure sandbox environment to execute user-submitted code in an isolated Docker container. This ensures controlled execution, prevents security risks, and limits resource usage.
Example in backend/sandbox-example folder
-
Syntax Check
Before executing the user submission, the system checks whether the submitted code is syntactically valid using Python’s built-in compile() function.
This prevents immediate syntax errors from being executed inside the sandbox.
If compilation fails, the system rejects the submission and provides the user with a detailed syntax error message.
-
Function Signature Check
To ensure users follow the required function name and parameter structure, the system extracts function definitions using Python’s ast module.
The submitted function is compared against the problem’s submission template to verify:
- The correct function name is implemented.
- The correct number and names of parameters are used.
And the additional helper function written by the user will not affected the check.
-
User Submission (Stored in Database)
When a user submits code, it is stored in raw text format inside the database.
-
Generating the Execution Files
Before execution, the system writes the user’s code into a Python file called
user_submission.py
.Each problem has an associated test case file (
testcase.py
), prepared by the admin when creating the problem.The
testcase.py
file imports the user's function, renaming it touser_submission()
so thatrun.py
can execute it generically. -
Running the Test Cases -
run.py
:Runs each test case.
Enforces a 5-second execution time limit using Python’s
signal
library.Captures pass, fail, or timeout results and prints them to
stdout
. -
Pre-built
python:3.10-slim-time
Docker Image for Sandbox ExecutionInstead of installing dependencies (like
/usr/bin/time
) every time the sandbox runs, we use a pre-built custom Docker image calledpython:3.10-slim-time
.The image is built before running the backend service and is used to execute all sandbox containers.
This ensures faster execution and avoids unnecessary package installations inside every new container.
To build the
python:3.10-slim-time
image, run:docker build -t python:3.10-slim-time ./backend/sandbox-example
Once built, this image is used for all sandbox executions.
-
Sandbox Execution in Docker -
sandbox.py
:Creates a temporary folder using the Python's
tempfile
library.Copies
user_submission.py
,testcase.py
, andrun.py
into the folder.Mounts this folder inside a Docker container running
python:3.10-slim
.Executes
run.py
inside Docker and capturesstdout
andstderr
. Also use thetime
module andmemory.usage_in_bytes
to monitor the resource usage. The full command is:sh -c '/usr/bin/time -p python3 run.py && echo memory $(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)'
When the container finishes, all the logs are extracted and use python
re
module to extract the case results, real time, and memory usage.Once execution finishes, the Docker container is removed, ensuring a clean and secure environment.
-
Backend Integration
The backend server runs inside a Docker container.
To allow sandbox execution inside Docker, the backend container is granted access to the host’s Docker engine using:
volumes: - /var/run/docker.sock:/var/run/docker.sock
This ensures the backend can spawn and control sandbox containers without requiring full Docker-in-Docker (DinD).
Why Use a Pre-built python3:10-slim-time
Image?
The pre built imsage is ~192MB. It is built upon the python:3.10-slim image, which is a lightweight Python image. The time
module is not in that image, so we need to install it.
Feature | Detail |
---|---|
Faster Execution | Eliminates the need to install /usr/bin/time inside each new container. |
Optimized Performance | Reduces unnecessary package installations, keeping the container small. |
Reproducibility | Ensures all sandbox containers run with a consistent Python environment. |
Security & Isolation | Prevents modifications inside the sandbox from affecting the backend. |
Why Use a Docker-Based Sandbox?
Feature | Detail |
---|---|
Security | Prevents malicious code from affecting the host system. |
Isolation | Each submission runs in a clean, temporary environment. |
Resource Control | Limits execution time (5s), memory (1GB), and CPU usage (1 core). |
Automatic Cleanup | Containers are deleted after execution to free resources. |