From f8f47e05ffbf805bf85c84b6e4568ffaeb5a454e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 17 Mar 2024 13:28:49 +0100 Subject: [PATCH 1/2] Fix: formsemestre_table_estim_cost: error handling --- app/models/formsemestre.py | 2 +- app/scodoc/sco_cost_formation.py | 75 +++++++++++++++----------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 5541d1780..ba08fed48 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -873,7 +873,7 @@ class FormSemestre(db.Model): descr_sem += " " + self.modalite return descr_sem - def get_abs_count(self, etudid): + def get_abs_count(self, etudid) -> tuple[int, int, int]: """Les comptes d'absences de cet étudiant dans ce semestre: tuple (nb abs non just, nb abs justifiées, nb abs total) Utilise un cache. diff --git a/app/scodoc/sco_cost_formation.py b/app/scodoc/sco_cost_formation.py index 5c167e6bc..649623a6c 100644 --- a/app/scodoc/sco_cost_formation.py +++ b/app/scodoc/sco_cost_formation.py @@ -30,17 +30,18 @@ (coût théorique en heures équivalent TD) """ -from flask import request +from flask import request, Response from app.models import FormSemestre -from app.scodoc.gen_tables import GenTable from app.scodoc import sco_preferences +from app.scodoc.gen_tables import GenTable +from app.scodoc.sco_exceptions import ScoValueError import app.scodoc.sco_utils as scu import sco_version def formsemestre_table_estim_cost( - formsemestre_id, + formsemestre: FormSemestre, n_group_td=1, n_group_tp=1, coef_tp=1, @@ -55,8 +56,6 @@ def formsemestre_table_estim_cost( peut conduire à une sur-estimation du coût s'il y a des modules optionnels (dans ce cas, retoucher le tableau excel exporté). """ - formsemestre = FormSemestre.get_formsemestre(formsemestre_id) - rows = [] for modimpl in formsemestre.modimpls: rows.append( @@ -76,14 +75,14 @@ def formsemestre_table_estim_cost( + coef_cours * row["heures_cours"] + coef_tp * row["heures_tp"] ) - sum_cours = sum([t["heures_cours"] for t in rows]) - sum_td = sum([t["heures_td"] for t in rows]) - sum_tp = sum([t["heures_tp"] for t in rows]) + sum_cours = sum(t["heures_cours"] for t in rows) + sum_td = sum(t["heures_td"] for t in rows) + sum_tp = sum(t["heures_tp"] for t in rows) sum_heqtd = sum_td + coef_cours * sum_cours + coef_tp * sum_tp - assert abs(sum([t["HeqTD"] for t in rows]) - sum_heqtd) < 0.01, "%s != %s" % ( - sum([t["HeqTD"] for t in rows]), - sum_heqtd, - ) + # assert abs(sum(t["HeqTD"] for t in rows) - sum_heqtd) < 0.01, "%s != %s" % ( + # sum(t["HeqTD"] for t in rows), + # sum_heqtd, + # ) rows.append( { @@ -117,7 +116,7 @@ def formsemestre_table_estim_cost( ), rows=rows, html_sortable=True, - preferences=sco_preferences.SemPreferences(formsemestre_id), + preferences=sco_preferences.SemPreferences(formsemestre.id), html_class="table_leftalign table_listegroupe", xls_before_table=[ [formsemestre.titre_annee()], @@ -146,47 +145,45 @@ def formsemestre_table_estim_cost( return tab +# view def formsemestre_estim_cost( - formsemestre_id, - n_group_td=1, - n_group_tp=1, - coef_tp=1, - coef_cours=1.5, + formsemestre_id: int, + n_group_td: int | str = 1, + n_group_tp: int | str = 1, + coef_tp: float | str = 1.0, + coef_cours: float | str = 1.5, fmt="html", -): +) -> str | Response: """Page (formulaire) estimation coûts""" + try: + n_group_td = int(n_group_td) + n_group_tp = int(n_group_tp) + coef_tp = float(coef_tp) + coef_cours = float(coef_cours) + except ValueError as exc: + raise ScoValueError("paramètre invalide: utiliser des nombres") from exc - n_group_td = int(n_group_td) - n_group_tp = int(n_group_tp) - coef_tp = float(coef_tp) - coef_cours = float(coef_cours) + formsemestre = FormSemestre.get_formsemestre(formsemestre_id) tab = formsemestre_table_estim_cost( - formsemestre_id, + formsemestre, n_group_td=n_group_td, n_group_tp=n_group_tp, coef_tp=coef_tp, coef_cours=coef_cours, ) - h = """ -
- - Nombre de groupes de TD:
- Nombre de groupes de TP: -  Coefficient heures TP: + tab.html_before_table = f""" + + + Nombre de groupes de TD:
+ Nombre de groupes de TP: +  Coefficient heures TP:
- """ % ( - request.base_url, - formsemestre_id, - n_group_td, - n_group_tp, - coef_tp, - ) - tab.html_before_table = h + """ tab.base_url = "%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s" % ( request.base_url, - formsemestre_id, + formsemestre.id, n_group_td, n_group_tp, coef_tp, From 0262b6e2ac27ecde364a7c6559a08f1bee4eeb44 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 18 Mar 2024 14:20:34 +0100 Subject: [PATCH 2/2] =?UTF-8?q?Affichage=20nb=20=C3=A9valuations=20en=20at?= =?UTF-8?q?tente=20su=20rtableau=20de=20bord.=20Ne=20consi=C3=A8re=20plus?= =?UTF-8?q?=20les=20=C3=A9valuations=20bloqu=C3=A9es=20comme=20en=20attent?= =?UTF-8?q?e.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/moy_mod.py | 30 ++++++++++++++++----------- app/comp/res_common.py | 2 ++ app/scodoc/sco_evaluations.py | 12 ++++++++++- app/scodoc/sco_formsemestre_status.py | 4 +++- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/app/comp/moy_mod.py b/app/comp/moy_mod.py index b1af5c062..dacc4d87b 100644 --- a/app/comp/moy_mod.py +++ b/app/comp/moy_mod.py @@ -148,6 +148,7 @@ class ModuleImplResults: evals_notes = pd.DataFrame(index=self.etudids, dtype=float) self.evaluations_completes = [] self.evaluations_completes_dict = {} + self.etudids_attente = set() # empty for evaluation in moduleimpl.evaluations: eval_df = self._load_evaluation_notes(evaluation) # is_complete ssi @@ -155,13 +156,13 @@ class ModuleImplResults: # ou évaluation déclarée "à prise en compte immédiate" # ou rattrapage, 2eme session, bonus # ET pas bloquée par date (is_blocked) - + is_blocked = evaluation.is_blocked() etudids_sans_note = inscrits_module - set(eval_df.index) # sans les dem. is_complete = ( (evaluation.evaluation_type != Evaluation.EVALUATION_NORMALE) or (evaluation.publish_incomplete) or (not etudids_sans_note) - ) and not evaluation.is_blocked() + ) and not is_blocked self.evaluations_completes.append(is_complete) self.evaluations_completes_dict[evaluation.id] = is_complete self.evals_etudids_sans_note[evaluation.id] = etudids_sans_note @@ -178,16 +179,21 @@ class ModuleImplResults: eval_notes_inscr = evals_notes[str(evaluation.id)][list(inscrits_module)] # Nombre de notes (non vides, incluant ATT etc) des inscrits: nb_notes = eval_notes_inscr.notna().sum() - # Etudiants avec notes en attente: - # = ceux avec note ATT - eval_etudids_attente = set( - eval_notes_inscr.iloc[ - (eval_notes_inscr == scu.NOTES_ATTENTE).to_numpy() - ].index - ) - if evaluation.publish_incomplete: - # et en "immédiat", tous ceux sans note - eval_etudids_attente |= etudids_sans_note + + if is_blocked: + eval_etudids_attente = set() + else: + # Etudiants avec notes en attente: + # = ceux avec note ATT + eval_etudids_attente = set( + eval_notes_inscr.iloc[ + (eval_notes_inscr == scu.NOTES_ATTENTE).to_numpy() + ].index + ) + if evaluation.publish_incomplete: + # et en "immédiat", tous ceux sans note + eval_etudids_attente |= etudids_sans_note + # Synthèse pour état du module: self.etudids_attente |= eval_etudids_attente self.evaluations_etat[evaluation.id] = EvaluationEtat( diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 89c0ca2a8..6e06487fc 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -209,6 +209,7 @@ class ResultatsSemestre(ResultatsCache): "evalcomplete" : bool, "last_modif" : datetime.datetime | None, # saisie de note la plus récente "nb_notes" : int, # nb notes d'étudiants inscrits + "nb_attente" : int, # nb de notes en ATTente (même si bloquée) }, "evaluation_id" : int, "jour" : datetime.datetime, # e.date_debut or datetime.datetime(1900, 1, 1) @@ -236,6 +237,7 @@ class ResultatsSemestre(ResultatsCache): "etat": { "blocked": evaluation.is_blocked(), "evalcomplete": etat.is_complete, + "nb_attente": etat.nb_attente, "nb_notes": etat.nb_notes, "last_modif": last_modif, }, diff --git a/app/scodoc/sco_evaluations.py b/app/scodoc/sco_evaluations.py index 683c5b6f4..32f1992a8 100644 --- a/app/scodoc/sco_evaluations.py +++ b/app/scodoc/sco_evaluations.py @@ -279,11 +279,18 @@ def _summarize_evals_etats(etat_evals: list[dict]) -> dict: nb_eval_completes (= prises en compte) nb_evals_en_cours (= avec des notes, mais pas complete) nb_evals_vides (= sans aucune note) + nb_evals_attente (= avec des notes en ATTente et pas bloquée) date derniere modif Une eval est "complete" ssi tous les etudiants *inscrits* ont une note. """ - nb_evals_completes, nb_evals_en_cours, nb_evals_vides, nb_evals_blocked = 0, 0, 0, 0 + ( + nb_evals_completes, + nb_evals_en_cours, + nb_evals_vides, + nb_evals_blocked, + nb_evals_attente, + ) = (0, 0, 0, 0, 0) dates = [] for e in etat_evals: if e["etat"]["blocked"]: @@ -294,6 +301,8 @@ def _summarize_evals_etats(etat_evals: list[dict]) -> dict: nb_evals_vides += 1 elif not e["etat"]["blocked"]: nb_evals_en_cours += 1 + if e["etat"]["nb_attente"] and not e["etat"]["blocked"]: + nb_evals_attente += 1 last_modif = e["etat"]["last_modif"] if last_modif is not None: dates.append(e["etat"]["last_modif"]) @@ -303,6 +312,7 @@ def _summarize_evals_etats(etat_evals: list[dict]) -> dict: return { "nb_evals": len(etat_evals), + "nb_evals_attente": nb_evals_attente, "nb_evals_blocked": nb_evals_blocked, "nb_evals_completes": nb_evals_completes, "nb_evals_en_cours": nb_evals_en_cours, diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 027ac8dff..1277df533 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -1312,7 +1312,9 @@ def formsemestre_tableau_modules( if etat["attente"]: H.append( f""" en attente""" + title="Il y a des notes en attente">{ + etat["nb_evals_attente"] + } en attente""" ) if not mod_is_conforme: H.append(