From aa0e49e94ba19166e2dcf23f81af59b7558d70d7 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Sun, 12 Oct 2014 01:04:20 -0500 Subject: [PATCH] Allow using data files in Python code questions --- TODO | 2 -- cfrunpy/cfrunpy | 4 ++-- cfrunpy/cfrunpy_backend.py | 22 ++++++++++++---------- course/page.py | 32 +++++++++++++++++++++++++++++--- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/TODO b/TODO index b04cdc43..4054973c 100644 --- a/TODO +++ b/TODO @@ -2,8 +2,6 @@ - Fix docker reliability -- Supply data to cfrunpy - - Unanswered questions for unanswered statistics q? - flow overview diff --git a/cfrunpy/cfrunpy b/cfrunpy/cfrunpy index cf8f0051..c9529236 100755 --- a/cfrunpy/cfrunpy +++ b/cfrunpy/cfrunpy @@ -29,7 +29,7 @@ import socketserver import json import sys import io -from cfrunpy_backend import dict_to_struct, run_code, package_exception +from cfrunpy_backend import Struct, run_code, package_exception from http.server import BaseHTTPRequestHandler PORT = 9941 @@ -76,7 +76,7 @@ class RunRequestHandler(BaseHTTPRequestHandler): print("CFRUNPY RECEIVED %d bytes" % len(recv_data), file=prev_stderr) - run_req = dict_to_struct(json.loads(recv_data.decode("utf-8"))) + run_req = Struct(json.loads(recv_data.decode("utf-8"))) print("REQUEST: %r" % run_req, file=prev_stderr) stdout = io.StringIO() diff --git a/cfrunpy/cfrunpy_backend.py b/cfrunpy/cfrunpy_backend.py index cfa27180..1e5c94c5 100644 --- a/cfrunpy/cfrunpy_backend.py +++ b/cfrunpy/cfrunpy_backend.py @@ -42,6 +42,10 @@ PROTOCOL .. attribute:: test_code + .. attribute:: data_files + + a dictionary from data file names to their contents + .. attribute:: compile_only :class:`bool` @@ -110,20 +114,11 @@ PROTOCOL class Struct(object): def __init__(self, entries): for name, val in entries.items(): - self.__dict__[name] = dict_to_struct(val) + self.__dict__[name] = val def __repr__(self): return repr(self.__dict__) - -def dict_to_struct(data): - if isinstance(data, list): - return [dict_to_struct(d) for d in data] - elif isinstance(data, dict): - return Struct(data) - else: - return data - # }}} @@ -194,10 +189,17 @@ def run_code(result, run_req): # {{{ run code + data_files = {} + if hasattr(run_req, "data_files"): + from base64 import b64decode + for name, contents in run_req.data_files.items(): + data_files[name] = b64decode(contents.encode()) + feedback = Feedback() maint_ctx = { "feedback": feedback, "user_code": user_code, + "data_files": data_files, "GradingComplete": GradingComplete, } diff --git a/course/page.py b/course/page.py index 8995549c..ff2005d4 100644 --- a/course/page.py +++ b/course/page.py @@ -28,7 +28,7 @@ from course.validation import validate_struct, ValidationError, validate_markup from course.content import remove_prefix from django.utils.safestring import mark_safe import django.forms as forms -from django.contrib import messages +from django.core.exceptions import ObjectDoesNotExist from courseflow.utils import StyledForm, Struct @@ -1346,6 +1346,18 @@ def request_python_run(run_req, run_timeout): class PythonCodeQuestion(PageBaseWithTitle, PageBaseWithValue): + def __init__(self, vctx, location, page_desc): + super(PythonCodeQuestion, self).__init__(vctx, location, page_desc) + + if vctx is not None and hasattr(page_desc, "data_files"): + for data_file in page_desc.data_files: + try: + from course.content import get_repo_blob + get_repo_blob(vctx.repo, data_file, vctx.commit_sha) + except ObjectDoesNotExist: + raise ValidationError("%s: data file '%s' not found" + % (location, data_file)) + def required_attrs(self): return super(PythonCodeQuestion, self).required_attrs() + ( ("prompt", "markup"), @@ -1360,6 +1372,7 @@ class PythonCodeQuestion(PageBaseWithTitle, PageBaseWithValue): ("test_code", str), ("correct_code", str), ("initial_code", str), + ("data_files", list), ) def _initial_code(self): @@ -1431,6 +1444,19 @@ class PythonCodeQuestion(PageBaseWithTitle, PageBaseWithValue): transfer_attr("names_from_user") transfer_attr("test_code") + if hasattr(self.page_desc, "data_files"): + run_req["data_files"] = {} + + from course.content import get_repo_blob + + for data_file in self.page_desc.data_files: + from base64 import b64encode + run_req["data_files"][data_file] = \ + b64encode( + get_repo_blob( + page_context.repo, data_file, + page_context.commit_sha).data) + try: response_dict = request_python_run(run_req, run_timeout=self.page_desc.timeout) @@ -1597,8 +1623,8 @@ class PythonCodeQuestionWithHumanTextFeedback( if (vctx is not None and self.page_desc.human_feedback_value > self.page_desc.value): raise ValidationError( - "human_feedback_value greater than overall " - "value of question") + "%s: human_feedback_value greater than overall " + "value of question" % location) def required_attrs(self): return super( -- GitLab