I’m considering using Django template system for a pretty peculiar use case and I’m looking for some guidance.
I have an app which allows users to solve programming problems by submitting a code solution. The app allows users to write programs in several languages, including Python, JS/TS, and C.
Each problem is associated with a suite of test cases meant to verify the correctness of the submitted solution. My app combines the user code and the test cases’ code into a program that is run by a sandboxed environment.
Right now, the way the submitted code and the test cases are combined is hard-coded and looks roughly like this:
def get_testcase_execution_block(
testcase: ExerciseTestCase, execution_results_list_identifier: str
) -> str:
results_dict = get_random_identifier()
exception_identifier = get_random_identifier()
return (
f"try:\n"
+ f" {testcase.code}\n"
+ f" {results_dict} = {{'passed': True, 'id': {testcase.pk}}}\n"
+ f"except Exception as {exception_identifier}:\n"
+ f" ex_type, ex_value, ex_traceback = sys.exc_info()\n"
+ f" trace_back = traceback.extract_tb(ex_traceback)\n"
+ f" stack_trace = list()\n"
+ f" for trace in trace_back:\n"
+ f' stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3]))\n'
+ f" {results_dict} = {{'passed': False, 'id': {testcase.pk}, 'error': ex_type.__name__ + ': ' + str(ex_value) + ' (' + str(stack_trace) +')'}}\n"
+ f"{execution_results_list_identifier}.append({results_dict})\n"
)
def get_python_program_for_vm(code: str, testcases: ExerciseTestCase) -> str:
execution_results_list_identifier = get_random_identifier()
testcases_str = "".join(
[
get_testcase_execution_block(t, execution_results_list_identifier)
for t in testcases
]
)
return (
"import sys\n"
+ "import traceback\n"
+ "import json\n"
+ f"{execution_results_list_identifier}=[]\n" # declare list to hold test case results
+ f"{code}\n" # inline submitted code
+ f"{testcases_str}\n" # run test cases in try - except blocks
+ f"print(json.dumps({execution_results_list_identifier}))" # print out the result list
)
What this essentially does it it creates a string with some imports, then injects the user code, then adds a series of try - except blocks, one for each test case (imagine a test case being some assert
that will therefore raise an exception if the code fails), in which a dict that represents the details of the test execution is pushed to a list which is ultimately printed to stdout and collected by the process in which Django runs.
This is fine for most cases, but I’d like to give the authors more flexibility as to how they want their programs to be tested.
Instead of hard-coding a string like this, I’d like the admin to be able to specify a template for combining the user code and test cases. For a C program, it might look like this (this is not Django template language, it’s just to give an idea):
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
{{ USER_CODE }}
int main() {
{% for TEST in TESTCASES %}
{
{{ TEST.testcode }};
}
{% endfor %}
return 0;
}
My question is: would the Django template language be appropriate for this?
My idea is to use an admin-defined Django template to ultimately render to a plain string, instead of an HTML page like it’s usually employed. Some concerns are escaping, properly (de)indenting injected code, and simplicity of use for those who need to create such templates.