summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--grades/urls.py2
-rw-r--r--online_test/urls.py2
-rw-r--r--requirements/requirements-codeserver.txt1
-rw-r--r--requirements/requirements-common.txt2
-rw-r--r--setup.py2
-rw-r--r--yaksh/decorators.py12
-rw-r--r--yaksh/error_messages.py38
-rw-r--r--yaksh/evaluator_tests/test_python_evaluation.py554
-rw-r--r--yaksh/grader.py44
-rw-r--r--yaksh/models.py31
-rw-r--r--yaksh/python_assertion_evaluator.py20
-rw-r--r--yaksh/send_emails.py2
-rw-r--r--yaksh/static/yaksh/js/requesthandler.js21
-rw-r--r--yaksh/templates/yaksh/error_template.html2
-rw-r--r--yaksh/templates/yaksh/question.html8
-rw-r--r--yaksh/test_models.py72
-rw-r--r--yaksh/test_views.py2
-rw-r--r--yaksh/tests/test_code_server.py34
-rw-r--r--yaksh/urls.py2
-rw-r--r--yaksh/urls_password_reset.py2
-rw-r--r--yaksh/views.py243
21 files changed, 597 insertions, 499 deletions
diff --git a/grades/urls.py b/grades/urls.py
index 49276ba9..32a7e4d 100644
--- a/grades/urls.py
+++ b/grades/urls.py
@@ -1,4 +1,4 @@
-from django.conf.urls import url, patterns
+from django.conf.urls import url
from grades import views
urlpatterns = [
diff --git a/online_test/urls.py b/online_test/urls.py
index 3e62fd6..e55864a 100644
--- a/online_test/urls.py
+++ b/online_test/urls.py
@@ -1,4 +1,4 @@
-from django.conf.urls import patterns, include, url
+from django.conf.urls import include, url
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
diff --git a/requirements/requirements-codeserver.txt b/requirements/requirements-codeserver.txt
index 004e45b..11bc0a2 100644
--- a/requirements/requirements-codeserver.txt
+++ b/requirements/requirements-codeserver.txt
@@ -4,3 +4,4 @@ six
requests
tornado==4.5.3
psutil
+nose==1.3.7
diff --git a/requirements/requirements-common.txt b/requirements/requirements-common.txt
index b170694..484111e 100644
--- a/requirements/requirements-common.txt
+++ b/requirements/requirements-common.txt
@@ -1,6 +1,6 @@
-r requirements-codeserver.txt
invoke==0.21.0
-django==1.9.5
+django==1.10
django-taggit==0.18.1
pytz==2016.4
python-social-auth==0.2.19
diff --git a/setup.py b/setup.py
index 83a5e42..e8e1394 100644
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@ def get_version():
return data.get('__version__')
install_requires = [
- 'django==1.9.5',
+ 'django==1.10',
'django-taggit==0.18.1',
'pytz==2016.4',
'python-social-auth==0.2.19',
diff --git a/yaksh/decorators.py b/yaksh/decorators.py
index 9e9bc6d..4b886a3 100644
--- a/yaksh/decorators.py
+++ b/yaksh/decorators.py
@@ -1,4 +1,4 @@
-from django.shortcuts import render_to_response, redirect
+from django.shortcuts import render, redirect
from django.conf import settings
from django.template import RequestContext
@@ -20,15 +20,13 @@ def has_profile(func):
def _wrapped_view(request, *args, **kwargs):
if user_has_profile(request.user):
return func(request, *args, **kwargs)
- ci = RequestContext(request)
if request.user.groups.filter(name='moderator').exists():
template = 'manage.html'
else:
template = 'user.html'
form = ProfileForm(user=request.user, instance=None)
context = {'template': template, 'form': form}
- return render_to_response('yaksh/editprofile.html', context,
- context_instance=ci)
+ return render(request, 'yaksh/editprofile.html', context)
return _wrapped_view
@@ -40,7 +38,6 @@ def email_verified(func):
"""
def is_email_verified(request, *args, **kwargs):
- ci = RequestContext(request)
user = request.user
context = {}
if not settings.IS_DEVELOPMENT:
@@ -49,7 +46,8 @@ def email_verified(func):
context['success'] = False
context['msg'] = "Your account is not verified. \
Please verify your account"
- return render_to_response('yaksh/activation_status.html',
- context, context_instance=ci)
+ return render(
+ request, 'yaksh/activation_status.html', context
+ )
return func(request, *args, **kwargs)
return is_email_verified \ No newline at end of file
diff --git a/yaksh/error_messages.py b/yaksh/error_messages.py
index 7ea8618..7a18c22 100644
--- a/yaksh/error_messages.py
+++ b/yaksh/error_messages.py
@@ -3,7 +3,9 @@ try:
except ImportError:
from itertools import izip_longest as zip_longest
-def prettify_exceptions(exception, message, traceback=None, testcase=None):
+
+def prettify_exceptions(exception, message, traceback=None,
+ testcase=None, line_no=None):
err = {"type": "assertion",
"exception": exception,
"traceback": traceback,
@@ -13,23 +15,28 @@ def prettify_exceptions(exception, message, traceback=None, testcase=None):
err["traceback"] = None
if exception == 'AssertionError':
- value = ("Expected answer from the"
- + " test case did not match the output")
- err["message"] = value
+ value = ("Expected answer from the" +
+ " test case did not match the output")
+ if message:
+ err["message"] = message
+ else:
+ err["message"] = value
err["traceback"] = None
- if testcase:
- err["test_case"] = testcase
+ err["test_case"] = testcase
+ err["line_no"] = line_no
return err
+
def _get_incorrect_user_lines(exp_lines, user_lines):
err_line_numbers = []
for line_no, (expected_line, user_line) in \
- enumerate(zip_longest(exp_lines, user_lines)):
- if not user_line or not expected_line or \
- user_line.strip() != expected_line.strip():
+ enumerate(zip_longest(exp_lines, user_lines)):
+ if (not user_line or not expected_line or
+ user_line.strip() != expected_line.strip()):
err_line_numbers.append(line_no)
return err_line_numbers
-
+
+
def compare_outputs(expected_output, user_output, given_input=None):
given_lines = user_output.splitlines()
exp_lines = expected_output.splitlines()
@@ -44,18 +51,17 @@ def compare_outputs(expected_output, user_output, given_input=None):
msg["error_line_numbers"] = err_line_numbers
if ng != ne:
msg["error_msg"] = ("Incorrect Answer: "
- + "We had expected {} number of lines. "\
- .format(ne)
+ + "We had expected {} number of lines. ".format(ne)
+ "We got {} number of lines.".format(ng)
)
return False, msg
else:
if err_line_numbers:
msg["error_msg"] = ("Incorrect Answer: "
- + "Line number(s) {0} did not match."
- .format(", ".join(map(
- str,[x+1 for x in err_line_numbers]
- ))))
+ + "Line number(s) {0} did not match."
+ .format(", ".join(
+ map(str, [x+1 for x in err_line_numbers])
+ )))
return False, msg
else:
msg["error_msg"] = "Correct Answer"
diff --git a/yaksh/evaluator_tests/test_python_evaluation.py b/yaksh/evaluator_tests/test_python_evaluation.py
index 71d7732..1933d17 100644
--- a/yaksh/evaluator_tests/test_python_evaluation.py
+++ b/yaksh/evaluator_tests/test_python_evaluation.py
@@ -1,7 +1,6 @@
from __future__ import unicode_literals
import unittest
import os
-import sys
import tempfile
import shutil
from textwrap import dedent
@@ -26,13 +25,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
self.in_dir = tmp_in_dir_path
self.test_case_data = [{"test_case_type": "standardtestcase",
"test_case": 'assert(add(1,2)==3)',
- 'weight': 0.0},
+ 'weight': 0.0},
{"test_case_type": "standardtestcase",
"test_case": 'assert(add(-1,2)==1)',
- 'weight': 0.0},
+ 'weight': 0.0},
{"test_case_type": "standardtestcase",
"test_case": 'assert(add(-1,-2)==-3)',
- 'weight': 0.0},
+ 'weight': 0.0},
]
self.timeout_msg = ("Code took more than {0} seconds to run. "
"You probably have an infinite loop in"
@@ -46,14 +45,12 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
def test_correct_answer(self):
# Given
user_answer = "def add(a,b):\n\treturn a + b"
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
}
# When
@@ -66,14 +63,12 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
def test_incorrect_answer(self):
# Given
user_answer = "def add(a,b):\n\treturn a - b"
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
}
# When
@@ -85,13 +80,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
given_test_case_list = [tc["test_case"] for tc in self.test_case_data]
for error in result.get("error"):
self.assertEqual(error['exception'], 'AssertionError')
- self.assertEqual(error['message'],
- "Expected answer from the test case did not match the output"
- )
+ self.assertEqual(
+ error['message'],
+ "Expected answer from the test case did not match the output"
+ )
error_testcase_list = [tc['test_case'] for tc in result.get('error')]
self.assertEqual(error_testcase_list, given_test_case_list)
-
def test_partial_incorrect_answer(self):
# Given
user_answer = "def add(a,b):\n\treturn abs(a) + abs(b)"
@@ -100,19 +95,17 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
'weight': 1.0},
{"test_case_type": "standardtestcase",
"test_case": 'assert(add(-1,-2)==-3)',
- 'weight': 1.0},
+ 'weight': 1.0},
{"test_case_type": "standardtestcase",
"test_case": 'assert(add(1,2)==3)',
'weight': 2.0}
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': True,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': True,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -126,22 +119,22 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
given_test_case_list.remove('assert(add(1,2)==3)')
for error in result.get("error"):
self.assertEqual(error['exception'], 'AssertionError')
- self.assertEqual(error['message'],
- "Expected answer from the test case did not match the output"
- )
+ self.assertEqual(
+ error['message'],
+ "Expected answer from the test case did not match the output"
+ )
error_testcase_list = [tc['test_case'] for tc in result.get('error')]
self.assertEqual(error_testcase_list, given_test_case_list)
+
def test_infinite_loop(self):
# Given
user_answer = "def add(a, b):\n\twhile True:\n\t\tpass"
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
}
# When
@@ -168,14 +161,12 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"SyntaxError",
"invalid syntax"
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
}
# When
@@ -201,14 +192,12 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"IndentationError",
"indented block"
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
}
# When
@@ -220,9 +209,9 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
self.assertFalse(result.get("success"))
self.assertEqual(5, len(err))
for msg in indent_error_msg:
- self.assert_correct_output(msg,
- result.get("error")[0]['traceback']
- )
+ self.assert_correct_output(
+ msg, result.get("error")[0]['traceback']
+ )
def test_name_error(self):
# Given
@@ -234,15 +223,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"defined"
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
+ }
# When
grader = Grader(self.in_dir)
@@ -258,15 +245,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
return add(3, 3)
""")
recursion_error_msg = "maximum recursion depth exceeded"
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
+ }
# When
grader = Grader(self.in_dir)
@@ -289,15 +274,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"argument"
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
+ }
# When
grader = Grader(self.in_dir)
@@ -323,25 +306,26 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"base"
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
+ }
# When
grader = Grader(self.in_dir)
result = grader.evaluate(kwargs)
- err = result.get("error")[0]['traceback']
+ errors = result.get("error")
# Then
self.assertFalse(result.get("success"))
for msg in value_error_msg:
- self.assert_correct_output(msg, err)
+ self.assert_correct_output(msg, errors[0]['traceback'])
+ for index, error in enumerate(errors):
+ self.assertEqual(error['test_case'],
+ self.test_case_data[index]['test_case'])
def test_file_based_assert(self):
# Given
@@ -356,15 +340,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
return f.read()[0]
""")
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data,
+ }
# When
grader = Grader(self.in_dir)
@@ -390,25 +372,23 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
]
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
+ }
# When
grader = Grader(self.in_dir)
result = grader.evaluate(kwargs)
- err = result.get("error")[0]['traceback']
+ err = result.get("error")[0]['traceback']
# Then
self.assertFalse(result.get("success"))
for msg in syntax_error_msg:
self.assert_correct_output(msg, err)
-
def test_multiple_testcase_error(self):
""" Tests the user answer with an correct test case
first and then with an incorrect test case """
@@ -418,7 +398,8 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"test_case": 'assert(palindrome("abba")==True)',
"weight": 0.0},
{"test_case_type": "standardtestcase",
- "test_case": 's="abbb"\nassert palindrome(S)==False',
+ "test_case": 's="abbb"\n'
+ 'assert palindrome(S)==False',
"weight": 0.0}
]
name_error_msg = ["Traceback",
@@ -426,15 +407,13 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
"NameError",
"name 'S' is not defined"
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
+ }
# When
grader = Grader(self.in_dir)
@@ -454,18 +433,15 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
return type(a)
""")
test_case_data = [{"test_case_type": "standardtestcase",
- "test_case": 'assert(strchar("hello")==str)',
- "weight": 0.0
- },]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
- }
+ "test_case": 'assert(strchar("hello")==str)',
+ "weight": 0.0}]
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
+ }
# When
grader = Grader(self.in_dir)
result = grader.evaluate(kwargs)
@@ -473,6 +449,31 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertTrue(result.get("success"))
+ def test_incorrect_answer_with_nose_assert(self):
+ user_answer = dedent("""\
+ def add(a, b):
+ return a - b
+ """)
+ test_case_data = [{"test_case_type": "standardtestcase",
+ "test_case": 'assert_equal(add(1, 2), 3)',
+ "weight": 0.0}]
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
+ }
+ # When
+ grader = Grader(self.in_dir)
+ result = grader.evaluate(kwargs)
+
+ # Then
+ self.assertFalse(result.get("success"))
+ error = result.get("error")[0]
+ self.assertEqual(error['exception'], 'AssertionError')
+ self.assertEqual(error['message'], '-1 != 3')
+
class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
def setUp(self):
@@ -501,13 +502,12 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
"""
)
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data
+ }
# When
grader = Grader(self.in_dir)
@@ -534,13 +534,12 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
)
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data
+ }
# When
grader = Grader(self.in_dir)
@@ -551,11 +550,13 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
def test_correct_answer_string(self):
# Given
- self.test_case_data = [{"test_case_type": "stdiobasedtestcase",
- "expected_input": ("the quick brown fox jumps over the lazy dog\nthe"),
- "expected_output": "2",
- "weight": 0.0
- }]
+ self.test_case_data = [{
+ "test_case_type": "stdiobasedtestcase",
+ "expected_input": ("the quick brown fox jumps over "
+ "the lazy dog\nthe"),
+ "expected_output": "2",
+ "weight": 0.0
+ }]
user_answer = dedent("""
from six.moves import input
a = str(input())
@@ -565,13 +566,12 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
)
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data
+ }
# When
grader = Grader(self.in_dir)
@@ -594,13 +594,12 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
"""
)
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data
+ }
# When
grader = Grader(self.in_dir)
@@ -629,13 +628,12 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
"""
)
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data
+ }
# When
grader = Grader(self.in_dir)
@@ -646,24 +644,24 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
def test_infinite_loop(self):
# Given
- self.test_case_data = [{"test_case_type": "stdiobasedtestcase",
- "expected_input": "1\n2",
- "expected_output": "3",
- "weight": 0.0
- }]
+ self.test_case_data = [{
+ "test_case_type": "stdiobasedtestcase",
+ "expected_input": "1\n2",
+ "expected_output": "3",
+ "weight": 0.0
+ }]
timeout_msg = ("Code took more than {0} seconds to run. "
- "You probably have an infinite loop in"
- " your code.").format(SERVER_TIMEOUT)
+ "You probably have an infinite loop in"
+ " your code.").format(SERVER_TIMEOUT)
user_answer = "while True:\n\tpass"
kwargs = {'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': self.test_case_data
- }
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': self.test_case_data
+ }
# When
grader = Grader(self.in_dir)
@@ -675,7 +673,6 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
)
self.assertFalse(result.get('success'))
-
def test_unicode_literal_bug(self):
# Given
user_answer = dedent("""\
@@ -687,21 +684,44 @@ class PythonStdIOEvaluationTestCases(EvaluatorBaseTest):
"expected_output": "str",
"weight": 0.0
}]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
- }
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
+ }
# When
grader = Grader(self.in_dir)
result = grader.evaluate(kwargs)
# Then
self.assertTrue(result.get("success"))
+ def test_get_error_lineno(self):
+ user_answer = dedent("""\
+ print(1/0)
+ """)
+ test_case_data = [{"test_case_type": "stdiobasedtestcase",
+ "expected_input": "",
+ "expected_output": "1",
+ "weight": 0.0
+ }]
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
+ }
+ # When
+ grader = Grader(self.in_dir)
+ result = grader.evaluate(kwargs)
+ # Then
+ self.assertFalse(result.get("success"))
+ error = result.get("error")[0]
+ self.assertEqual(error['line_no'], 1)
+ self.assertEqual(error['exception'], "ZeroDivisionError")
+
class PythonHookEvaluationTestCases(EvaluatorBaseTest):
@@ -733,19 +753,17 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 1.0
return success, err, mark_fraction
"""
- )
+ )
test_case_data = [{"test_case_type": "hooktestcase",
- "hook_code": hook_code,"weight": 1.0
- }]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': True,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ "hook_code": hook_code, "weight": 1.0
+ }]
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': True,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -768,20 +786,18 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 1.0
return success, err, mark_fraction
"""
- )
+ )
test_case_data = [{"test_case_type": "hooktestcase",
- "hook_code": hook_code,"weight": 1.0
- }]
-
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ "hook_code": hook_code, "weight": 1.0
+ }]
+
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -805,21 +821,19 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 1.0
return success, err, mark_fraction
"""
- )
+ )
test_case_data = [{"test_case_type": "standardtestcase",
"test_case": assert_test_case, 'weight': 1.0},
{"test_case_type": "hooktestcase",
"hook_code": hook_code, 'weight': 1.0},
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': True,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': True,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -842,7 +856,7 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 0.5
return success, err, mark_fraction
"""
- )
+ )
hook_code_2 = dedent("""\
def check_answer(user_answer):
success = False
@@ -853,22 +867,19 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 1.0
return success, err, mark_fraction
"""
- )
-
+ )
test_case_data = [{"test_case_type": "hooktestcase",
"hook_code": hook_code_1, 'weight': 1.0},
{"test_case_type": "hooktestcase",
"hook_code": hook_code_2, 'weight': 1.0},
]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': True,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': True,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -892,19 +903,18 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 1.0
return success, err, mark_fraction
"""
- )
+ )
+
test_case_data = [{"test_case_type": "hooktestcase",
- "hook_code": hook_code,"weight": 1.0
- }]
-
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ "hook_code": hook_code, "weight": 1.0
+ }]
+
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -931,19 +941,18 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
success, err, mark_fraction = True, "", 1.0
return success, err, mark_fraction
"""
- )
+ )
+
test_case_data = [{"test_case_type": "hooktestcase",
- "hook_code": hook_code,"weight": 1.0
- }]
- kwargs = {
- 'metadata': {
- 'user_answer': user_answer,
- 'file_paths': self.file_paths,
- 'assign_files': [(self.tmp_file, False)],
- 'partial_grading': False,
- 'language': 'python'
- },
- 'test_case_data': test_case_data,
+ "hook_code": hook_code, "weight": 1.0
+ }]
+ kwargs = {'metadata': {
+ 'user_answer': user_answer,
+ 'file_paths': self.file_paths,
+ 'assign_files': [(self.tmp_file, False)],
+ 'partial_grading': False,
+ 'language': 'python'},
+ 'test_case_data': test_case_data,
}
# When
@@ -953,5 +962,6 @@ class PythonHookEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertTrue(result.get('success'))
+
if __name__ == '__main__':
unittest.main()
diff --git a/yaksh/grader.py b/yaksh/grader.py
index 38cce8d..320e7e7 100644
--- a/yaksh/grader.py
+++ b/yaksh/grader.py
@@ -1,22 +1,12 @@
#!/usr/bin/env python
from __future__ import unicode_literals
import sys
-import pwd
import os
-import stat
import contextlib
-from os.path import isdir, dirname, abspath, join, isfile, exists
+from os.path import dirname, abspath
import signal
import traceback
-from multiprocessing import Process, Queue
-import subprocess
-import re
-try:
- from SimpleXMLRPCServer import SimpleXMLRPCServer
-except ImportError:
- # The above import will not work on Python-3.x.
- from xmlrpc.server import SimpleXMLRPCServer
# Local imports
from .settings import SERVER_TIMEOUT
@@ -26,11 +16,13 @@ from .error_messages import prettify_exceptions
MY_DIR = abspath(dirname(__file__))
registry = None
+
# Raised when the code times-out.
# c.f. http://pguides.net/python/timeout-a-function
class TimeoutException(Exception):
pass
+
@contextlib.contextmanager
def change_dir(path):
cur_dir = abspath(dirname(MY_DIR))
@@ -75,7 +67,6 @@ class Grader(object):
self.timeout_msg = msg
self.in_dir = in_dir if in_dir else MY_DIR
-
def evaluate(self, kwargs):
"""Evaluates given code with the test cases based on
given arguments in test_case_data.
@@ -122,7 +113,6 @@ class Grader(object):
test_case_instances.append(test_case_instance)
return test_case_instances
-
def safe_evaluate(self, test_case_instances):
"""
Handles code evaluation along with compilation, signal handling
@@ -131,7 +121,9 @@ class Grader(object):
# Add a new signal handler for the execution of this code.
prev_handler = create_signal_handler()
success = False
- test_case_success_status = [False] * len(test_case_instances)
+ test_case_success_status = [False]
+ if len(test_case_instances) != 0:
+ test_case_success_status = [False] * len(test_case_instances)
error = []
weight = 0.0
@@ -155,20 +147,24 @@ class Grader(object):
test_case_instance.teardown()
except TimeoutException:
- error.append(prettify_exceptions("TimeoutException",
- self.timeout_msg
- )
- )
- except Exception:
+ error.append(
+ prettify_exceptions("TimeoutException", self.timeout_msg)
+ )
+ except Exception as e:
exc_type, exc_value, exc_tb = sys.exc_info()
tb_list = traceback.format_exception(exc_type, exc_value, exc_tb)
+ try:
+ line_no = e.lineno
+ except AttributeError:
+ line_no = traceback.extract_tb(exc_tb)[-1][1]
if len(tb_list) > 2:
del tb_list[1:3]
- error.append(prettify_exceptions(exc_type.__name__,
- str(exc_value),
- "".join(tb_list),
- )
- )
+ error.append(
+ prettify_exceptions(
+ exc_type.__name__, str(exc_value), "".join(tb_list),
+ line_no=line_no
+ )
+ )
finally:
# Set back any original signal handler.
set_original_signal_handler(prev_handler)
diff --git a/yaksh/models.py b/yaksh/models.py
index 36e859c..50a5cc2 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -317,7 +317,7 @@ class Quiz(models.Model):
attempts_allowed = models.IntegerField(default=1, choices=attempts)
time_between_attempts = models.FloatField(
- "Time Between Quiz Attempts in hours"
+ "Time Between Quiz Attempts in hours", default=0.0
)
is_trial = models.BooleanField(default=False)
@@ -387,6 +387,20 @@ class Quiz(models.Model):
course=course, passed=False
).values_list("user", flat=True).distinct().count()
+ def get_answerpaper_status(self, user, course):
+ try:
+ qp = self.questionpaper_set.get().id
+ except QuestionPaper.DoesNotExist:
+ qp = None
+ ans_ppr = AnswerPaper.objects.filter(
+ user=user, course=course, question_paper=qp
+ ).order_by("-attempt_number")
+ if ans_ppr.exists():
+ status = ans_ppr.first().status
+ else:
+ status = "not attempted"
+ return status
+
def _create_quiz_copy(self, user):
question_papers = self.questionpaper_set.all()
new_quiz = self
@@ -425,6 +439,8 @@ class LearningUnit(models.Model):
if course_status.exists():
if self in course_status.first().completed_units.all():
state = "completed"
+ elif self.type == "quiz":
+ state = self.quiz.get_answerpaper_status(user, course)
elif course_status.first().current_unit == self:
state = "inprogress"
return state
@@ -1373,11 +1389,18 @@ class QuestionPaper(models.Model):
)
if last_attempt:
time_lag = (timezone.now() - last_attempt.start_time).total_seconds() / 3600
- return time_lag >= self.quiz.time_between_attempts
+ can_attempt = time_lag >= self.quiz.time_between_attempts
+ msg = "You cannot start the next attempt for this quiz before {0} hour(s)".format(
+ self.quiz.time_between_attempts
+ ) if not can_attempt else None
+ return can_attempt, msg
else:
- return True
+ return True, None
else:
- return False
+ msg = "You cannot attempt {0} quiz more than {1} time(s)".format(
+ self.quiz.description, self.quiz.attempts_allowed
+ )
+ return False, msg
def create_demo_quiz_ppr(self, demo_quiz, user):
question_paper = QuestionPaper.objects.create(quiz=demo_quiz,
diff --git a/yaksh/python_assertion_evaluator.py b/yaksh/python_assertion_evaluator.py
index 440f422..4b016a1 100644
--- a/yaksh/python_assertion_evaluator.py
+++ b/yaksh/python_assertion_evaluator.py
@@ -1,10 +1,6 @@
#!/usr/bin/env python
import sys
import traceback
-import os
-import re
-from os.path import join
-import importlib
# Local imports
from .file_utils import copy_files, delete_files
@@ -53,22 +49,24 @@ class PythonAssertionEvaluator(BaseEvaluator):
--------
Returns a tuple (success, error, test_case_weight)
- success - Boolean, indicating if code was executed successfully, correctly
+ success - Boolean, indicating if code was executed successfully,
+ correctly
weight - Float, indicating total weight of all successful test cases
error - String, error message if success is false
- returns (True, "Correct answer", 1.0) : If the student script passes all
- test cases/have same output, when compared to the instructor script
+ returns (True, "Correct answer", 1.0) : If the student script passes
+ all test cases/have same output, when compared to the instructor script
returns (False, error_msg, 0.0): If the student script fails a single
test/have dissimilar output, when compared to the instructor script.
- Returns (False, error_msg, 0.0): If mandatory arguments are not files or if
- the required permissions are not given to the file(s).
+ Returns (False, error_msg, 0.0): If mandatory arguments are not files
+ or if the required permissions are not given to the file(s).
"""
success = False
mark_fraction = 0.0
try:
+ exec("from nose.tools import *", self.exec_scope)
_tests = compile(self.test_case, '<string>', mode='exec')
exec(_tests, self.exec_scope)
except TimeoutException:
@@ -76,12 +74,14 @@ class PythonAssertionEvaluator(BaseEvaluator):
except Exception:
exc_type, exc_value, exc_tb = sys.exc_info()
tb_list = traceback.format_exception(exc_type, exc_value, exc_tb)
+ line_no = traceback.extract_tb(exc_tb)[-1][1]
if len(tb_list) > 2:
del tb_list[1:3]
err = prettify_exceptions(exc_type.__name__,
str(exc_value),
"".join(tb_list),
- self.test_case
+ self.test_case,
+ line_no
)
else:
success = True
diff --git a/yaksh/send_emails.py b/yaksh/send_emails.py
index ae49f23..4c9a7dc 100644
--- a/yaksh/send_emails.py
+++ b/yaksh/send_emails.py
@@ -65,7 +65,7 @@ def send_bulk_mail(subject, email_body, recipients, attachments):
try:
text_msg = ""
msg = EmailMultiAlternatives(subject, text_msg, settings.SENDER_EMAIL,
- recipients
+ [settings.SENDER_EMAIL], bcc=recipients
)
msg.attach_alternative(email_body, "text/html")
if attachments:
diff --git a/yaksh/static/yaksh/js/requesthandler.js b/yaksh/static/yaksh/js/requesthandler.js
index a215ce4..952de3a 100644
--- a/yaksh/static/yaksh/js/requesthandler.js
+++ b/yaksh/static/yaksh/js/requesthandler.js
@@ -75,6 +75,24 @@ function response_handler(method_type, content_type, data, uid){
var error_output = document.getElementById("error_panel");
error_output.innerHTML = res.error;
focus_on_error(error_output);
+ if(global_editor.editor){
+ err_lineno = $("#err_lineno").val();
+ if(marker){
+ marker.clear();
+ }
+ if(err_lineno){
+ var lineno = parseInt(err_lineno) - 1;
+ var editor = global_editor.editor;
+ var line_length = editor.getLine(lineno).length;
+ marker = editor.markText({line: lineno, ch: 0}, {line: lineno, ch: line_length},
+ {className: "activeline", clearOnEnter:true});
+ }
+ else{
+ if(marker){
+ marker.clear();
+ }
+ }
+ }
}
} else {
reset_values();
@@ -125,6 +143,8 @@ function ajax_check_code(url, method_type, data_type, data, uid)
var global_editor = {};
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
+var err_lineno;
+var marker;
$(document).ready(function(){
if(is_exercise == "True" && can_skip == "False"){
setTimeout(function() {show_solution();}, delay_time*1000);
@@ -148,6 +168,7 @@ $(document).ready(function(){
mode: mode_dict[lang],
gutter: true,
lineNumbers: true,
+ styleSelectedText: true,
onChange: function (instance, changes) {
render();
}
diff --git a/yaksh/templates/yaksh/error_template.html b/yaksh/templates/yaksh/error_template.html
index 61657ae..301020e 100644
--- a/yaksh/templates/yaksh/error_template.html
+++ b/yaksh/templates/yaksh/error_template.html
@@ -3,7 +3,6 @@
{% endblock %}
{% load custom_filters %}
-
{% if error_message %}
{% for error in error_message %}
@@ -35,6 +34,7 @@
</tr>
<tr>
{% if error.traceback %}
+ <input type="hidden" id="err_lineno" value="{{error.line_no}}">
<td><b>Full Traceback: </b></td>
<td><pre>{{error.traceback}}</pre></td>
{% endif %}
diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html
index b65073a..ebfe066 100644
--- a/yaksh/templates/yaksh/question.html
+++ b/yaksh/templates/yaksh/question.html
@@ -11,6 +11,10 @@
.CodeMirror{
border-style: groove;
}
+ .activeline {
+ background: #FBC2C4 !important;
+ color: #8a1f11 !important;
+ }
</style>
{% endblock %}
@@ -221,7 +225,7 @@ question_type = "{{ question.type }}"
{% if question.type == "integer" %}
Enter Integer:<br/>
- <input autofocus name="answer" type="number" id="integer" value={{ last_attempt|safe }} />
+ <input autofocus name="answer" type="number" id="integer" value="{{ last_attempt|safe }}" />
<br/><br/>
{% endif %}
@@ -233,7 +237,7 @@ question_type = "{{ question.type }}"
{% if question.type == "float" %}
Enter Decimal Value :<br/>
- <input autofocus name="answer" type="number" step="any" id="float" value={{ last_attempt|safe }} />
+ <input autofocus name="answer" type="number" step="any" id="float" value="{{ last_attempt|safe }}" />
<br/><br/>
{% endif %}
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index 4cea419..f97b7b2 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -210,10 +210,11 @@ class LearningModuleTestCases(unittest.TestCase):
# Given
module_status = 'not attempted'
# When
+ self.learning_module.learning_unit.remove(self.learning_unit_two)
status = self.learning_module.get_status(self.student, self.course)
# Then
self.assertEqual(status, module_status)
-
+ self.learning_module.learning_unit.add(self.learning_unit_two)
# Module in progress
# Given
@@ -630,6 +631,15 @@ class QuestionPaperTestCases(unittest.TestCase):
# All active questions
self.questions = Question.objects.filter(active=True, user=self.user)
self.quiz = Quiz.objects.get(description="demo quiz 1")
+ self.quiz_with_time_between_attempts = Quiz.objects.create(
+ description="demo quiz with time between attempts",
+ start_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzinfo=pytz.utc),
+ end_date_time=datetime(2199, 10, 9, 10, 8, 15, 0, tzinfo=pytz.utc),
+ duration=30, active=True,
+ attempts_allowed=3, time_between_attempts=1.0,
+ pass_criteria=0,
+ instructions="Demo Instructions"
+ )
# create question paper with only fixed questions
self.question_paper_fixed_questions = QuestionPaper.objects.create(
@@ -657,6 +667,12 @@ class QuestionPaperTestCases(unittest.TestCase):
shuffle_questions=True
)
+ self.question_paper_with_time_between_attempts = QuestionPaper.objects.create(
+ quiz=self.quiz_with_time_between_attempts,
+ total_marks=0.0,
+ shuffle_questions=True
+ )
+
self.question_paper.fixed_question_order = "{0}, {1}".format(
self.questions[3].id, self.questions[5].id
)
@@ -708,6 +724,9 @@ class QuestionPaperTestCases(unittest.TestCase):
self.trial_course = Course.objects.create_trial_course(self.user)
self.trial_quiz = Quiz.objects.create_trial_quiz(self.user)
+ @classmethod
+ def tearDownClass(self):
+ self.quiz.questionpaper_set.all().delete()
def test_get_question_bank(self):
# Given
@@ -784,8 +803,10 @@ class QuestionPaperTestCases(unittest.TestCase):
answerpaper.passed = True
answerpaper.save()
# test can_attempt_now(self):
- self.assertFalse(self.question_paper.can_attempt_now(self.user,
- self.course.id))
+ result = (False, u'You cannot attempt demo quiz 1 quiz more than 1 time(s)')
+ self.assertEquals(
+ self.question_paper.can_attempt_now(self.user, self.course.id), result
+ )
# trying to create an answerpaper with same parameters passed.
answerpaper2 = self.question_paper.make_answerpaper(self.user, self.ip,
attempt_num,
@@ -794,6 +815,46 @@ class QuestionPaperTestCases(unittest.TestCase):
self.assertEqual(answerpaper, answerpaper2)
+ def test_time_between_attempt(self):
+ """ Test make_answerpaper() method of Question Paper"""
+ already_attempted = self.attempted_papers.count()
+ attempt_num = 1
+
+ self.first_start_time = timezone.now()
+ self.first_end_time = self.first_start_time + timedelta(minutes=20)
+ self.second_start_time = self.first_start_time + timedelta(minutes=30)
+ self.second_end_time = self.second_start_time + timedelta(minutes=20)
+
+ # create answerpaper
+ self.first_answerpaper = AnswerPaper(
+ user=self.user,
+ question_paper=self.question_paper_with_time_between_attempts,
+ start_time=self.first_start_time,
+ end_time=self.first_end_time,
+ user_ip=self.ip,
+ course=self.course,
+ attempt_number=attempt_num
+ )
+ self.first_answerpaper.passed = True
+ self.first_answerpaper.save()
+
+ self.second_answerpaper = AnswerPaper(
+ user=self.user,
+ question_paper=self.question_paper_with_time_between_attempts,
+ start_time=self.second_start_time,
+ end_time=self.second_end_time,
+ user_ip=self.ip,
+ course=self.course,
+ attempt_number=attempt_num + 1
+ )
+ self.second_answerpaper.passed = True
+ self.second_answerpaper.save()
+
+ result = (False, u'You cannot start the next attempt for this quiz before 1.0 hour(s)')
+ self.assertEquals(
+ self.question_paper_with_time_between_attempts.can_attempt_now(self.user, self.course.id), result
+ )
+
def test_create_trial_paper_to_test_quiz(self):
qu_list = [str(self.questions_list[0]), str(self.questions_list[1])]
@@ -996,9 +1057,10 @@ class AnswerPaperTestCases(unittest.TestCase):
self.server_pool = server_pool
self.server_thread = t = Thread(target=server_pool.run)
t.start()
-
+
@classmethod
def tearDownClass(self):
+ self.quiz.questionpaper_set.all().delete()
self.server_pool.stop()
self.server_thread.join()
settings.code_evaluators['python']['standardtestcase'] = \
@@ -1670,7 +1732,7 @@ class CourseTestCases(unittest.TestCase):
modules = self.course.get_learning_modules()
percent = self.course.percent_completed(self.student1, modules)
self.assertEqual(percent, 0)
-
+ self.quiz1.questionpaper_set.all().delete()
# for course with module but zero percent completed
percent = self.course.percent_completed(self.student1, modules)
self.assertEqual(percent, 0)
diff --git a/yaksh/test_views.py b/yaksh/test_views.py
index 7f72e61..33747c8 100644
--- a/yaksh/test_views.py
+++ b/yaksh/test_views.py
@@ -2564,7 +2564,7 @@ class TestCourseDetail(TestCase):
attachment_file = mail.outbox[0].attachments[0][0]
subject = mail.outbox[0].subject
body = mail.outbox[0].alternatives[0][0]
- recipients = mail.outbox[0].recipients()
+ recipients = mail.outbox[0].bcc
self.assertEqual(attachment_file, "file.txt")
self.assertEqual(subject, "test_bulk_mail")
self.assertEqual(body, "Test_Mail")
diff --git a/yaksh/tests/test_code_server.py b/yaksh/tests/test_code_server.py
index 1309624..e2781df 100644
--- a/yaksh/tests/test_code_server.py
+++ b/yaksh/tests/test_code_server.py
@@ -106,6 +106,40 @@ class TestCodeServer(unittest.TestCase):
self.assertFalse(data['success'])
self.assertTrue('AssertionError' in data['error'][0]['exception'])
+ def test_question_with_no_testcases(self):
+ # Given
+ testdata = {
+ 'metadata': {
+ 'user_answer': 'def f(): return 1',
+ 'language': 'python',
+ 'partial_grading': False
+ },
+ 'test_case_data': []
+ }
+
+ # When
+ submit(self.url, '0', json.dumps(testdata), '')
+ result = get_result(self.url, '0', block=True)
+
+ # Then
+ data = json.loads(result.get('result'))
+ self.assertFalse(data['success'])
+
+ # With correct answer and test case
+ testdata["metadata"]["user_answer"] = 'def f(): return 2'
+ testdata["test_case_data"] = [{'test_case': 'assert f() == 2',
+ 'test_case_type': 'standardtestcase',
+ 'weight': 0.0
+ }
+ ]
+ # When
+ submit(self.url, '0', json.dumps(testdata), '')
+ result = get_result(self.url, '0', block=True)
+
+ # Then
+ data = json.loads(result.get('result'))
+ self.assertTrue(data['success'])
+
def test_multiple_simultaneous_hits(self):
# Given
results = Queue()
diff --git a/yaksh/urls.py b/yaksh/urls.py
index 4d35e10..2af1e70 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -1,4 +1,4 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from yaksh import views
urlpatterns = [
diff --git a/yaksh/urls_password_reset.py b/yaksh/urls_password_reset.py
index c1e36c6..4a7ddf3 100644
--- a/yaksh/urls_password_reset.py
+++ b/yaksh/urls_password_reset.py
@@ -1,4 +1,4 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from django.contrib.auth.views import password_reset, password_reset_confirm,\
password_reset_done, password_reset_complete, password_change,\
password_change_done
diff --git a/yaksh/views.py b/yaksh/views.py
index f458ad8..d8d630b 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -7,7 +7,7 @@ import csv
from django.http import HttpResponse, JsonResponse
from django.core.urlresolvers import reverse
from django.contrib.auth import login, logout, authenticate
-from django.shortcuts import render_to_response, get_object_or_404, redirect
+from django.shortcuts import render, get_object_or_404, redirect
from django.template import RequestContext, Context, Template
from django.template.loader import get_template, render_to_string
from django.http import Http404
@@ -65,14 +65,14 @@ def my_redirect(url):
return redirect(URL_ROOT + url)
-def my_render_to_response(template, context=None, **kwargs):
+def my_render_to_response(request, template, context=None, **kwargs):
"""Overridden render_to_response.
"""
if context is None:
context = {'URL_ROOT': URL_ROOT}
else:
context['URL_ROOT'] = URL_ROOT
- return render_to_response(template, context, **kwargs)
+ return render(request, template, context, **kwargs)
def is_moderator(user):
@@ -115,7 +115,6 @@ def user_register(request):
Create a user and corresponding profile and store roll_number also."""
user = request.user
- ci = RequestContext(request)
if user.is_authenticated():
return my_redirect("/exam/quizzes/")
context = {}
@@ -130,16 +129,18 @@ def user_register(request):
success, msg = send_user_mail(user_email, key)
context = {'activation_msg': msg}
return my_render_to_response(
+ request,
'yaksh/activation_status.html', context
)
return index(request)
else:
- return my_render_to_response('yaksh/register.html', {'form': form},
- context_instance=ci)
+ return my_render_to_response(
+ request, 'yaksh/register.html', {'form': form}
+ )
else:
form = UserRegisterForm()
return my_render_to_response(
- 'yaksh/register.html', {'form': form}, context_instance=ci
+ request, 'yaksh/register.html', {'form': form}
)
@@ -147,7 +148,7 @@ def user_logout(request):
"""Show a page to inform user that the quiz has been compeleted."""
logout(request)
context = {'message': "You have been logged out successfully"}
- return my_render_to_response('yaksh/complete.html', context)
+ return my_render_to_response(request, 'yaksh/complete.html', context)
@login_required
@@ -156,7 +157,6 @@ def user_logout(request):
def quizlist_user(request, enrolled=None, msg=None):
"""Show All Quizzes that is available to logged-in user."""
user = request.user
- ci = RequestContext(request)
if request.method == "POST":
course_code = request.POST.get('course_code')
@@ -178,9 +178,7 @@ def quizlist_user(request, enrolled=None, msg=None):
context = {'user': user, 'courses': courses, 'title': title,
'msg': msg}
- return my_render_to_response(
- "yaksh/quizzes_user.html", context, context_instance=ci
- )
+ return my_render_to_response(request, "yaksh/quizzes_user.html", context)
@login_required
@@ -190,14 +188,13 @@ def results_user(request):
user = request.user
papers = AnswerPaper.objects.get_user_answerpapers(user)
context = {'papers': papers}
- return my_render_to_response("yaksh/results_user.html", context)
+ return my_render_to_response(request, "yaksh/results_user.html", context)
@login_required
@email_verified
def add_question(request, question_id=None):
user = request.user
- ci = RequestContext(request)
test_case_type = None
if question_id is None:
@@ -259,7 +256,7 @@ def add_question(request, question_id=None):
'uploaded_files': uploaded_files
}
return my_render_to_response(
- "yaksh/add_question.html", context, context_instance=ci
+ request, "yaksh/add_question.html", context
)
qform = QuestionForm(instance=question)
@@ -284,7 +281,7 @@ def add_question(request, question_id=None):
context = {'qform': qform, 'fileform': fileform, 'question': question,
'formsets': formsets, 'uploaded_files': uploaded_files}
return my_render_to_response(
- "yaksh/add_question.html", context, context_instance=ci
+ request, "yaksh/add_question.html", context
)
@@ -294,7 +291,6 @@ def add_quiz(request, quiz_id=None, course_id=None):
"""To add a new quiz in the database.
Create a new quiz and store it."""
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this course !')
if quiz_id:
@@ -325,16 +321,13 @@ def add_quiz(request, quiz_id=None, course_id=None):
context["course_id"] = course_id
context["quiz"] = quiz
context["form"] = form
- return my_render_to_response(
- 'yaksh/add_quiz.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/add_quiz.html', context)
@login_required
@email_verified
def add_exercise(request, quiz_id=None, course_id=None):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this course !')
if quiz_id:
@@ -374,9 +367,7 @@ def add_exercise(request, quiz_id=None, course_id=None):
context["exercise"] = quiz
context["course_id"] = course_id
context["form"] = form
- return my_render_to_response(
- 'yaksh/add_exercise.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/add_exercise.html', context)
@login_required
@@ -386,7 +377,6 @@ def prof_manage(request, msg=None):
"""Take credentials of the user with professor/moderator
rights/permissions and log in."""
user = request.user
- ci = RequestContext(request)
if not user.is_authenticated():
return my_redirect('/exam/login')
if not is_moderator(user):
@@ -416,7 +406,7 @@ def prof_manage(request, msg=None):
'trial_paper': trial_paper, 'msg': msg
}
return my_render_to_response(
- 'yaksh/moderator_dashboard.html', context, context_instance=ci
+ request, 'yaksh/moderator_dashboard.html', context
)
@@ -424,7 +414,6 @@ def user_login(request):
"""Take the credentials of the user and log the user in."""
user = request.user
- ci = RequestContext(request)
context = {}
if user.is_authenticated():
return index(request)
@@ -444,8 +433,7 @@ def user_login(request):
form = UserLoginForm()
context = {"form": form}
- return my_render_to_response('yaksh/login.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/login.html', context)
@login_required
@@ -455,7 +443,6 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
"""Check the user cedentials and if any quiz is available,
start the exam."""
user = request.user
- ci = RequestContext(request)
# check conditions
try:
quest_paper = QuestionPaper.objects.get(id=questionpaper_id)
@@ -534,9 +521,8 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
previous_question=last_attempt.current_question()
)
# allowed to start
- if not quest_paper.can_attempt_now(user, course_id):
- msg = "You cannot attempt {0} quiz more than {1} time(s)".format(
- quest_paper.quiz.description, quest_paper.quiz.attempts_allowed)
+ if not quest_paper.can_attempt_now(user, course_id)[0]:
+ msg = quest_paper.can_attempt_now(user, course_id)[1]
if is_moderator(user):
return prof_manage(request, msg=msg)
return view_module(request, module_id=module_id, course_id=course_id,
@@ -555,8 +541,7 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
}
if is_moderator(user):
context["status"] = "moderator"
- return my_render_to_response('yaksh/intro.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/intro.html', context)
else:
ip = request.META['REMOTE_ADDR']
if not hasattr(user, 'profile'):
@@ -565,10 +550,11 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
new_paper = quest_paper.make_answerpaper(user, ip, attempt_number,
course_id)
if new_paper.status == 'inprogress':
- return show_question(request, new_paper.current_question(),
- new_paper, course_id=course_id,
- module_id=module_id, previous_question=None
- )
+ return show_question(
+ request, new_paper.current_question(),
+ new_paper, course_id=course_id,
+ module_id=module_id, previous_question=None
+ )
else:
msg = 'You have already finished the quiz!'
raise Http404(msg)
@@ -647,9 +633,7 @@ def show_question(request, question, paper, error_message=None, notification=Non
last_attempt = answers[0].answer
if last_attempt:
context['last_attempt'] = last_attempt.encode('unicode-escape')
- ci = RequestContext(request)
- return my_render_to_response('yaksh/question.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/question.html', context)
@login_required
@@ -903,8 +887,7 @@ def quit(request, reason=None, attempt_num=None, questionpaper_id=None,
course_id=course_id)
context = {'paper': paper, 'message': reason, 'course_id': course_id,
'module_id': module_id}
- return my_render_to_response('yaksh/quit.html', context,
- context_instance=RequestContext(request))
+ return my_render_to_response(request, 'yaksh/quit.html', context)
@login_required
@@ -917,7 +900,7 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None,
message = reason or "An Unexpected Error occurred. Please contact your '\
'instructor/administrator.'"
context = {'message': message}
- return my_render_to_response('yaksh/complete.html', context)
+ return my_render_to_response(request, 'yaksh/complete.html', context)
else:
q_paper = QuestionPaper.objects.get(id=questionpaper_id)
paper = AnswerPaper.objects.get(
@@ -937,14 +920,13 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None,
'course_id': course_id, 'learning_unit': learning_unit}
if is_moderator(user):
context['user'] = "moderator"
- return my_render_to_response('yaksh/complete.html', context)
+ return my_render_to_response(request, 'yaksh/complete.html', context)
@login_required
@email_verified
def add_course(request, course_id=None):
user = request.user
- ci = RequestContext(request)
if course_id:
course = Course.objects.get(id=course_id)
if not course.is_creator(user) and not course.is_teacher(user):
@@ -963,12 +945,12 @@ def add_course(request, course_id=None):
return my_redirect('/exam/manage/courses')
else:
return my_render_to_response(
- 'yaksh/add_course.html', {'form': form}, context_instance=ci
+ request, 'yaksh/add_course.html', {'form': form}
)
else:
form = CourseForm(instance=course)
return my_render_to_response(
- 'yaksh/add_course.html', {'form': form}, context_instance=ci
+ request, 'yaksh/add_course.html', {'form': form}
)
@@ -976,7 +958,6 @@ def add_course(request, course_id=None):
@email_verified
def enroll_request(request, course_id):
user = request.user
- ci = RequestContext(request)
course = get_object_or_404(Course, pk=course_id)
if not course.is_active_enrollment() and course.hidden:
msg = (
@@ -996,7 +977,6 @@ def enroll_request(request, course_id):
@email_verified
def self_enroll(request, course_id):
user = request.user
- ci = RequestContext(request)
course = get_object_or_404(Course, pk=course_id)
if course.is_self_enroll():
was_rejected = False
@@ -1011,7 +991,6 @@ def self_enroll(request, course_id):
@email_verified
def courses(request):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page')
courses = Course.objects.filter(
@@ -1020,15 +999,13 @@ def courses(request):
teachers=user, is_trial=False).order_by('-active', '-id')
context = {'courses': courses, "allotted_courses": allotted_courses,
"type": "courses"}
- return my_render_to_response('yaksh/courses.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/courses.html', context)
@login_required
@email_verified
def course_detail(request, course_id):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page')
@@ -1038,7 +1015,7 @@ def course_detail(request, course_id):
raise Http404('This course does not belong to you')
return my_render_to_response(
- 'yaksh/course_detail.html', {'course': course}, context_instance=ci
+ request, 'yaksh/course_detail.html', {'course': course}
)
@@ -1046,7 +1023,6 @@ def course_detail(request, course_id):
@email_verified
def enroll(request, course_id, user_id=None, was_rejected=False):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page')
@@ -1068,7 +1044,7 @@ def enroll(request, course_id, user_id=None, was_rejected=False):
enroll_ids = [user_id]
if not enroll_ids:
return my_render_to_response(
- 'yaksh/course_detail.html', {'course': course}, context_instance=ci
+ request, 'yaksh/course_detail.html', {'course': course}
)
users = User.objects.filter(id__in=enroll_ids)
course.enroll(was_rejected, *users)
@@ -1079,7 +1055,6 @@ def enroll(request, course_id, user_id=None, was_rejected=False):
@email_verified
def send_mail(request, course_id, user_id=None):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page')
@@ -1103,16 +1078,13 @@ def send_mail(request, course_id, user_id=None):
'course': course, 'message': message,
'state': 'mail'
}
- return my_render_to_response(
- 'yaksh/course_detail.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/course_detail.html', context)
@login_required
@email_verified
def reject(request, course_id, user_id=None, was_enrolled=False):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page')
@@ -1127,8 +1099,8 @@ def reject(request, course_id, user_id=None, was_enrolled=False):
if not reject_ids:
message = "Please select atleast one User"
return my_render_to_response(
- 'yaksh/course_detail.html', {'course': course, 'message': message},
- context_instance=ci
+ request, 'yaksh/course_detail.html',
+ {'course': course, 'message': message},
)
users = User.objects.filter(id__in=reject_ids)
course.reject(was_enrolled, *users)
@@ -1168,8 +1140,9 @@ def show_statistics(request, questionpaper_id, attempt_number=None,
context = {'quiz': quiz, 'attempts': attempt_numbers,
'questionpaper_id': questionpaper_id,
'course_id': course_id}
- return my_render_to_response('yaksh/statistics_question.html', context,
- context_instance=RequestContext(request))
+ return my_render_to_response(
+ request, 'yaksh/statistics_question.html', context
+ )
total_attempt = AnswerPaper.objects.get_count(questionpaper_id,
attempt_number,
course_id)
@@ -1183,8 +1156,9 @@ def show_statistics(request, questionpaper_id, attempt_number=None,
'questionpaper_id': questionpaper_id,
'attempts': attempt_numbers, 'total': total_attempt,
'course_id': course_id}
- return my_render_to_response('yaksh/statistics_question.html', context,
- context_instance=RequestContext(request))
+ return my_render_to_response(
+ request, 'yaksh/statistics_question.html', context
+ )
@login_required
@@ -1193,7 +1167,6 @@ def monitor(request, quiz_id=None, course_id=None):
"""Monitor the progress of the papers taken so far."""
user = request.user
- ci = RequestContext(request)
if not user.is_authenticated() or not is_moderator(user):
raise Http404('You are not allowed to view this page!')
@@ -1206,9 +1179,7 @@ def monitor(request, quiz_id=None, course_id=None):
"papers": [], "course_details": course_details,
"msg": "Monitor"
}
- return my_render_to_response(
- 'yaksh/monitor.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/monitor.html', context)
# quiz_id is not None.
try:
quiz = get_object_or_404(Quiz, id=quiz_id)
@@ -1254,8 +1225,7 @@ def monitor(request, quiz_id=None, course_id=None):
"attempt_numbers": attempt_numbers,
"course": course
}
- return my_render_to_response('yaksh/monitor.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/monitor.html', context)
@csrf_exempt
@@ -1279,7 +1249,7 @@ def ajax_questions_filter(request):
questions = list(Question.objects.filter(**filter_dict))
return my_render_to_response(
- 'yaksh/ajax_question_filter.html', {'questions': questions}
+ request, 'yaksh/ajax_question_filter.html', {'questions': questions}
)
@@ -1408,9 +1378,7 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None,
'course_id': course_id
}
return my_render_to_response(
- 'yaksh/design_questionpaper.html',
- context,
- context_instance=RequestContext(request)
+ request, 'yaksh/design_questionpaper.html', context
)
@@ -1420,7 +1388,6 @@ def show_all_questions(request):
"""Show a list of all the questions currently in the database."""
user = request.user
- ci = RequestContext(request)
context = {}
if not is_moderator(user):
raise Http404("You are not allowed to view this page !")
@@ -1497,8 +1464,7 @@ def show_all_questions(request):
user=user).distinct()
context['questions'] = search_result
- return my_render_to_response('yaksh/showquestions.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/showquestions.html', context)
@login_required
@@ -1512,8 +1478,7 @@ def user_data(request, user_id, questionpaper_id=None, course_id=None):
data = AnswerPaper.objects.get_user_data(user, questionpaper_id, course_id)
context = {'data': data, 'course_id': course_id}
- return my_render_to_response('yaksh/user_data.html', context,
- context_instance=RequestContext(request))
+ return my_render_to_response(request, 'yaksh/user_data.html', context)
def _expand_questions(questions, field_list):
@@ -1602,7 +1567,6 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None,
and update all their marks and also give comments for each paper.
"""
current_user = request.user
- ci = RequestContext(request)
if not current_user.is_authenticated() or not is_moderator(current_user):
raise Http404('You are not allowed to view this page!')
course_details = Course.objects.filter(Q(creator=current_user) |
@@ -1676,9 +1640,7 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None,
if course_status.exists():
course_status.first().set_grade()
- return my_render_to_response(
- 'yaksh/grade_user.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/grade_user.html', context)
@login_required
@@ -1687,13 +1649,12 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None,
def view_profile(request):
""" view moderators and users profile """
user = request.user
- ci = RequestContext(request)
if is_moderator(user):
template = 'manage.html'
else:
template = 'user.html'
context = {'template': template, 'user': user}
- return my_render_to_response('yaksh/view_profile.html', context)
+ return my_render_to_response(request, 'yaksh/view_profile.html', context)
@login_required
@@ -1702,7 +1663,6 @@ def edit_profile(request):
""" edit profile details facility for moderator and students """
user = request.user
- ci = RequestContext(request)
if is_moderator(user):
template = 'manage.html'
else:
@@ -1722,19 +1682,17 @@ def edit_profile(request):
form_data.user.last_name = request.POST['last_name']
form_data.user.save()
form_data.save()
- return my_render_to_response(
- 'yaksh/profile_updated.html', context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/profile_updated.html')
else:
context['form'] = form
return my_render_to_response(
- 'yaksh/editprofile.html', context, context_instance=ci
+ request, 'yaksh/editprofile.html', context
)
else:
form = ProfileForm(user=user, instance=profile)
context['form'] = form
return my_render_to_response(
- 'yaksh/editprofile.html', context, context_instance=ci
+ request, 'yaksh/editprofile.html', context
)
@@ -1743,7 +1701,6 @@ def edit_profile(request):
def search_teacher(request, course_id):
""" search teachers for the course """
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
@@ -1770,9 +1727,7 @@ def search_teacher(request, course_id):
)
context['success'] = True
context['teachers'] = teachers
- return my_render_to_response(
- 'yaksh/addteacher.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/addteacher.html', context)
@login_required
@@ -1781,7 +1736,6 @@ def add_teacher(request, course_id):
""" add teachers to the course """
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
@@ -1800,9 +1754,7 @@ def add_teacher(request, course_id):
course.add_teachers(*teachers)
context['status'] = True
context['teachers_added'] = teachers
- return my_render_to_response(
- 'yaksh/addteacher.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/addteacher.html', context)
@login_required
@@ -1882,7 +1834,9 @@ def view_answerpaper(request, questionpaper_id, course_id):
).exists()
context = {'data': data, 'quiz': quiz,
"has_user_assignment": has_user_assignment}
- return my_render_to_response('yaksh/view_answerpaper.html', context)
+ return my_render_to_response(
+ request, 'yaksh/view_answerpaper.html', context
+ )
else:
return my_redirect('/exam/quizzes/')
@@ -1892,7 +1846,6 @@ def view_answerpaper(request, questionpaper_id, course_id):
def create_demo_course(request):
""" creates a demo course for user """
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404("You are not allowed to view this page")
demo_course = Course()
@@ -1915,7 +1868,7 @@ def grader(request, extra_context=None):
context = {'courses': user_courses}
if extra_context:
context.update(extra_context)
- return my_render_to_response('yaksh/regrade.html', context)
+ return my_render_to_response(request, 'yaksh/regrade.html', context)
@login_required
@@ -1999,14 +1952,13 @@ def download_course_csv(request, course_id):
def activate_user(request, key):
- ci = RequestContext(request)
profile = get_object_or_404(Profile, activation_key=key)
context = {}
context['success'] = False
if profile.is_email_verified:
context['activation_msg'] = "Your account is already verified"
return my_render_to_response(
- 'yaksh/activation_status.html', context, context_instance=ci
+ request, 'yaksh/activation_status.html', context
)
if timezone.now() > profile.key_expiry_time:
@@ -2020,12 +1972,11 @@ def activate_user(request, key):
profile.save()
context['msg'] = "Your account is activated"
return my_render_to_response(
- 'yaksh/activation_status.html', context, context_instance=ci
+ request, 'yaksh/activation_status.html', context
)
def new_activation(request, email=None):
- ci = RequestContext(request)
context = {}
if request.method == "POST":
email = request.POST.get('email')
@@ -2036,15 +1987,13 @@ def new_activation(request, email=None):
context['email_err_msg'] = "Multiple entries found for this email"\
"Please change your email"
return my_render_to_response(
- 'yaksh/activation_status.html', context, context_instance=ci
+ request, 'yaksh/activation_status.html', context
)
except ObjectDoesNotExist:
context['success'] = False
context['msg'] = "Your account is not verified. \
Please verify your account"
- return render_to_response(
- 'yaksh/activation_status.html', context, context_instance=ci
- )
+ return render_to_response('yaksh/activation_status.html', context)
if not user.profile.is_email_verified:
user.profile.activation_key = generate_activation_key(user.username)
@@ -2063,13 +2012,12 @@ def new_activation(request, email=None):
context['activation_msg'] = "Your account is already verified"
return my_render_to_response(
- 'yaksh/activation_status.html', context, context_instance=ci
+ request, 'yaksh/activation_status.html', context
)
def update_email(request):
context = {}
- ci = RequestContext(request)
if request.method == "POST":
email = request.POST.get('email')
username = request.POST.get('username')
@@ -2080,7 +2028,7 @@ def update_email(request):
else:
context['email_err_msg'] = "Please Update your email"
return my_render_to_response(
- 'yaksh/activation_status.html', context, context_instance=ci
+ request, 'yaksh/activation_status.html', context
)
@@ -2119,7 +2067,6 @@ def download_assignment_file(request, quiz_id, question_id=None, user_id=None):
@email_verified
def upload_users(request, course_id):
user = request.user
- ci = RequestContext(request)
course = get_object_or_404(Course, pk=course_id)
context = {'course': course}
@@ -2129,32 +2076,35 @@ def upload_users(request, course_id):
if request.method == 'POST':
if 'csv_file' not in request.FILES:
context['message'] = "Please upload a CSV file."
- return my_render_to_response('yaksh/course_detail.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ request, 'yaksh/course_detail.html', context
+ )
csv_file = request.FILES['csv_file']
is_csv_file, dialect = is_csv(csv_file)
if not is_csv_file:
context['message'] = "The file uploaded is not a CSV file."
- return my_render_to_response('yaksh/course_detail.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ request, 'yaksh/course_detail.html', context
+ )
required_fields = ['firstname', 'lastname', 'email']
try:
reader = csv.DictReader(csv_file.read().decode('utf-8').splitlines(),
dialect=dialect)
except TypeError:
context['message'] = "Bad CSV file"
- return my_render_to_response('yaksh/course_detail.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ request, 'yaksh/course_detail.html', context
+ )
stripped_fieldnames = [field.strip().lower() for field in reader.fieldnames]
for field in required_fields:
if field not in stripped_fieldnames:
context['message'] = "The CSV file does not contain the required headers"
- return my_render_to_response('yaksh/course_detail.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ request, 'yaksh/course_detail.html', context
+ )
reader.fieldnames = stripped_fieldnames
context['upload_details'] = _read_user_csv(reader, course)
- return my_render_to_response('yaksh/course_detail.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/course_detail.html', context)
def _read_user_csv(reader, course):
@@ -2312,7 +2262,6 @@ def download_yaml_template(request):
@email_verified
def edit_lesson(request, lesson_id=None, course_id=None):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
if lesson_id:
@@ -2365,9 +2314,7 @@ def edit_lesson(request, lesson_id=None, course_id=None):
context['lesson_file_form'] = lesson_files_form
context['lesson_files'] = lesson_files
context['course_id'] = course_id
- return my_render_to_response(
- 'yaksh/add_lesson.html', context, context_instance=ci
- )
+ return my_render_to_response(request, 'yaksh/add_lesson.html', context)
@login_required
@@ -2408,14 +2355,13 @@ def show_lesson(request, lesson_id, module_id, course_id):
'course': course, 'state': "lesson", "all_modules": all_modules,
'learning_units': learning_units, "current_unit": learn_unit,
'learning_module': learn_module}
- return my_render_to_response('yaksh/show_video.html', context)
+ return my_render_to_response(request, 'yaksh/show_video.html', context)
@login_required
@email_verified
def design_module(request, module_id, course_id=None):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
context = {}
@@ -2481,15 +2427,13 @@ def design_module(request, module_id, course_id=None):
context['status'] = 'design'
context['module_id'] = module_id
context['course_id'] = course_id
- return my_render_to_response('yaksh/add_module.html', context,
- context_instance=ci)
+ return my_render_to_response(request, 'yaksh/add_module.html', context)
@login_required
@email_verified
def add_module(request, module_id=None, course_id=None):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
redirect_url = "/exam/manage/courses/all_learning_module/"
@@ -2522,8 +2466,7 @@ def add_module(request, module_id=None, course_id=None):
context['module_form'] = module_form
context['course_id'] = course_id
context['status'] = "add"
- return my_render_to_response("yaksh/add_module.html",
- context, context_instance=ci)
+ return my_render_to_response(request, "yaksh/add_module.html", context)
@login_required
@@ -2534,7 +2477,7 @@ def show_all_quizzes(request):
raise Http404('You are not allowed to view this page!')
quizzes = Quiz.objects.filter(creator=user, is_trial=False)
context = {"quizzes": quizzes, "type": "quiz"}
- return my_render_to_response('yaksh/courses.html', context)
+ return my_render_to_response(request, 'yaksh/courses.html', context)
@login_required
@@ -2545,7 +2488,7 @@ def show_all_lessons(request):
raise Http404('You are not allowed to view this page!')
lessons = Lesson.objects.filter(creator=user)
context = {"lessons": lessons, "type": "lesson"}
- return my_render_to_response('yaksh/courses.html', context)
+ return my_render_to_response(request, 'yaksh/courses.html', context)
@login_required
@@ -2557,7 +2500,7 @@ def show_all_modules(request):
learning_modules = LearningModule.objects.filter(
creator=user, is_trial=False)
context = {"learning_modules": learning_modules, "type": "learning_module"}
- return my_render_to_response('yaksh/courses.html', context)
+ return my_render_to_response(request, 'yaksh/courses.html', context)
@login_required
@@ -2629,7 +2572,6 @@ def get_next_unit(request, course_id, module_id, current_unit_id=None,
@email_verified
def design_course(request, course_id):
user = request.user
- ci = RequestContext(request)
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
course = Course.objects.get(id=course_id)
@@ -2683,8 +2625,9 @@ def design_course(request, course_id):
context['added_learning_modules'] = added_learning_modules
context['learning_modules'] = learning_modules
context['course_id'] = course_id
- return my_render_to_response('yaksh/design_course_session.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ request, 'yaksh/design_course_session.html', context
+ )
@login_required
@@ -2719,7 +2662,7 @@ def view_module(request, module_id, course_id, msg=None):
context['course'] = course
context['state'] = "module"
context['msg'] = msg
- return my_render_to_response('yaksh/show_video.html', context)
+ return my_render_to_response(request, 'yaksh/show_video.html', context)
@login_required
@@ -2745,7 +2688,7 @@ def course_modules(request, course_id, msg=None):
if not course_status.grade:
course_status.set_grade()
context['grade'] = course_status.get_grade()
- return my_render_to_response('yaksh/course_modules.html', context)
+ return my_render_to_response(request, 'yaksh/course_modules.html', context)
@login_required
@@ -2765,7 +2708,7 @@ def course_status(request, course_id):
'course': course, 'student_details': stud_details,
'state': 'course_status'
}
- return my_render_to_response('yaksh/course_detail.html', context)
+ return my_render_to_response(request, 'yaksh/course_detail.html', context)
def _update_unit_status(course_id, user, unit):
@@ -2802,7 +2745,7 @@ def preview_questionpaper(request, questionpaper_id):
}
return my_render_to_response(
- 'yaksh/preview_questionpaper.html', context
+ request, 'yaksh/preview_questionpaper.html', context
)