From 3fe840b52e4d780587f14d06a46fcab523ba23c3 Mon Sep 17 00:00:00 2001
From: maheshgudi
Date: Mon, 20 Aug 2018 17:35:55 +0530
Subject: Add syntax highlight for code answers in answerpaper
---
yaksh/templates/yaksh/grade_user.html | 5 ++++-
yaksh/templates/yaksh/user_data.html | 4 +++-
yaksh/templates/yaksh/view_answerpaper.html | 4 +++-
yaksh/templatetags/custom_filters.py | 13 +++++++++++++
4 files changed, 23 insertions(+), 3 deletions(-)
(limited to 'yaksh')
diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html
index 2e5a403..bc9ed87 100644
--- a/yaksh/templates/yaksh/grade_user.html
+++ b/yaksh/templates/yaksh/grade_user.html
@@ -298,7 +298,9 @@ Status : Failed
{% if question.type == "code" %}
-
{{ ans.answer.answer.strip|safe }}
+ {% pygmentise_user_answer question.language ans.answer.answer.strip as user_answer %}
+
+
{{user_answer.0|safe}}
{% elif question.type == "mcc"%}
{% for testcases in question.get_test_cases %}
@@ -327,6 +329,7 @@ Status :
Failed
{% else %}
{{ ans.answer.answer.strip|safe }}
+
{% endif %}
diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html
index 9449fcc..72397dc 100644
--- a/yaksh/templates/yaksh/user_data.html
+++ b/yaksh/templates/yaksh/user_data.html
@@ -233,7 +233,9 @@ User IP address: {{ paper.user_ip }}
{{ answer.answer.answer.strip|safe }}
{% else %}
-
-
{{ answer.answer.answer.strip }}
+ {% pygmentise_user_answer question.language answer.answer.answer.strip as user_answer %}
+
+
{{user_answer.0|safe}}
{% endif %}
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py
index 056421f..2fdc1d2 100644
--- a/yaksh/templatetags/custom_filters.py
+++ b/yaksh/templatetags/custom_filters.py
@@ -6,6 +6,9 @@ try:
from itertools import zip_longest
except ImportError:
from itertools import izip_longest as zip_longest
+from pygments import highlight
+from pygments.lexers import get_lexer_by_name
+from pygments.formatters import HtmlFormatter
register = template.Library()
@@ -87,3 +90,13 @@ def get_answer_for_arrange_options(ans, question):
@register.filter(name='replace_spaces')
def replace_spaces(name):
return name.replace(" ", "_")
+
+@register.simple_tag
+def pygmentise_user_answer(language, answer):
+ lexer = get_lexer_by_name(language, stripall=True)
+ formatter = HtmlFormatter(linenos="inline",
+ cssclass="highlight",
+ style="colorful")
+ style = formatter.get_style_defs('.highlight')
+ result = highlight(answer, lexer, formatter)
+ return result, style
--
cgit
From 4def423d573beceee07780f21bcd55836d50b558 Mon Sep 17 00:00:00 2001
From: maheshgudi
Date: Mon, 13 Aug 2018 15:36:48 +0530
Subject: Allow new line to be added in an stdio testcase
---
yaksh/error_messages.py | 5 ++---
yaksh/python_stdio_evaluator.py | 3 ++-
yaksh/templates/yaksh/add_question.html | 2 ++
yaksh/templates/yaksh/error_template.html | 11 +++++++++--
yaksh/templates/yaksh/moderator_dashboard.html | 6 +++++-
yaksh/templatetags/custom_filters.py | 10 ++++++++++
yaksh/views.py | 16 ++++++++++++++--
7 files changed, 44 insertions(+), 9 deletions(-)
(limited to 'yaksh')
diff --git a/yaksh/error_messages.py b/yaksh/error_messages.py
index f34bf28..bf79ef8 100644
--- a/yaksh/error_messages.py
+++ b/yaksh/error_messages.py
@@ -33,9 +33,8 @@ def prettify_exceptions(exception, message, traceback=None,
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 user_line != expected_line:
err_line_numbers.append(line_no)
return err_line_numbers
diff --git a/yaksh/python_stdio_evaluator.py b/yaksh/python_stdio_evaluator.py
index 64a2809..a1e8f72 100644
--- a/yaksh/python_stdio_evaluator.py
+++ b/yaksh/python_stdio_evaluator.py
@@ -46,6 +46,7 @@ class PythonStdIOEvaluator(BaseEvaluator):
if self.file_paths:
self.files = copy_files(self.file_paths)
submitted = compile(self.user_answer, '', mode='exec')
+ self.expected_output = self.expected_output.replace('\r', '')
if self.expected_input:
self.expected_input = self.expected_input.replace('\r', '')
input_buffer = StringIO()
@@ -55,7 +56,7 @@ class PythonStdIOEvaluator(BaseEvaluator):
with redirect_stdout() as output_buffer:
exec_scope = {}
exec(submitted, exec_scope)
- self.output_value = output_buffer.getvalue().rstrip("\n")
+ self.output_value = output_buffer.getvalue()
return self.output_value
def check_code(self):
diff --git a/yaksh/templates/yaksh/add_question.html b/yaksh/templates/yaksh/add_question.html
index 692af48..c4cd8a7 100644
--- a/yaksh/templates/yaksh/add_question.html
+++ b/yaksh/templates/yaksh/add_question.html
@@ -50,7 +50,9 @@
{% for form in formset %}
+ {% autoescape off %}
{{ form.as_p }}
+ {% endautoescape %}
{% endfor %}
diff --git a/yaksh/templates/yaksh/error_template.html b/yaksh/templates/yaksh/error_template.html
index 5530844..00fa306 100644
--- a/yaksh/templates/yaksh/error_template.html
+++ b/yaksh/templates/yaksh/error_template.html
@@ -1,4 +1,11 @@
+{% block css%}
+
+{% endblock %}
+{% block script %}
+
+{% endblock %}
+
{% load custom_filters %}
{% if error_message %}
@@ -64,8 +71,8 @@
{% for expected,user in error.expected_output|zip:error.user_output %}
{{forloop.counter}} |
- {{expected|default:""}} |
- {{user|default:""}} |
+ {{expected|default:""|highlight_spaces|safe}} |
+ {{user|default:""|highlight_spaces|safe}} |
{% if forloop.counter0 in error.error_line_numbers or not expected or not user %}
|
{% else %}
diff --git a/yaksh/templates/yaksh/moderator_dashboard.html b/yaksh/templates/yaksh/moderator_dashboard.html
index 503cc72..59dd123 100644
--- a/yaksh/templates/yaksh/moderator_dashboard.html
+++ b/yaksh/templates/yaksh/moderator_dashboard.html
@@ -102,7 +102,11 @@
{% endfor %}
-
+
+
{% endif %}
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py
index b59d320..e51b8aa 100644
--- a/yaksh/templatetags/custom_filters.py
+++ b/yaksh/templatetags/custom_filters.py
@@ -101,3 +101,13 @@ def pygmentise_user_answer(language, answer):
style = formatter.get_style_defs('.highlight')
result = highlight(answer, lexer, formatter)
return result, style
+
+
+@register.simple_tag
+def course_grade(course, user):
+ return course.get_grade(user)
+
+
+@register.filter(name='highlight_spaces')
+def highlight_spaces(text):
+ return text.replace(" ",' ')
diff --git a/yaksh/views.py b/yaksh/views.py
index 0bf91eb..440236c 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -6,10 +6,12 @@ from django.shortcuts import render, get_object_or_404, redirect
from django.template import Context, Template
from django.http import Http404
from django.db.models import Max, Q, F
+from django.db import models
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.forms.models import inlineformset_factory
+from django.forms import fields
from django.utils import timezone
from django.core.exceptions import (
MultipleObjectsReturned, ObjectDoesNotExist
@@ -96,6 +98,12 @@ def get_html_text(md_text):
"""Takes markdown text and converts it to html"""
return Markdown().convert(md_text)
+def formfield_callback(field):
+ if (isinstance(field, models.TextField)
+ and field.name == 'expected_output'
+ or field.name == 'expected_input'):
+ return fields.CharField(strip=False)
+ return field.formfield()
@email_verified
def index(request, next_url=None):
@@ -243,8 +251,12 @@ def add_question(request, question_id=None):
file.toggle_hide_status()
formsets = []
for testcase in TestCase.__subclasses__():
- formset = inlineformset_factory(Question, testcase, extra=0,
- fields='__all__')
+
+ formset = inlineformset_factory(
+ Question, testcase, extra=0,
+ fields='__all__',
+ formfield_callback = formfield_callback
+ )
formsets.append(formset(
request.POST, request.FILES, instance=question
)
--
cgit
From 3a0acf73017899067b75b23b7df0eac0ab888abf Mon Sep 17 00:00:00 2001
From: maheshgudi
Date: Mon, 15 Oct 2018 16:08:54 +0530
Subject: Add testcase for highlight spaces
---
yaksh/templatetags/test_custom_filters.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
(limited to 'yaksh')
diff --git a/yaksh/templatetags/test_custom_filters.py b/yaksh/templatetags/test_custom_filters.py
index eb1f0fb..9816dc8 100644
--- a/yaksh/templatetags/test_custom_filters.py
+++ b/yaksh/templatetags/test_custom_filters.py
@@ -11,7 +11,8 @@ from yaksh.models import (User, Profile, Question, Quiz, QuestionPaper,
from yaksh.templatetags.custom_filters import (completed, inprogress,
get_ordered_testcases,
- get_answer_for_arrange_options
+ get_answer_for_arrange_options,
+ highlight_spaces
)
@@ -148,3 +149,9 @@ class CustomFiltersTestCases(unittest.TestCase):
self.assertSequenceEqual(testcases, ordered_testcases)
new_answerpaper.delete()
+
+ def test_highlight_spaces(self):
+ expected_output = "A "
+ highlighted_output = highlight_spaces(expected_output)
+ self.assertEqual(highlighted_output,
+ 'A ')
--
cgit
From 28c64f6f1771fe93385e3767d5bee9fe55af8c82 Mon Sep 17 00:00:00 2001
From: maheshgudi
Date: Mon, 15 Oct 2018 17:23:43 +0530
Subject: Fix pep8 for stdio spacing error
---
yaksh/error_messages.py | 2 +-
yaksh/templatetags/custom_filters.py | 4 +++-
yaksh/templatetags/test_custom_filters.py | 4 +++-
yaksh/views.py | 16 ++++++++--------
4 files changed, 15 insertions(+), 11 deletions(-)
(limited to 'yaksh')
diff --git a/yaksh/error_messages.py b/yaksh/error_messages.py
index bf79ef8..2d27417 100644
--- a/yaksh/error_messages.py
+++ b/yaksh/error_messages.py
@@ -33,7 +33,7 @@ def prettify_exceptions(exception, message, traceback=None,
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)):
+ enumerate(zip_longest(exp_lines, user_lines)):
if user_line != expected_line:
err_line_numbers.append(line_no)
return err_line_numbers
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py
index e51b8aa..92a1169 100644
--- a/yaksh/templatetags/custom_filters.py
+++ b/yaksh/templatetags/custom_filters.py
@@ -110,4 +110,6 @@ def course_grade(course, user):
@register.filter(name='highlight_spaces')
def highlight_spaces(text):
- return text.replace(" ",' ')
+ return text.replace(
+ " ", ' '
+ )
diff --git a/yaksh/templatetags/test_custom_filters.py b/yaksh/templatetags/test_custom_filters.py
index 9816dc8..9d7f246 100644
--- a/yaksh/templatetags/test_custom_filters.py
+++ b/yaksh/templatetags/test_custom_filters.py
@@ -58,6 +58,7 @@ def tearDownModule():
User.objects.get(username="teacher2000").delete()
Group.objects.all().delete()
+
class CustomFiltersTestCases(unittest.TestCase):
@classmethod
@@ -154,4 +155,5 @@ class CustomFiltersTestCases(unittest.TestCase):
expected_output = "A "
highlighted_output = highlight_spaces(expected_output)
self.assertEqual(highlighted_output,
- 'A ')
+ 'A '
+ )
diff --git a/yaksh/views.py b/yaksh/views.py
index 440236c..56f1873 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -98,13 +98,14 @@ def get_html_text(md_text):
"""Takes markdown text and converts it to html"""
return Markdown().convert(md_text)
+
def formfield_callback(field):
- if (isinstance(field, models.TextField)
- and field.name == 'expected_output'
- or field.name == 'expected_input'):
+ if (isinstance(field, models.TextField) and field.name == 'expected_output'
+ or field.name == 'expected_input'):
return fields.CharField(strip=False)
return field.formfield()
+
@email_verified
def index(request, next_url=None):
"""The start page.
@@ -255,7 +256,7 @@ def add_question(request, question_id=None):
formset = inlineformset_factory(
Question, testcase, extra=0,
fields='__all__',
- formfield_callback = formfield_callback
+ formfield_callback=formfield_callback
)
formsets.append(formset(
request.POST, request.FILES, instance=question
@@ -941,10 +942,9 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None,
"""Show a page to inform user that the quiz has been completed."""
user = request.user
if questionpaper_id is None:
- message = (
- reason or "An Unexpected Error occurred."
- " Please contact your instructor/administrator."
- )
+ message = reason or ("An Unexpected Error occurred. Please "
+ "contact your instructor/administrator."
+ )
context = {'message': message}
return my_render_to_response(request, 'yaksh/complete.html', context)
else:
--
cgit
From 6eca1dd646eff0c1f90c129e10e7959e79eb83a2 Mon Sep 17 00:00:00 2001
From: ankitjavalkar
Date: Wed, 18 Dec 2019 14:49:16 +0530
Subject: Fix bug to only allow self created grading systems to show up in the
course form
---
yaksh/forms.py | 24 +++++++++++++++++-------
yaksh/views.py | 4 ++--
2 files changed, 19 insertions(+), 9 deletions(-)
(limited to 'yaksh')
diff --git a/yaksh/forms.py b/yaksh/forms.py
index 57140bc..742212a 100644
--- a/yaksh/forms.py
+++ b/yaksh/forms.py
@@ -3,6 +3,7 @@ from yaksh.models import (
get_model_class, Profile, Quiz, Question, Course, QuestionPaper, Lesson,
LearningModule
)
+from grades.models import GradingSystem
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.conf import settings
@@ -268,6 +269,13 @@ class QuestionFilterForm(forms.Form):
class CourseForm(forms.ModelForm):
""" course form for moderators """
+ class Meta:
+ model = Course
+ fields = [
+ 'name', 'enrollment', 'active', 'code', 'instructions',
+ 'start_enroll_time', 'end_enroll_time', 'grading_system',
+ 'view_grade'
+ ]
def save(self, commit=True, *args, **kwargs):
instance = super(CourseForm, self).save(commit=False)
@@ -280,13 +288,15 @@ class CourseForm(forms.ModelForm):
instance.save()
return instance
- class Meta:
- model = Course
- fields = [
- 'name', 'enrollment', 'active', 'code', 'instructions',
- 'start_enroll_time', 'end_enroll_time', 'grading_system',
- 'view_grade'
- ]
+ def __init__(self, user, *args, **kwargs):
+ super(CourseForm, self).__init__(*args, **kwargs)
+ if self.instance.id and self.instance.teachers.filter(id=user.id).exists():
+ self.fields['grading_system'].widget.attrs['disabled'] = True
+ else:
+ grading_choices = GradingSystem.objects.filter(
+ creator=user
+ )
+ self.fields['grading_system'].queryset = grading_choices
class ProfileForm(forms.ModelForm):
diff --git a/yaksh/views.py b/yaksh/views.py
index 0bf91eb..afb69ac 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -970,7 +970,7 @@ def add_course(request, course_id=None):
if not is_moderator(user):
raise Http404('You are not allowed to view this page')
if request.method == 'POST':
- form = CourseForm(request.POST, instance=course)
+ form = CourseForm(user, request.POST, instance=course)
if form.is_valid():
new_course = form.save(commit=False)
if course_id is None:
@@ -982,7 +982,7 @@ def add_course(request, course_id=None):
request, 'yaksh/add_course.html', {'form': form}
)
else:
- form = CourseForm(instance=course)
+ form = CourseForm(user, instance=course)
return my_render_to_response(
request, 'yaksh/add_course.html', {'form': form}
)
--
cgit
From ca07207d515ecdc8466bb5dc4203bbcfab1a04b1 Mon Sep 17 00:00:00 2001
From: prathamesh
Date: Sun, 12 Jan 2020 12:25:28 +0530
Subject: evaluator for r- Initial
---
yaksh/models.py | 1 +
yaksh/r_code_evaluator.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++
yaksh/settings.py | 4 ++
3 files changed, 101 insertions(+)
create mode 100644 yaksh/r_code_evaluator.py
(limited to 'yaksh')
diff --git a/yaksh/models.py b/yaksh/models.py
index 6881b4f..6edb9ea 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -46,6 +46,7 @@ languages = (
("cpp", "C++ Language"),
("java", "Java Language"),
("scilab", "Scilab"),
+ ("r", "R"),
)
question_types = (
diff --git a/yaksh/r_code_evaluator.py b/yaksh/r_code_evaluator.py
new file mode 100644
index 0000000..ca4c94a
--- /dev/null
+++ b/yaksh/r_code_evaluator.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+from __future__ import unicode_literals
+import os
+import subprocess
+import re
+
+# Local imports
+from .base_evaluator import BaseEvaluator
+from .file_utils import copy_files, delete_files
+
+
+class RCodeEvaluator(BaseEvaluator):
+ """Tests the R code obtained from Code Server"""
+ def __init__(self, metadata, test_case_data):
+ self.files = []
+ self.submit_code_path = ""
+ self.test_code_path = ""
+ # Set metadata values
+ self.user_answer = metadata.get('user_answer')
+ self.file_paths = metadata.get('file_paths')
+ self.partial_grading = metadata.get('partial_grading')
+
+ # Set test case data values
+ self.test_case = test_case_data.get('test_case')
+ self.weight = test_case_data.get('weight')
+
+ def teardown(self):
+ # Delete the created file.
+ if os.path.exists(self.submit_code_path):
+ os.remove(self.submit_code_path)
+ if os.path.exists(self.test_code_path):
+ os.remove(self.test_code_path)
+ if self.files:
+ delete_files(self.files)
+
+ def check_code(self):
+ self.submit_code_path = self.create_submit_code_file('function.r')
+ self.test_code_path = self.create_submit_code_file('main.r')
+ if self.file_paths:
+ self.files = copy_files(self.file_paths)
+ clean_ref_path = self.test_code_path
+ self.user_answer, terminate_commands = \
+ self._remove_r_quit(self.user_answer.lstrip())
+
+ success = False
+ mark_fraction = 0.0
+ self.write_to_submit_code_file(self.submit_code_path, self.user_answer)
+ self.write_to_submit_code_file(self.test_code_path, self.test_case)
+ # Throw message if there are commmands that terminates scilab
+ add_err = ""
+ if terminate_commands:
+ add_err = "Please do not use quit() in your\
+ code.\n Otherwise your code will not be evaluated\
+ correctly.\n"
+
+ cmd = 'Rscript main.r'
+ ret = self._run_command(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE
+ )
+ proc, stdout, stderr = ret
+
+ if stderr is '':
+ # Clean output
+ stdout = self._strip_output(stdout)
+ if proc.returncode == 31:
+ success, err = True, None
+ mark_fraction = 1.0 if self.partial_grading else 0.0
+ else:
+ err = add_err + stdout
+ else:
+ err = add_err + stderr
+
+ return success, err, mark_fraction
+
+ def _remove_r_quit(self, string):
+ """
+ Removes quit from the R code
+ """
+ new_string = ""
+ terminate_commands = False
+ for line in string.splitlines():
+ new_line = re.sub(r"quit.*$", "", line)
+ if line != new_line:
+ terminate_commands = True
+ new_string = new_string + '\n' + new_line
+ return new_string, terminate_commands
+
+ def _strip_output(self, out):
+ """
+ Cleans whitespace from the output
+ """
+ strip_out = "Message"
+ for l in out.split('\n'):
+ if l.strip():
+ strip_out = strip_out+"\n"+l.strip()
+ return strip_out + out
diff --git a/yaksh/settings.py b/yaksh/settings.py
index 9e9597d..7b42298 100644
--- a/yaksh/settings.py
+++ b/yaksh/settings.py
@@ -55,4 +55,8 @@ code_evaluators = {
"standardtestcase": "yaksh.scilab_code_evaluator.ScilabCodeEvaluator",
"hooktestcase": "yaksh.hook_evaluator.HookEvaluator"
},
+ "r": {
+ "standardtestcase": "yaksh.r_code_evaluator.RCodeEvaluator",
+ "hooktestcase": "yaksh.hook_evaluator.HookEvaluator"
+ },
}
--
cgit