Generic code evaluation in isolated Docker containers
Project description
docker-evaluator
A code evaluation backend for competitive programming judges. Runs untrusted submissions in isolated Docker containers, enforces time and memory limits, and checks output against expected results — similar to how Codeforces/CodeChef judge submissions.
Supports Python 2/3, C, and C++.
Requirements
- Docker (running and accessible to the current user)
- Python 3.9+
Installation
pip install docker-evaluator
Usage
from docker_evaluator import DockerEvaluator
evaluator = DockerEvaluator()
result = evaluator.evaluate(
code='n = int(input()); print(n * 2)',
input="21",
expected_output="42",
language="py3",
time_limit=1,
memory_limit=256 * 1024, # 256 MB in KB
)
print(result)
# {'correct': True, 'details': 'OK (8ms)'}
evaluator.close()
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
code |
str |
— | Submission source code |
input |
str |
— | Problem input (stdin or file content) |
expected_output |
str |
— | Correct output to compare against |
language |
str |
— | "py3", "py2", "c", or "cpp" |
time_limit |
int |
— | Time limit in seconds |
input_type |
str |
"stdin" |
"stdin" or "file" |
file_io_name |
str |
"" |
File name when using file I/O (e.g. "input.txt") |
memory_limit |
int |
1024 |
Memory limit in KB (minimum enforced: 256 MB) |
Return value
{"correct": bool, "details": str}
details is one of:
OK (Xms)— acceptedWrong AnswerTime Limit ExceededMemory Limit ExceededRuntime Error (exit code N)Compilation Error
Supported languages
| Key | Language |
|---|---|
py3 |
Python 3 |
py2 |
Python 2 |
c |
C |
cpp |
C++ |
Docker images are built automatically on first use and cached for subsequent runs.
File I/O
For problems that read/write files instead of stdin/stdout:
result = evaluator.evaluate(
code=open("solution.cpp").read(),
input="5\n1 2 3 4 5",
expected_output="15",
language="cpp",
time_limit=2,
input_type="file",
file_io_name="input.txt",
)
Configuration
Create a .env file in your working directory:
| Variable | Default | Description |
|---|---|---|
KEEP_EVAL_CONTAINERS |
0 |
Set to 1 to keep containers after a run (useful for debugging) |
ENVIRONMENT |
— | If set, also loads .env.<ENVIRONMENT> |
How It Works
- The submission is written to a temporary directory
- A language-specific Docker image is built (once) and cached for subsequent runs
- A container is started with the submission mounted read-only
- Resource limits (CPU, memory, PID count) are applied before execution
- The code is compiled (if needed) and executed inside the container with no network access
- Output is captured and compared against expected output
- The container is removed after execution
Security Model
- Code runs inside isolated Docker containers with no network access
- No access to the host filesystem outside the mounted read-only workspace
- Containers are ephemeral and removed after execution
- Resource limits prevent abuse (memory exhaustion, fork bombs, infinite loops)
- PID limit (64) restricts process spawning inside the container
Note: This is not a fully hardened sandbox and should not be exposed directly to the internet without additional isolation (e.g. VM-level sandboxing). Docker isolation has known escape vectors in misconfigured environments.
Design Decisions
Why Docker? Provides portable, language-agnostic process isolation without requiring a VM. Adding a new language is as simple as writing a Dockerfile and entrypoint script.
Why cache compilation? Compiled languages (C, C++) are recompiled only when the source changes. Repeated evaluations of the same submission skip compilation entirely, reducing latency significantly in judge workloads.
Why a synchronous API? Keeps integration simple. The library can be wrapped in an async worker or job queue by the caller without imposing an execution model.
Limitations
- Not a fully secure sandbox — Docker isolation has known escape risks in misconfigured environments
- No distributed execution (single-machine only)
- No built-in concurrency control or request queuing
- Memory limit enforcement has a minimum floor of 256 MB (Docker constraint)
Compilation cache
C and C++ submissions are cached by source hash — repeated evaluations of the same code skip recompilation. To clear the cache:
from docker_evaluator import clear_cache
clear_cache()
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file docker_evaluator-0.1.2.tar.gz.
File metadata
- Download URL: docker_evaluator-0.1.2.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf2c0846309422bd0084f22e7e0328890d42ade8c62485b1d0c48ab185da2e01
|
|
| MD5 |
6b80c4a7e1fadaa5357a1e443d6b0971
|
|
| BLAKE2b-256 |
7ba8c983aac9a1c9de35f09bce1c1962bb08ccdaec3226349e47076f14dee7e7
|
File details
Details for the file docker_evaluator-0.1.2-py3-none-any.whl.
File metadata
- Download URL: docker_evaluator-0.1.2-py3-none-any.whl
- Upload date:
- Size: 14.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f9ac65c214d849cf592628df82bf677db5d5747e2916e78b7bbbbea2f21aeeb
|
|
| MD5 |
5e299ad6b5881fcde2999f9699d97c92
|
|
| BLAKE2b-256 |
d16bc61b6c4e6daa7a3ee62d000f948cf62a8d2ff80e3a5f17b1a57946189dc5
|