Make personal evaluation creation and deployment steps executable

This commit is contained in:
sebastien committed 2026-11-03 11:38:14 +01:00
1 parent 8c1fa0af57
commit 5de70dbc0d
4 files changed
+67 -9

No files matched your search

+8 -1
View File
@@ -357,7 +357,14 @@ OU
- `python -m copienator read-grouped --update-score Interro` - `python -m copienator read-grouped --update-score Interro`
pour mettre à jour les scores dans les images. pour mettre à jour les scores dans les images.
4. (gestion perso) 4. (gestion perso)
+ =gestion_classe ne= pour créer l'interro puis + =gestion_classe ne INT05 --defaults= pour créer l'interro sans saisie
(nom du fichier dans Staging, sans suffixe ; semaine suivante pour ce type,
sans duplication ni saisie des notes). Ajouter =--week 3= pour imposer la
semaine, notamment pour la première évaluation de ce type. Dans l'interface,
« Créer l'interro dans gestion_classe » propose le nom du dossier et une
semaine facultative, puis exécute cette commande. Un fichier absent ou un
type inconnu provoque une erreur. =gestion_classe ne= reste interactif.
Puis
+ =gestion_classe we= (set barème here) + =gestion_classe we= (set barème here)
+ =python -m copienator update-ods Interro= + =python -m copienator update-ods Interro=
ou =python -m copienator update-ods Interro --sum= (en l'absence de barème) ou =python -m copienator update-ods Interro --sum= (en l'absence de barème)
+1 -3
View File
@@ -1117,8 +1117,6 @@ class CopienatorApp(tk.Tk):
self.run_button.configure(text="Make modifications" if step.id == "modify_annotations" else "Enregistrer la sélection" if step.id == "refaire_selection" else ("Marquer terminée" if step.is_manual else "Exécuter")) self.run_button.configure(text="Make modifications" if step.id == "modify_annotations" else "Enregistrer la sélection" if step.id == "refaire_selection" else ("Marquer terminée" if step.is_manual else "Exécuter"))
if step.id == "remove_copy": if step.id == "remove_copy":
self.run_button.configure(text="Supprimer la copie sélectionnée") self.run_button.configure(text="Supprimer la copie sélectionnée")
if step.id == "personal_create":
self.run_button.configure(text="Marquer Réussie")
if step.id == "personal_read": if step.id == "personal_read":
self.run_button.configure(text="Marquer réussie") self.run_button.configure(text="Marquer réussie")
self.skip_button.configure(state="normal" if step.optional else "disabled") self.skip_button.configure(state="normal" if step.optional else "disabled")
@@ -1815,7 +1813,7 @@ class CopienatorApp(tk.Tk):
except (OSError, ValueError, TypeError) as exc: except (OSError, ValueError, TypeError) as exc:
messagebox.showerror("Sélection à vérifier", str(exc)) messagebox.showerror("Sélection à vérifier", str(exc))
return return
if (step.is_manual or step.id == "personal_create" if (step.is_manual
or (step.id == "personal_read" and review_command is None)): or (step.id == "personal_read" and review_command is None)):
self._mark_step("success") self._mark_step("success")
if step.id == "general_remarks": if step.id == "general_remarks":
+14 -5
View File
@@ -777,9 +777,15 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
"personal_create", "personal_create",
"Étapes personnelles", "Étapes personnelles",
"Créer l’interro dans gestion_classe", "Créer l’interro dans gestion_classe",
"Copiez la commande gestion_classe ne et exécutez-la dans un terminal, " "Crée l’évaluation avec les valeurs par défaut : semaine suivante pour ce type, "
"puis cliquez sur « Marquer Réussie ».", "sans duplication ni saisie des notes. Pour la première évaluation de ce type, indiquez la semaine.",
(CommandVariant("default", "gestion_classe ne", "gestion_classe", "external", ("ne",)),), (CommandVariant("default", "gestion_classe ne", "gestion_classe", "external", ("ne", "--defaults"), fixed_args_before_positionals=True),),
arguments=(
arg_evaluation_name(),
ArgumentSpec("week", "Semaine (facultatif)", "int", "--week",
help="Laissez vide pour utiliser la dernière semaine de ce type + 1. "
"Obligatoire pour la première évaluation de ce type (0 à 255)."),
),
personal=True, personal=True,
), ),
StepDefinition( StepDefinition(
@@ -850,8 +856,11 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
"personal_deploy", "personal_deploy",
"Étapes personnelles", "Étapes personnelles",
"Déployer et publier les copies", "Déployer et publier les copies",
"Étape manuelle : déployer miqmacs-copies-assets et la section `Interro` (inutile : mettre à jour les copies depuis l’administration).", "Publie toutes les copies puis exécute la procédure « L’interro » de deploy.org. "
(manual("deploy"),), "Prérequis : récupérer les PDF de Staging et exporter MPSI depuis index.org. "
"Après modification de deploy.org, régénérez manuellement le script dans Emacs (C-c C-v t).",
(CommandVariant("deploy", "Publier les copies et l’interro", "bash", "external",
(str(Path.home() / "Scripts" / "deploy-copies-interro.sh"),)),),
personal=True, personal=True,
), ),
StepDefinition( StepDefinition(
+44
View File
@@ -64,6 +64,50 @@ class GuiConvenienceTests(unittest.TestCase):
self.assertEqual(command[-2:], ['repair-orientation', str(self.evaluation)]) self.assertEqual(command[-2:], ['repair-orientation', str(self.evaluation)])
self.assertEqual(self.app.active_step_id, 'labels') self.assertEqual(self.app.active_step_id, 'labels')
def test_personal_deploy_runs_generated_script_and_tracks_result(self):
from copienator_gui.workflow import build_workflow
step = next(step for step in build_workflow(True) if step.id == "personal_deploy")
self.app.step_by_id[step.id] = step
self.app.current_step = step
self.app._render_step()
self.assertEqual(self.app.run_button.cget("text"), "Exécuter")
with patch.object(self.app.runner, "start") as start, \
patch.object(self.app, "_move_selection_from"):
self.app.run_button.invoke()
self.assertEqual(start.call_args.args[0],
["bash", str(Path.home() / "Scripts" / "deploy-copies-interro.sh")])
self.assertNotEqual(self.app.state_store.step(step.id)["status"], "success")
self.app._finish_process(1, False)
self.assertNotEqual(self.app.state_store.step(step.id)["status"], "success")
self.app.run_button.invoke()
self.app._finish_process(0, False)
self.assertEqual(self.app.state_store.step(step.id)["status"], "success")
def test_personal_create_executes_with_defaults_and_tracks_result(self):
from copienator_gui.workflow import build_workflow
step = next(step for step in build_workflow(True) if step.id == "personal_create")
self.app.step_by_id[step.id] = step
self.app.current_step = step
self.app._render_step()
self.assertEqual(self.app.run_button.cget("text"), "Exécuter")
self.assertEqual(self.app.arg_vars["evaluation_name"].get(), self.evaluation.name)
self.assertEqual(self.app.arg_vars["week"].get(), "")
with patch.object(self.app.runner, "start") as start, \
patch.object(self.app, "_move_selection_from"):
self.app.run_button.invoke()
self.assertEqual(start.call_args.args[0],
["gestion_classe", "ne", "--defaults", self.evaluation.name])
self.assertNotEqual(self.app.state_store.step(step.id)["status"], "success")
self.app._finish_process(1, False)
self.assertNotEqual(self.app.state_store.step(step.id)["status"], "success")
self.app.arg_vars["evaluation_name"].set("DS02VB custom")
self.app.arg_vars["week"].set("3")
self.app.run_button.invoke()
self.assertEqual(start.call_args.args[0],
["gestion_classe", "ne", "--defaults", "DS02VB custom", "--week", "3"])
self.app._finish_process(0, False)
self.assertEqual(self.app.state_store.step(step.id)["status"], "success")
def test_personal_review_commands_require_explicit_completion(self): def test_personal_review_commands_require_explicit_completion(self):
from copienator_gui.workflow import build_workflow from copienator_gui.workflow import build_workflow
step = next(step for step in build_workflow(True) if step.id == "personal_read") step = next(step for step in build_workflow(True) if step.id == "personal_read")