Code cleaning

This commit is contained in:
Emmanuel Viennet 2022-04-02 13:30:26 +02:00
parent ae0baf8c1a
commit c65689b2a3
4 changed files with 55 additions and 44 deletions

View File

@ -32,7 +32,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
def __init__(self, formsemestre): def __init__(self, formsemestre):
super().__init__(formsemestre) super().__init__(formsemestre)
"""DataFrame, row UEs(sans bonus), cols modimplid, value coef"""
self.sem_cube = None self.sem_cube = None
"""ndarray (etuds x modimpl x ue)""" """ndarray (etuds x modimpl x ue)"""
@ -43,7 +43,8 @@ class ResultatsSemestreBUT(NotesTableCompat):
self.store() self.store()
t2 = time.time() t2 = time.time()
log( log(
f"ResultatsSemestreBUT: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)" f"""ResultatsSemestreBUT: cached formsemestre_id={formsemestre.id
} ({(t1-t0):g}s +{(t2-t1):g}s)"""
) )
def compute(self): def compute(self):

View File

@ -50,7 +50,8 @@ class ResultatsSemestreClassic(NotesTableCompat):
self.store() self.store()
t2 = time.time() t2 = time.time()
log( log(
f"ResultatsSemestreClassic: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)" f"""ResultatsSemestreClassic: cached formsemestre_id={
formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)"""
) )
# recalculé (aussi rapide que de les cacher) # recalculé (aussi rapide que de les cacher)
self.moy_min = self.etud_moy_gen.min() self.moy_min = self.etud_moy_gen.min()
@ -220,36 +221,29 @@ class ResultatsSemestreClassic(NotesTableCompat):
moyenne générale. moyenne générale.
Coef = somme des coefs des modules de l'UE auxquels il est inscrit Coef = somme des coefs des modules de l'UE auxquels il est inscrit
""" """
c = comp_etud_sum_coef_modules_ue(self.formsemestre.id, etudid, ue["ue_id"]) coef = comp_etud_sum_coef_modules_ue(self.formsemestre.id, etudid, ue["ue_id"])
if c is not None: # inscrit à au moins un module de cette UE if coef is not None: # inscrit à au moins un module de cette UE
return c return coef
# arfff: aucun moyen de déterminer le coefficient de façon sûre # arfff: aucun moyen de déterminer le coefficient de façon sûre
log( log(
"* oups: calcul coef UE impossible\nformsemestre_id='%s'\netudid='%s'\nue=%s" f"""* oups: calcul coef UE impossible\nformsemestre_id='{self.formsemestre.id
% (self.formsemestre.id, etudid, ue) }'\netudid='{etudid}'\nue={ue}"""
) )
etud: Identite = Identite.query.get(etudid) etud: Identite = Identite.query.get(etudid)
raise ScoValueError( raise ScoValueError(
"""<div class="scovalueerror"><p>Coefficient de l'UE capitalisée %s impossible à déterminer f"""<div class="scovalueerror"><p>Coefficient de l'UE capitalisée {ue.acronyme}
pour l'étudiant <a href="%s" class="discretelink">%s</a></p> impossible à déterminer pour l'étudiant <a href="{
<p>Il faut <a href="%s">saisir le coefficient de cette UE avant de continuer</a></p> url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
}" class="discretelink">{etud.nom_disp()}</a></p>
<p>Il faut <a href="{
url_for("notes.formsemestre_edit_uecoefs", scodoc_dept=g.scodoc_dept,
formsemestre_id=self.formsemestre.id, err_ue_id=ue["ue_id"],
)
}">saisir le coefficient de cette UE avant de continuer</a></p>
</div> </div>
""" """
% (
ue.acronyme,
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
etud.nom_disp(),
url_for(
"notes.formsemestre_edit_uecoefs",
scodoc_dept=g.scodoc_dept,
formsemestre_id=self.formsemestre.id,
err_ue_id=ue["ue_id"],
),
)
) )
return 0.0 # ?
def notes_sem_load_matrix(formsemestre: FormSemestre) -> tuple[np.ndarray, dict]: def notes_sem_load_matrix(formsemestre: FormSemestre) -> tuple[np.ndarray, dict]:
"""Calcule la matrice des notes du semestre """Calcule la matrice des notes du semestre
@ -279,7 +273,7 @@ def notes_sem_assemble_matrix(modimpls_notes: list[pd.Series]) -> np.ndarray:
(Series rendus par compute_module_moy, index: etud) (Series rendus par compute_module_moy, index: etud)
Resultat: ndarray (etud x module) Resultat: ndarray (etud x module)
""" """
if not len(modimpls_notes): if not modimpls_notes:
return np.zeros((0, 0), dtype=float) return np.zeros((0, 0), dtype=float)
modimpls_notes_arr = [s.values for s in modimpls_notes] modimpls_notes_arr = [s.values for s in modimpls_notes]
modimpls_notes = np.stack(modimpls_notes_arr) modimpls_notes = np.stack(modimpls_notes_arr)

View File

@ -4,6 +4,9 @@
# See LICENSE # See LICENSE
############################################################################## ##############################################################################
"""Résultats semestre: méthodes communes aux formations classiques et APC
"""
from collections import Counter from collections import Counter
from functools import cached_property from functools import cached_property
import numpy as np import numpy as np
@ -25,7 +28,6 @@ from app.scodoc import sco_groups
from app.scodoc import sco_users from app.scodoc import sco_users
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
# Il faut bien distinguer # Il faut bien distinguer
# - ce qui est caché de façon persistente (via redis): # - ce qui est caché de façon persistente (via redis):
# ce sont les attributs listés dans `_cached_attrs` # ce sont les attributs listés dans `_cached_attrs`
@ -41,6 +43,8 @@ class ResultatsSemestre(ResultatsCache):
""" """
_cached_attrs = ( _cached_attrs = (
"bonus",
"bonus_ues",
"etud_moy_gen_ranks", "etud_moy_gen_ranks",
"etud_moy_gen", "etud_moy_gen",
"etud_moy_ue", "etud_moy_ue",
@ -55,6 +59,10 @@ class ResultatsSemestre(ResultatsCache):
# BUT ou standard ? (apc == "approche par compétences") # BUT ou standard ? (apc == "approche par compétences")
self.is_apc = formsemestre.formation.is_apc() self.is_apc = formsemestre.formation.is_apc()
# Attributs "virtuels", définis dans les sous-classes # Attributs "virtuels", définis dans les sous-classes
self.bonus: pd.Series = None # virtuel
"Bonus sur moy. gen. Series de float, index etudid"
self.bonus_ues: pd.DataFrame = None # virtuel
"DataFrame de float, index etudid, columns: ue.id"
# ResultatsSemestreBUT ou ResultatsSemestreClassic # ResultatsSemestreBUT ou ResultatsSemestreClassic
self.etud_moy_ue = {} self.etud_moy_ue = {}
"etud_moy_ue: DataFrame columns UE, rows etudid" "etud_moy_ue: DataFrame columns UE, rows etudid"
@ -102,6 +110,14 @@ class ResultatsSemestre(ResultatsCache):
"dict { etudid : indice dans les inscrits }" "dict { etudid : indice dans les inscrits }"
return {e.id: idx for idx, e in enumerate(self.etuds)} return {e.id: idx for idx, e in enumerate(self.etuds)}
def modimpl_notes(self, modimpl_id: int, ue_id: int) -> np.ndarray:
"""Les notes moyennes des étudiants du sem. à ce modimpl dans cette ue.
Utile pour stats bottom tableau recap.
Résultat: 1d array of float
"""
# différent en BUT et classique: virtuelle
raise NotImplementedError
@cached_property @cached_property
def etuds_dict(self) -> dict[int, Identite]: def etuds_dict(self) -> dict[int, Identite]:
"""dict { etudid : Identite } inscrits au semestre, """dict { etudid : Identite } inscrits au semestre,
@ -230,6 +246,13 @@ class ResultatsSemestre(ResultatsCache):
0.0, min(self.etud_moy_gen[etudid], 20.0) 0.0, min(self.etud_moy_gen[etudid], 20.0)
) )
def get_etud_etat(self, etudid: int) -> str:
"Etat de l'etudiant: 'I', 'D', DEF ou '' (si pas connu dans ce semestre)"
ins = self.formsemestre.etuds_inscriptions.get(etudid, None)
if ins is None:
return ""
return ins.etat
def _get_etud_ue_cap(self, etudid: int, ue: UniteEns) -> dict: def _get_etud_ue_cap(self, etudid: int, ue: UniteEns) -> dict:
"""Donne les informations sur la capitalisation de l'UE ue pour cet étudiant. """Donne les informations sur la capitalisation de l'UE ue pour cet étudiant.
Résultat: Résultat:
@ -304,11 +327,11 @@ class ResultatsSemestre(ResultatsCache):
if coef_ue is None: if coef_ue is None:
orig_sem = FormSemestre.query.get(ue_cap["formsemestre_id"]) orig_sem = FormSemestre.query.get(ue_cap["formsemestre_id"])
raise ScoValueError( raise ScoValueError(
f"""L'UE capitalisée {ue_capitalized.acronyme} f"""L'UE capitalisée {ue_capitalized.acronyme}
du semestre {orig_sem.titre_annee()} du semestre {orig_sem.titre_annee()}
n'a pas d'indication d'ECTS. n'a pas d'indication d'ECTS.
Corrigez ou faite corriger le programme Corrigez ou faite corriger le programme
<a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, <a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
formation_id=ue_capitalized.formation_id)}">via cette page</a>. formation_id=ue_capitalized.formation_id)}">via cette page</a>.
""" """
) )
@ -333,6 +356,11 @@ class ResultatsSemestre(ResultatsCache):
"capitalized_ue_id": ue_cap["ue_id"] if is_capitalized else None, "capitalized_ue_id": ue_cap["ue_id"] if is_capitalized else None,
} }
def compute_etud_ue_coef(self, etudid: int, ue: UniteEns) -> float:
"Détermine le coefficient de l'UE pour cet étudiant."
# calcul différent en classqiue et BUT
raise NotImplementedError()
def get_etud_ue_cap_coef(self, etudid, ue, ue_cap): def get_etud_ue_cap_coef(self, etudid, ue, ue_cap):
"""Calcule le coefficient d'une UE capitalisée, pour cet étudiant, """Calcule le coefficient d'une UE capitalisée, pour cet étudiant,
injectée dans le semestre courant. injectée dans le semestre courant.
@ -401,7 +429,6 @@ class ResultatsSemestre(ResultatsCache):
titles = { titles = {
"rang": "Rg", "rang": "Rg",
# ordre des colonnes: # ordre des colonnes:
"_rang_col_order": 1,
"_civilite_str_col_order": 2, "_civilite_str_col_order": 2,
"_nom_disp_col_order": 3, "_nom_disp_col_order": 3,
"_prenom_col_order": 4, "_prenom_col_order": 4,
@ -544,8 +571,7 @@ class ResultatsSemestre(ResultatsCache):
# --- TABLE FOOTER: ECTS, moyennes, min, max... # --- TABLE FOOTER: ECTS, moyennes, min, max...
footer_rows = [] footer_rows = []
for bottom_line in bottom_infos: for (bottom_line, row) in bottom_infos.items():
row = bottom_infos[bottom_line]
# Cases vides à styler: # Cases vides à styler:
row["moy_gen"] = row.get("moy_gen", "") row["moy_gen"] = row.get("moy_gen", "")
row["_moy_gen_class"] = "col_moy_gen" row["_moy_gen_class"] = "col_moy_gen"
@ -621,7 +647,7 @@ class ResultatsSemestre(ResultatsCache):
# if dec: # if dec:
# codes_nb[dec["code"]] += 1 # codes_nb[dec["code"]] += 1
row_class = "" row_class = ""
etud_etat = self.get_etud_etat(etudid) # dans NotesTableCompat, à revoir etud_etat = self.get_etud_etat(etudid)
if etud_etat == DEM: if etud_etat == DEM:
gr_name = "Dém." gr_name = "Dém."
row_class = "dem" row_class = "dem"

View File

@ -32,8 +32,6 @@ class NotesTableCompat(ResultatsSemestre):
""" """
_cached_attrs = ResultatsSemestre._cached_attrs + ( _cached_attrs = ResultatsSemestre._cached_attrs + (
"bonus",
"bonus_ues",
"malus", "malus",
"etud_moy_gen_ranks", "etud_moy_gen_ranks",
"etud_moy_gen_ranks_int", "etud_moy_gen_ranks_int",
@ -44,8 +42,6 @@ class NotesTableCompat(ResultatsSemestre):
super().__init__(formsemestre) super().__init__(formsemestre)
nb_etuds = len(self.etuds) nb_etuds = len(self.etuds)
self.bonus = None # virtuel
self.bonus_ues = None # virtuel
self.ue_rangs = {u.id: (None, nb_etuds) for u in self.ues} self.ue_rangs = {u.id: (None, nb_etuds) for u in self.ues}
self.mod_rangs = None # sera surchargé en Classic, mais pas en APC self.mod_rangs = None # sera surchargé en Classic, mais pas en APC
"""{ modimpl_id : (rangs, effectif) }""" """{ modimpl_id : (rangs, effectif) }"""
@ -251,13 +247,6 @@ class NotesTableCompat(ResultatsSemestre):
) )
return self.validations.decisions_jury.get(etudid, None) return self.validations.decisions_jury.get(etudid, None)
def get_etud_etat(self, etudid: int) -> str:
"Etat de l'etudiant: 'I', 'D', DEF ou '' (si pas connu dans ce semestre)"
ins = self.formsemestre.etuds_inscriptions.get(etudid, None)
if ins is None:
return ""
return ins.etat
def get_etud_mat_moy(self, matiere_id: int, etudid: int) -> str: def get_etud_mat_moy(self, matiere_id: int, etudid: int) -> str:
"""moyenne d'un étudiant dans une matière (ou NA si pas de notes)""" """moyenne d'un étudiant dans une matière (ou NA si pas de notes)"""
if not self.moyennes_matieres: if not self.moyennes_matieres:
@ -316,6 +305,7 @@ class NotesTableCompat(ResultatsSemestre):
return self.etud_moy_gen_ranks.get(etudid, 99999) return self.etud_moy_gen_ranks.get(etudid, 99999)
def get_etud_rang_group(self, etudid: int, group_id: int): def get_etud_rang_group(self, etudid: int, group_id: int):
"Le rang de l'étudiant dans ce groupe (NON IMPLEMENTE)"
return (None, 0) # XXX unimplemented TODO return (None, 0) # XXX unimplemented TODO
def get_evals_in_mod(self, moduleimpl_id: int) -> list[dict]: def get_evals_in_mod(self, moduleimpl_id: int) -> list[dict]: