Overview
Online coding platforms enable students to practice programming by solving problems and submitting solutions. The platform executes code securely, validates against test cases, and provides feedback.Prerequisites
- HopX API key (Get one here)
- Python 3.8+ or Node.js 16+
- Understanding of test case validation
- Basic knowledge of educational platform architecture
Architecture
┌──────────────┐
│ Student │ Submits code
└──────┬───────┘
│
▼
┌─────────────────┐
│ Platform API │ Validates & queues
└──────┬──────────┘
│
▼
┌─────────────────┐
│ HopX Sandbox │ Execute code
└──────┬──────────┘
│
▼
┌─────────────────┐
│ Test Runner │ Validate results
└──────┬──────────┘
│
▼
┌─────────────────┐
│ Feedback │ Return results
└─────────────────┘
Implementation
Step 1: Basic Code Submission and Execution
Create a system that accepts code submissions and executes them:from hopx_ai import Sandbox
import os
import json
from typing import Dict, List, Any
class CodingPlatform:
def __init__(self, api_key: str):
self.api_key = api_key
def execute_submission(self, code: str, language: str, timeout: int = 10) -> Dict[str, Any]:
"""Execute student code submission"""
sandbox = None
try:
# Create isolated sandbox for this submission
sandbox = Sandbox.create(
template="code-interpreter",
api_key=self.api_key,
timeout_seconds=timeout + 5 # Extra buffer
)
# Execute code
result = sandbox.run_code(code, language=language, timeout=timeout)
return {
"success": result.success,
"stdout": result.stdout,
"stderr": result.stderr,
"exit_code": result.exit_code,
"execution_time": result.execution_time,
"timeout": result.execution_time >= timeout
}
except Exception as e:
return {
"success": False,
"error": str(e),
"stderr": str(e)
}
finally:
if sandbox:
sandbox.kill()
def validate_solution(self, code: str, test_cases: List[Dict], language: str = "python") -> Dict[str, Any]:
"""Validate solution against test cases"""
results = []
all_passed = True
for i, test_case in enumerate(test_cases):
# Prepare test code
test_code = self._prepare_test_code(code, test_case, language)
# Execute
execution_result = self.execute_submission(test_code, language, timeout=5)
# Check result
passed = self._check_test_result(execution_result, test_case)
results.append({
"test_case": i + 1,
"passed": passed,
"input": test_case.get("input"),
"expected": test_case.get("expected"),
"actual": execution_result.get("stdout", "").strip(),
"error": execution_result.get("stderr") if not passed else None
})
if not passed:
all_passed = False
return {
"all_passed": all_passed,
"total_tests": len(test_cases),
"passed_tests": sum(1 for r in results if r["passed"]),
"results": results
}
def _prepare_test_code(self, code: str, test_case: Dict, language: str) -> str:
"""Prepare code with test case"""
if language == "python":
input_data = test_case.get("input", "")
expected = test_case.get("expected", "")
# Wrap student code with test
test_code = f"""
{code}
# Test case
test_input = {input_data}
result = solution(test_input) # Assuming function named 'solution'
expected = {expected}
if result == expected:
print("PASS")
else:
print(f"FAIL: Expected {{expected}}, got {{result}}")
"""
return test_code
else:
# Similar for other languages
return code
def _check_test_result(self, execution_result: Dict, test_case: Dict) -> bool:
"""Check if test case passed"""
if not execution_result.get("success"):
return False
stdout = execution_result.get("stdout", "").strip()
return "PASS" in stdout or stdout == str(test_case.get("expected", "")).strip()
# Usage
platform = CodingPlatform(api_key=os.getenv("HOPX_API_KEY"))
# Student submission
student_code = """
def solution(nums):
return sum(nums)
"""
# Test cases
test_cases = [
{"input": "[1, 2, 3]", "expected": 6},
{"input": "[10, 20, 30]", "expected": 60},
{"input": "[]", "expected": 0}
]
# Validate
result = platform.validate_solution(student_code, test_cases)
print(json.dumps(result, indent=2))
import { Sandbox } from '@hopx-ai/sdk';
class CodingPlatform {
constructor(apiKey) {
this.apiKey = apiKey;
}
async executeSubmission(code, language, timeout = 10) {
let sandbox = null;
try {
// Create isolated sandbox for this submission
sandbox = await Sandbox.create({
template: 'code-interpreter',
apiKey: this.apiKey,
timeoutSeconds: timeout + 5 // Extra buffer
});
// Execute code
const result = await sandbox.runCode(code, {
language,
timeout
});
return {
success: result.success,
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exit_code,
executionTime: result.execution_time,
timeout: result.execution_time >= timeout
};
} catch (error) {
return {
success: false,
error: error.message,
stderr: error.toString()
};
} finally {
if (sandbox) {
await sandbox.kill();
}
}
}
async validateSolution(code, testCases, language = 'python') {
const results = [];
let allPassed = true;
for (let i = 0; i < testCases.length; i++) {
const testCase = testCases[i];
// Prepare test code
const testCode = this.prepareTestCode(code, testCase, language);
// Execute
const executionResult = await this.executeSubmission(testCode, language, 5);
// Check result
const passed = this.checkTestResult(executionResult, testCase);
results.push({
testCase: i + 1,
passed,
input: testCase.input,
expected: testCase.expected,
actual: executionResult.stdout ? executionResult.stdout.trim() : '',
error: !passed ? executionResult.stderr : null
});
if (!passed) {
allPassed = false;
}
}
return {
allPassed,
totalTests: testCases.length,
passedTests: results.filter(r => r.passed).length,
results
};
}
prepareTestCode(code, testCase, language) {
if (language === 'python') {
const inputData = testCase.input || '';
const expected = testCase.expected || '';
// Wrap student code with test
return `
${code}
# Test case
test_input = ${inputData}
result = solution(test_input) # Assuming function named 'solution'
expected = ${expected}
if result == expected:
print("PASS")
else:
print(f"FAIL: Expected {expected}, got {result}")
`;
} else {
// Similar for other languages
return code;
}
}
checkTestResult(executionResult, testCase) {
if (!executionResult.success) {
return false;
}
const stdout = executionResult.stdout ? executionResult.stdout.trim() : '';
return stdout.includes('PASS') || stdout === String(testCase.expected).trim();
}
}
// Usage
const platform = new CodingPlatform(process.env.HOPX_API_KEY);
// Student submission
const studentCode = `
def solution(nums):
return sum(nums)
`;
// Test cases
const testCases = [
{ input: '[1, 2, 3]', expected: 6 },
{ input: '[10, 20, 30]', expected: 60 },
{ input: '[]', expected: 0 }
];
// Validate
const result = await platform.validateSolution(studentCode, testCases);
console.log(JSON.stringify(result, null, 2));
Step 2: Multi-Language Support
Support multiple programming languages:class MultiLanguagePlatform(CodingPlatform):
SUPPORTED_LANGUAGES = {
"python": {
"template": "code-interpreter",
"extension": ".py",
"runner": "python"
},
"javascript": {
"template": "code-interpreter",
"extension": ".js",
"runner": "node"
},
"java": {
"template": "code-interpreter",
"extension": ".java",
"runner": "javac && java"
}
}
def execute_submission(self, code: str, language: str, timeout: int = 10) -> Dict[str, Any]:
"""Execute code in specified language"""
if language not in self.SUPPORTED_LANGUAGES:
return {
"success": False,
"error": f"Unsupported language: {language}"
}
lang_config = self.SUPPORTED_LANGUAGES[language]
sandbox = None
try:
sandbox = Sandbox.create(
template=lang_config["template"],
api_key=self.api_key,
timeout_seconds=timeout + 5
)
# Write code to file
filename = f"/workspace/solution{lang_config['extension']}"
sandbox.files.write(filename, code)
# Execute based on language
if language == "python":
result = sandbox.run_code(code, language="python", timeout=timeout)
elif language == "javascript":
result = sandbox.run_code(code, language="javascript", timeout=timeout)
elif language == "java":
# Compile and run Java
compile_result = sandbox.commands.run(
f"javac {filename}",
timeout=5
)
if not compile_result.exit_code == 0:
return {
"success": False,
"stderr": compile_result.stderr,
"error": "Compilation failed"
}
# Run compiled class
result = sandbox.commands.run(
"java -cp /workspace Solution",
timeout=timeout
)
return {
"success": result.success if hasattr(result, 'success') else result.exit_code == 0,
"stdout": result.stdout if hasattr(result, 'stdout') else result.stdout,
"stderr": result.stderr if hasattr(result, 'stderr') else result.stderr,
"exit_code": result.exit_code if hasattr(result, 'exit_code') else result.exit_code,
"language": language
}
except Exception as e:
return {
"success": False,
"error": str(e),
"language": language
}
finally:
if sandbox:
sandbox.kill()
# Usage
platform = MultiLanguagePlatform(api_key=os.getenv("HOPX_API_KEY"))
# Python submission
python_code = "print('Hello from Python!')"
result = platform.execute_submission(python_code, "python")
print(result)
# JavaScript submission
js_code = "console.log('Hello from JavaScript!');"
result = platform.execute_submission(js_code, "javascript")
print(result)
class MultiLanguagePlatform extends CodingPlatform {
constructor(apiKey) {
super(apiKey);
this.supportedLanguages = {
python: {
template: 'code-interpreter',
extension: '.py',
runner: 'python'
},
javascript: {
template: 'code-interpreter',
extension: '.js',
runner: 'node'
},
java: {
template: 'code-interpreter',
extension: '.java',
runner: 'javac && java'
}
};
}
async executeSubmission(code, language, timeout = 10) {
if (!this.supportedLanguages[language]) {
return {
success: false,
error: `Unsupported language: ${language}`
};
}
const langConfig = this.supportedLanguages[language];
let sandbox = null;
try {
sandbox = await Sandbox.create({
template: langConfig.template,
apiKey: this.apiKey,
timeoutSeconds: timeout + 5
});
// Write code to file
const filename = `/workspace/solution${langConfig.extension}`;
await sandbox.files.write(filename, code);
// Execute based on language
let result;
if (language === 'python') {
result = await sandbox.runCode(code, { language: 'python', timeout });
} else if (language === 'javascript') {
result = await sandbox.runCode(code, { language: 'javascript', timeout });
} else if (language === 'java') {
// Compile and run Java
const compileResult = await sandbox.commands.run(
`javac ${filename}`,
{ timeout: 5 }
);
if (compileResult.exit_code !== 0) {
return {
success: false,
stderr: compileResult.stderr,
error: 'Compilation failed'
};
}
// Run compiled class
result = await sandbox.commands.run(
'java -cp /workspace Solution',
{ timeout }
);
}
return {
success: result.success !== undefined ? result.success : result.exit_code === 0,
stdout: result.stdout || '',
stderr: result.stderr || '',
exitCode: result.exit_code || result.exit_code,
language
};
} catch (error) {
return {
success: false,
error: error.message,
language
};
} finally {
if (sandbox) {
await sandbox.kill();
}
}
}
}
// Usage
const platform = new MultiLanguagePlatform(process.env.HOPX_API_KEY);
// Python submission
const pythonCode = "print('Hello from Python!')";
const result1 = await platform.executeSubmission(pythonCode, 'python');
console.log(result1);
// JavaScript submission
const jsCode = "console.log('Hello from JavaScript!');";
const result2 = await platform.executeSubmission(jsCode, 'javascript');
console.log(result2);
Step 3: Resource Limits and Timeout Management
Implement resource limits to prevent abuse:class ResourceLimitedPlatform(CodingPlatform):
def __init__(self, api_key: str, max_execution_time: int = 10, max_memory_mb: int = 512):
super().__init__(api_key)
self.max_execution_time = max_execution_time
self.max_memory_mb = max_memory_mb
def execute_submission(self, code: str, language: str, timeout: int = None) -> Dict[str, Any]:
"""Execute with resource limits"""
# Enforce maximum timeout
actual_timeout = min(timeout or self.max_execution_time, self.max_execution_time)
sandbox = None
try:
# Create sandbox with resource limits
sandbox = Sandbox.create(
template="code-interpreter", # Template defines resources
api_key=self.api_key,
timeout_seconds=actual_timeout + 2 # Small buffer
)
# Set environment variables for resource monitoring
sandbox.env.set_all({
"MAX_EXECUTION_TIME": str(actual_timeout),
"MAX_MEMORY_MB": str(self.max_memory_mb)
})
# Execute with strict timeout
result = sandbox.run_code(code, language=language, timeout=actual_timeout)
# Check if timeout was exceeded
if result.execution_time >= actual_timeout:
return {
"success": False,
"error": "Execution timeout exceeded",
"timeout": True,
"execution_time": result.execution_time
}
# Check memory usage (if available)
metrics = sandbox.get_metrics_snapshot()
memory_used = metrics.get('memory_usage_mb', 0) if hasattr(metrics, 'get') else 0
if memory_used > self.max_memory_mb:
return {
"success": False,
"error": f"Memory limit exceeded: {memory_used}MB > {self.max_memory_mb}MB",
"memory_exceeded": True
}
return {
"success": result.success,
"stdout": result.stdout,
"stderr": result.stderr,
"execution_time": result.execution_time,
"memory_used_mb": memory_used
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
finally:
if sandbox:
sandbox.kill()
# Usage
platform = ResourceLimitedPlatform(
api_key=os.getenv("HOPX_API_KEY"),
max_execution_time=5, # 5 second limit
max_memory_mb=256 # 256MB limit
)
result = platform.execute_submission("print('Hello')", "python")
print(result)
class ResourceLimitedPlatform extends CodingPlatform {
constructor(apiKey, maxExecutionTime = 10, maxMemoryMB = 512) {
super(apiKey);
this.maxExecutionTime = maxExecutionTime;
this.maxMemoryMB = maxMemoryMB;
}
async executeSubmission(code, language, timeout = null) {
// Enforce maximum timeout
const actualTimeout = Math.min(timeout || this.maxExecutionTime, this.maxExecutionTime);
let sandbox = null;
try {
// Create sandbox with resource limits
sandbox = await Sandbox.create({
template: 'code-interpreter', // Template defines resources
apiKey: this.apiKey,
timeoutSeconds: actualTimeout + 2 // Small buffer
});
// Set environment variables for resource monitoring
await sandbox.env.setAll({
MAX_EXECUTION_TIME: String(actualTimeout),
MAX_MEMORY_MB: String(this.maxMemoryMB)
});
// Execute with strict timeout
const result = await sandbox.runCode(code, {
language,
timeout: actualTimeout
});
// Check if timeout was exceeded
if (result.execution_time >= actualTimeout) {
return {
success: false,
error: 'Execution timeout exceeded',
timeout: true,
executionTime: result.execution_time
};
}
// Check memory usage (if available)
const metrics = await sandbox.getSystemMetrics();
const memoryUsed = metrics.memory_usage_mb || 0;
if (memoryUsed > this.maxMemoryMB) {
return {
success: false,
error: `Memory limit exceeded: ${memoryUsed}MB > ${this.maxMemoryMB}MB`,
memoryExceeded: true
};
}
return {
success: result.success,
stdout: result.stdout,
stderr: result.stderr,
executionTime: result.execution_time,
memoryUsedMB: memoryUsed
};
} catch (error) {
return {
success: false,
error: error.message
};
} finally {
if (sandbox) {
await sandbox.kill();
}
}
}
}
// Usage
const platform = new ResourceLimitedPlatform(
process.env.HOPX_API_KEY,
5, // 5 second limit
256 // 256MB limit
);
const result = await platform.executeSubmission("print('Hello')", 'python');
console.log(result);
Step 4: Grading and Feedback System
Create a comprehensive grading system:class GradingSystem:
def __init__(self, platform: CodingPlatform):
self.platform = platform
def grade_submission(self, code: str, problem: Dict, language: str = "python") -> Dict[str, Any]:
"""Grade a student submission"""
# Validate solution
validation_result = self.platform.validate_solution(
code,
problem.get("test_cases", []),
language
)
# Calculate score
score = self._calculate_score(validation_result, problem)
# Generate feedback
feedback = self._generate_feedback(validation_result, problem)
return {
"score": score,
"max_score": problem.get("max_score", 100),
"percentage": (score / problem.get("max_score", 100)) * 100,
"all_tests_passed": validation_result["all_passed"],
"test_results": validation_result["results"],
"feedback": feedback,
"submission_time": self._get_timestamp()
}
def _calculate_score(self, validation_result: Dict, problem: Dict) -> float:
"""Calculate score based on test results"""
if validation_result["all_passed"]:
return problem.get("max_score", 100)
# Partial credit based on passed tests
passed = validation_result["passed_tests"]
total = validation_result["total_tests"]
max_score = problem.get("max_score", 100)
return (passed / total) * max_score
def _generate_feedback(self, validation_result: Dict, problem: Dict) -> str:
"""Generate feedback for student"""
if validation_result["all_passed"]:
return "Excellent! All test cases passed."
failed_tests = [r for r in validation_result["results"] if not r["passed"]]
feedback = f"Some test cases failed ({len(failed_tests)}/{validation_result['total_tests']}).\n\n"
for test in failed_tests[:3]: # Show first 3 failures
feedback += f"Test {test['test_case']}: Expected {test['expected']}, got {test['actual']}\n"
if test.get("error"):
feedback += f" Error: {test['error']}\n"
return feedback
def _get_timestamp(self) -> str:
from datetime import datetime
return datetime.now().isoformat()
# Usage
platform = CodingPlatform(api_key=os.getenv("HOPX_API_KEY"))
grader = GradingSystem(platform)
problem = {
"title": "Sum of Array",
"description": "Write a function that returns the sum of all elements in an array",
"max_score": 100,
"test_cases": [
{"input": "[1, 2, 3]", "expected": 6},
{"input": "[10, 20, 30]", "expected": 60},
{"input": "[]", "expected": 0}
]
}
student_code = """
def solution(nums):
return sum(nums)
"""
grade = grader.grade_submission(student_code, problem)
print(json.dumps(grade, indent=2))
class GradingSystem {
constructor(platform) {
this.platform = platform;
}
async gradeSubmission(code, problem, language = 'python') {
// Validate solution
const validationResult = await this.platform.validateSolution(
code,
problem.testCases || [],
language
);
// Calculate score
const score = this.calculateScore(validationResult, problem);
// Generate feedback
const feedback = this.generateFeedback(validationResult, problem);
return {
score,
maxScore: problem.maxScore || 100,
percentage: (score / (problem.maxScore || 100)) * 100,
allTestsPassed: validationResult.allPassed,
testResults: validationResult.results,
feedback,
submissionTime: new Date().toISOString()
};
}
calculateScore(validationResult, problem) {
if (validationResult.allPassed) {
return problem.maxScore || 100;
}
// Partial credit based on passed tests
const passed = validationResult.passedTests;
const total = validationResult.totalTests;
const maxScore = problem.maxScore || 100;
return (passed / total) * maxScore;
}
generateFeedback(validationResult, problem) {
if (validationResult.allPassed) {
return 'Excellent! All test cases passed.';
}
const failedTests = validationResult.results.filter(r => !r.passed);
let feedback = `Some test cases failed (${failedTests.length}/${validationResult.totalTests}).\n\n`;
for (const test of failedTests.slice(0, 3)) { // Show first 3 failures
feedback += `Test ${test.testCase}: Expected ${test.expected}, got ${test.actual}\n`;
if (test.error) {
feedback += ` Error: ${test.error}\n`;
}
}
return feedback;
}
}
// Usage
const platform = new CodingPlatform(process.env.HOPX_API_KEY);
const grader = new GradingSystem(platform);
const problem = {
title: 'Sum of Array',
description: 'Write a function that returns the sum of all elements in an array',
maxScore: 100,
testCases: [
{ input: '[1, 2, 3]', expected: 6 },
{ input: '[10, 20, 30]', expected: 60 },
{ input: '[]', expected: 0 }
]
};
const studentCode = `
def solution(nums):
return sum(nums)
`;
const grade = await grader.gradeSubmission(studentCode, problem);
console.log(JSON.stringify(grade, null, 2));
Best Practices
Security
Always create a fresh sandbox for each student submission to ensure complete isolation between submissions.
- Sandbox Isolation: Never reuse sandboxes between different students
- Code Validation: Check for dangerous patterns before execution
- Resource Limits: Enforce strict timeouts and memory limits
- Input Sanitization: Validate all inputs before processing
Performance
Use parallel execution for multiple test cases when possible, but ensure each test case runs in isolation.
- Sandbox Pooling: Consider sandbox pooling for high-volume platforms
- Caching: Cache problem definitions and test cases
- Async Processing: Process submissions asynchronously for better scalability
- Resource Monitoring: Monitor sandbox usage and optimize accordingly
Educational Value
- Clear Feedback: Provide detailed, actionable feedback
- Progressive Difficulty: Structure problems from easy to hard
- Hints System: Offer hints without revealing solutions
- Performance Metrics: Track execution time and memory usage
Real-World Examples
This pattern is used by:- LeetCode: Online coding interview platform
- HackerRank: Competitive programming platform
- Codecademy: Interactive coding lessons
- Educational Platforms: Various platforms that provide secure code execution for students
Related Cookbooks
- Interactive Programming Tutorials - Step-by-step learning
- Coding Interview Platform - Interview preparation
- Isolated Test Execution - Test isolation strategies
Next Steps
- Implement your problem database
- Add user authentication and submission tracking
- Create a web interface for code submission
- Implement leaderboards and progress tracking
- Add support for more programming languages

