Skip to content

Commit

Permalink
added TP2Ex3
Browse files Browse the repository at this point in the history
  • Loading branch information
mpostaire committed Jul 5, 2019
1 parent 3b8ac2d commit 7fb9c51
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 4 deletions.
171 changes: 171 additions & 0 deletions TP2Ex3/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#! /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
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:
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:])
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))


if __name__ == '__main__':
language = init_translations()
num_exercises = compute_code()
compile_code()
run_code(num_exercises, language)
11 changes: 11 additions & 0 deletions TP2Ex3/src/CorrQ.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-


def amende(vmax, v):
if v > vmax:
result = (v - vmax) * 5
if v - vmax > 10:
result *= 2
return max(12.5, result)
return 0
5 changes: 5 additions & 0 deletions TP2Ex3/src/Templates/q
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-


@@q1@@
35 changes: 35 additions & 0 deletions TP2Ex3/src/TestQ.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-


import unittest
import random

import CorrQ as corr
import q

INPUTS = [
{ "v": 62, "vmax": 50 },
{ "v": 53, "vmax": 50 },
{ "v": 0, "vmax": 50 },
{ "v": 51, "vmax": 50 },
{ "v": 1, "vmax": 1 },
{ "v": 2, "vmax": 1 },
]


class TestAmende(unittest.TestCase):
def test_specs(self):
self.assertTrue(hasattr(q, "amende") and callable(
q.amende), _("Vous n'avez pas bien spécifié votre fonction"))

def test_q1(self):
for i in INPUTS:
student = q.amende(i["vmax"], i["v"])
sol = corr.amende(i["vmax"], i["v"])
self.assertEqual(student, sol, _(
"Pour vmax = {} et v = {}\nvotre code a produit : {}\nmais le résultat attendu est : {}".format(i["vmax"], i["v"], student, sol)))


if __name__ == '__main__':
unittest.main()
37 changes: 37 additions & 0 deletions TP2Ex3/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
accessible: true
author: Maxime Postaire
context: |-
La police vous engage pour développer un programme permettant de calculer l'amende qu'un conducteur de voiture devra payer en cas d'infraction. La loi stipule que le conducteur devra payer 5 euros par km/h au-dessus de la vitesse maximale autorisée, avec un minimum de 12.5 euros. Pour tout dépassement de plus de 10 km/h, l'amende est doublée !
Ecrivez une fonction ``amende`` qui reçoit la vitesse maximale autorisée ``vmax`` et la vitesse réelle ``v`` de la voiture et qui renvoie l’éventuelle amende (on considère que les valeurs d'entrée sont toujours correctes : pas de vitese négative, ...).
**Exemple :** Si la vitesse maximum est de 50km/h et que le véhicule roule à 62km/h, l''amende sera de 12*5*2=120€.
La signature de cette fonction est :
.. code:: python
def amende(vmax, v)
environment: default
evaluate: best
groups: false
input_random: '0'
limits:
memory: '100'
output: '2'
time: '30'
name: TP2 exercice 3
network_grading: false
problems:
q1:
header: ''
type: code
language: python
default: ''
name: 'Implémentation :'
stored_submissions: 0
submission_limit:
amount: -1
period: -1
tags: {}
weight: 1.0
8 changes: 4 additions & 4 deletions TP6Ex6/task.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
accessible: true
author: ''
author: Maxime Postaire
context: |-
On vous demande d’écrire la fonction ``produitMatrice`` qui calcule le **produit matriciel ordinaire** de deux matrices :math:`A` et :math:`B`. Le produit de deux matrices ne peut se définir que si le nombre de colonnes de la première matrice est le même que le nombre de lignes de la deuxième matrice.
Si :math:`A = (aij)` (:math:`aij` sont les éléments de la matrice) est une matrice de taille :math:`(m, n)` et :math:`B = (bij)` est une matrice de taille :math:`(n, p)`, alors leur produit, noté :math:`AB = (cij)` est une matrice de taille :math:`(m, p)` donnée par :
Expand Down Expand Up @@ -38,11 +38,11 @@ name: TP6 exercice 6
network_grading: false
problems:
q1:
default: ''
header: ''
type: code
language: python
name: 'Implémentation :'
default: ''
language: python
header: ''
stored_submissions: 0
submission_limit:
amount: -1
Expand Down

0 comments on commit 7fb9c51

Please sign in to comment.