diff options
-rw-r--r-- | yaksh/python_stdio_evaluator.py | 66 | ||||
-rw-r--r-- | yaksh/static/yaksh/css/exam.css | 1 | ||||
-rw-r--r-- | yaksh/templates/exam.html | 53 | ||||
-rw-r--r-- | yaksh/templates/yaksh/question.html | 1 | ||||
-rw-r--r-- | yaksh/templatetags/custom_filters.py | 5 |
5 files changed, 95 insertions, 31 deletions
diff --git a/yaksh/python_stdio_evaluator.py b/yaksh/python_stdio_evaluator.py index a8c797d..ec5ed71 100644 --- a/yaksh/python_stdio_evaluator.py +++ b/yaksh/python_stdio_evaluator.py @@ -1,12 +1,16 @@ import sys from contextlib import contextmanager - try: from StringIO import StringIO except ImportError: from io import StringIO +try: + from itertools import zip_longest +except ImportError: + from itertools import izip_longest as zip_longest + # Local imports from .file_utils import copy_files, delete_files from .base_evaluator import BaseEvaluator @@ -21,35 +25,42 @@ def redirect_stdout(): finally: sys.stdout = old_target # restore to the previous value - -def _show_expected_given(expected, given): - return "Expected:\n{0}\nGiven:\n{1}\n".format(expected, given) - - -def compare_outputs(given, expected): - given_lines = given.splitlines() +def _incorrect_user_lines(exp_lines, user_lines): + err_line_no = [] + for i, (expected_line, user_line) in enumerate(zip_longest(exp_lines, user_lines)): + if not user_line or not expected_line: + err_line_no.append(i) + else: + if user_line.strip() != expected_line.strip(): + err_line_no.append(i) + return err_line_no + +def compare_outputs(expected_output, user_output,given_input=None): + given_lines = user_output.splitlines() + exp_lines = expected_output.splitlines() + # if given_input: + # given_input = given_input.splitlines() + msg = {"given_input":given_input, + "expected_output": exp_lines, + "user_output":given_lines + } ng = len(given_lines) - exp_lines = expected.splitlines() ne = len(exp_lines) if ng != ne: - msg = "ERROR: Got {0} lines in output, we expected {1}.\n".format( - ng, ne - ) - msg += _show_expected_given(expected, given) + err_line_no = _incorrect_user_lines(exp_lines, given_lines) + msg["error_no"] = err_line_no + msg["error"] = "We had expected {0} number of lines. We got {1} number of lines.".format(ne, ng) return False, msg else: - for i, (given_line, expected_line) in \ - enumerate(zip(given_lines, exp_lines)): - if given_line.strip() != expected_line.strip(): - msg = "ERROR:\n" - msg += _show_expected_given(expected, given) - msg += "\nError in line %d of output.\n" % (i+1) - msg += "Expected line {0}:\n{1}\nGiven line {0}:\n{2}\n"\ - .format( - i+1, expected_line, given_line - ) - return False, msg - return True, "Correct answer." + err_line_no = _incorrect_user_lines(exp_lines, given_lines) + if err_line_no: + msg["error_no"] = err_line_no + msg["error"] = "Line number(s) {0} did not match."\ + .format(", ".join(map(str,[x+1 for x in err_line_no]))) + return False, msg + else: + msg["error"] = "Correct answer" + return True, msg class PythonStdIOEvaluator(BaseEvaluator): @@ -89,5 +100,8 @@ class PythonStdIOEvaluator(BaseEvaluator): def check_code(self): mark_fraction = self.weight - success, err = compare_outputs(self.output_value, self.expected_output) + success, err = compare_outputs(self.expected_output, + self.output_value, + self.expected_input + ) return success, err, mark_fraction diff --git a/yaksh/static/yaksh/css/exam.css b/yaksh/static/yaksh/css/exam.css new file mode 100644 index 0000000..88111dc --- /dev/null +++ b/yaksh/static/yaksh/css/exam.css @@ -0,0 +1 @@ +.table td { border: black solid 1px !important; }
\ No newline at end of file diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html index a18a962..b5b6c46 100644 --- a/yaksh/templates/exam.html +++ b/yaksh/templates/exam.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load custom_filters %} {% block css%} <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/dashboard.css" type="text/css" /> {% endblock %} @@ -77,13 +78,55 @@ {% if error_message %} <div class="row" id="error_panel"> {% for error in error_message %} - {% if error == "Correct answer" %} - <div class="panel panel-success"> - {% else %} <div class="panel panel-danger"> - {% endif %} <div class="panel-heading">Testcase No. {{ forloop.counter }}</div> - <div class="panel-body"><pre><code>{{ error }}</code></pre></div> + <div class="panel-body"> + <div class="well well-sm"> + {% if not error.expected_output %} + <pre><code> {{error|safe}} </code></pre> + {% else %} + {% if error.given_input %} + <table class="table table-bordered" width="100%"> + <col width="30%"> + <tr class = "active"> + <td> For given Input value(s):</td> + <td>{{error.given_input}}</td> + </table> + {% endif %} + <table class="table table-bordered" width="100%"> + <col width="10%"> + <col width="40%"> + <col width="40%"> + <col width="10%"> + <tr class="info"> + <td><b><center>Line No.</center></b></td> + <td><b><center>Expected Output</center></b></td> + <td><b><center>User output</center></b></td> + <td><b><center>Status</center></b></td> + </tr> + {% for expected,user in error.expected_output|zip:error.user_output %} + <td> {{forloop.counter}} </td> + <td>{{expected|default:""}} </td> + <td>{{user|default:""}}</td> + {% if forloop.counter0 in error.error_no or not expected or not user %} + <td><span class ="glyphicon glyphicon-remove text-warning"></td> + {% else %} + <td><span class ="glyphicon glyphicon-ok text-success"></td> + {% endif %} + </tr> + {% endfor %} + </table> + <table width="100%" class='table table-bordered'> + <col width="10"> + <tr class = "danger"> + <td><b>Error:</b></td> + <td>{{error.error}}</td> + + </table> + + {% endif %} + </div> + </div> </div> {% endfor %} diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html index 0dad59d..e1cdcf8 100644 --- a/yaksh/templates/yaksh/question.html +++ b/yaksh/templates/yaksh/question.html @@ -6,6 +6,7 @@ <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/dashboard.css" type="text/css" /> <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/question.css" type="text/css" /> <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/codemirror/lib/codemirror.css" type="text/css" /> +<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/exam.css" type="text/css" /> <style> .CodeMirror{ border-style: groove; diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index f610cc6..35ae795 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -1,5 +1,6 @@ from django import template from django.template.defaultfilters import stringfilter +from itertools import zip_longest register = template.Library() @@ -19,3 +20,7 @@ def completed(answerpaper): @register.assignment_tag(name="inprogress") def inprogress(answerpaper): return answerpaper.filter(status="inprogress").count() + +@register.filter(name='zip') +def zip_longest_out(a, b): + return zip_longest(a, b)
\ No newline at end of file |