HackInScience est un logiciel de publication et de correction automatique d'exercices, son instance hackinscience.org est une collection d'exercices Python.
HackInScience est né en 2014 : j'enseignais alors le Python en université (promos d'environ 70 élèves), et avec les collègues on s'est dit qu'il serait bon de passer plus de temps à aider les élèves qu'a les corriger, que la correction c'était automatisable, mais que passer du temps avec eux, ça ne l'était pas.
Deux "on jette tout et on recommence" plus tard, et deux confinements plus tard, on en est là :
Tout le code est open-source, c'est un simple Django pour présenter les exercices, des websockets pour recevoir sans attendre la correction du bot, et un Celery pour "load-balancer" les rendus aux serveurs de correction. Je n'enseigne plus en université mais le site étant toujours en ligne, et les confinements aidant, il a trouvé son public : 1500 exercices sont réussis par semaine en ce moment.
J’essaye de passer deux semaines par an à plein temps sur le projet, en 2019 j’ai travaillé l’internationalisation (être traducteur de la doc de Python et ne pas traduire ses propres projets n’était pas bien sérieux…), et en 2020 la notion de classement et d’équipes.
Du point de vue d'un élève
L'interface est minimaliste (d'abord parce que je suis plutôt nul en front :p) :
À gauche l'énoncé, au milieu l'utilisateur rédige son code, et à droite la réponse du bot. C'est simple et il n'y a pas de place pour de la pub ;)
Du point de vue admin
C'est toute suite plus compliqué et mon but n'étant pas de rédiger la documentation ici je vais passer vite sur les détails les moins intéressants.
Pour l'installation d'une instance HackInScience je pense qu'un bon point de départ serait de s'inspirer de notre playbook Ansible, mais pour un test local un python manage.py runserver
suffit.
La création d'exercices se passe dans un django-admin classique :
Mais pour plus de confort j'ai pris l'habitude d'éditer les exercices localement (emacs étant un peu plus confortable que ACE Editor pour éditer du Python), de les versionner, et de tester mes modifications avant de les publier, pour ça j'utilise fetch.py
et push.py
dans le dossier scripts/
.
La partie intéressante de la création d'un exercice, c'est son bot de correction : c'est aussi un script Python qui est appelé dans une sandbox à côté du rendu. La rédaction de ce script est totalement libre, la seule règle c'est : s'il print (sur stderr ou stdout) l'exercice est faux, sinon il est considéré juste.
Pour me faciliter le travail j'ai crée correction-helper qui lui même utilise friendly-traceback, à l'usage, rédiger un bot de correction ressemble à :
for message in test_messages:
expected = bencode(message)
with student_code():
got = student_encode(message)
if expected != got:
message = _("Wrong answer while testing `{thing}`").format(thing=f"bencode({message!r})")
if type(got) != bytes:
message += "\n\n" + f"Expected a `bytes` instance, got a `{type(got)}`."
fail(message, _("Got:"), code(got), _("Expected:"), code(expected))
Alors corriger du Python depuis du Python c'est assez simple, je peux soit utiliser subprocess.run
pour exécuter le code de l'élève, soit importer ses fonctions et les tester, ça ressemble beaucoup à de la rédaction de tests unitaires, sauf qu'au lieu de se contenter d'un assert
on rédige une description explicite de l'erreur, et parfois des conseils pour l'éviter.
Mais corriger du bash, du C, ou n'importe quoi d'autre doit être tout à fait possible aussi : rien n'empêche de rédiger une moulinette qui compile le code de l'élève puis le teste à coup de subprocess.run
aussi.
Aller plus loin
- Site d'HackInScience (364 clics)
# Sécurité ?
Posté par Colin Pitrat (site web personnel) . Évalué à 7.
Et niveau sécurité/isolation comment sont gérés les programmes qui ne terminent pas, ceux qui consomment beaucoup de ressources, ceux qui essaient d'accéder à /etc/passwd, d'ouvrir des sockets, etc … ?
J'ai souvent eu envie de faire des challenges avec ce genre d'approche mais j'ai jamais trop osé mettre ça entre des mains potentiellement hostiles (ou juste taquines).
[^] # Re: Sécurité ?
Posté par Pol' uX (site web personnel) . Évalué à 4.
Le code semble utiliser firejail.
Adhérer à l'April, ça vous tente ?
[^] # Re: Sécurité ?
Posté par JulienPalard . Évalué à 3.
Exact, j'utilise firejail (comme ça) pour exécuter le code des étudiants avec le moins de droits possible, même pas d'accès internet. J'imagine qu'avec du talent on doit pouvoir trouver des choses à faire, mais pour le moment (et j'en suis étonné) je n'ai vu personne tenter de contourner la sandbox.
[^] # Re: Sécurité ?
Posté par Pierre Jarillon (site web personnel) . Évalué à 3.
C'est parce que leur niveau n'est pas très bon ;-)
Ou alors leur prof est trop fort !
[^] # Re: Sécurité ?
Posté par moi1392 . Évalué à 5.
Ou alors, c'est eux qui sont trop bons…
# précisions sur le(s) bot(s)
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 1.
Si j'ai bien compris la fin de la présentation, il faut un bot pour la correction automatique de l'exercice mai je n'ai pas bien compris s'il en faut un différent par exercice ou s'ils utilisent tous le même.
D'après le gabarit de code posté, ce bot prend la saisie effectuée par l'élève et s'attend à ce que ça ne renvoie pas d'erreur en l'exécutant. Du coup, on peut mettre n'importe quel code Python pourvu que ça ne fasse pas d'erreur ?
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: précisions sur le(s) bot(s)
Posté par tisaac (Mastodon) . Évalué à 2.
Je pense que oui.
Je me suis amusé sur un des premiers exercices à écrire plein de choses inutiles mais qui ne créaient pas d'erreur et c'est passé nickel crème.
Surtout, ne pas tout prendre au sérieux !
[^] # Re: précisions sur le(s) bot(s)
Posté par JulienPalard . Évalué à 1.
J'écris un "correcteur" par exercice. Pour 72 exercices ça fait 5049 lignes de Python, soit en moyenne 70 lignes par "correcteur" (avec bien sur un peu de redondance : les imports toujours pareil, le setup de gettext, le main …). Je trouve ça plus propre et maintenable comme ça : quand je veux améliorer la correction de tel ou tel exercice, je sais rapidement où c'est (le script
fetch.py
me crée un dossier par exercice avec dedans :wording-fr.md, wording-en.md
le texte présenté à droite,check.py
le code de correction, …Chaque "code de correction" prend l'approche qu'il veut, parfois j'exécute le code de l'élève avec
subprocess.run()
, parfois une seule fois, parfois plusieurs fois si je veux tester plusieurs paramètres. Sinon j'importe les fonctions de l'élève et je les exécute avec différents paramètres pour vérifier leur résultats. Dans le code d'exemple que j'ai mis, qui teste la bonne implémentation d'une fonctionbencode
par l'élève :bencode
, pour encoder le message de testbencode
de l'étudiantfail
est celle quiprint
l'erreur, l'exercice sera donc considéré faux.Dans tous les cas si quelqu'un rend une fonction de trop, innutilisée, mais que son programme fonctionne, je ne pourrai pas m'en rendre compte. Par contre s'il se met à print en trop, ça risque de déplaire au bot.
[^] # Re: précisions sur le(s) bot(s)
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 1.
Merci pour le retour. Ce n'est pas déconnant d'avoir un correcteur par exercice, c'est plus simple et plus propre (et ça répond à ma question).
L'approche de correction est en fait celui des « tests » donc : vérification de sorties attendues pour des entrées données.
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: précisions sur le(s) bot(s)
Posté par JulienPalard . Évalué à 3.
Oui complètement, ça ressemble parfois comme deux gouttes d'eau à des tests unitaires. Sauf qu'au lieu de sortir un
AssertionError
j'essaye de rédiger un message qui explique pourquoi c'est faux, de manière à ce qu'un utilisateur ne soit jamais bloqué (utopique peut être).Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.