Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
6 changed files with 245 additions and 113 deletions
Showing only changes of commit 960f8a3462 - Show all commits

View File

@ -78,7 +78,7 @@ class RCSTag(pe_tabletags.TableTag):
"""Le fid du semestre final""" """Le fid du semestre final"""
# Affichage pour debug # Affichage pour debug
pe_affichage.pe_print(f"-> {self.get_repr(verbose=True)}") pe_affichage.pe_print(f"*** {self.get_repr(verbose=True)}")
# Les données aggrégés (RCRCF + SxTags # Les données aggrégés (RCRCF + SxTags
self.semXs_aggreges: dict[(str, int) : pe_rcsemx.RCSemX] = rcsemx.semXs_aggreges self.semXs_aggreges: dict[(str, int) : pe_rcsemx.RCSemX] = rcsemx.semXs_aggreges
@ -103,25 +103,26 @@ class RCSTag(pe_tabletags.TableTag):
# Les compétences (extraites de tous les Sxtags) # Les compétences (extraites de tous les Sxtags)
self.acronymes_ues_to_competences = self._do_acronymes_to_competences() self.acronymes_ues_to_competences = self._do_acronymes_to_competences()
"""L'association acronyme d'UEs -> compétence (extraites des SxTag aggrégés)""" """L'association acronyme d'UEs -> compétence (extraites des SxTag aggrégés)"""
pe_affichage.pe_print(
f"* Association UEs -> compétences : {self.acronymes_ues_to_competences}"
)
self.competences_sorted = sorted( self.competences_sorted = sorted(
set(self.acronymes_ues_to_competences.values()) set(self.acronymes_ues_to_competences.values())
) )
"""Compétences (triées par nom, extraites des SxTag aggrégés)""" """Compétences (triées par nom, extraites des SxTag aggrégés)"""
pe_affichage.pe_print(f"* Compétences : {', '.join(self.competences_sorted)}") self._aff_comp_et_ues_debug()
# pe_affichage.pe_print(f"--> Compétences : {', '.join(self.competences_sorted)}")
# Les tags # Les tags
self.tags_sorted = self._do_taglist() self.tags_sorted = self._do_taglist()
"""Tags extraits de tous les SxTag aggrégés""" """Tags extraits de tous les SxTag aggrégés"""
pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}") aff_tag = ["👜" + tag for tag in self.tags_sorted]
pe_affichage.pe_print(f"--> Tags : {', '.join(aff_tag)}")
# Les moyennes # Les moyennes
self.moyennes_tags: dict[str, pe_moytag.MoyennesTag] = {} self.moyennes_tags: dict[str, pe_moytag.MoyennesTag] = {}
"""Synthétise les moyennes/classements par tag (qu'ils soient personnalisé ou de compétences)""" """Synthétise les moyennes/classements par tag (qu'ils soient personnalisé ou de compétences)"""
for tag in self.tags_sorted: for tag in self.tags_sorted:
pe_affichage.pe_print(f"--> Moyennes du tag 👜{tag}")
# Cube de notes (etudids_sorted x compétences_sorted x sxstags) # Cube de notes (etudids_sorted x compétences_sorted x sxstags)
notes_df, notes_cube = self.compute_notes_comps_cube( notes_df, notes_cube = self.compute_notes_comps_cube(
tag, self.etudids_sorted, self.competences_sorted, self.sxstags tag, self.etudids_sorted, self.competences_sorted, self.sxstags
@ -143,6 +144,8 @@ class RCSTag(pe_tabletags.TableTag):
matrice_coeffs_moy_gen = compute_coeffs_competences( matrice_coeffs_moy_gen = compute_coeffs_competences(
coeffs_cube, notes_cube, self.etudids_sorted, self.competences_sorted coeffs_cube, notes_cube, self.etudids_sorted, self.competences_sorted
) )
self.__aff_profil_coeffs(matrice_coeffs_moy_gen)
# Mémorise les moyennes et les coeff associés # Mémorise les moyennes et les coeff associés
self.moyennes_tags[tag] = pe_moytag.MoyennesTag( self.moyennes_tags[tag] = pe_moytag.MoyennesTag(
tag, tag,
@ -308,6 +311,42 @@ class RCSTag(pe_tabletags.TableTag):
dict_competences |= sxtag.acronymes_ues_to_competences dict_competences |= sxtag.acronymes_ues_to_competences
return dict_competences return dict_competences
def _aff_comp_et_ues_debug(self):
"""Affichage pour debug"""
aff_comp = []
for comp in self.competences_sorted:
liste = []
for acro in self.acronymes_ues_to_competences:
if self.acronymes_ues_to_competences[acro] == comp:
liste += ["📍" + acro]
aff_comp += [f" 💡{comp} (⇔ {', '.join(liste)})"]
pe_affichage.pe_print(f"--> Compétences :")
pe_affichage.pe_print("\n".join(aff_comp))
def __aff_profil_coeffs(self, matrice_coeffs_moy_gen):
"""Extrait de la matrice des coeffs, les différents types d'inscription
et de coefficients (appelés profil) des étudiants et les affiche
(pour debug)
"""
# Les profils des coeffs d'UE (pour debug)
profils = []
for i in matrice_coeffs_moy_gen.index:
val = matrice_coeffs_moy_gen.loc[i].fillna("-")
val = " | ".join([str(v) for v in val])
if val not in profils:
profils += [val]
# L'affichage
if len(profils) > 1:
profils_aff = "\n" + "\n".join([" " * 10 + prof for prof in profils])
else:
profils_aff = "\n".join(profils)
pe_affichage.pe_print(
f" > Moyenne calculée avec pour coeffs (de compétences) : {profils_aff}"
)
def compute_coeffs_competences( def compute_coeffs_competences(
coeff_cube: np.array, coeff_cube: np.array,

View File

@ -66,7 +66,7 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
# Le nom du res_semestre taggué # Le nom du res_semestre taggué
self.nom = self.get_repr(verbose=True) self.nom = self.get_repr(verbose=True)
pe_affichage.pe_print(f"--> ResultatsSemestreBUT taggués {self.nom}") pe_affichage.pe_print(f"*** ResSemBUTTag du {self.nom}")
# Les étudiants (etuds, états civils & etudis) ajouté # Les étudiants (etuds, états civils & etudis) ajouté
self.add_etuds(self.etuds) self.add_etuds(self.etuds)
@ -100,9 +100,11 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
list(set(self.acronymes_ues_to_competences.values())) list(set(self.acronymes_ues_to_competences.values()))
) )
"""Les compétences triées par nom""" """Les compétences triées par nom"""
self._aff_ue_et_comp_debug()
# Les tags personnalisés et auto: # Les tags personnalisés et auto:
tags_dict = self._get_tags_dict() tags_dict = self._get_tags_dict()
self._aff_tags_debug(tags_dict)
self._check_tags(tags_dict) self._check_tags(tags_dict)
# Les coefficients pour le calcul de la moyenne générale, donnés par # Les coefficients pour le calcul de la moyenne générale, donnés par
@ -111,6 +113,7 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
self.ues_inscr_parcours_df, self.ues_standards self.ues_inscr_parcours_df, self.ues_standards
) )
"""DataFrame indiquant les coeffs des UEs par ordre alphabétique d'acronyme""" """DataFrame indiquant les coeffs des UEs par ordre alphabétique d'acronyme"""
self.__aff_profil_coeffs()
# Les capitalisations (mask etuids x acronyme_ue valant True si capitalisée, False sinon) # Les capitalisations (mask etuids x acronyme_ue valant True si capitalisée, False sinon)
self.capitalisations = self._get_capitalisations(self.ues_standards) self.capitalisations = self._get_capitalisations(self.ues_standards)
@ -291,7 +294,6 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
dict_tags["personnalises"] = get_synthese_tags_personnalises_semestre( dict_tags["personnalises"] = get_synthese_tags_personnalises_semestre(
self.formsemestre self.formsemestre
) )
noms_tags_perso = sorted(list(set(dict_tags["personnalises"].keys())))
# Les tags automatiques # Les tags automatiques
# Déduit des compétences # Déduit des compétences
@ -300,16 +302,25 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
# BUT # BUT
dict_tags["auto"] = {"but": {}} dict_tags["auto"] = {"but": {}}
return dict_tags
def _aff_ue_et_comp_debug(self):
"""Affichage pour debug"""
aff_comp = []
for acro in self.acronymes_sorted:
aff_comp += [f"📍{acro} (∈ 💡{self.acronymes_ues_to_competences[acro]})"]
pe_affichage.pe_print(f"--> UEs/Compétences : {', '.join(aff_comp)}")
def _aff_tags_debug(self, dict_tags):
"""Affichage pour debug"""
noms_tags_perso = sorted(list(set(dict_tags["personnalises"].keys())))
noms_tags_auto = sorted(list(set(dict_tags["auto"].keys()))) # + noms_tags_comp noms_tags_auto = sorted(list(set(dict_tags["auto"].keys()))) # + noms_tags_comp
aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto]) aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto])
aff_tags_perso = ", ".join([f"👜{nom}" for nom in noms_tags_perso]) aff_tags_perso = ", ".join([f"👜{nom}" for nom in noms_tags_perso])
# Affichage # Affichage
pe_affichage.pe_print( pe_affichage.pe_print(
f"* Tags du programme de formation : {aff_tags_perso} + " f"""--> Tags du programme de formation : {aff_tags_perso} + Automatiques : {aff_tags_auto}"""
+ f"Tags automatiques : {aff_tags_auto}"
) )
return dict_tags
def _check_tags(self, dict_tags): def _check_tags(self, dict_tags):
"""Vérifie l'unicité des tags""" """Vérifie l'unicité des tags"""
@ -336,6 +347,29 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
""" """
raise ScoValueError(message) raise ScoValueError(message)
def __aff_profil_coeffs(self):
"""Extrait de la matrice des coeffs, les différents types d'inscription
et de coefficients (appelés profil) des étudiants et les affiche
(pour debug)
"""
# Les profils des coeffs d'UE (pour debug)
profils = []
for i in self.matrice_coeffs_moy_gen.index:
val = self.matrice_coeffs_moy_gen.loc[i].fillna("-")
val = " | ".join([str(v) for v in val])
if val not in profils:
profils += [val]
# L'affichage
if len(profils) > 1:
profils_aff = "\n" + "\n".join([" " * 10 + prof for prof in profils])
else:
profils_aff = "\n".join(profils)
pe_affichage.pe_print(
f"--> Moyenne générale calculée avec pour coeffs d'UEs : {profils_aff}"
)
def get_synthese_tags_personnalises_semestre(formsemestre: FormSemestre): def get_synthese_tags_personnalises_semestre(formsemestre: FormSemestre):
"""Etant données les implémentations des modules du semestre (modimpls), """Etant données les implémentations des modules du semestre (modimpls),

View File

@ -116,12 +116,13 @@ class SxTag(pe_tabletags.TableTag):
"""Les etudids triés""" """Les etudids triés"""
# Affichage # Affichage
pe_affichage.pe_print(f"--> {self.get_repr(verbose=True)}") pe_affichage.pe_print(f"*** {self.get_repr(verbose=True)}")
# Les tags # Les tags
self.tags_sorted = self.ressembuttag_final.tags_sorted self.tags_sorted = self.ressembuttag_final.tags_sorted
"""Tags (extraits du ReSemBUTTag final)""" """Tags (extraits du ReSemBUTTag final)"""
pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}") aff_tag = ["👜" + tag for tag in self.tags_sorted]
pe_affichage.pe_print(f"--> Tags : {', '.join(aff_tag)}")
# Les UE données par leur acronyme # Les UE données par leur acronyme
self.acronymes_sorted = self.ressembuttag_final.acronymes_sorted self.acronymes_sorted = self.ressembuttag_final.acronymes_sorted
@ -134,10 +135,13 @@ class SxTag(pe_tabletags.TableTag):
"""L'association acronyme d'UEs -> compétence""" """L'association acronyme d'UEs -> compétence"""
self.competences_sorted = sorted(self.acronymes_ues_to_competences.values()) self.competences_sorted = sorted(self.acronymes_ues_to_competences.values())
"""Les compétences triées par nom""" """Les compétences triées par nom"""
self._aff_ue_et_comp_debug()
# Les coeffs pour la moyenne générale (traduisant également l'inscription # Les coeffs pour la moyenne générale (traduisant également l'inscription
# des étudiants aux UEs) (etudids_sorted x acronymes_ues_sorted) # des étudiants aux UEs) (etudids_sorted x acronymes_ues_sorted)
self.matrice_coeffs_moy_gen = self.ressembuttag_final.matrice_coeffs_moy_gen self.matrice_coeffs_moy_gen = self.ressembuttag_final.matrice_coeffs_moy_gen
"""La matrice des coeffs pour la moyenne générale"""
self.__aff_profil_coeffs()
# Masque des inscriptions et des capitalisations # Masque des inscriptions et des capitalisations
self.masque_df = None self.masque_df = None
@ -153,10 +157,13 @@ class SxTag(pe_tabletags.TableTag):
# Les moyennes par tag # Les moyennes par tag
self.moyennes_tags: dict[str, pd.DataFrame] = {} self.moyennes_tags: dict[str, pd.DataFrame] = {}
"""Moyennes aux UEs (identifiées par leur acronyme) des différents tags""" """Moyennes aux UEs (identifiées par leur acronyme) des différents tags"""
if self.tags_sorted:
pe_affichage.pe_print("--> Calcul des moyennes par tags :")
for tag in self.tags_sorted: for tag in self.tags_sorted:
# Y-a-t-il des notes ? # Y-a-t-il des notes ?
if not self.has_notes(tag): if not self.has_notes(tag):
pe_affichage.pe_print(f"> MoyTag 🏷{tag} actuellement sans notes") pe_affichage.pe_print(f" > MoyTag 👜{tag} actuellement sans notes")
matrice_moys_ues = pd.DataFrame( matrice_moys_ues = pd.DataFrame(
np.nan, index=self.etudids_sorted, columns=self.acronymes_sorted np.nan, index=self.etudids_sorted, columns=self.acronymes_sorted
) )
@ -198,17 +205,24 @@ class SxTag(pe_tabletags.TableTag):
(pour debug) (pour debug)
""" """
# Les profils d'ects (pour debug) # Les profils des coeffs d'UE (pour debug)
profils_ects = [] profils = []
for i in self.matrice_coeffs_moy_gen.index: for i in self.matrice_coeffs_moy_gen.index:
val = tuple(self.matrice_coeffs_moy_gen.loc[i].fillna("x")) val = self.matrice_coeffs_moy_gen.loc[i].fillna("-")
if tuple(val) not in profils_ects: val = " | ".join([str(v) for v in val])
profils_ects.append(tuple(val)) if val not in profils:
profils += [val]
# L'affichage
if len(profils) > 1:
profils_aff = "\n" + "\n".join([" " * 10 + prof for prof in profils])
else:
profils_aff = "\n".join(profils)
# L'affichage # L'affichage
ues = ", ".join(self.acronymes_sorted) ues = ", ".join(self.acronymes_sorted)
pe_affichage.pe_print( pe_affichage.pe_print(
f"> MoyTag 🏷{tag} avec " + f"ues={ues} " + f"inscr/ects={profils_ects}" f" > MoyTag 👜{tag} pour UES: {ues} avec pour coeffs : {profils_aff}"
) )
def has_notes(self, tag): def has_notes(self, tag):
@ -243,8 +257,16 @@ class SxTag(pe_tabletags.TableTag):
# affichage = [str(fid) for fid in self.ressembuttags] # affichage = [str(fid) for fid in self.ressembuttags]
return f"SXTag {self.nom_rcs}#{self.fid_final}" return f"SXTag {self.nom_rcs}#{self.fid_final}"
def _aff_ue_et_comp_debug(self):
"""Affichage pour debug"""
aff_comp = []
for acro in self.acronymes_sorted:
aff_comp += [f"📍{acro} (∈ 💡{self.acronymes_ues_to_competences[acro]})"]
pe_affichage.pe_print(f"--> UEs/Compétences : {', '.join(aff_comp)}")
def _aff_capitalisations(self): def _aff_capitalisations(self):
"""Affichage des capitalisations du sxtag pour debug""" """Affichage des capitalisations du sxtag pour debug"""
aff_cap = []
for etud in self.etuds: for etud in self.etuds:
cap = [] cap = []
for frmsem_id in self.ressembuttags: for frmsem_id in self.ressembuttags:
@ -253,9 +275,33 @@ class SxTag(pe_tabletags.TableTag):
if self.masque_df[frmsem_id].loc[etud.etudid, accr] > 0.0: if self.masque_df[frmsem_id].loc[etud.etudid, accr] > 0.0:
cap += [accr] cap += [accr]
if cap: if cap:
pe_affichage.pe_print( aff_cap += [f" > {etud.nomprenom} : {', '.join(cap)}"]
f" ⚠ Capitalisation de {etud.etat_civil} : {', '.join(cap)}" if aff_cap:
) pe_affichage.pe_print(f"--> ⚠️ Capitalisations :")
pe_affichage.pe_print("\n".join(aff_cap))
def __aff_profil_coeffs(self):
"""Extrait de la matrice des coeffs, les différents types d'inscription
et de coefficients (appelés profil) des étudiants et les affiche
(pour debug)
"""
# Les profils des coeffs d'UE (pour debug)
profils = []
for i in self.matrice_coeffs_moy_gen.index:
val = self.matrice_coeffs_moy_gen.loc[i].fillna("-")
val = " | ".join([str(v) for v in val])
if val not in profils:
profils += [val]
# L'affichage
if len(profils) > 1:
profils_aff = "\n" + "\n".join([" " * 10 + prof for prof in profils])
else:
profils_aff = "\n".join(profils)
pe_affichage.pe_print(
f"--> Moyenne générale calculée avec pour coeffs d'UEs : {profils_aff}"
)
def compute_notes_ues_cube( def compute_notes_ues_cube(

View File

@ -43,6 +43,7 @@ from app.pe import pe_comp, pe_affichage
from app.scodoc import codes_cursus from app.scodoc import codes_cursus
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.comp.res_sem import load_formsemestre_results from app.comp.res_sem import load_formsemestre_results
import warnings
class EtudiantsJuryPE: class EtudiantsJuryPE:
@ -100,10 +101,10 @@ class EtudiantsJuryPE:
self.cosemestres = cosemestres self.cosemestres = cosemestres
pe_affichage.pe_print( pe_affichage.pe_print(
f"1) Recherche des coSemestres -> {len(cosemestres)} trouvés" f"1) Recherche des cosemestres -> {len(cosemestres)} trouvés"
) )
pe_affichage.pe_print("2) Liste des étudiants dans les différents co-semestres") pe_affichage.pe_print("2) Liste des étudiants dans les différents cosemestres")
self.etudiants_ids = get_etudiants_dans_semestres(cosemestres) self.etudiants_ids = get_etudiants_dans_semestres(cosemestres)
pe_affichage.pe_print( pe_affichage.pe_print(
f" => {len(self.etudiants_ids)} étudiants trouvés dans les cosemestres" f" => {len(self.etudiants_ids)} étudiants trouvés dans les cosemestres"
@ -135,23 +136,16 @@ class EtudiantsJuryPE:
# Les identifiants des étudiants ayant redoublés ou ayant abandonnés # Les identifiants des étudiants ayant redoublés ou ayant abandonnés
# Synthèse # Synthèse
pe_affichage.pe_print(f"4) Bilan")
pe_affichage.pe_print( pe_affichage.pe_print(
f" => {len(self.etudiants_diplomes)} étudiants à diplômer en {self.annee_diplome}" f"--> {len(self.etudiants_diplomes)} étudiants à diplômer en {self.annee_diplome}"
) )
nbre_abandons = len(self.etudiants_ids) - len(self.etudiants_diplomes) nbre_abandons = len(self.etudiants_ids) - len(self.etudiants_diplomes)
assert nbre_abandons == len(self.abandons_ids) assert nbre_abandons == len(self.abandons_ids)
pe_affichage.pe_print( pe_affichage.pe_print(
f" => {nbre_abandons} étudiants traités mais non diplômés (redoublement, réorientation, abandon)" f"--> {nbre_abandons} étudiants traités mais non diplômés (redoublement, réorientation, abandon)"
) )
# pe_affichage.pe_print(
# " => quelques étudiants futurs diplômés : "
# + ", ".join([str(etudid) for etudid in list(self.etudiants_diplomes)[:10]])
# )
# pe_affichage.pe_print(
# " => semestres dont il faut calculer les moyennes : "
# + ", ".join([str(fid) for fid in list(self.formsemestres_jury_ids)])
# )
def get_etudiants_diplomes(self) -> dict[int, Identite]: def get_etudiants_diplomes(self) -> dict[int, Identite]:
"""Identités des étudiants (sous forme d'un dictionnaire `{etudid: Identite(etudid)}` """Identités des étudiants (sous forme d'un dictionnaire `{etudid: Identite(etudid)}`
@ -240,7 +234,8 @@ class EtudiantsJuryPE:
if self.cursus[etudid]["diplome"] == self.annee_diplome: if self.cursus[etudid]["diplome"] == self.annee_diplome:
# Est-il démissionnaire : charge son dernier semestre pour connaitre son état ? # Est-il démissionnaire : charge son dernier semestre pour connaitre son état ?
dernier_semes_etudiant = formsemestres[0] dernier_semes_etudiant = formsemestres[0]
res = load_formsemestre_results(dernier_semes_etudiant) with warnings.catch_warnings():
res = load_formsemestre_results(dernier_semes_etudiant)
etud_etat = res.get_etud_etat(etudid) etud_etat = res.get_etud_etat(etudid)
if etud_etat == scu.DEMISSION: if etud_etat == scu.DEMISSION:
self.cursus[etudid]["abandon"] = True self.cursus[etudid]["abandon"] = True
@ -547,45 +542,11 @@ def arret_de_formation(etud: Identite, cosemestres: dict[int, FormSemestre]) ->
pe_affichage.pe_print( pe_affichage.pe_print(
f"--> ⛔ {etud.etat_civil} ({etud.etudid}), non inscrit dans {affichage} amenant à diplômation" f"--> ⛔ {etud.etat_civil} ({etud.etudid}), non inscrit dans {affichage} amenant à diplômation"
) )
else:
pe_affichage.pe_print(f"--> ✅ {etud.etat_civil} ({etud.etudid})")
return est_demissionnaire return est_demissionnaire
# # Son dernier semestre APC en date
# dernier_formsemestre = get_dernier_semestre_en_date(semestres_apc)
# numero_dernier_formsemestre = dernier_formsemestre.semestre_id
#
# # Les numéro de semestres possible dans lesquels il pourrait s'incrire
# # semestre impair => passage de droit en semestre pair suivant (effet de l'annualisation)
# if numero_dernier_formsemestre % 2 == 1:
# numeros_possibles = list(
# range(numero_dernier_formsemestre + 1, pe_comp.NBRE_SEMESTRES_DIPLOMANT)
# )
# # semestre pair => passage en année supérieure ou redoublement
# else: #
# numeros_possibles = list(
# range(
# max(numero_dernier_formsemestre - 1, 1),
# pe_comp.NBRE_SEMESTRES_DIPLOMANT,
# )
# )
#
# # Y-a-t-il des cosemestres dans lesquels il aurait pu s'incrire ?
# formsestres_superieurs_possibles = []
# for fid, sem in cosemestres.items(): # Les semestres ayant des inscrits
# if (
# fid != dernier_formsemestre.formsemestre_id
# and sem.semestre_id in numeros_possibles
# and sem.date_debut.year >= dernier_formsemestre.date_debut.year
# ):
# # date de debut des semestres possibles postérieur au dernier semestre de l'étudiant
# # et de niveau plus élevé que le dernier semestre valide de l'étudiant
# formsestres_superieurs_possibles.append(fid)
#
# if len(formsestres_superieurs_possibles) > 0:
# return True
#
# return False
def etapes_du_cursus( def etapes_du_cursus(
semestres: dict[int, FormSemestre], nbre_etapes_max: int semestres: dict[int, FormSemestre], nbre_etapes_max: int
@ -650,6 +611,6 @@ def nom_semestre_etape(semestre: FormSemestre, avec_fid=False) -> str:
f"{semestre.date_debut.year}-{semestre.date_fin.year}", f"{semestre.date_debut.year}-{semestre.date_fin.year}",
] ]
if avec_fid: if avec_fid:
description.append(f"({semestre.formsemestre_id})") description.append(f"(#{semestre.formsemestre_id})")
return " ".join(description) return " ".join(description)

View File

@ -91,11 +91,14 @@ class JuryPE(object):
) )
# Chargement des étudiants à prendre en compte dans le jury # Chargement des étudiants à prendre en compte dans le jury
pe_affichage.pe_print( pe_affichage.pe_print(
f"""*** Recherche des étudiants diplômés 🎓 en {self.diplome}""" f"""***********************************************************\n"""
f"""*** Recherche des étudiants diplômés 🎓 en {self.diplome}\n"""
f"""***********************************************************\n"""
) )
self.etudiants = pe_etudiant.EtudiantsJuryPE(
self.diplome # Les infos sur les étudiants
) # Les infos sur les étudiants self.etudiants = pe_etudiant.EtudiantsJuryPE(self.diplome)
"""Les informations sur les étudiants du jury PE"""
self.etudiants.find_etudiants() self.etudiants.find_etudiants()
self.diplomes_ids = self.etudiants.diplomes_ids self.diplomes_ids = self.etudiants.diplomes_ids
@ -153,13 +156,14 @@ class JuryPE(object):
def _gen_xls_ressembuttags(self, zipfile: ZipFile): def _gen_xls_ressembuttags(self, zipfile: ZipFile):
"""Calcule les moyennes par tag des résultats des Semestres BUT""" """Calcule les moyennes par tag des résultats des Semestres BUT"""
pe_affichage.pe_print( pe_affichage.pe_print(
"*** Génère les ResSemBUTTag (résultats des semestres BUT taggués)" f"""*************************************************************************\n"""
f"""*** Génère les ResSemBUTTag (ResSemestreBUT taggués)\n"""
f"""*************************************************************************"""
) )
# Tous les formsestres des étudiants
formsemestres = get_formsemestres_etudiants(self.etudiants) formsemestres = get_formsemestres_etudiants(self.etudiants)
pe_affichage.pe_print( pe_affichage.pe_print(f"1) Génère les {len(formsemestres)} ResSemBUTTag")
f"--> {len(formsemestres)} résultats de semestres à considérer"
)
self.ressembuttags = {} self.ressembuttags = {}
for frmsem_id, formsemestre in formsemestres.items(): for frmsem_id, formsemestre in formsemestres.items():
@ -167,6 +171,7 @@ class JuryPE(object):
self.ressembuttags[frmsem_id] = pe_ressemtag.ResSemBUTTag(formsemestre) self.ressembuttags[frmsem_id] = pe_ressemtag.ResSemBUTTag(formsemestre)
# Intègre le bilan des semestres taggués au zip final # Intègre le bilan des semestres taggués au zip final
pe_affichage.pe_print(f"2) Bilan")
output = io.BytesIO() output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl" output, engine="openpyxl"
@ -174,13 +179,14 @@ class JuryPE(object):
onglets = [] onglets = []
for res_sem_tag in self.ressembuttags.values(): for res_sem_tag in self.ressembuttags.values():
onglet = res_sem_tag.get_repr(verbose=True) onglet = res_sem_tag.get_repr(verbose=True)
onglets += [] onglet = onglet.replace("Semestre ", "S")
onglets += ["📊" + onglet]
df = res_sem_tag.to_df() df = res_sem_tag.to_df()
# Conversion colonnes en multiindex # Conversion colonnes en multiindex
df = convert_colonnes_to_multiindex(df) df = convert_colonnes_to_multiindex(df)
# écriture dans l'onglet # écriture dans l'onglet
df.to_excel(writer, onglet, index=True, header=True) df.to_excel(writer, onglet, index=True, header=True)
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}") pe_affichage.pe_print(f"--> Export excel de {', '.join(onglets)}")
output.seek(0) output.seek(0)
self.add_file_to_zip( self.add_file_to_zip(
@ -196,10 +202,13 @@ class JuryPE(object):
RCS (par ex: 'S2' ou '3S'). RCS (par ex: 'S2' ou '3S').
""" """
pe_affichage.pe_print( pe_affichage.pe_print(
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants" "***************************************************************************\n"
"*** Génère les trajectoires (≠tes combinaisons de semestres) des étudiants"
"***************************************************************************\n"
) )
self.rcss_jury.cree_trajectoires(self.etudiants) self.rcss_jury.cree_trajectoires(self.etudiants)
self.rcss_jury._aff_trajectoires(self.etudiants)
def _gen_semXs(self): def _gen_semXs(self):
"""Génère les SemXs (trajectoires/combinaisons de semestre de même rang x) """Génère les SemXs (trajectoires/combinaisons de semestre de même rang x)
@ -218,10 +227,13 @@ class JuryPE(object):
""" """
# Génère les moyennes des RCS de type Sx # Génère les moyennes des RCS de type Sx
pe_affichage.pe_print( pe_affichage.pe_print(
"*** Calcule les moyennes des SxTag (moyennes d'un SemX/RCS de type Sx)" "***************************************************************************\n"
"*** Calcule les moyennes des SxTag (moyennes d'un RCS de type Sx)"
"***************************************************************************\n"
) )
# Les SxTag (moyenne de Sx par UE) # Les SxTag (moyenne de Sx par UE)
pe_affichage.pe_print("1) Calcul des moyennes")
self.sxtags = {} self.sxtags = {}
for rcf_id, rcf in self.rcss_jury.semXs.items(): for rcf_id, rcf in self.rcss_jury.semXs.items():
# SxTag traduisant le RCF # SxTag traduisant le RCF
@ -229,6 +241,7 @@ class JuryPE(object):
self.sxtags[sxtag_id] = pe_sxtag.SxTag(sxtag_id, rcf, self.ressembuttags) self.sxtags[sxtag_id] = pe_sxtag.SxTag(sxtag_id, rcf, self.ressembuttags)
# Intègre le bilan des semestres taggués au zip final # Intègre le bilan des semestres taggués au zip final
pe_affichage.pe_print("2) Bilan")
output = io.BytesIO() output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl" output, engine="openpyxl"
@ -240,10 +253,10 @@ class JuryPE(object):
df = sxtag.to_df() df = sxtag.to_df()
# Conversion colonnes en multiindex # Conversion colonnes en multiindex
df = convert_colonnes_to_multiindex(df) df = convert_colonnes_to_multiindex(df)
onglets += [onglet] onglets += ["📊" + onglet]
# écriture dans l'onglet # écriture dans l'onglet
df.to_excel(writer, onglet, index=True, header=True) df.to_excel(writer, onglet, index=True, header=True)
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}") pe_affichage.pe_print(f"--> Export excel de {', '.join(onglets)}")
output.seek(0) output.seek(0)
if onglets: if onglets:
@ -258,8 +271,10 @@ class JuryPE(object):
"""Génère les regroupements cohérents de RCFs qu'ont suivi chaque étudiant""" """Génère les regroupements cohérents de RCFs qu'ont suivi chaque étudiant"""
pe_affichage.pe_print( pe_affichage.pe_print(
"*** Génère les RCSemX (regroupements cohérents de données" """******************************************************************************\n"""
" extraites des SemX) amenant du S1 à un semestre final***" """*** Génère les RCSemX (regroupements cohérents de données extraites des SemX)\n"""
"""*** amenant du S1 à un semestre final\n"""
"""******************************************************************************"""
) )
self.rcss_jury.cree_rcsemxs(self.etudiants) self.rcss_jury.cree_rcsemxs(self.etudiants)
self.rcss_jury._aff_rcsemxs_suivis(self.etudiants) self.rcss_jury._aff_rcsemxs_suivis(self.etudiants)
@ -284,7 +299,11 @@ class JuryPE(object):
""" """
# Génère les moyennes des RCS de type Sx # Génère les moyennes des RCS de type Sx
pe_affichage.pe_print("*** Calcule les moyennes des RC de RCFS") pe_affichage.pe_print(
"""****************************************************\n"""
"""*** Génère les moyennes associées aux RCSemX \n"""
"""****************************************************"""
)
self.rcss_tags = {} self.rcss_tags = {}
for rcs_id, rcsemx in self.rcss_jury.rcsemxs.items(): for rcs_id, rcsemx in self.rcss_jury.rcsemxs.items():

View File

@ -93,15 +93,19 @@ class RCSsJuryPE:
# Mémorise le RCS suivi par l'étudiant # Mémorise le RCS suivi par l'étudiant
self.trajectoires_suivies[etudid][nom_rcs] = rcs self.trajectoires_suivies[etudid][nom_rcs] = rcs
def _aff_trajectoires(self, etudiants: pe_etudiant.EtudiantsJuryPE):
"""Affiche les chemins trouvés pour debug"""
# Affichage pour debug # Affichage pour debug
jeunes = list(enumerate(self.trajectoires_suivies)) jeunes = list(enumerate(self.trajectoires_suivies))
for no_etud, etudid in jeunes[:20]: for no_etud, etudid in jeunes:
etat = "" if etudid in etudiants.abandons_ids else ""
pe_affichage.pe_print( pe_affichage.pe_print(
f"--> {etudiants.identites[etudid].nomprenom} (#{etudid}) :" f"--> {etat} {etudiants.identites[etudid].nomprenom} (#{etudid}) :"
) )
for nom_rcs, rcs in self.trajectoires_suivies[etudid].items(): for nom_rcs, rcs in self.trajectoires_suivies[etudid].items():
if rcs: if rcs:
pe_affichage.pe_print(f" > RCS {nom_rcs}: {rcs.get_repr()}") pe_affichage.pe_print(f" > RCS ⏯️{nom_rcs}: {rcs.get_repr()}")
def cree_semxs(self, etudiants: pe_etudiant.EtudiantsJuryPE): def cree_semxs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
"""Créé les les SemXs (trajectoires/combinaisons de semestre de même rang x), """Créé les les SemXs (trajectoires/combinaisons de semestre de même rang x),
@ -126,16 +130,26 @@ class RCSsJuryPE:
def _aff_semxs_suivis(self, etudiants: pe_etudiant.EtudiantsJuryPE): def _aff_semxs_suivis(self, etudiants: pe_etudiant.EtudiantsJuryPE):
"""Affichage des SemX pour debug""" """Affichage des SemX pour debug"""
jeunes = list(enumerate(self.semXs_suivis)) jeunes = list(enumerate(self.semXs_suivis))
vides = []
for no_etud, etudid in jeunes[:20]: for no_etud, etudid in jeunes:
pe_affichage.pe_print(f"-> {etudiants.identites[etudid].nomprenom} :") etat = "" if etudid in etudiants.abandons_ids else ""
pe_affichage.pe_print(
f"--> {etat} {etudiants.identites[etudid].nomprenom} :"
)
for nom_rcs, rcs in self.semXs_suivis[etudid].items(): for nom_rcs, rcs in self.semXs_suivis[etudid].items():
if rcs: if rcs:
pe_affichage.pe_print(f" > SemX {nom_rcs}: {rcs.get_repr()}") pe_affichage.pe_print(f" > SemX ⏯️{nom_rcs}: {rcs.get_repr()}")
else:
vides += [nom_rcs] vides = []
for nom_rcs in pe_rcs.TOUS_LES_SEMESTRES:
les_semX_suivis = []
for no_etud, etudid in jeunes:
if self.semXs_suivis[etudid][nom_rcs]:
les_semX_suivis.append(self.semXs_suivis[etudid][nom_rcs])
if not les_semX_suivis:
vides += [nom_rcs]
vides = sorted(list(set(vides))) vides = sorted(list(set(vides)))
pe_affichage.pe_print(f"-> ⚠ SemX vides : {', '.join(vides)}") pe_affichage.pe_print(f"⚠️ SemX sans données : {', '.join(vides)}")
def cree_rcsemxs(self, etudiants: pe_etudiant.EtudiantsJuryPE): def cree_rcsemxs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
"""Créé tous les RCSemXs, au regard du cursus des étudiants """Créé tous les RCSemXs, au regard du cursus des étudiants
@ -146,6 +160,7 @@ class RCSsJuryPE:
self.rcsemxs = {} self.rcsemxs = {}
# Pour tous les étudiants du jury # Pour tous les étudiants du jury
pas_de_semestres = []
for etudid in self.trajectoires_suivies: for etudid in self.trajectoires_suivies:
self.rcsemxs_suivis[etudid] = { self.rcsemxs_suivis[etudid] = {
nom_rcs: None for nom_rcs in pe_rcs.TOUS_LES_RCS_AVEC_PLUSIEURS_SEM nom_rcs: None for nom_rcs in pe_rcs.TOUS_LES_RCS_AVEC_PLUSIEURS_SEM
@ -160,6 +175,7 @@ class RCSsJuryPE:
# Pour chaque aggréggat de type xA ou Sx # Pour chaque aggréggat de type xA ou Sx
tous_les_agregats = pe_rcs.TOUS_LES_RCS tous_les_agregats = pe_rcs.TOUS_LES_RCS
for nom_rcs in tous_les_agregats: for nom_rcs in tous_les_agregats:
trajectoire = self.trajectoires_suivies[etudid][nom_rcs] trajectoire = self.trajectoires_suivies[etudid][nom_rcs]
if not trajectoire: if not trajectoire:
@ -183,9 +199,9 @@ class RCSsJuryPE:
for Sx in noms_sems_aggregat: for Sx in noms_sems_aggregat:
semestres_etudiants = etudiants.cursus[etudid][Sx] semestres_etudiants = etudiants.cursus[etudid][Sx]
if not semestres_etudiants: if not semestres_etudiants:
pe_affichage.pe_print( pas_de_semestres += [
f"-> ⚠ Pas de semestres {Sx} pour {etudiants.identites[etudid].etat_civil}" f"{Sx} pour {etudiants.identites[etudid].nomprenom}"
) ]
else: else:
semx_id = get_semx_from_semestres_aggreges( semx_id = get_semx_from_semestres_aggreges(
self.semXs, semestres_etudiants self.semXs, semestres_etudiants
@ -204,20 +220,37 @@ class RCSsJuryPE:
# Mémoire du RCSemX aux informations de suivi de l'étudiant # Mémoire du RCSemX aux informations de suivi de l'étudiant
self.rcsemxs_suivis[etudid][nom_rcs] = rcsemx self.rcsemxs_suivis[etudid][nom_rcs] = rcsemx
# Affichage des étudiants pour lesquels il manque un semestre
pas_de_semestres = sorted(set(pas_de_semestres))
if pas_de_semestres:
pe_affichage.pe_print("⚠️ Semestres manquants :")
pe_affichage.pe_print(
"\n".join([" " * 10 + psd for psd in pas_de_semestres])
)
def _aff_rcsemxs_suivis(self, etudiants): def _aff_rcsemxs_suivis(self, etudiants):
"""Affiche les RCSemX suivis par les étudiants""" """Affiche les RCSemX suivis par les étudiants"""
# Affichage pour debug # Affichage pour debug
jeunes = list(enumerate(self.rcsemxs_suivis.keys())) jeunes = list(enumerate(self.rcsemxs_suivis.keys()))
vides = []
for no_etud, etudid in jeunes: for no_etud, etudid in jeunes:
if etudid not in etudiants.abandons_ids: etat = "" if etudid in etudiants.abandons_ids else ""
pe_affichage.pe_print(f"-> {etudiants.identites[etudid].nomprenom} :") pe_affichage.pe_print(
for nom_rcs, rcs in self.rcsemxs_suivis[etudid].items(): f"-> {etat} {etudiants.identites[etudid].nomprenom} :"
if rcs: )
pe_affichage.pe_print(f" > RCSemX {nom_rcs}: {rcs.get_repr()}") for nom_rcs, rcs in self.rcsemxs_suivis[etudid].items():
else: if rcs:
vides += [f"{nom_rcs}"] pe_affichage.pe_print(f" > RCSemX ⏯️{nom_rcs}: {rcs.get_repr()}")
pe_affichage.pe_print(f"-> ⚠ RCSemX vides : {', '.join(list(set(vides)))}")
vides = []
for nom_rcs in pe_rcs.TOUS_LES_RCS:
les_rcssemX_suivis = []
for no_etud, etudid in jeunes:
if self.rcsemxs_suivis[etudid][nom_rcs]:
les_rcssemX_suivis.append(self.rcsemxs_suivis[etudid][nom_rcs])
if not les_rcssemX_suivis:
vides += [nom_rcs]
vides = sorted(list(set(vides)))
pe_affichage.pe_print(f"⚠️ RCSemX vides : {', '.join(vides)}")
def get_rcs_etudiant( def get_rcs_etudiant(