diff --git a/app/comp/res_but.py b/app/comp/res_but.py index f70ed0b086..b74efb105f 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -6,9 +6,11 @@ """Résultats semestres BUT """ +import time import numpy as np import pandas as pd +from app import log from app.comp import moy_ue, moy_sem, inscr_mod from app.comp.res_common import NotesTableCompat from app.comp.bonus_spo import BonusSport @@ -30,8 +32,14 @@ class ResultatsSemestreBUT(NotesTableCompat): super().__init__(formsemestre) if not self.load_cached(): + t0 = time.time() self.compute() + t1 = time.time() self.store() + t2 = time.time() + log( + f"ResultatsSemestreBUT: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)" + ) def compute(self): "Charge les notes et inscriptions et calcule les moyennes d'UE et gen." diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py index 0a892f4b27..2152997261 100644 --- a/app/comp/res_classic.py +++ b/app/comp/res_classic.py @@ -6,7 +6,7 @@ """Résultats semestres classiques (non APC) """ - +import time import numpy as np import pandas as pd from sqlalchemy.sql import text @@ -40,8 +40,14 @@ class ResultatsSemestreClassic(NotesTableCompat): super().__init__(formsemestre) if not self.load_cached(): + t0 = time.time() self.compute() + t1 = time.time() self.store() + t2 = time.time() + log( + f"ResultatsSemestreClassic: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)" + ) # recalculé (aussi rapide que de les cacher) self.moy_min = self.etud_moy_gen.min() self.moy_max = self.etud_moy_gen.max() diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 649970ad70..b53c942fc7 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -213,9 +213,10 @@ class ResultatsSemestre(ResultatsCache): def get_etud_ue_status(self, etudid: int, ue_id: int) -> dict: """L'état de l'UE pour cet étudiant. - L'UE doit être du semestre. - Result: dict. + Result: dict, ou None si l'UE n'est pas dans ce semestre. """ + if not ue_id in self.etud_moy_ue: + return None if not self.validations: self.validations = res_sem.load_formsemestre_validations(self.formsemestre) ue = UniteEns.query.get(ue_id) # TODO cacher nos UEs ? @@ -333,8 +334,8 @@ class NotesTableCompat(ResultatsSemestre): @cached_property def sem(self) -> dict: - """le formsemestre, comme un dict (nt.sem)""" - return self.formsemestre.to_dict() + """le formsemestre, comme un gros et gras dict (nt.sem)""" + return self.formsemestre.get_infos_dict() @cached_property def inscrlist(self) -> list[dict]: # utilisé par PE seulement diff --git a/app/comp/res_sem.py b/app/comp/res_sem.py index 5da2c7f061..607ad16811 100644 --- a/app/comp/res_sem.py +++ b/app/comp/res_sem.py @@ -25,7 +25,7 @@ def load_formsemestre_results(formsemestre: FormSemestre) -> ResultatsSemestre: """ # --- Try local cache (within the same request context) if not hasattr(g, "formsemestre_results_cache"): - g.formsemestre_results_cache = {} # pylint: disable=C0237 + g.formsemestre_results_cache = {} else: if formsemestre.id in g.formsemestre_results_cache: return g.formsemestre_results_cache[formsemestre.id] diff --git a/app/pe/pe_jurype.py b/app/pe/pe_jurype.py index 71ee98c6c5..bccd12f191 100644 --- a/app/pe/pe_jurype.py +++ b/app/pe/pe_jurype.py @@ -1133,7 +1133,7 @@ class JuryPE(object): def get_cache_notes_d_un_semestre(self, formsemestre_id: int) -> NotesTableCompat: """Charge la table des notes d'un formsemestre""" formsemestre = FormSemestre.query.get_or_404(formsemestre_id) - nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + return res_sem.load_formsemestre_results(formsemestre) # ------------------------------------------------------------------------------------------------------------------ diff --git a/app/pe/pe_semestretag.py b/app/pe/pe_semestretag.py index 369fe25db7..f48e69c403 100644 --- a/app/pe/pe_semestretag.py +++ b/app/pe/pe_semestretag.py @@ -40,6 +40,7 @@ from app import log from app.comp import res_sem from app.comp.res_common import NotesTableCompat from app.models import FormSemestre +from app.models.moduleimpls import ModuleImpl from app.models.ues import UniteEns from app.scodoc import sco_codes_parcours @@ -55,7 +56,7 @@ class SemestreTag(pe_tagtable.TableTag): - nt: le tableau de notes du semestre considéré - nt.inscrlist: étudiants inscrits à ce semestre, par ordre alphabétique (avec demissions) - nt.identdict: { etudid : ident } - - nt._modimpls : liste des moduleimpl { ... 'module_id', ...} + - liste des moduleimpl { ... 'module_id', ...} Attributs supplémentaires : - inscrlist/identdict: étudiants inscrits hors démissionnaires ou défaillants @@ -100,7 +101,11 @@ class SemestreTag(pe_tagtable.TableTag): self.nt = notetable # Les attributs hérités : la liste des étudiants - self.inscrlist = [etud for etud in self.nt.inscrlist if etud["etat"] == "I"] + self.inscrlist = [ + etud + for etud in self.nt.inscrlist + if self.nt.get_etud_etat(etud["etudid"]) == "I" + ] self.identdict = { etudid: ident for (etudid, ident) in self.nt.identdict.items() @@ -110,12 +115,15 @@ class SemestreTag(pe_tagtable.TableTag): # Les modules pris en compte dans le calcul des moyennes par tag => ceux des UE standards self.modimpls = [ modimpl - for modimpl in self.nt._modimpls - if modimpl["ue"]["type"] == sco_codes_parcours.UE_STANDARD + for modimpl in self.nt.formsemestre.modimpls_sorted + if modimpl.module.ue.type == sco_codes_parcours.UE_STANDARD ] # la liste des modules (objet modimpl) - # self._modimpl_ids = [modimpl['moduleimpl_id'] for modimpl in self._modimpls] # la liste de id des modules (modimpl_id) self.somme_coeffs = sum( - [modimpl["module"]["coefficient"] for modimpl in self.modimpls] + [ + modimpl.module.coefficient + for modimpl in self.modimpls + if modimpl.module.coefficient is not None + ] ) # ----------------------------------------------------------------------------- @@ -159,9 +167,9 @@ class SemestreTag(pe_tagtable.TableTag): tagdict = {} for modimpl in self.modimpls: - modimpl_id = modimpl["moduleimpl_id"] + modimpl_id = modimpl.id # liste des tags pour le modimpl concerné: - tags = sco_tag_module.module_tag_list(modimpl["module_id"]) + tags = sco_tag_module.module_tag_list(modimpl.module.id) for ( tag @@ -175,17 +183,13 @@ class SemestreTag(pe_tagtable.TableTag): # Ajout du modimpl au tagname considéré tagdict[tagname][modimpl_id] = { - "module_id": modimpl["module_id"], # les données sur le module - "coeff": modimpl["module"][ - "coefficient" - ], # le coeff du module dans le semestre + "module_id": modimpl.module.id, # les données sur le module + "coeff": modimpl.module.coefficient, # le coeff du module dans le semestre "ponderation": ponderation, # la pondération demandée pour le tag sur le module - "module_code": modimpl["module"][ - "code" - ], # le code qui doit se retrouver à l'identique dans des ue capitalisee - "ue_id": modimpl["ue"]["ue_id"], # les données sur l'ue - "ue_code": modimpl["ue"]["ue_code"], - "ue_acronyme": modimpl["ue"]["acronyme"], + "module_code": modimpl.module.code, # le code qui doit se retrouver à l'identique dans des ue capitalisee + "ue_id": modimpl.module.ue.id, # les données sur l'ue + "ue_code": modimpl.module.ue.ue_code, + "ue_acronyme": modimpl.module.ue.acronyme, } return tagdict @@ -221,7 +225,9 @@ class SemestreTag(pe_tagtable.TableTag): def get_moyennes_DUT(self): """Lit les moyennes DUT du semestre pour tous les étudiants et les renvoie au même format que comp_MoyennesTag""" - return [(self.nt.moy_gen[etudid], 1.0, etudid) for etudid in self.get_etudids()] + return [ + (self.nt.etud_moy_gen[etudid], 1.0, etudid) for etudid in self.get_etudids() + ] # ----------------------------------------------------------------------------- def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2): @@ -233,7 +239,7 @@ class SemestreTag(pe_tagtable.TableTag): """ (note, coeff_norm) = (None, None) - modimpl = get_moduleimpl(self.nt, modimpl_id) # Le module considéré + modimpl = get_moduleimpl(modimpl_id) # Le module considéré if modimpl == None or profondeur < 0: return (None, None) @@ -241,14 +247,14 @@ class SemestreTag(pe_tagtable.TableTag): ue_capitalisees = self.get_ue_capitalisees( etudid ) # les ue capitalisées des étudiants - ue_capitalisees_id = [ - ue.id for ue in ue_capitalisees - ] # les id des ue capitalisées + ue_capitalisees_id = { + ue_cap["ue_id"] for ue_cap in ue_capitalisees + } # les id des ue capitalisées # Si le module ne fait pas partie des UE capitalisées - if modimpl["module"]["ue_id"] not in ue_capitalisees_id: + if modimpl.module.ue.id not in ue_capitalisees_id: note = self.nt.get_etud_mod_moy(modimpl_id, etudid) # lecture de la note - coeff = modimpl["module"]["coefficient"] # le coeff + coeff = modimpl.module.coefficient # le coeff coeff_norm = ( coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0 ) # le coeff normalisé @@ -259,12 +265,10 @@ class SemestreTag(pe_tagtable.TableTag): self.nt, etudid, modimpl_id ) # la moyenne actuelle # A quel semestre correspond l'ue capitalisée et quelles sont ses notes ? - # fid_prec = [ ue['formsemestre_id'] for ue in ue_capitalisees if ue['ue_id'] == modimpl['module']['ue_id'] ][0] - # semestre_id = modimpl['module']['semestre_id'] fids_prec = [ - ue["formsemestre_id"] - for ue in ue_capitalisees - if ue.ue_code == modimpl["ue"]["ue_code"] + ue_cap["formsemestre_id"] + for ue_cap in ue_capitalisees + if ue_cap["ue_code"] == modimpl.module.ue.ue_code ] # and ue['semestre_id'] == semestre_id] if len(fids_prec) > 0: # => le formsemestre_id du semestre dont vient la capitalisation @@ -277,13 +281,14 @@ class SemestreTag(pe_tagtable.TableTag): ) # Y-a-t-il un module équivalent c'est à dire correspondant au même code (le module_id n'étant pas significatif en cas de changement de PPN) + modimpl_prec = [ - module - for module in nt_prec._modimpls - if module["module"]["code"] == modimpl["module"]["code"] + modi + for modi in nt_prec.formsemestre.modimpls_sorted + if modi.module.code == modimpl.module.code ] if len(modimpl_prec) > 0: # si une correspondance est trouvée - modprec_id = modimpl_prec[0]["moduleimpl_id"] + modprec_id = modimpl_prec[0].id moy_ue_capitalisee = get_moy_ue_from_nt(nt_prec, etudid, modprec_id) if ( moy_ue_capitalisee is None @@ -291,7 +296,7 @@ class SemestreTag(pe_tagtable.TableTag): note = self.nt.get_etud_mod_moy( modimpl_id, etudid ) # lecture de la note - coeff = modimpl["module"]["coefficient"] # le coeff + coeff = modimpl.module.coefficient # le coeff coeff_norm = ( coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0 ) # le coeff normalisé @@ -305,13 +310,11 @@ class SemestreTag(pe_tagtable.TableTag): return (note, coeff_norm) # ----------------------------------------------------------------------------- - def get_ue_capitalisees(self, etudid) -> list[UniteEns]: - """Renvoie la liste des ue_id effectivement capitalisées par un étudiant""" - ue_ids = [ - ue_id - for ue_id in self.nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"] - ] - return [UniteEns.query.get(ue_id) for ue_id in ue_ids] + def get_ue_capitalisees(self, etudid) -> list[dict]: + """Renvoie la liste des capitalisation effectivement capitalisées par un étudiant""" + if etudid in self.nt.validations.ue_capitalisees.index: + return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records") + return [] # ----------------------------------------------------------------------------- def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid): @@ -477,37 +480,27 @@ def comp_coeff_pond(coeffs, ponderations): # ----------------------------------------------------------------------------- -def get_moduleimpl(nt, modimpl_id): - """Renvoie l'objet modimpl dont l'id est modimpl_id fourni dans la note table nt, - en utilisant l'attribut nt._modimpls""" - modimplids = [ - modimpl["moduleimpl_id"] for modimpl in nt._modimpls - ] # la liste de id des modules (modimpl_id) - if modimpl_id not in modimplids: - if SemestreTag.DEBUG: - log( - "SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas" - % (modimpl_id) - ) - return None - return nt._modimpls[modimplids.index(modimpl_id)] +def get_moduleimpl(modimpl_id) -> dict: + """Renvoie l'objet modimpl dont l'id est modimpl_id""" + modimpl = ModuleImpl.query.get(modimpl_id) + if modimpl: + return modimpl + if SemestreTag.DEBUG: + log( + "SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas" + % (modimpl_id) + ) + return None # ********************************************** -def get_moy_ue_from_nt(nt, etudid, modimpl_id): - """Renvoie la moyenne de l'UE d'un etudid dans laquelle se trouve le module de modimpl_id - en partant du note table nt""" - mod = get_moduleimpl(nt, modimpl_id) # le module - indice = 0 - while indice < len(nt._ues): - if ( - nt._ues[indice]["ue_id"] == mod["module"]["ue_id"] - ): # si les ue_id correspond - data = [ - ligne for ligne in nt.T if ligne[-1] == etudid - ] # les notes de l'étudiant - if data: - return data[0][indice + 1] # la moyenne à l'ue - else: - indice += 1 - return None # si non trouvé +def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float: + """Renvoie la moyenne de l'UE d'un etudid dans laquelle se trouve + le module de modimpl_id + """ + # ré-écrit + modimpl = get_moduleimpl(modimpl_id) # le module + ue_status = nt.get_etud_ue_status(etudid, modimpl.module.ue.id) + if ue_status is None: + return None + return ue_status["moy"] diff --git a/app/pe/pe_tagtable.py b/app/pe/pe_tagtable.py index 54e5e3955c..0e5045cbaa 100644 --- a/app/pe/pe_tagtable.py +++ b/app/pe/pe_tagtable.py @@ -68,7 +68,7 @@ class TableTag(object): self.taglist = [] self.resultats = {} - self.etud_moy_gen_ranks = {} + self.rangs = {} self.statistiques = {} # *****************************************************************************************************************