ScoDoc-PE/app/pe/pe_jurype.py

757 lines
31 KiB
Python

# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2024 Emmanuel Viennet. 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
##############################################################################
# Module "Avis de poursuite d'étude"
# conçu et développé par Cléo Baras (IUT de Grenoble)
##############################################################################
"""
Created on Fri Sep 9 09:15:05 2016
@author: barasc
"""
import datetime
# ----------------------------------------------------------
# Ensemble des fonctions et des classes
# permettant les calculs preliminaires (hors affichage)
# a l'edition d'un jury de poursuites d'etudes
# ----------------------------------------------------------
import io
import os
from zipfile import ZipFile
import app.pe.pe_etudiant
import app.pe.pe_settag_interclasse
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.comp.res_sem import load_formsemestre_results
from app.models import Formation, FormSemestre
from app.models.etudiants import Identite
from app.pe.pe_semestretag import SemestreTag
from app.scodoc.gen_tables import GenTable, SeqGenTable
import app.scodoc.sco_utils as scu
from app.scodoc import (
codes_cursus,
sco_formsemestre_inscriptions,
) # codes_cursus.NEXT -> sem suivant
from app.scodoc import sco_etud
from app.scodoc import sco_report
from app.scodoc import sco_formsemestre
from app.pe import pe_tagtable
from app.pe import pe_tools
from app.pe import pe_semestretag
from app.pe import pe_settag
from app.pe.pe_etudiant import EtudiantsJuryPE
# ----------------------------------------------------------------------------------------
def comp_nom_semestre_dans_parcours(sem):
"""Le nom a afficher pour titrer un semestre
par exemple: "semestre 2 FI 2015"
"""
formation: Formation = Formation.query.get_or_404(sem["formation_id"])
parcours = codes_cursus.get_cursus_from_code(formation.type_parcours)
return "%s %s %s %s" % (
parcours.SESSION_NAME, # eg "semestre"
sem["semestre_id"], # eg 2
sem.get("modalite", ""), # eg FI ou FC
sem["annee_debut"], # eg 2015
)
# ----------------------------------------------------------------------------------------
class JuryPE(object):
"""Classe mémorisant toutes les informations nécessaires pour établir un jury de PE.
Modèle basé sur NotesTable.
Attributs :
* diplome : l'année d'obtention du diplome BUT et du jury de PE (généralement février XXXX)
* juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives +
celles des semestres valides à prendre en compte permettant le calcul des moyennes ...
``{'etudid : { 'nom', 'prenom', 'civilite', 'diplome', '', }}``
Rq: il contient à la fois les étudiants qui vont être diplomés à la date prévue
et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif
"""
# Variables de classe décrivant les aggrégats, leur ordre d'apparition temporelle et
# leur affichage dans les avis latex
# ------------------------------------------------------------------------------------------------------------------
def __init__(self, diplome, formation_id):
"""
Création d'une table PE sur la base d'un semestre selectionné. De ce semestre est déduit :
1. l'année d'obtention du DUT,
2. tous les étudiants susceptibles à ce stade (au regard de leur parcours) d'être diplomés.
Args:
sem_base: le FormSemestre donnant le semestre à la base du jury PE
semBase: le dictionnaire sem donnant la base du jury (CB: TODO: A supprimer à long term)
meme_programme: si True, impose un même programme pour tous les étudiants participant au jury,
si False, permet des programmes differents
"""
self.promoTagDict = {}
"L'année du diplome"
self.diplome = diplome
"La formation associée au diplome"
self.formation_id = formation_id
"Un zip où ranger les fichiers générés"
self.nom_export_zip = "Jury_PE_%s" % self.diplome
self.zipdata = io.BytesIO()
self.zipfile = ZipFile(self.zipdata, "w")
self.syntheseJury = {} # Le jury de synthèse
"""Chargement des étudiants à prendre en compte dans le jury"""
pe_tools.pe_print(
f"*** Recherche et chargement des étudiants diplômés en {self.diplome} pour la formation {self.formation_id}"
)
self.etudiants = EtudiantsJuryPE() # Les infos sur les étudiants
self.etudiants.find_etudiants(self.diplome, self.formation_id)
"""Génère les semestres taggués (avec le calcul des moyennes) pour le jury PE"""
self.semestres_taggues = compute_semestres_tag(self.etudiants)
if pe_tools.PE_DEBUG:
"""Intègre le bilan des semestres taggués au zip final"""
for fid in self.semestres_taggues:
formsemestretag = self.semestres_taggues[fid]
filename = formsemestretag.nom.replace(" ", "_") + ".csv"
pe_tools.pe_print(f" - Export csv de {filename} ")
self.add_file_to_zip(
filename, formsemestretag.str_tagtable(), path="details_semestres"
)
"""Génère les aggrégats de semestre (par ex: 1A, 3S, 5S) avec calcul
des moyennes pour le jury"""
self.aggregats_taggues = compute_aggregats_tag(self.etudiants, self.semestres_taggues)
if pe_tools.PE_DEBUG:
"""Intègre le bilan des aggrégats de semestres au zip final"""
for aggregat in self.aggregats_taggues:
for fid in self.aggregats_taggues[aggregat]:
set_tag = self.aggregats_taggues[aggregat][fid]
filename = set_tag.nom.replace(" ", "_") + ".csv"
pe_tools.pe_print(f" - Export csv de {filename} ")
self.add_file_to_zip(
filename, set_tag.str_tagtable(), path="details_semestres"
)
"""Génère les interclassements par (nom d') aggrégat"""
"""Synthèse des éléments du jury PE"""
if False:
self.synthetise_juryPE()
# Export des données => mode 1 seule feuille -> supprimé
# filename = self.NOM_EXPORT_ZIP + "jurySyntheseDict_" + str(self.diplome) + '.xls'
# self.xls = self.table_syntheseJury(mode="singlesheet")
# self.add_file_to_zip(filename, self.xls.excel())
# Fabrique 1 fichier excel résultat avec 1 seule feuille => trop gros
if False:
filename = self.nom_export_zip + "_jurySyntheseDict" + scu.XLSX_SUFFIX
self.xlsV2 = self.table_syntheseJury(mode="multiplesheet")
if self.xlsV2:
pe_tools.add_file_to_zip(
self.nom_export_zip, filename, self.xlsV2.excel()
)
# Pour debug
# self.syntheseJury = pe_tools.JURY_SYNTHESE_POUR_DEBUG #Un dictionnaire fictif pour debug
# Les interclassements
# --------------------
if pe_tools.PE_DEBUG:
pe_tools.pe_print(
"*** Création des interclassements au sein de la promo sur différentes combinaisons de semestres"
)
if False:
self.get_promotags_in_jury()
def add_file_to_zip(self, filename: str, data, path=""):
"""Add a file to our zip
All files under NOM_EXPORT_ZIP/
path may specify a subdirectory
Args:
filename: Le nom du fichier à intégrer au zip
data: Les données du fichier
path: Un dossier dans l'arborescence du zip
"""
path_in_zip = os.path.join(self.nom_export_zip, path, filename)
self.zipfile.writestr(path_in_zip, data)
def get_zipped_data(self):
"""returns file-like data with a zip of all generated (CSV) files.
Reset file cursor at the beginning !
"""
if self.zipfile:
self.zipfile.close()
self.zipfile = None
self.zipdata.seek(0)
return self.zipdata
# **************************************************************************************************************** #
# Traitements des semestres impliqués dans le jury
# **************************************************************************************************************** #
# **************************************************************************************************************** #
# Traitements des moyennes sur différentes combinaisons de parcours 1A, 2A, 3S et 4S,
# impliquées dans le jury
# **************************************************************************************************************** #
def get_promotags_in_jury(self):
"""Interclasse les étudiants, (nom d') aggrégat par aggrégat,
pour fournir un classement sur la promo.
"""
lesEtudids = self.etudiants.get_etudids(self.diplome)
for i, nom in enumerate(pe_tools.PARCOURS.keys()):
settag = app.pe.pe_settag_interclasse.SetTagInterClasse(
nom, diplome=self.diplome
)
nbreEtudInscrits = settag.set_Etudiants(
lesEtudids, self.etudiants.cursus, self.etudiants.identites
)
if nbreEtudInscrits > 0:
if pe_tools.PE_DEBUG:
pe_tools.pe_print(
"%d) %s avec interclassement sur la promo" % (i + 1, nom)
)
if nom in pe_tools.TOUS_LES_SEMESTRES:
settag.set_SetTagDict(self.semestres_taggues)
else: # cas des aggrégats
settag.set_SetTagDict(self.aggregats_taggues[nom])
settag.comp_data_settag()
self.promoTagDict[nom] = settag
else:
pe_tools.pe_print(
"%d) Pas d'interclassement %s sur la promo faute de notes"
% (i + 1, nom)
)
# **************************************************************************************************************** #
# Méthodes pour la synthèse du juryPE
# *****************************************************************************************************************
def synthetise_juryPE(self):
"""Synthétise tous les résultats du jury PE dans un dictionnaire"""
self.syntheseJury = {}
for etudid in self.etudiants.get_etudids(self.diplome):
etudinfo = self.ETUDINFO_DICT[etudid]
self.syntheseJury[etudid] = {
"nom": etudinfo["nom"],
"prenom": etudinfo["prenom"],
"civilite": etudinfo["civilite"],
"civilite_str": etudinfo["civilite_str"],
"age": str(pe_tools.calcul_age(etudinfo["date_naissance"])),
"lycee": etudinfo["nomlycee"]
+ (
" (" + etudinfo["villelycee"] + ")"
if etudinfo["villelycee"] != ""
else ""
),
"bac": etudinfo["bac"],
"code_nip": etudinfo["code_nip"], # pour la photo
"entree": self.get_dateEntree(etudid),
"promo": self.diplome,
}
# Le parcours
self.syntheseJury[etudid]["parcours"] = self.get_parcoursIUT(
etudid
) # liste des semestres
self.syntheseJury[etudid]["nbSemestres"] = len(
self.syntheseJury[etudid]["parcours"]
) # nombre de semestres
# Ses résultats
for nom in pe_tools.PARCOURS: # S1, puis S2, puis 1A
# dans le groupe : la table tagguée dans les semtag ou les settag si aggrégat
self.syntheseJury[etudid][nom] = {"groupe": {}, "promo": {}}
if (
self.etudiants.cursus[etudid][nom] != None
): # Un parcours valide existe
if nom in pe_tools.TOUS_LES_SEMESTRES:
tagtable = self.semestres_taggues[
self.etudiants.cursus[etudid][nom]
]
else:
tagtable = self.aggregats_taggues[nom][
self.etudiants.cursus[etudid][nom]
]
for tag in tagtable.get_all_tags():
self.syntheseJury[etudid][nom]["groupe"][
tag
] = tagtable.get_resultatsEtud(
tag, etudid
) # Le tuple des résultats
# interclassé dans la promo
tagtable = self.promoTagDict[nom]
for tag in tagtable.get_all_tags():
self.syntheseJury[etudid][nom]["promo"][
tag
] = tagtable.get_resultatsEtud(tag, etudid)
def get_dateEntree(self, etudid):
"""Renvoie l'année d'entrée de l'étudiant à l'IUT"""
# etudinfo = self.ETUDINFO_DICT[etudid]
semestres = self.get_semestresBUT_d_un_etudiant(etudid)
if semestres:
# le 1er sem à l'IUT
return semestres[0]["annee_debut"]
else:
return ""
def get_parcoursIUT(self, etudid):
"""Renvoie une liste d'infos sur les semestres du parcours d'un étudiant"""
# etudinfo = self.ETUDINFO_DICT[etudid]
sems = self.etudiants.semestres_etudiant(etudid)
infos = []
for sem in sems:
nomsem = comp_nom_semestre_dans_parcours(sem)
infos.append(
{
"nom_semestre_dans_parcours": nomsem,
"titreannee": sem["titreannee"],
"formsemestre_id": sem["formsemestre_id"], # utile dans le futur ?
}
)
return infos
# **************************************************************************************************************** #
# Méthodes d'affichage pour debug
# **************************************************************************************************************** #
def str_etudiants_in_jury(self, delim=";"):
# En tete:
entete = ["Id", "Nom", "Abandon", "Diplome"]
for nom_sem in pe_tools.TOUS_LES_PARCOURS:
entete += [nom_sem, "descr"]
chaine = delim.join(entete) + "\n"
for etudid in self.etudiants.cursus:
donnees = self.etudiants.cursus[etudid]
# pe_tools.pe_print(etudid, donnees)
# les infos générales
descr = [
etudid,
donnees["nom"],
str(donnees["abandon"]),
str(donnees["diplome"]),
]
# les semestres et les aggrégats
for nom_sem in pe_tools.TOUS_LES_PARCOURS:
table = (
self.semestres_taggues[donnees[nom_sem]].nom
if donnees[nom_sem] in self.semestres_taggues
else "manquant"
)
descr += [
donnees[nom_sem] if donnees[nom_sem] != None else "manquant",
table,
]
chaine += delim.join(descr) + "\n"
return chaine
#
def export_juryPEDict(self):
"""Export csv de self.PARCOURSINFO_DICT"""
fichier = "juryParcoursDict_" + str(self.diplome)
pe_tools.pe_print(" -> Export de " + fichier)
filename = self.nom_export_zip + fichier + ".csv"
self.zipfile.writestr(filename, self.str_etudiants_in_jury())
def get_allTagForAggregat(self, nom_aggregat):
"""Extrait du dictionnaire syntheseJury la liste des tags d'un semestre ou
d'un aggrégat donné par son nom (S1, S2, S3 ou S4, 1A, ...). Renvoie [] si aucun tag.
"""
taglist = set()
for etudid in self.etudiants.get_etudids():
taglist = taglist.union(
set(self.syntheseJury[etudid][nom_aggregat]["groupe"].keys())
)
taglist = taglist.union(
set(self.syntheseJury[etudid][nom_aggregat]["promo"].keys())
)
return list(taglist)
def get_allTagInSyntheseJury(self):
"""Extrait tous les tags du dictionnaire syntheseJury trié par
ordre alphabétique. [] si aucun tag"""
allTags = set()
for nom in pe_tools.TOUS_LES_PARCOURS:
allTags = allTags.union(set(self.get_allTagForAggregat(nom)))
return sorted(list(allTags)) if len(allTags) > 0 else []
def table_syntheseJury(self, mode="singlesheet"): # was str_syntheseJury
"""Table(s) du jury
mode: singlesheet ou multiplesheet pour export excel
"""
sT = SeqGenTable() # le fichier excel à générer
# Les etudids des étudiants à afficher, triés par ordre alphabétiques de nom+prénom
donnees_tries = sorted(
[
(
etudid,
self.syntheseJury[etudid]["nom"]
+ " "
+ self.syntheseJury[etudid]["prenom"],
)
for etudid in self.syntheseJury.keys()
],
key=lambda c: c[1],
)
etudids = [e[0] for e in donnees_tries]
if not etudids: # Si pas d'étudiants
T = GenTable(
columns_ids=["pas d'étudiants"],
rows=[],
titles={"pas d'étudiants": "pas d'étudiants"},
html_sortable=True,
xls_sheet_name="but",
)
sT.add_genTable("but", T)
return sT
# Si des étudiants
maxParcours = max(
[self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
)
infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
entete = ["etudid"]
entete.extend(infos)
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)])
champs = [
"note",
"class groupe",
"class promo",
"min/moy/max groupe",
"min/moy/max promo",
]
# Les aggrégats à afficher par ordre tel que indiqué dans le dictionnaire parcours
aggregats = list(pe_tools.PARCOURS.keys()) # ['S1', 'S2', ..., '1A', '4S']
# aggregats = sorted(
# aggregats, key=lambda t: pe_tools.PARCOURS[t]["ordre"]
# ) # Tri des aggrégats
if mode == "multiplesheet":
allSheets = (
self.get_allTagInSyntheseJury()
) # tous les tags de syntheseJuryDict
allSheets = sorted(allSheets) # Tri des tags par ordre alphabétique
for sem in pe_tools.TOUS_LES_PARCOURS:
entete.extend(["%s %s" % (sem, champ) for champ in champs])
else: # "singlesheet"
allSheets = ["singlesheet"]
for (
sem
) in (
pe_tools.TOUS_LES_PARCOURS
): # pe_tools.PARCOURS.keys() -> ['S1', 'S2', ..., '1A', '4S']
tags = self.get_allTagForAggregat(sem)
entete.extend(
["%s %s %s" % (sem, tag, champ) for tag in tags for champ in champs]
)
columns_ids = entete # les id et les titres de colonnes sont ici identiques
titles = {i: i for i in columns_ids}
for (
sheet
) in (
allSheets
): # Pour tous les sheets à générer (1 si singlesheet, autant que de tags si multiplesheet)
rows = []
for etudid in etudids:
e = self.syntheseJury[etudid]
# Les info générales:
row = {
"etudid": etudid,
"civilite": e["civilite"],
"nom": e["nom"],
"prenom": e["prenom"],
"age": e["age"],
"nbSemestres": e["nbSemestres"],
}
# Les parcours: P1, P2, ...
n = 1
for p in e["parcours"]:
row["P%d" % n] = p["titreannee"]
n += 1
# if self.syntheseJury[etudid]['nbSemestres'] < maxParcours:
# descr += delim.join( ['']*( maxParcours -self.syntheseJury[etudid]['nbSemestres']) ) + delim
for sem in aggregats: # pe_tools.PARCOURS.keys():
listeTags = (
self.get_allTagForAggregat(sem)
if mode == "singlesheet"
else [sheet]
)
for tag in listeTags:
if tag in self.syntheseJury[etudid][sem]["groupe"]:
resgroupe = self.syntheseJury[etudid][sem]["groupe"][
tag
] # tuple
else:
resgroupe = (None, None, None, None, None, None, None)
if tag in self.syntheseJury[etudid][sem]["promo"]:
respromo = self.syntheseJury[etudid][sem]["promo"][tag]
else:
respromo = (None, None, None, None, None, None, None)
# note = "%2.2f" % resgroupe[0] if isinstance(resgroupe[0], float) else str(resgroupe[0])
champ = (
"%s %s " % (sem, tag)
if mode == "singlesheet"
else "%s " % (sem)
)
row[champ + "note"] = scu.fmt_note(resgroupe[0])
row[champ + "class groupe"] = "%s / %s" % (
resgroupe[2] if resgroupe[2] else "-",
resgroupe[3] if resgroupe[3] else "-",
)
row[champ + "class promo"] = "%s / %s" % (
respromo[2] if respromo[2] else "-",
respromo[3] if respromo[3] else "-",
)
row[champ + "min/moy/max groupe"] = "%s / %s / %s" % tuple(
(scu.fmt_note(x) if x is not None else "-")
for x in (resgroupe[6], resgroupe[4], resgroupe[5])
)
row[champ + "min/moy/max promo"] = "%s / %s / %s" % tuple(
(scu.fmt_note(x) if x is not None else "-")
for x in (respromo[6], respromo[4], respromo[5])
)
rows.append(row)
T = GenTable(
columns_ids=columns_ids,
rows=rows,
titles=titles,
html_sortable=True,
xls_sheet_name=sheet,
)
sT.add_genTable(sheet, T)
if mode == "singlesheet":
return sT.get_genTable("singlesheet")
else:
return sT
# **************************************************************************************************************** #
# Méthodes de classe pour gestion d'un cache de données accélérant les calculs / intérêt à débattre
# **************************************************************************************************************** #
# ------------------------------------------------------------------------------------------------------------------
def get_cache_etudInfo_d_un_etudiant(self, etudid):
"""Renvoie les informations sur le parcours d'un étudiant soit en les relisant depuis
ETUDINFO_DICT si mémorisée soit en les chargeant et en les mémorisant
TODO:: A supprimer à long terme
"""
if etudid not in self.ETUDINFO_DICT:
self.ETUDINFO_DICT[etudid] = Identite.get_etud(etudid=etudid)
# sco_etud.get_etud_info(
# etudid=etudid, filled=True
# ))[0]
return self.ETUDINFO_DICT[etudid]
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_cache_notes_d_un_semestre(self, formsemestre_id: int) -> NotesTableCompat:
"""Charge la table des notes d'un formsemestre"""
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
return res_sem.load_formsemestre_results(formsemestre)
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_semestresBUT_d_un_etudiant(self, identite: Identite, semestre_id=None):
"""cf. pe_etudiant.semestres_etudiant()"""
return None
# *********************************************
# Fonctions d'affichage pour debug
def get_resultat_d_un_etudiant(self, etudid):
chaine = ""
for nom_sem in pe_tools.TOUS_LES_SEMESTRES:
semtagid = self.etudiants.cursus[etudid][
nom_sem
] # le formsemestre_id du semestre taggué de l'étudiant
semtag = self.semestres_taggues[semtagid]
chaine += "Semestre " + nom_sem + str(semtagid) + "\n"
# le détail du calcul tag par tag
# chaine += "Détail du calcul du tag\n"
# chaine += "-----------------------\n"
# for tag in semtag.taglist:
# chaine += "Tag=" + tag + "\n"
# chaine += semtag.str_detail_resultat_d_un_tag(tag, etudid=etudid) + "\n"
# le bilan des tags
chaine += "Bilan des tags\n"
chaine += "--------------\n"
for tag in semtag.taglist:
chaine += (
tag + ";" + semtag.str_resTag_d_un_etudiant(tag, etudid) + "\n"
)
chaine += "\n"
return chaine
def get_date_entree_etudiant(self, etudid) -> str:
"""Renvoie la date d'entree d'un étudiant: "1996" """
annees_debut = [
int(sem["annee_debut"]) for sem in self.ETUDINFO_DICT[etudid]["sems"]
]
if annees_debut:
return str(min(annees_debut))
return ""
def compute_semestres_tag(etudiants: EtudiantsJuryPE):
"""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_tools.pe_print("*** Création des semestres taggués")
formsemestres = etudiants.get_formsemestres_jury(
semestres_recherches=pe_tools.TOUS_LES_SEMESTRES
)
semestres_tags = {}
for frmsem_id, formsemestre in formsemestres.items():
"""Choix d'un nom pour le semestretag"""
nom = "S%d %d %d-%d" % (
formsemestre.semestre_id,
frmsem_id,
formsemestre.date_debut.year,
formsemestre.date_fin.year,
)
pe_tools.pe_print(f" --> Semestre taggué {nom} sur la base de {formsemestre}")
"""Créé le semestre_tag et exécute les calculs de moyennes"""
formsemestretag = pe_semestretag.SemestreTag(nom, frmsem_id)
"""Stocke le semestre taggué"""
semestres_tags[frmsem_id] = formsemestretag
return semestres_tags
def compute_aggregats_tag(
self, etudiants: EtudiantsJuryPE, semestres_tag: dict[SemestreTag]
):
"""Créé les combinaisons de semestres (aggrégat), en calculant les moyennes et les
classements par tag pour chacune. Chaque combinaison (aggrégat) est identifiée
par un formsemestre terminal.
Par exemple :
* combinaisons '3S' : S1+S2+S3 en prenant en compte tous les S3 qu'ont fréquentés les
étudiants du jury PE. Ces S3 marquent les formsemestre terminal de chaque combinaison.
Args:
etudiants: Les données des étudiants
semestres_tag: Les semestres tag (pour lesquels des moyennes par tag ont été calculés)
Return:
Un dictionnaire de la forme {nom_aggregat: {fid_terminal: SetTag(fid_terminal)} }
"""
pe_tools.pe_print(" *** Création des aggrégats ")
sets_tags = {}
for aggregat in pe_tools.TOUS_LES_AGGREGATS:
sets_tags[aggregat] = {}
"""Semestres aggrégés"""
noms_semestres_aggreges = pe_tools.PARCOURS[aggregat]["aggregat"]
nom_semestre_terminal = noms_semestres_aggreges[-1]
pe_tools.pe_print(f"* {aggregat}: " + "+".join(noms_semestres_aggreges))
"""Les formsemestres terminaux des aggrégats"""
formsemestres_terminal = etudiants.get_formsemestres_terminaux_aggregat(
aggregat
)
for frmsem_id in formsemestres_terminal:
formsemestre_terminal = formsemestres_terminal[frmsem_id]
"""Nom du set_tag"""
nom = "Aggrégat S%d %d %d-%d" % (
formsemestre_terminal.semestre_id,
frmsem_id,
formsemestre_terminal.date_debut.year,
formsemestre_terminal.date_fin.year,
)
"""Semestres à aggreger dans l'aggrégat ayant amené des étudiants jusqu'au formsemestre_terminal"""
semestres_aggreges = etudiants.get_semestres_a_aggreger(aggregat, frmsem_id)
pe_tools.pe_print(" --> Fusion de :")
for fid in semestres_aggreges:
pe_tools.pe_print(str(semestres_aggreges[fid]))
"""Création du settag associé"""
settag = pe_settag.SetTag(
nom, formsemestre_terminal, semestres_aggreges, semestres_tag, etudiants
)
settag.compute_notes_cube() # Calcul les moyennes, les rangs, ..
sets_tags[aggregat][fid] = settag # Mémorise le résultat
return sets_tags