From d7ca37496fc4a41bf5dad7084479565a104fa5de Mon Sep 17 00:00:00 2001 From: GreatSamJ Date: Thu, 4 Jul 2019 14:26:00 +0200 Subject: [PATCH] TP6Ex1 --- TP6Ex1/run | 190 +++++++++++++++++++++++++++++++++++++++++ TP6Ex1/src/Templates/q | 3 + TP6Ex1/src/TestQ.py | 26 ++++++ TP6Ex1/src/inverse.py | 7 ++ TP6Ex1/task.yaml | 29 +++++++ 5 files changed, 255 insertions(+) create mode 100644 TP6Ex1/run create mode 100644 TP6Ex1/src/Templates/q create mode 100644 TP6Ex1/src/TestQ.py create mode 100644 TP6Ex1/src/inverse.py create mode 100644 TP6Ex1/task.yaml diff --git a/TP6Ex1/run b/TP6Ex1/run new file mode 100644 index 0000000..8af34e8 --- /dev/null +++ b/TP6Ex1/run @@ -0,0 +1,190 @@ +#! /usr/bin/python3 +# -*- coding: utf-8 -*- + +import subprocess +import gettext +import shlex +import sys +import os +import re + +from inginious import feedback +from inginious import rst +from inginious import input + + +# This runner suits for typical exercises of LSINF1101/FSAB1401 +# Should be adapted if used in another occasion +# Structure used: +# -One folder : src with a proposer answer, the tests and a subdirectory containing the templates +# -A run file +# -A task file +# Note that beside this structure we use the global folder common (c) and common/student (cs) containing: +# -The compiler script (c) +# -The tests runner script (c) +# -The translations folder (cs) + +def init_translations(): + """ + Move the translations files to student directory + Initialize gettext and translate to the proper language + """ + lang = input.get_lang() + try: + trad = gettext.GNUTranslations(open("../course/common/student/$i18n/" + lang + ".mo", "rb")) + except FileNotFoundError: + trad = gettext.NullTranslations() + trad.install() + return lang + + +def compute_code(): + """ + Fills the template file with the student answer + Returns the task's number of questions + """ + for file in os.listdir('./src/Templates'): + input.parse_template('./src/Templates/' + file, './student/' + file + '.py') + data = input.load_input() + return len([k for k in data['input'].keys() if '@' not in k]) + + +def compile_code(): + """ + Compiles both the student code and the exercise code + Provides feedback if there is any compilation error + """ + pyc_cmd = "python3 ../course/common/compiler.py " + + with open('log.out', 'w+', encoding="utf-8") as f: + subprocess.call(shlex.split(pyc_cmd + './student/'), universal_newlines=True, stderr=f) + f.seek(0) + out_student = f.read() + + if out_student != "": + rawhtml = rst.get_codeblock("", out_student) + feedback.set_global_result('failed') + feedback.set_global_feedback(_("Your program does not compile: \n ") + rawhtml + "\n") + sys.exit(0) + + with open('logTests.out', 'w+', encoding="utf-8") as f: + subprocess.call(shlex.split(pyc_cmd + './src/'), universal_newlines=True, stderr=f) + f.seek(0) + out_tests = f.read() + + if out_tests != "": + rawhtml = rst.get_codeblock("", out_tests) + feedback.set_global_result('failed') + feedback.set_global_feedback(_("The program does not compile for external reasons," + "please contact an administrator asap: \n ") + rawhtml + "\n") + sys.exit(0) + + with open('logRunner.out', 'w+', encoding="utf-8") as f: + subprocess.call(shlex.split(pyc_cmd + '../course/common/'), universal_newlines=True, stderr=f) + f.seek(0) + out_runner = f.read() + + if out_runner != "": + rawhtml = rst.get_codeblock("", out_runner) + feedback.set_global_result('failed') + feedback.set_global_feedback(_("The program does not compile for external reasons," + "please contact an administrator asap: \n ") + rawhtml + "\n") + sys.exit(0) + + +def cleanup_output(error_content): + """ + Provides a cleaner output from the error trace + + :param error_content: string returned by the unittest failures + """ + cleaned_lines = [] + indexes = [match.start() for match in re.finditer('AssertionError: ', error_content)] + for i in indexes: + cleaned_lines.append(_('Failed test:\n')) + cleaned_lines.append(error_content[i + len("AssertionError: "): error_content.find("=" * 70, i)]) + return ''.join(cleaned_lines) if len(indexes) > 0 else error_content + + +def run_code(n_exercises, lang): + """ + Runs the student code with the tests + Provides feedback if it contains errors + + :param n_exercises: the task's number of exercices + :param lang: the language used by the user + """ + with open('err.txt', 'w+', encoding="utf-8") as f: + os.chdir('./student') + py_cmd = "run_student python3 Runner.pyc " + lang + try: + resproc = subprocess.Popen(shlex.split(py_cmd), universal_newlines=True, stderr=f, stdout=subprocess.PIPE) + resproc.communicate() + result = resproc.returncode + except (IOError, BrokenPipeError): + result = 252 + f.flush() + f.seek(0) + errors = f.read() + print(errors) + outerr = rst.get_codeblock("python", cleanup_output(errors)) + + # expected error code: 252=outofmemory, 253=timedout + # 127 = code returned by our runner + grade=0 + if result == 127: + feedback.set_global_result('success') + elif result == 252: + feedback.set_global_result('overflow') + elif result == 253: + feedback.set_global_result('timeout') + else: # Tests failed + if n_exercises == 1: + feedback.set_global_result('failed') + feedback.set_global_feedback(_("It seems that you have made mistakes in your code…\n\n") + outerr + "\n") + else: + sub_found = False + for i in range(1, n_exercises + 1): + regex = '@' + str(i) + '@: ((.+)(\n|\r){1})+' + regex_question = re.search(regex, errors) + if regex_question: + sub_found = True + break + if not sub_found: + feedback.set_global_result('failed') + feedback.set_global_feedback(_("custom…\n\n") + outerr + "\n") + return + sub_found = False + for i in range(0, n_exercises + 1): + regex = '@' + str(i) + '@: ((.+)(\n|\r){1})+' + regex_question = re.search(regex, errors) + if regex_question: + outerr_question = re.sub('"', '', regex_question.group(0)[5:]) + sub_found = True + else: + outerr_question = False + + if i == 0: + feedback.set_global_result('failed') + if outerr_question: + feed = _("You have made mistakes: \n\n") + rst.get_codeblock("python", outerr_question) + "\n" + feedback.set_global_feedback(feed) + else: + if outerr_question: + feed = _("You have made mistakes: \n\n") + rst.get_codeblock("python", outerr_question) + "\n" + feedback.set_problem_feedback(feed, "q" + str(i)) + else: + feedback.set_problem_feedback(_("You answered well this question"), "q" + str(i)) + feedback.set_problem_result('success', "q" + str(i)) + grade+=1 + if not sub_found: + feedback.set_global_result('failed') + feedback.set_global_feedback(_("It seems that you have made mistakes in your code…\n\n") + outerr + "\n") + else: + feedback.set_grade(grade*100/n_exercises) + +if __name__ == '__main__': + language = init_translations() + num_exercises = compute_code() + compile_code() + run_code(num_exercises, language) diff --git a/TP6Ex1/src/Templates/q b/TP6Ex1/src/Templates/q new file mode 100644 index 0000000..3c002e6 --- /dev/null +++ b/TP6Ex1/src/Templates/q @@ -0,0 +1,3 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +@@q1@@ \ No newline at end of file diff --git a/TP6Ex1/src/TestQ.py b/TP6Ex1/src/TestQ.py new file mode 100644 index 0000000..f8c4e61 --- /dev/null +++ b/TP6Ex1/src/TestQ.py @@ -0,0 +1,26 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + + +import unittest +import q +from inverse import * +import random as rd +rd.seed(2019) + +#Correct solution +L=[rd.randint(1,100) for i in range(20)] +ans=inverse(L) +student=q.inverse(L) + +class TestPageRank(unittest.TestCase): + + def test_exist_inverse(self): + self.assertTrue(hasattr(q, 'inverse'), "@1@: " + _("You did not name the method as expected.")) + + def test_inverse(self): + for i in range(len(ans)): + self.assertEqual(ans[i],student[i],"@1@: Il y a un problème dans la fonction inverse()") + +if __name__ == '__main__': + unittest.main() diff --git a/TP6Ex1/src/inverse.py b/TP6Ex1/src/inverse.py new file mode 100644 index 0000000..771db9e --- /dev/null +++ b/TP6Ex1/src/inverse.py @@ -0,0 +1,7 @@ +def inverse(u): + inv=[] + for i in range(len(u)): + inv.append(u[len(u)-i-1]) + return inv + + diff --git a/TP6Ex1/task.yaml b/TP6Ex1/task.yaml new file mode 100644 index 0000000..3753b0c --- /dev/null +++ b/TP6Ex1/task.yaml @@ -0,0 +1,29 @@ +accessible: true +author: Alain Mbungu +context: Ecrire une méthode, appelée **inverse**, ayant comme paramètre d’entrée **u**, + un tableau de réels à une dimension, et retournant en sortie ce même vecteur, + mais inversé; c'est-à-dire que le dernier élément devient le premier, l'avant-dernier + le deuxième, etc. +environment: default +evaluate: best +groups: false +input_random: '0' +limits: + time: '30' + memory: '100' + output: '2' +name: TP6Ex1 Examen Septembre 2008 – question 1 +network_grading: false +problems: + q1: + default: '' + type: code + language: '' + header: La fonction ``inverse(u)`` + name: Implémentation +stored_submissions: 0 +submission_limit: + amount: -1 + period: -1 +tags: {} +weight: 1.0