Система шаблонов Django для генерации запускаемых программ
Я рассматриваю возможность использования системы шаблонов Django для довольно необычного случая использования и ищу некоторые рекомендации.
У меня есть приложение, которое позволяет пользователям решать проблемы программирования, представляя кодовое решение. Приложение позволяет пользователям писать программы на нескольких языках, включая Python, JS/TS и C.
Каждая задача связана с набором тестовых примеров, предназначенных для проверки правильности представленного решения. Мое приложение объединяет пользовательский код и код тестовых примеров в программу, которая выполняется в изолированной среде.
<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
)
По сути, это создает строку с некоторыми импортами, затем вводит пользовательский код, затем добавляет серию блоков try - except, по одному для каждого тестового случая (представьте, что тестовый случай - это некий assert
, который вызовет исключение, если код не сработает), в котором dict, представляющий детали выполнения теста, выталкивается в список, который в конечном итоге выводится в stdout и собирается процессом, в котором работает Django.
Это нормально для большинства случаев, но я хотел бы дать авторам больше гибкости в том, как они хотят тестировать свои программы.
Вместо того, чтобы жестко кодировать такую строку, я бы хотел, чтобы администратор мог указать шаблон для объединения пользовательского кода и тестовых примеров. Для программы на C это могло бы выглядеть так (это не язык шаблонов Django, это просто чтобы дать представление):
#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;
}
<
Моя идея состоит в том, чтобы использовать определяемый администратором шаблон Django для конечного рендеринга в обычную строку, а не в HTML-страницу, как это обычно делается. Некоторые проблемы связаны с экранированием, правильным (де)отступом внедренного кода и простотой использования для тех, кому нужно создавать такие шаблоны.