Skip to content

Commit

Permalink
TP6Ex8/
Browse files Browse the repository at this point in the history
  • Loading branch information
GreatSamJ committed Jul 5, 2019
1 parent c2513b5 commit b5f1b02
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 0 deletions.
190 changes: 190 additions & 0 deletions TP6Ex8/run
Original file line number Diff line number Diff line change
@@ -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)
17 changes: 17 additions & 0 deletions TP6Ex8/src/Merge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
def merge(tab1, tab2):
sol =[0 for i in range(len(tab1)+len(tab2))]
if len(tab1)<len(tab2):
for i in range(len(tab1)):
sol[2*i] = tab1[i]
sol[2*i+1] = tab2[i]

for i in range(len(tab1),len(tab2)):
sol[len(tab1)+i] = tab2[i]
else:
for i in range(len(tab2)):
sol[2*i] = tab1[i]
sol[2*i+1] = tab2[i]

for i in range(len(tab2),len(tab1)):
sol[len(tab2)+i] = tab1[i]
return sol
3 changes: 3 additions & 0 deletions TP6Ex8/src/Templates/q
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
@@q1@@
40 changes: 40 additions & 0 deletions TP6Ex8/src/TestQ.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-


import unittest
import q
from Merge import *
import random as rd
rd.seed(2019)

#Correct solution


class TestPageRank(unittest.TestCase):

def test_exist_arrToMat(self):
self.assertTrue(hasattr(q, 'merge'), "@1@: " + _("You did not name the method as expected."))

def test_merge_1(self):
#test len(tab1)<len(tab2)
tab1=[rd.randint(1,100) for i in range(13)]
tab2=[rd.randint(1,100) for i in range(37)]
ans=merge(tab1,tab2)
student=q.merge(tab1,tab2)
for i in range(len(ans)):
for j in range(len(ans)):
self.assertEqual(ans[i],student[i],"@1@: Il y a un problème dans la fonction merge()")

def test_merge_2(self):
#test len(tab1)>len(tab2)
tab1=[rd.randint(1,100) for i in range(37)]
tab2=[rd.randint(1,100) for i in range(13)]
ans=merge(tab1,tab2)
student=q.merge(tab1,tab2)
for i in range(len(ans)):
for j in range(len(ans)):
self.assertEqual(ans[i],student[i],"@1@: Il y a un problème dans la fonction merge()")

if __name__ == '__main__':
unittest.main()
34 changes: 34 additions & 0 deletions TP6Ex8/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
accessible: true
author: Alain Mbungu
context: |
Écrire une méthode **merge** qui prend en paramètre deux tableaux d'entiers à une dimension (vecteurs *tab1* et *tab2*) de longueurs quelconques. La méthode doit renvoyer un nouveau tableau d'entiers qui contient les éléments des deux tableaux reçus en paramètre entrelacés. Plus précisément, soient ``s1, s2, s3, ..., sm`` les éléments du premier tableau (*tab1*) et ``t1, t2, t3, ..., tn`` les éléments du second tableau (*tab2*). Les éléments du tableau renvoyé sont ``s1, t1, s2, t2, s3, t3,....`` Faites bien attention au fait que les deux tableaux n'ont pas forcément la même longueur et qu’ils peuvent même être vides. Notez aussi que les tableaux passés en paramètre *tab1* et *tab2* ne doivent pas être modifiés !
*Exemple:* **tab1=[1,2,3,4]** et **tab2=[5,6]** donnent
.. code-block:: python
[1,5,2,6,3,4]
environment: default
evaluate: best
groups: false
input_random: '0'
limits:
output: '2'
memory: '100'
time: '30'
name: TP6Ex8 Examen Janvier 2009
network_grading: false
problems:
q1:
type: code
language: ''
header: La fonction ``merge(tab1,tab2)``
name: Implémentation
default: ''
stored_submissions: 0
submission_limit:
amount: -1
period: -1
tags: {}
weight: 1.0

0 comments on commit b5f1b02

Please sign in to comment.