Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreFiset001 committed Jul 5, 2019
2 parents 6465f30 + 10054ac commit e7724ad
Show file tree
Hide file tree
Showing 10 changed files with 556 additions and 0 deletions.
190 changes: 190 additions & 0 deletions TP1Ex3/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)
8 changes: 8 additions & 0 deletions TP1Ex3/src/Ex3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import math as m

def volume(r):
return((4.0/3.0)*m.pi*(r**3))


def surface(r):
return(4*m.pi*(r**2))
7 changes: 7 additions & 0 deletions TP1Ex3/src/Templates/q
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import math as m

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


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

#Correct solution


class TestPageRank(unittest.TestCase):

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

def test_exist_surface(self):
self.assertTrue(hasattr(q, 'surface'), "@2@: " + _("You did not name the method as expected."))

def test_volume(self):
val=[rd.randint(1,100) for i in range(10)]
for i in val:
self.assertEqual(volume(i),q.volume(i),"@1@: Il y a un problème dans la fonction volume()")

def test_surface(self):
val=[rd.randint(1,100) for i in range(10)]
for i in val:
self.assertEqual(surface(i),q.surface(i),"@2@: Il y a un problème dans la fonction surface()")

if __name__ == '__main__':
unittest.main()
34 changes: 34 additions & 0 deletions TP1Ex3/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
accessible: true
author: Alain Mbungu
context: Écrivez une méthode ``volume`` qui reçoit le rayon du sphère en entrée, et
renvoie en sortie le volume du sphère (4πr³/3), ainsi qu'une méthode ``surface``
qui renvoie sa surface (4πr²).
environment: default
evaluate: best
groups: false
input_random: '0'
limits:
output: '2'
memory: '100'
time: '30'
name: TP1 Exercice 3 - Volume
network_grading: false
problems:
q1:
type: code
language: ''
header: Méthode ``volume(r)``
name: Implémentation
default: ''
q2:
language: ''
type: code
header: Méthode ``surface(r)``
name: Implémentation
default: ''
stored_submissions: 0
submission_limit:
amount: -1
period: -1
tags: {}
weight: 1.0
Loading

0 comments on commit e7724ad

Please sign in to comment.