From 27e9704120dce7f64cedc90bd35c92976426c4b7 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 17 Nov 2014 02:17:30 -0600 Subject: [PATCH] Add utility functions to code feedback --- TODO | 5 ++++ cfrunpy/cfrunpy_backend.py | 49 ++++++++++++++++++++++++++++++++++++++ course/page/code.py | 7 +++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 82f37e56..a4d0e208 100644 --- a/TODO +++ b/TODO @@ -13,6 +13,11 @@ Ideas ===== +- Auto-expire + +- Do print() and plot() from testing code count? + Make a setting. + - Session reset UI - Allow just viewing flow without any possibility for submission diff --git a/cfrunpy/cfrunpy_backend.py b/cfrunpy/cfrunpy_backend.py index aab583eb..ddcbbb42 100644 --- a/cfrunpy/cfrunpy_backend.py +++ b/cfrunpy/cfrunpy_backend.py @@ -152,6 +152,55 @@ class Feedback: self.set_points(points) raise GradingComplete() + def _check_numpy_array_base(self, name, ref, data): + import numpy as np + assert isinstance(ref, np.ndarray) + + if not isinstance(data, np.ndarray): + self.finish(0, "'%s' is not a numpy array" % name) + + if ref.shape != data.shape: + self.finish( + 0, "'%s' does not have correct shape--" + "got: '%s', expected: '%s'" % ( + name, data.shape, ref.shape)) + + if ref.dtype.kind != data.dtype.kind: + self.finish( + 0, "'%s' does not have correct data type--" + "got: '%s', expected: '%s'" % ( + name, data.dtype.kind, ref.dtype.kind)) + + def check_numpy_array_allclose(self, name, ref, data, accuracy_critical=True, + rtol=1e-05, atol=1e-08): + import numpy as np + + self._check_numpy_array_base(name, ref, data) + good = np.allclose(ref, data, rtol=rtol, atol=atol) + + if not good: + self.add_feedback("'%s' is inaccurate" % name) + + if accuracy_critical and not good: + self.set_points(0) + raise GradingComplete() + + return good + + def check_list(self, name, ref, data, entry_type=None): + assert isinstance(ref, list) + if not isinstance(data, list): + self.finish(0, "'%s' is not a list" % name) + + if len(ref) != len(data): + self.finish(0, "'%s' has the wrong length--expected %d, got %d" + % (name, len(ref), len(list))) + + if entry_type is not None: + for i, entry in enumerate(data): + if not isinstance(entry, entry_type): + self.finish(0, "'%s[i]' has the wrong type" % (name, i)) + def run_code(result, run_req): # {{{ compile code diff --git a/course/page/code.py b/course/page/code.py index d13681ab..9e7e8e31 100644 --- a/course/page/code.py +++ b/course/page/code.py @@ -351,7 +351,7 @@ class PythonCodeQuestion(PageBaseWithTitle, PageBaseWithValue): * ``GradingComplete``: An exception class that can be raised to indicated that the grading code has concluded. - * ``feedback``: A class instance with three methods:: + * ``feedback``: A class instance with the following interface:: feedback.set_points(0.5) # 0<=points<=1 (usually) feedback.add_feedback("This was wrong") @@ -359,6 +359,11 @@ class PythonCodeQuestion(PageBaseWithTitle, PageBaseWithValue): # combines the above two and raises GradingComplete feedback.finish(0, "This was wrong") + feedback.check_numpy_array_allclose(name, ref, data, + accuracy_critical=True, rtol=1e-5, atol=1e-8) + + feedback.check_list(name, ref, data, entry_type=None) + * ``data_files``: A dictionary mapping file names from :attr:`data_files` to :class:`bytes` instances with that file's contents. -- GitLab