From 828c619c74395f1a29a570f02524b2a9e6126d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9o=20BARAS=20=28IUT1=20Grenoble=29?= Date: Sat, 17 Feb 2024 02:35:43 +0100 Subject: [PATCH] =?UTF-8?q?Am=C3=A9liorations=20diverses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/pe/pe_etudiant.py | 72 +++++++----- app/pe/pe_jury.py | 114 ++++++++----------- app/pe/pe_rcs.py | 102 +++++++++-------- app/pe/pe_rcstag.py | 42 +++---- app/pe/pe_ressemtag.py | 64 +++-------- app/pe/{pe_semtag.py => pe_sxtag.py} | 164 +++++++++++---------------- app/pe/pe_tabletags.py | 8 +- 7 files changed, 259 insertions(+), 307 deletions(-) rename app/pe/{pe_semtag.py => pe_sxtag.py} (58%) diff --git a/app/pe/pe_etudiant.py b/app/pe/pe_etudiant.py index 7448bf04..9851e313 100644 --- a/app/pe/pe_etudiant.py +++ b/app/pe/pe_etudiant.py @@ -5,7 +5,7 @@ # # Gestion scolarite IUT # -# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved. +# Copyright (c) 1999 - 2024 Emmanuel Viennet. c All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -59,7 +59,7 @@ class EtudiantsJuryPE: self.identites: dict[int, Identite] = {} # ex. ETUDINFO_DICT "Les identités des étudiants traités pour le jury" - self.cursus: dict[int, dict] = {} + self.trajectoires: dict[int, dict] = {} "Les cursus (semestres suivis, abandons) des étudiants" self.trajectoires = {} @@ -164,7 +164,7 @@ class EtudiantsJuryPE: """ etudids = [ etudid - for etudid, cursus_etud in self.cursus.items() + for etudid, cursus_etud in self.trajectoires.items() if cursus_etud["diplome"] == self.annee_diplome and cursus_etud["abandon"] is False ] @@ -181,7 +181,7 @@ class EtudiantsJuryPE: """ etudids = [ etudid - for etudid, cursus_etud in self.cursus.items() + for etudid, cursus_etud in self.trajectoires.items() if cursus_etud["diplome"] != self.annee_diplome or cursus_etud["abandon"] is True ] @@ -225,7 +225,7 @@ class EtudiantsJuryPE: if formsemestre.formation.is_apc() } - self.cursus[etudid] = { + self.trajectoires[etudid] = { "etudid": etudid, # les infos sur l'étudiant "etat_civil": identite.etat_civil, # Ajout à la table jury "nom": identite.nom, @@ -241,32 +241,36 @@ class EtudiantsJuryPE: } # Si l'étudiant est succeptible d'être diplomé - if self.cursus[etudid]["diplome"] == self.annee_diplome: + if self.trajectoires[etudid]["diplome"] == self.annee_diplome: # Est-il démissionnaire : charge son dernier semestre pour connaitre son état ? dernier_semes_etudiant = formsemestres[0] res = load_formsemestre_results(dernier_semes_etudiant) etud_etat = res.get_etud_etat(etudid) if etud_etat == scu.DEMISSION: - self.cursus[etudid]["abandon"] = True + self.trajectoires[etudid]["abandon"] = True else: # Est-il réorienté ou a-t-il arrêté (volontairement) sa formation ? - self.cursus[etudid]["abandon"] = arret_de_formation( + self.trajectoires[etudid]["abandon"] = arret_de_formation( identite, cosemestres ) def get_semestres_significatifs(self, etudid: int): - """Ensemble des semestres d'un étudiant, qui l'auraient amené à être diplomé - l'année visée (supprime les semestres qui conduisent à une diplomation - postérieure à celle du jury visé) + """Ensemble des semestres d'un étudiant, qui : + + * l'amènent à être diplômé à l'année visée + * l'auraient amené à être diplômé à l'année visée s'il n'avait pas redoublé et sera donc + diplômé plus tard + + Supprime les semestres qui conduisent à une diplomation postérieure à celle du jury visé. Args: etudid: L'identifiant d'un étudiant Returns: - Un dictionnaire ``{fid: FormSemestre(fid)`` dans lequel les semestres - amènent à une diplomation avant l'annee de diplomation du jury + Un dictionnaire ``{fid: FormSemestre(fid)}`` dans lequel les semestres + amènent à une diplômation antérieur à celle de la diplômation visée par le jury jury """ - semestres_etudiant = self.cursus[etudid]["formsemestres"] + semestres_etudiant = self.trajectoires[etudid]["formsemestres"] semestres_significatifs = {} for fid in semestres_etudiant: semestre = semestres_etudiant[fid] @@ -281,7 +285,7 @@ class EtudiantsJuryPE: Cette structuration s'appuie sur les numéros de semestre: pour chaque Si, stocke : le dernier semestre (en date) de numéro i qu'il a suivi (1 ou 0 si pas encore suivi). - Ce semestre influera les interclassement par semestre dans la promo. + Ce semestre influera les interclassements par semestre dans la promo. """ semestres_significatifs = self.get_semestres_significatifs(etudid) @@ -293,14 +297,14 @@ class EtudiantsJuryPE: for fid, sem_sig in semestres_significatifs.items() if sem_sig.semestre_id == i } - self.cursus[etudid][f"S{i}"] = semestres_i + self.trajectoires[etudid][f"S{i}"] = semestres_i - def get_formsemestres_terminaux_aggregat( - self, aggregat: str + def get_formsemestres_finals_des_rcs( + self, nom_rcs: str ) -> dict[int, FormSemestre]: - """Pour un aggrégat donné, ensemble des formsemestres terminaux possibles pour l'aggrégat - (pour l'aggrégat '3S' incluant S1+S2+S3, a pour semestre terminal S3). - Ces formsemestres traduisent : + """Pour un nom de RCS donné, ensemble des formsemestres finals possibles + pour les RCS. Par ex. un RCS '3S' incluant S1+S2+S3 a pour semestre final un S3. + Les formsemestres finals obtenus traduisent : * les différents parcours des étudiants liés par exemple au choix de modalité (par ex: S1 FI + S2 FI + S3 FI ou S1 FI + S2 FI + S3 UFA), en renvoyant les @@ -311,14 +315,14 @@ class EtudiantsJuryPE: renvoyant les formsemestre_id du S3 (1ère session) et du S3 (2ème session) Args: - aggregat: L'aggrégat + nom_rcs: Le nom du RCS (parmi Sx, xA, xS) Returns: Un dictionnaire ``{fid: FormSemestre(fid)}`` """ formsemestres_terminaux = {} for trajectoire_aggr in self.trajectoires.values(): - trajectoire = trajectoire_aggr[aggregat] + trajectoire = trajectoire_aggr[nom_rcs] if trajectoire: # Le semestre terminal de l'étudiant de l'aggrégat fid = trajectoire.formsemestre_final.formsemestre_id @@ -334,7 +338,7 @@ class EtudiantsJuryPE: """ nbres_semestres = [] for etudid in etudids: - nbres_semestres.append(self.cursus[etudid]["nb_semestres"]) + nbres_semestres.append(self.trajectoires[etudid]["nb_semestres"]) if not nbres_semestres: return 0 return max(nbres_semestres) @@ -355,7 +359,7 @@ class EtudiantsJuryPE: for etudid in etudids: etudiant = self.identites[etudid] - cursus = self.cursus[etudid] + cursus = self.trajectoires[etudid] formsemestres = cursus["formsemestres"] if cursus["diplome"]: @@ -442,7 +446,7 @@ def get_annee_diplome(etud: Identite) -> int | None: def get_semestres_apc(identite: Identite) -> list: - """Liste des semestres d'un étudiant qui corresponde à une formation APC. + """Liste des semestres d'un étudiant qui correspondent à une formation APC. Args: identite: L'identité d'un étudiant @@ -675,3 +679,19 @@ def nom_semestre_etape(semestre: FormSemestre, avec_fid=False) -> str: description.append(f"({semestre.formsemestre_id})") return " ".join(description) + + +def convert_trajectoire_to_sxtag_id(trajectoire: dict[int:FormSemestre]) -> (int, int): + """Partant d'une trajectoire (dictionnaire de la forme {fid: FormSemestre}), + renvoie l'identifiant (rang_sem, fid du semestre_terminal) associé""" + if not trajectoire: + return None + rangs = [formsemestre.semestre_id for formsemestre in trajectoire.values()] + assert rangs == min(rangs), "Les trajectoires doivent être de même rang" + rang = min(rangs) + fid_terminal = list(trajectoire.values())[0].formsemestre_id + for fid, formsemestre in trajectoire.items(): + if trajectoire[fid_terminal].date_fin <= formsemestre.date_fin: + fid_terminal = fid + return (rang, fid_terminal) + diff --git a/app/pe/pe_jury.py b/app/pe/pe_jury.py index 70d97237..e63cd227 100644 --- a/app/pe/pe_jury.py +++ b/app/pe/pe_jury.py @@ -50,13 +50,13 @@ from zipfile import ZipFile import numpy as np import pandas as pd -from app.pe import pe_semtag +from app.pe import pe_sxtag from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE import app.pe.pe_affichage as pe_affichage from app.pe.pe_etudiant import * # TODO A éviter -> pe_etudiant. import app.pe.pe_rcs as pe_rcs from app.pe.pe_rcstag import RCSTag -from app.pe.pe_ressemtag import ResSemTag +from app.pe.pe_ressemtag import ResSemBUTTag from app.pe.pe_interclasstag import RCSInterclasseTag @@ -97,10 +97,10 @@ class JuryPE(object): pe_affichage.pe_print("*** Aucun étudiant diplômé") else: self._gen_xls_diplomes(zipfile) - self._gen_rcss() - self._gen_xls_resultats_semestres_taggues(zipfile) - self._gen_xls_semestres_taggues(zipfile) - # self._gen_xls_rcss_tags(zipfile) + + self._gen_xls_ressembuttags(zipfile) + self._gen_xls_sxtags(zipfile) + self._gen_xls_rcss_tags(zipfile) # self._gen_xls_interclassements_rcss(zipfile) # self._gen_xls_synthese_jury_par_tag(zipfile) # self._gen_xls_synthese_par_etudiant(zipfile) @@ -134,17 +134,26 @@ class JuryPE(object): path="details", ) - def _gen_xls_resultats_semestres_taggues(self, zipfile: ZipFile): - """Génère les semestres taggués (avec le calcul des moyennes) pour le jury PE""" - pe_affichage.pe_print("*** Génère les résultats des semestres taggués") - self.res_sems_tags = compute_resultats_semestres_tag(self.etudiants) + def _gen_xls_ressembuttags(self, zipfile: ZipFile): + """Calcule les moyennes par tag des résultats des Semestres BUT""" + pe_affichage.pe_print("*** Génère les ResSemBUTTag (résultats des semestres BUT taggués)") + + formsemestres = get_formsemestres_etudiants(self.etudiants) + pe_affichage.pe_print(f" --> {len(formsemestres)} résultats de semestres à considérer") + + ressembuttags = {} + for frmsem_id, formsemestre in formsemestres.items(): + # Crée le semestre_tag et exécute les calculs de moyennes + ressembuttags[frmsem_id] = ResSemBUTTag(formsemestre) + + return ressembuttags # Intègre le bilan des semestres taggués au zip final output = io.BytesIO() with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated output, engine="openpyxl" ) as writer: - for res_sem_tag in self.res_sems_tags.values(): + for res_sem_tag in self.ressembuttags.values(): onglet = res_sem_tag.get_repr(verbose=False) df = res_sem_tag.df_moyennes_et_classements() # écriture dans l'onglet @@ -153,14 +162,14 @@ class JuryPE(object): self.add_file_to_zip( zipfile, - f"resultats_semestres_taggues_{self.diplome}.xlsx", + f"ResSemBUTTags_{self.diplome}.xlsx", output.read(), path="details", ) def _gen_rcss(self): """Génère les RCS (attribut `rcss_jury`), combinaisons de semestres suivis par les étudiants au sens - d'un nom de RCS (par ex: '3S'). + d'un nom de RCS (par ex: 'S2' ou '3S'). """ pe_affichage.pe_print( "*** Génère les RCS (différentes combinaisons de semestres) des étudiants" @@ -168,24 +177,35 @@ class JuryPE(object): self.rcss_jury = pe_rcs.RCSsJuryPE(self.diplome) self.rcss_jury.cree_rcss(self.etudiants) - def _gen_xls_semestres_taggues(self, zipfile: ZipFile): + def _gen_xls_sxtags(self, zipfile: ZipFile): """Génère les semestres taggués en s'appuyant sur les RCS de type Sx (pour identifier les redoublements impactant les semestres taggués). """ # Génère les moyennes des RCS de type Sx - pe_affichage.pe_print("*** Calcule les moyennes de semestres = RCS de type Sx") + pe_affichage.pe_print("*** Calcule les moyennes des SxTag") - self.sems_tags = {} - for rcs_id, rcs in self.rcss_jury.rcss.items(): - if rcs.nom.startswith("S"): - self.sems_tags[rcs_id] = pe_semtag.SemTag(rcs, self.res_sems_tags) + # Les regroupements de Sx + self.regroupements = {} + for rang in range(1, pe_comp.NBRE_SEMESTRES_DIPLOMANT+1): + self.regroupements[rang] = {} + for etudid in self.etudiants.etudiants_ids: + trajectoire = self.etudiants.cursus[etudid][f"S{rang}"] + self.regroupements[rang] |= trajectoire + + # Les SxTag + self.sxtags = {} + for rang in range(1, pe_comp.NBRE_SEMESTRES_DIPLOMANT+1): + trajectoire = self.regroupements[rang] + sxtag_id = pe_sxtag.get_sxtag_from_semestres(trajectoire) + ressemstags = {fid: self.ressembuttags[fid] for fid in trajectoire} + self.sxtags[sxtag_id] = pe_sxtag.SxTag(sxtag_id, ressemtags) # Intègre le bilan des semestres taggués au zip final output = io.BytesIO() with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated output, engine="openpyxl" ) as writer: - for sem_tag in self.sems_tags.values(): + for sem_tag in self.sxtags.values(): onglet = sem_tag.get_repr(verbose=False) df = sem_tag.df_moyennes_et_classements() # écriture dans l'onglet @@ -200,11 +220,11 @@ class JuryPE(object): ) def _gen_xls_rcss_tags(self, zipfile: ZipFile): - """Génère les RCS tagguées des RCS, en calculant les moyennes et les classements par tag - pour chacune. + """Génère les RCS taggués (autres que ceux de type Sx), etc... + en calculant les moyennes et les classements par tag pour chaque RCS. Stocke le résultat dans self.rccs_tag, un dictionnaire de - la forme ``{nom_aggregat: {fid_terminal: SetTag(fid_terminal)} }`` + la forme ``{nom_aggregat: {fid_terminal: RCSTag(fid_terminal)} }`` Pour rappel : Chaque RCS est identifié par un nom d'aggrégat et par un formsemestre terminal. @@ -213,19 +233,13 @@ class JuryPE(object): * combinaisons '3S' : S1+S2+S3 en prenant en compte tous les S3 qu'ont fréquenté les étudiants du jury PE. Ces S3 marquent les formsemestre terminal de chaque combinaison. - * combinaisons 'S2' : 1 seul S2 pour des étudiants n'ayant pas redoublé, 2 pour des redoublants (dont les - notes seront moyennées sur leur 2 semestres S2). Ces combinaisons ont pour formsemestre le dernier S2 en - date (le S2 redoublé par les redoublants est forcément antérieur) - Args: etudiants: Les données des étudiants semestres_tag: Les semestres tag (pour lesquels des moyennes par tag ont été calculés) - - """ # Génère les moyennes des RCS de type Sx - pe_affichage.pe_print("*** Calcule les moyennes des RCS de type Sx") + pe_affichage.pe_print("*** Calcule les moyennes des RCS") self.rcss_tags = {} for rcs_id, rcs in self.rcss_jury.rcss.items(): @@ -409,7 +423,7 @@ class JuryPE(object): for etudid in etudids: trajectoire = self.rcss_jury.suivi[etudid][aggregat] if trajectoire: - tid = trajectoire.rcs_id + tid = trajectoire.sxtag_id trajectoire_tagguee = self.rcss_tags[tid] if ( tag in trajectoire_tagguee.moyennes_tags @@ -555,7 +569,7 @@ class JuryPE(object): # La trajectoire de l'étudiant sur l'aggrégat trajectoire = self.rcss_jury.suivi[etudid][aggregat] if trajectoire: - trajectoire_tagguee = self.rcss_tags[trajectoire.rcs_id] + trajectoire_tagguee = self.rcss_tags[trajectoire.sxtag_id] if tag in trajectoire_tagguee.moyennes_tags: # L'interclassement interclass = self.interclassements_taggues[aggregat] @@ -581,9 +595,8 @@ class JuryPE(object): def get_formsemestres_etudiants(etudiants: EtudiantsJuryPE) -> dict: """Ayant connaissance des étudiants dont il faut calculer les moyennes pour - le jury PE (attribut `self.etudiant_ids) et de leur cursus (semestres - parcourus), - renvoie un dictionnaire ``{fid: FormSemestre(fid)}`` + le jury PE (attribut `self.etudiant_ids) et de leurs trajectoires (semestres + parcourus), renvoie un dictionnaire ``{fid: FormSemestre(fid)}`` contenant l'ensemble des formsemestres de leurs cursus, dont il faudra calculer la moyenne. @@ -592,44 +605,17 @@ def get_formsemestres_etudiants(etudiants: EtudiantsJuryPE) -> dict: Returns: Un dictionnaire de la forme `{fid: FormSemestre(fid)}` - """ semestres = {} for etudid in etudiants.etudiants_ids: - for cle in etudiants.cursus[etudid]: + for cle in etudiants.trajectoires[etudid]: if cle.startswith("S"): - semestres = semestres | etudiants.cursus[etudid][cle] + semestres = semestres | etudiants.trajectoires[etudid][cle] return semestres -def compute_resultats_semestres_tag(etudiants: EtudiantsJuryPE) -> dict: - """Créé les semestres taggués, de type 'S1', 'S2', ..., pour un groupe d'étudiants donnés. - Chaque semestre taggué est rattaché à l'un des FormSemestre faisant partie du cursus scolaire - des étudiants (cf. attribut etudiants.cursus). - En crééant le semestre taggué, sont calculées les moyennes/classements par tag associé. - . - Args: - etudiants: Un groupe d'étudiants participant au jury - Returns: - Un dictionnaire {fid: SemestreTag(fid)} - """ - - # Création des semestres taggués, de type 'S1', 'S2', ... - pe_affichage.pe_print("*** Création des semestres taggués") - - formsemestres = get_formsemestres_etudiants(etudiants) - - semestres_tags = {} - for frmsem_id, formsemestre in formsemestres.items(): - # Crée le semestre_tag et exécute les calculs de moyennes - formsemestretag = ResSemTag(frmsem_id) - - # Stocke le semestre taggué - semestres_tags[frmsem_id] = formsemestretag - - return semestres_tags def compute_interclassements( diff --git a/app/pe/pe_rcs.py b/app/pe/pe_rcs.py index ecd5d764..136109e4 100644 --- a/app/pe/pe_rcs.py +++ b/app/pe/pe_rcs.py @@ -12,9 +12,9 @@ Created on 01-2024 import app.pe.pe_comp as pe_comp from app.models import FormSemestre +from app.pe import pe_sxtag from app.pe.pe_etudiant import EtudiantsJuryPE, get_dernier_semestre_en_date - TYPES_RCS = { "S1": { "aggregat": ["S1"], @@ -81,11 +81,11 @@ TOUS_LES_SEMESTRES = [cle for cle in TYPES_RCS if cle.startswith("S")] class RCS: - """Modélise un ensemble de semestres d'étudiants + """Modélise un ensemble de semestres finals d'étudiants associé à un type de regroupement cohérent de semestres donné (par ex: 'S2', '3S', '2A'). - Si le RCS est un semestre de type Si, stocke le (ou les) + Si le RCS est un semestre de type Si, stocke le formsemestres de numéro i qu'ont suivi l'étudiant pour atteindre le Si (en général 1 si personnes n'a redoublé, mais 2 s'il y a des redoublants) @@ -104,38 +104,40 @@ class RCS: """ def __init__(self, nom_rcs: str, semestre_final: FormSemestre): - self.nom = nom_rcs + self.nom: str = nom_rcs """Nom du RCS""" - self.formsemestre_final = semestre_final + self.formsemestre_final: FormSemestre = semestre_final """FormSemestre terminal du RCS""" - self.rcs_id = (nom_rcs, semestre_final.formsemestre_id) + self.rcs_id: (str, int) = (nom_rcs, semestre_final.formsemestre_id) """Identifiant du RCS sous forme (nom_rcs, id du semestre_terminal)""" - self.semestres_aggreges = {} - """Semestres regroupés dans le RCS""" + # self.semestres_aggreges: dict[int:FormSemestre] = {} + # """Semestres regroupés dans le RCS""" + + self.sxtags_aggreges: dict[(str, int): pe_sxtag.SxTag] = {} + """Les SxTag aggrégés""" def get_formsemestre_id_final(self): """Renvoie l'identifiant du formsemestre final du RCS""" return self.formsemestre_final.formsemestre_id - def add_semestres_a_aggreger(self, semestres: dict[int:FormSemestre]): - """Ajout de semestres aux semestres à regrouper + def add_sxtags_a_aggreger(self, sxtags: dict[(str,int): pe_sxtag.SxTag]): + """Ajout des SxTag aux semestres à regrouper Args: - semestres: Dictionnaire ``{fid: FormSemestre(fid)}`` à ajouter + sxtags: Dictionnaire ``{(str,fid): SxTag}`` à ajouter """ - self.semestres_aggreges = self.semestres_aggreges | semestres + self.sxtags_aggreges = self.sxtags_aggreges | sxtags def get_repr(self, verbose=True) -> str: """Représentation textuelle d'un RCS - basé sur ses semestres aggrégés""" + basé sur ses sxtags aggrégés""" noms = [] - for fid in self.semestres_aggreges: - semestre = self.semestres_aggreges[fid] - noms.append(f"S{semestre.semestre_id}({fid})") + for sxtag_id, sxtag in self.sxtags_aggreges.items(): + noms.append(f"S{sxtag.semestre_id}") noms = sorted(noms) title = f"""{self.nom} ({ self.formsemestre_final.formsemestre_id}) {self.formsemestre_final.date_fin.year}""" @@ -145,7 +147,7 @@ class RCS: class RCSsJuryPE: - """Classe centralisant toutes les regroupements cohérents de + """Classe centralisant tous les regroupements cohérents de semestres (RCS) des étudiants à prendre en compte dans un jury PE Args: @@ -163,21 +165,24 @@ class RCSsJuryPE: """Dictionnaire associant, pour chaque étudiant et pour chaque type de RCS, son RCS : {etudid: {nom_RCS: RCS}}""" - def cree_rcss(self, etudiants: EtudiantsJuryPE): + def cree_rcss(self, etudiants: EtudiantsJuryPE, sxtags: dict[(str, int), pe_sxtag.SxTag]): """Créé tous les RCS, au regard du cursus des étudiants - analysés + les mémorise dans les données de l'étudiant + analysés et des SxTag calculés. + + Les mémorise dans les données de chaque étudiant. Args: etudiants: Les étudiants à prendre en compte dans le Jury PE + pe_sxtag: Les Sx taggués """ for nom_rcs in pe_comp.TOUS_LES_SEMESTRES + TOUS_LES_RCS_AVEC_PLUSIEURS_SEM: # L'aggrégat considéré (par ex: 3S=S1+S2+S3), son nom de son semestre # terminal (par ex: S3) et son numéro (par ex: 3) - noms_semestre_de_aggregat = TYPES_RCS[nom_rcs]["aggregat"] - nom_semestre_terminal = noms_semestre_de_aggregat[-1] + noms_semestre_de_aggregat = TYPES_RCS[nom_rcs]["aggregat"] # ["S1", "S2", "S3"] + nom_semestre_terminal = noms_semestre_de_aggregat[-1] # "S3" - for etudid in etudiants.cursus: + for etudid in etudiants.trajectoires: if etudid not in self.suivi: self.suivi[etudid] = { aggregat: None @@ -188,54 +193,57 @@ class RCSsJuryPE: # Le formsemestre terminal (dernier en date) associé au # semestre marquant la fin de l'aggrégat # (par ex: son dernier S3 en date) - semestres = etudiants.cursus[etudid][nom_semestre_terminal] + semestres = etudiants.trajectoires[etudid][nom_semestre_terminal] if semestres: formsemestre_final = get_dernier_semestre_en_date(semestres) # Ajout ou récupération de la trajectoire - trajectoire_id = (nom_rcs, formsemestre_final.formsemestre_id) - if trajectoire_id not in self.rcss: - trajectoire = RCS(nom_rcs, formsemestre_final) - self.rcss[trajectoire_id] = trajectoire + rcs_id = (nom_rcs, formsemestre_final.formsemestre_id) + if rcs_id not in self.rcss: + rcs = RCS(nom_rcs, formsemestre_final) + self.rcss[rcs_id] = rcs else: - trajectoire = self.rcss[trajectoire_id] + rcs = self.rcss[rcs_id] # La liste des semestres de l'étudiant à prendre en compte # pour cette trajectoire - semestres_a_aggreger = get_rcs_etudiant( - etudiants.cursus[etudid], formsemestre_final, nom_rcs + semestres_a_aggreger = get_trajectoire_etudiant( + etudiants.trajectoires[etudid], formsemestre_final, nom_rcs ) + # Extrait les sxtags correspondants aux semestres à aggréger + # (par ex. des 2 semestres S1(18)+S1(26) récupère le sxtag S1(26) + sxtags_a_aggreger = {} + semestres_tries = pe_comp.tri_semestres_par_rang(semestres_a_aggreger) + for rang in semestres_tries: + sems = semestres_tries[rang] # les 1 ou 2 semestres de même rang suivi + sxtag_id = pe_sxtag.get_sxtag_from_semestres(sems, sxtags) + if not sxtag_id: + raise ValueError(f"Il manque un sxtag pour {sems}") + sxtags_a_aggreger[sxtag_id] = sxtags[sxtag_id] + # Ajout des semestres à la trajectoire - trajectoire.add_semestres_a_aggreger(semestres_a_aggreger) + rcs.add_sxtags_a_aggreger(sxtags_a_aggreger) # Mémoire la trajectoire suivie par l'étudiant - self.suivi[etudid][nom_rcs] = trajectoire + self.suivi[etudid][nom_rcs] = rcs -def get_rcs_etudiant( +def get_trajectoire_etudiant( semestres: dict[int:FormSemestre], formsemestre_final: FormSemestre, nom_rcs: str ) -> dict[int, FormSemestre]: - """Ensemble des semestres parcourus par un étudiant, connaissant - les semestres de son cursus, - dans le cadre du RCS visé et ayant pour semestre terminal `formsemestre_final`. + """Ensemble des semestres parcourus (trajectoire) + par un étudiant dans le cadre + d'un RCS de type Sx, iA ou iS et ayant pour semestre terminal `formsemestre_final`. - Si le RCS est de type "Si", limite les semestres à ceux de numéro i. - Par ex: si formsemestre_terminal est un S3 et nom_agrregat "S3", ne prend en compte que les - semestres 3. - - Si le RCS est de type "iA" ou "iS" (incluant plusieurs numéros de semestres), prend en - compte les dit numéros de semestres. - - Par ex: si formsemestre_terminal est un S3, ensemble des S1, - S2, S3 suivi pour l'amener au S3 (il peut y avoir plusieurs S1, - ou S2, ou S3 s'il a redoublé). + Par ex: pour un RCS "3S", dont le formsemestre_terminal est un S3, regroupe + le ou les S1 qu'il a suivi (1 ou 2 si redoublement) + le ou les S2 + le ou les S3. Les semestres parcourus sont antérieurs (en terme de date de fin) au formsemestre_terminal. Args: - cursus: Dictionnaire {fid: FormSemestre(fid)} donnant l'ensemble des semestres + cursus: Dictionnaire {fid: Formsemestre} donnant l'ensemble des semestres dans lesquels l'étudiant a été inscrit formsemestre_final: le semestre final visé nom_rcs: Nom du RCS visé diff --git a/app/pe/pe_rcstag.py b/app/pe/pe_rcstag.py index ef458589..5af9ee04 100644 --- a/app/pe/pe_rcstag.py +++ b/app/pe/pe_rcstag.py @@ -38,7 +38,7 @@ Created on Fri Sep 9 09:15:05 2016 from app.comp.res_sem import load_formsemestre_results from app.pe import pe_affichage -from app.pe.pe_ressemtag import ResSemTag +from app.pe.pe_ressemtag import ResSemBUTTag import pandas as pd import numpy as np from app.pe.pe_rcs import RCS @@ -48,26 +48,25 @@ from app.pe.pe_moytag import MoyennesTag class RCSTag(TableTag): + def __init__( - self, rcs: RCS, semestres_taggues: dict[int, ResSemTag] + self, rcs: RCS, semestres_taggues: dict[int, ResSemBUTTag] ): """Calcule les moyennes par tag d'une combinaison de semestres (RCS), pour extraire les classements par tag pour un groupe d'étudiants donnés. Le groupe d'étudiants est formé par ceux ayant tous participé au semestre terminal. - Args: rcs: Un RCS (identifié par un nom et l'id de son semestre terminal) semestres_taggues: Les données sur les semestres taggués """ TableTag.__init__(self) - - self.rcs_id = rcs.rcs_id + self.rcs_id: tuple(str, int) = rcs.rcs_id """Identifiant du RCS taggué (identique au RCS sur lequel il s'appuie)""" - self.rcs = rcs + self.rcs: RCS = rcs """RCS associé au RCS taggué""" self.nom = self.get_repr() @@ -82,20 +81,21 @@ class RCSTag(TableTag): self.semestres_aggreges = rcs.semestres_aggreges """Les semestres aggrégés""" - self.semestres_tags_aggreges = {} + self.res_sems_tags = {} """Les semestres tags associés aux semestres aggrégés""" - for frmsem_id in self.semestres_aggreges: - try: - self.semestres_tags_aggreges[frmsem_id] = semestres_taggues[frmsem_id] - except: - raise ValueError("Semestres taggués manquants") + try: + for frmsem_id in self.semestres_aggreges: + self.res_sems_tags[frmsem_id] = semestres_taggues[frmsem_id] + except: + raise ValueError("Semestres taggués manquants") - """Les étudiants (état civil + cursus connu)""" - self.etuds = nt.etuds + # Les étudiants (etuds, états civils & etudis) + self.add_etuds(nt.etuds) - # assert self.etuds == trajectoire.suivi # manque-t-il des étudiants ? - self.etats_civils = {etud.etudid: etud.nomprenom for etud in self.etuds} + # Les compétences (extraites des ues de tous les semestres) + self.ues = self.comp_ues(tag="but") + # Les tags self.tags_sorted = self.do_taglist() """Tags extraits de tous les semestres""" @@ -114,7 +114,7 @@ class RCSTag(TableTag): def __eq__(self, other): """Egalité de 2 RCS taggués sur la base de leur identifiant""" - return self.rcs_id == other.rcs_id + return self.rcs_id == other.sxtag_id def get_repr(self, verbose=False) -> str: """Renvoie une représentation textuelle (celle de la trajectoire sur laquelle elle @@ -132,7 +132,7 @@ class RCSTag(TableTag): # Index du cube (etudids -> dim 0, tags -> dim 1) etudids = [etud.etudid for etud in self.etuds] tags = self.tags_sorted - semestres_id = list(self.semestres_tags_aggreges.keys()) + semestres_id = list(self.res_sems_tags.keys()) dfs = {} @@ -141,7 +141,7 @@ class RCSTag(TableTag): df = pd.DataFrame(np.nan, index=etudids, columns=tags) # Charge les notes du semestre tag - notes = self.semestres_tags_aggreges[frmsem_id].notes + notes = self.res_sems_tags[frmsem_id].notes # Les étudiants & les tags commun au dataframe final et aux notes du semestre) etudids_communs = df.index.intersection(notes.index) @@ -172,8 +172,8 @@ class RCSTag(TableTag): Une liste de tags triés par ordre alphabétique """ tags = [] - for frmsem_id in self.semestres_tags_aggreges: - tags.extend(self.semestres_tags_aggreges[frmsem_id].tags_sorted) + for frmsem_id in self.res_sems_tags: + tags.extend(self.res_sems_tags[frmsem_id].tags_sorted) pe_affichage.pe_print(f"* Tags : {', '.join(tags)}") return sorted(set(tags)) diff --git a/app/pe/pe_ressemtag.py b/app/pe/pe_ressemtag.py index 5dff02ea..8274e02d 100644 --- a/app/pe/pe_ressemtag.py +++ b/app/pe/pe_ressemtag.py @@ -37,37 +37,38 @@ Created on Fri Sep 9 09:15:05 2016 """ import pandas as pd -import app.pe.pe_etudiant from app import db, ScoValueError from app import comp +from app.comp.res_but import ResultatsSemestreBUT from app.comp.res_sem import load_formsemestre_results from app.models import FormSemestre from app.models.moduleimpls import ModuleImpl import app.pe.pe_affichage as pe_affichage import app.pe.pe_etudiant as pe_etudiant -from app.pe.pe_tabletags import TableTag +import app.pe.pe_tabletags as pe_tabletags from app.pe.pe_moytag import MoyennesTag from app.scodoc import sco_tag_module from app.scodoc.codes_cursus import UE_SPORT -class ResSemTag(TableTag): +class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag): """ - Un ResSemTag représente les résultats des étudiants à un semestre, en donnant + Un ResSemBUTTag représente les résultats des étudiants à un semestre, en donnant accès aux moyennes par tag. Il s'appuie principalement sur FormSemestre et sur ResultatsSemestreBUT. """ - def __init__(self, formsemestre_id: int): + def __init__(self, formsemestre: FormSemestre): """ Args: - formsemestre_id: Identifiant du ``FormSemestre`` sur lequel il se base + formsemestre: le ``FormSemestre`` sur lequel il se base """ - TableTag.__init__(self) + ResultatsSemestreBUT.__init__(self, formsemestre) + pe_tabletags.TableTag.__init__(self) # Le semestre - self.formsemestre_id = formsemestre_id - self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id) + # self.formsemestre_id = self.formsemestre.formsemestre_id + # self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id) # Le nom du res_semestre taggué self.nom = self.get_repr(verbose=True) @@ -75,25 +76,14 @@ class ResSemTag(TableTag): pe_affichage.pe_print(f"--> Résultats de semestre taggués {self.nom}") # Les résultats du semestre - self.nt = load_formsemestre_results(self.formsemestre) + # self.nt = load_formsemestre_results(self.formsemestre) - # Les étudiants (etuds, états civils & etudis) - self.add_etuds(self.nt.etuds) - - # Les notes, les modules implémentés triés, les étudiants, les coeffs, - # récupérés notamment de py:mod:`res_but` - self.sem_cube = self.nt.sem_cube - self.modimpls_sorted = self.nt.formsemestre.modimpls_sorted - self.modimpl_coefs_df = self.nt.modimpl_coefs_df - - # Les inscriptions aux modules - self.modimpl_inscr_df = self.nt.modimpl_inscr_df + # Les étudiants (etuds, états civils & etudis) ajouté + self.add_etuds(self.etuds) # Les UEs (et les dispenses d'UE) - self.ues = self.nt.ues ues_hors_sport = [ue for ue in self.ues if ue.type != UE_SPORT] - self.ues_inscr_parcours_df = self.nt.load_ues_inscr_parcours() - self.dispense_ues = self.nt.dispense_ues + self.ues_inscr_parcours_df = self.load_ues_inscr_parcours() # Les tags personnalisés et auto: tags_dict = self._get_tags_dict() @@ -124,7 +114,7 @@ class ResSemTag(TableTag): # Ajoute les moyennes par UEs (et donc par compétence) + la moyenne générale (but) df_ues = pd.DataFrame( - {ue.id: self.nt.etud_moy_ue[ue.id] for ue in ues_hors_sport}, + {ue.id: self.etud_moy_ue[ue.id] for ue in ues_hors_sport}, index=self.etudids, ) # moy_ues = self.nt.etud_moy_ue[ue_id] @@ -150,7 +140,7 @@ class ResSemTag(TableTag): def get_repr(self, verbose=False): """Nom affiché pour le semestre taggué""" if verbose: - return f"{self.formsemestre} ({self.formsemestre_id})" + return f"{self.formsemestre} ({self.formsemestre.formsemestre_id})" else: return pe_etudiant.nom_semestre_etape(self.formsemestre, avec_fid=True) @@ -209,7 +199,7 @@ class ResSemTag(TableTag): dict_tags = {"personnalises": dict(), "auto": dict()} # Les tags perso dict_tags["personnalises"] = get_synthese_tags_personnalises_semestre( - self.nt.formsemestre + self.formsemestre ) noms_tags_perso = sorted(list(set(dict_tags["personnalises"].keys()))) pe_affichage.pe_print( @@ -256,26 +246,6 @@ class ResSemTag(TableTag): raise ScoValueError(message) -def get_moduleimpl(modimpl_id) -> dict: - """Renvoie l'objet modimpl dont l'id est modimpl_id""" - modimpl = db.session.get(ModuleImpl, modimpl_id) - if modimpl: - return modimpl - return None - - -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"] - - def get_synthese_tags_personnalises_semestre(formsemestre: FormSemestre): """Etant données les implémentations des modules du semestre (modimpls), synthétise les tags renseignés dans le programme pédagogique & diff --git a/app/pe/pe_semtag.py b/app/pe/pe_sxtag.py similarity index 58% rename from app/pe/pe_semtag.py rename to app/pe/pe_sxtag.py index d98cd084..1dd1960f 100644 --- a/app/pe/pe_semtag.py +++ b/app/pe/pe_sxtag.py @@ -37,87 +37,79 @@ Created on Fri Sep 9 09:15:05 2016 """ from app.comp.res_sem import load_formsemestre_results -from app.models import UniteEns +from app.models import UniteEns, FormSemestre from app.pe import pe_affichage -from app.pe.pe_ressemtag import ResSemTag +from app.pe.pe_ressemtag import ResSemBUTTag import pandas as pd import numpy as np -from app.pe.pe_rcs import RCS from app.pe.pe_tabletags import TableTag from app.pe.pe_moytag import MoyennesTag -class SemTag(TableTag): - def __init__(self, rcs: RCS, res_sems_tags: dict[int, ResSemTag]): - """Calcule les moyennes/classements par tag à un RCS d'un seul semestre - (ici semestre) de type 'Sx' (par ex. 'S1', 'S2', ...) : +class SxTag(TableTag): + def __init__(self, sxtag_id: (int, int), ressembuttags: dict[int, ResSemBUTTag]): + """Calcule les moyennes/classements par tag d'un semestre de type 'Sx' + (par ex. 'S1', 'S2', ...) : * pour les étudiants non redoublants, ce sont les moyennes/classements du semestre suivi * pour les étudiants redoublants, c'est une fusion des moyennes/classements - suivis les différents 'Sx' (donné par dans le rcs) + dans les (2) 'Sx' qu'il a suivi - Les **tags considérés** sont uniquement ceux du dernier semestre du RCS + Un SxTag peut donc regrouper plusieurs semestres. + + Un SxTag est identifié par un tuple (x, fid) où x est le numéro (semestre_id) + du semestre et fid le formsemestre_id du semestre final (le plus récent) du + regrouprement. + + Les **tags**, les **UE** et les inscriptions aux UEs (pour les etudiants) + considérés sont uniquement ceux du semestre final. Args: - rcs: Un RCS (identifié par un nom et l'id de son semestre terminal) - res_sems_tags: Les données sur les résultats des semestres taggués + sxtag_id: L'identifiant de SxTag + ressembuttags: Un dictionnaire de la forme `{fid: ResSemBUTTag(fid)}` donnant + les semestres à regrouper et les résultats/moyennes par tag des + semestres """ TableTag.__init__(self) - self.rcs_id = rcs.rcs_id - """Identifiant du RCS taggué (identique au RCS sur lequel il s'appuie)""" + assert sxtag_id and len(sxtag_id) == 2 and sxtag_id in ressembuttags - self.rcs = rcs - """RCS associé au RCS taggué""" + self.sxtag_id: (int, int) = sxtag_id + """Identifiant du SxTag de la forme (semestre_id, fid_semestre_final)""" - assert self.rcs.nom.startswith( - "S" - ), "Un SemTag ne peut être utilisé que pour un RCS de la forme Sx" - self.nom = self.get_repr() - """Représentation textuelle du RCS taggué""" + self.ressembuttags = ressembuttags + """Les ResSemBUTTags à regrouper dans le SxTag""" - # Les données du formsemestre_terminal - self.formsemestre_terminal = rcs.formsemestre_final - """Le formsemestre terminal""" - - # Les résultats du formsemestre terminal - nt = load_formsemestre_results(self.formsemestre_terminal) - - self.semestres_aggreges = rcs.semestres_aggreges - """Les semestres aggrégés""" - - self.res_sems_tags = {} - """Les résultats des semestres taggués (limités aux semestres aggrégés)""" - try: - for frmsem_id in self.semestres_aggreges: - self.res_sems_tags[frmsem_id] = res_sems_tags[frmsem_id] - except: - raise ValueError("Résultats des semestres taggués manquants") + # Les données du semestre final + self.fid_final = sxtag_id[1] + self.ressembuttag_final = ressembuttags[self.fid_final] + """Le ResSemBUTTag final""" # Les étudiants (etuds, états civils & etudis) - self.add_etuds(nt.etuds) + self.etuds = ressembuttags[self.fid_final].etuds + self.add_etuds(self.etuds) # Les tags - self.tags_sorted = self.comp_tags_list() - """Tags (extraits uniquement du semestre terminal de l'aggrégat)""" + self.tags_sorted = self.ressembuttag_final.tags_sorted + """Tags (extraits uniquement du semestre final)""" + pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}") - # Les UEs - self.ues = self.comp_ues(tag="but") + # Les UE + self.ues = self.ressembuttag_final.moyennes_tags["but"].ues + + # Les acronymes des UE self.acronymes_ues_sorted = sorted([ue.acronyme for ue in self.ues.values()]) - """UEs extraites du semestre terminal de l'aggrégat (avec - check de concordance sur les UE des semestres_aggrégés)""" - # Les inscriptions aux UEs - self.ues_inscr_parcours_df = self.comp_ues_inscr_parcours(tag="but") - """Les inscriptions aux UEs (extraites uniquement du semestre terminal)""" - - self.moyennes_tags: dict[str, MoyennesTag] = {} - """Moyennes/classements par tag (qu'ils soient personnalisés ou automatiques)""" + # Les inscriptions des étudiants aux UEs + # => ne conserve que les UEs du semestre final (pour les redoublants) + self.ues_inscr_parcours_df = self.ressembuttag_final.moyennes_tags["but"].ues_inscr_parcours_df + # Les moyennes par tag self.moyennes_tags: dict[str, pd.DataFrame] = {} """Les notes aux UEs dans différents tags""" + # Masque des inscriptions inscr_mask = self.ues_inscr_parcours_df.to_numpy() for tag in self.tags_sorted: @@ -132,19 +124,19 @@ class SemTag(TableTag): inscr_mask, ) # Les moyennes - self.moyennes_tags[tag] = MoyennesTag(tag, - self.ues, - moys_ues, - self.ues_inscr_parcours_df) + self.moyennes_tags[tag] = MoyennesTag( + tag, self.ues, moys_ues, self.ues_inscr_parcours_df + ) def __eq__(self, other): - """Egalité de 2 RCS taggués sur la base de leur identifiant""" - return self.rcs_id == other.rcs_id + """Egalité de 2 SxTag sur la base de leur identifiant""" + return self.sxtag_id == other.sxtag_id def get_repr(self, verbose=False) -> str: """Renvoie une représentation textuelle (celle de la trajectoire sur laquelle elle est basée)""" - return self.rcs.get_repr(verbose=verbose) + affichage = str(fid) for fid in self.res + return f"S{sxtag_id[0]}Tag ({'+'.join()})" def compute_notes_ues_cube(self, tag, acronymes_ues_sorted): """Construit le cube de notes des UEs (etudid x accronyme_ue x semestre_aggregé) @@ -153,7 +145,7 @@ class SemTag(TableTag): # Index du cube (etudids -> dim 0, ues -> dim 1, semestres -> dim2) etudids = [etud.etudid for etud in self.etuds] # acronymes_ues = sorted([ue.acronyme for ue in self.ues.values()]) - semestres_id = list(self.res_sems_tags.keys()) + semestres_id = list(self.ressembuttags.keys()) dfs = {} @@ -162,7 +154,7 @@ class SemTag(TableTag): df = pd.DataFrame(np.nan, index=etudids, columns=acronymes_ues_sorted) # Charge les notes du semestre tag - sem_tag = self.res_sems_tags[frmsem_id] + sem_tag = self.ressembuttags[frmsem_id] moys_tag = sem_tag.moyennes_tags[tag] notes = moys_tag.notes_ues # dataframe etudids x ues acronymes_ues_sem = list( @@ -192,43 +184,6 @@ class SemTag(TableTag): etudids_x_ues_x_semestres = np.stack(semestres_x_etudids_x_ues, axis=-1) return etudids_x_ues_x_semestres - def comp_tags_list(self) -> list[str]: - """Récupère les tag du semestre taggué associé au semestre final du RCS - - Returns: - Une liste de tags triés par ordre alphabétique - """ - tags = [] - dernier_frmid = self.formsemestre_terminal.formsemestre_id - dernier_semestre_tag = self.res_sems_tags[dernier_frmid] - tags = dernier_semestre_tag.tags_sorted - pe_affichage.pe_print(f"* Tags : {', '.join(tags)}") - return tags - - def comp_ues(self, tag="but") -> dict[int, UniteEns]: - """Récupère les UEs à aggréger, en s'appuyant sur la moyenne générale - (tag but) du semestre final du RCS - - Returns: - Un dictionnaire donnant les UEs - """ - dernier_frmid = self.formsemestre_terminal.formsemestre_id - dernier_semestre_tag = self.res_sems_tags[dernier_frmid] - moy_tag = dernier_semestre_tag.moyennes_tags[tag] - return moy_tag.ues # les UEs - - def comp_ues_inscr_parcours(self, tag="but") -> pd.DataFrame: - """Récupère les informations d'inscription des étudiants aux UEs : ne - conserve que les UEs du semestre terminal (pour les redoublants) - - Returns: - Un dataFrame etudids x UE indiquant si un étudiant est inscrit à une UE - """ - dernier_frmid = self.formsemestre_terminal.formsemestre_id - dernier_semestre_tag = self.res_sems_tags[dernier_frmid] - moy_tag = dernier_semestre_tag.moyennes_tags[tag] - return moy_tag.ues_inscr_parcours_df - def compute_notes_ues( set_cube: np.array, @@ -261,8 +216,8 @@ def compute_notes_ues( mask = ~np.isnan(set_cube) # Entrées à garder dans le cube en fonction du mask d'inscription - inscr_mask_3D = np.stack([inscr_mask]*nb_semestres, axis=-1) - set_cube = set_cube*inscr_mask_3D + inscr_mask_3D = np.stack([inscr_mask] * nb_semestres, axis=-1) + set_cube = set_cube * inscr_mask_3D # Enlève les NaN du cube pour les entrées manquantes : NaN -> -1.0 set_cube_no_nan = np.nan_to_num(set_cube, nan=-1.0) @@ -284,3 +239,16 @@ def compute_notes_ues( etud_moy_tag_df.fillna(np.nan) return etud_moy_tag_df + + +def get_sxtag_from_semestres( + formsemestres: dict[int:FormSemestre], sxtags: dict[(str, int):SxTag] +) -> (str, int): + """Partant d'un dictionnaire de SxTags, renvoie l'identifiant (str, fid) du + sxtag correspondant aux semestres de formsemestres. + (Utilisé pour transformer une trajectoire d'étudiants (par ex. S1+S2+S1+S2+S3) + en une suite de sxtags (S1+S2+S3) + """ + for sxtag_id, sxtag in sxtags: + if set(formsemestres.keys()) == set(sxtag.semestres_aggreges.keys()): + return sxtag_id diff --git a/app/pe/pe_tabletags.py b/app/pe/pe_tabletags.py index f876dedb..596aeae4 100644 --- a/app/pe/pe_tabletags.py +++ b/app/pe/pe_tabletags.py @@ -50,11 +50,11 @@ class TableTag(object): SemestreTag, TrajectoireTag, AggregatInterclassTag """ # Les étudiants - self.etuds: list[Identite] = None # A venir + # self.etuds: list[Identite] = None # A venir """Les étudiants""" - self.etats_civils: dict[int, Identite] = None + # self.etats_civils: dict[int, Identite] = None """Les états civils""" - self.etudids: list[int] = None + # self.etudids: list[int] = None """Les etudids""" def add_etuds(self, etuds: list[Identite]): @@ -63,7 +63,7 @@ class TableTag(object): Args: etuds: la liste des identités de l'étudiant """ - self.etuds = etuds + # self.etuds = etuds self.etats_civils = {etud.etudid: etud.etat_civil for etud in self.etuds} self.etudids = list(self.etats_civils.keys())