forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -45,10 +45,15 @@ class ParametrageClasseurPE(FlaskForm):
|
||||
default=True,
|
||||
render_kw={"checked": ""},
|
||||
)
|
||||
moyennes_ues_rcues = BooleanField("Générer les moyennes par RCUEs (compétences)")
|
||||
moyennes_ues_rcues = BooleanField(
|
||||
"Générer les moyennes par RCUEs (compétences)",
|
||||
default=True,
|
||||
render_kw={"checked": ""},
|
||||
)
|
||||
|
||||
min_max_moy = BooleanField("Afficher les colonnes min/max/moy")
|
||||
synthese_individuelle_etud = BooleanField(
|
||||
"Générer la feuille synthèse avec un onglet par étudiant"
|
||||
"Générer les synthèses HTML étudiant par étudiant"
|
||||
)
|
||||
|
||||
submit = SubmitField("Générer les classeurs poursuites d'études")
|
||||
|
@ -207,3 +207,28 @@ def repr_comp_et_ues(acronymes_ues_to_competences):
|
||||
liste += ["📍" + acro]
|
||||
aff_comp += [f" 💡{comp} (⇔ {', '.join(liste)})"]
|
||||
return "\n".join(aff_comp)
|
||||
|
||||
|
||||
def aff_rcsemxs_suivis_par_etudiants(etudiants):
|
||||
"""Affiche les RCSemX (regroupement de SemX)
|
||||
amenant un étudiant du S1 à un Sx"""
|
||||
etudiants_ids = etudiants.etudiants_ids
|
||||
jeunes = list(enumerate(etudiants_ids))
|
||||
|
||||
for no_etud, etudid in jeunes:
|
||||
etat = "⛔" if etudid in etudiants.abandons_ids else "✅"
|
||||
pe_print(f"-> {etat} {etudiants.identites[etudid].nomprenom} :")
|
||||
for nom_rcs, rcs in etudiants.rcsemXs[etudid].items():
|
||||
if rcs:
|
||||
pe_print(f" > RCSemX ⏯️{nom_rcs}: {rcs.get_repr()}")
|
||||
|
||||
vides = []
|
||||
for nom_rcs in pe_rcs.TOUS_LES_RCS:
|
||||
les_rcssemX_suivis = []
|
||||
for no_etud, etudid in jeunes:
|
||||
if etudiants.rcsemXs[etudid][nom_rcs]:
|
||||
les_rcssemX_suivis.append(etudiants.rcsemXs[etudid][nom_rcs])
|
||||
if not les_rcssemX_suivis:
|
||||
vides += [nom_rcs]
|
||||
vides = sorted(list(set(vides)))
|
||||
pe_print(f"⚠️ RCSemX vides : {', '.join(vides)}")
|
||||
|
@ -69,6 +69,9 @@ class EtudiantsJuryPE:
|
||||
self.semXs: dict[int:dict] = {}
|
||||
"""Les semXs (RCS de type Sx) suivis par chaque étudiant"""
|
||||
|
||||
self.rcsemXs: dict[int:dict] = {}
|
||||
"""Les RC de SemXs (RCS de type Sx, xA, xS) suivis par chaque étudiant"""
|
||||
|
||||
self.etudiants_diplomes = {}
|
||||
"""Les identités des étudiants à considérer au jury (ceux qui seront effectivement
|
||||
diplômés)"""
|
||||
@ -274,6 +277,7 @@ class EtudiantsJuryPE:
|
||||
# Initialise ses trajectoires/SemX/RCSemX
|
||||
self.trajectoires[etudid] = {aggregat: None for aggregat in pe_rcs.TOUS_LES_RCS}
|
||||
self.semXs[etudid] = {aggregat: None for aggregat in pe_rcs.TOUS_LES_SEMESTRES}
|
||||
self.rcsemXs[etudid] = {aggregat: None for aggregat in pe_rcs.TOUS_LES_RCS}
|
||||
|
||||
def structure_cursus_etudiant(self, etudid: int):
|
||||
"""Structure les informations sur les semestres suivis par un
|
||||
|
@ -102,9 +102,8 @@ class JuryPE(object):
|
||||
"Nom du zip où ranger les fichiers générés"
|
||||
|
||||
# Les options
|
||||
|
||||
self.options = options
|
||||
"""Options de configuration"""
|
||||
"""Options de configuration (cf. pe_sem_recap)"""
|
||||
|
||||
pe_affichage.pe_print(
|
||||
f"Données de poursuite d'étude générées le {time.strftime('%d/%m/%Y à %H:%M')}\n",
|
||||
@ -350,8 +349,9 @@ class JuryPE(object):
|
||||
pe_affichage.pe_print(
|
||||
"""******************************************************************************"""
|
||||
)
|
||||
self.rcss_jury.cree_rcsemxs(self.etudiants)
|
||||
self.rcss_jury._aff_rcsemxs_suivis(self.etudiants)
|
||||
self.rcss_jury.cree_rcsemxs(options=self.options)
|
||||
if "moyennes_ues_rcues" in self.options and self.options["moyennes_ues_rcues"]:
|
||||
pe_affichage.aff_rcsemxs_suivis_par_etudiants(self.etudiants)
|
||||
|
||||
def _gen_xls_rcstags(self, zipfile: ZipFile):
|
||||
"""Génère les RCS taggués traduisant les moyennes (orientées compétences)
|
||||
@ -384,6 +384,20 @@ class JuryPE(object):
|
||||
)
|
||||
|
||||
pe_affichage.pe_print("1) Calcul des moyennes des RCSTag", info=True)
|
||||
if not self.rcss_jury.rcsemxs:
|
||||
if (
|
||||
"moyennes_ues_rcues" in self.options
|
||||
and not self.options["moyennes_ues_rcues"]
|
||||
):
|
||||
pe_affichage.pe_print(" -> Pas de RCSemX à calculer (cf. options)")
|
||||
else:
|
||||
pe_affichage.pe_print(
|
||||
" -> Pas de RCSemX à calculer (alors qu'aucune option ne les limite) => problème"
|
||||
)
|
||||
self.rcsstags = {}
|
||||
return
|
||||
|
||||
# Calcul des RCSTags sur la base des RCSemX
|
||||
self.rcsstags = {}
|
||||
for rcs_id, rcsemx in self.rcss_jury.rcsemxs.items():
|
||||
self.rcsstags[rcs_id] = pe_rcstag.RCSemXTag(
|
||||
@ -431,20 +445,26 @@ class JuryPE(object):
|
||||
"""******************************************************************"""
|
||||
)
|
||||
pe_affichage.pe_print(
|
||||
"""*** Génère les interclassements sur chaque type de RCS/agrgégat"""
|
||||
"""*** Génère les interclassements sur chaque type de RCS/agrégat"""
|
||||
)
|
||||
pe_affichage.pe_print(
|
||||
"""******************************************************************"""
|
||||
)
|
||||
|
||||
self.interclasstags = {
|
||||
pe_moytag.CODE_MOY_UE: {},
|
||||
pe_moytag.CODE_MOY_COMPETENCES: {},
|
||||
}
|
||||
if (
|
||||
"moyennes_ues_rcues" not in self.options
|
||||
or self.options["moyennes_ues_rcues"]
|
||||
):
|
||||
self.interclasstags = {
|
||||
pe_moytag.CODE_MOY_UE: {},
|
||||
pe_moytag.CODE_MOY_COMPETENCES: {},
|
||||
}
|
||||
else:
|
||||
self.interclasstags = {pe_moytag.CODE_MOY_UE: {}}
|
||||
|
||||
etudiants_diplomes = self.etudiants.etudiants_diplomes
|
||||
|
||||
# Les interclassements par UE
|
||||
# Les interclassements par UE (toujours présents par défaut)
|
||||
for Sx in pe_rcs.TOUS_LES_SEMESTRES:
|
||||
interclass = pe_interclasstag.InterClassTag(
|
||||
Sx,
|
||||
@ -457,16 +477,22 @@ class JuryPE(object):
|
||||
self.interclasstags[pe_moytag.CODE_MOY_UE][Sx] = interclass
|
||||
|
||||
# Les interclassements par compétences
|
||||
for nom_rcs in pe_rcs.TOUS_LES_RCS:
|
||||
interclass = pe_interclasstag.InterClassTag(
|
||||
nom_rcs,
|
||||
pe_moytag.CODE_MOY_COMPETENCES,
|
||||
etudiants_diplomes,
|
||||
self.rcss_jury.rcsemxs,
|
||||
self.rcsstags,
|
||||
self.rcss_jury.rcsemxs_suivis,
|
||||
)
|
||||
self.interclasstags[pe_moytag.CODE_MOY_COMPETENCES][nom_rcs] = interclass
|
||||
if (
|
||||
"moyennes_ues_rcues" not in self.options
|
||||
or self.options["moyennes_ues_rcues"]
|
||||
):
|
||||
for nom_rcs in pe_rcs.TOUS_LES_RCS:
|
||||
interclass = pe_interclasstag.InterClassTag(
|
||||
nom_rcs,
|
||||
pe_moytag.CODE_MOY_COMPETENCES,
|
||||
etudiants_diplomes,
|
||||
self.rcss_jury.rcsemxs,
|
||||
self.rcsstags,
|
||||
self.rcss_jury.rcsemxs_suivis,
|
||||
)
|
||||
self.interclasstags[pe_moytag.CODE_MOY_COMPETENCES][
|
||||
nom_rcs
|
||||
] = interclass
|
||||
|
||||
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
|
||||
output = io.BytesIO()
|
||||
@ -474,10 +500,9 @@ class JuryPE(object):
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for type_interclass in [
|
||||
pe_moytag.CODE_MOY_UE,
|
||||
pe_moytag.CODE_MOY_COMPETENCES,
|
||||
]:
|
||||
for (
|
||||
type_interclass
|
||||
) in self.interclasstags: # Pour les types d'interclassements prévus
|
||||
interclasstag = self.interclasstags[type_interclass]
|
||||
for nom_rcs, interclass in interclasstag.items():
|
||||
if interclass.is_significatif():
|
||||
@ -522,7 +547,7 @@ class JuryPE(object):
|
||||
|
||||
tags = self._do_tags_list(self.interclasstags)
|
||||
for tag in tags:
|
||||
for type_moy in [pe_moytag.CODE_MOY_UE, pe_moytag.CODE_MOY_COMPETENCES]:
|
||||
for type_moy in self.interclasstags:
|
||||
self.synthese[(tag, type_moy)] = self.df_tag_type(tag, type_moy)
|
||||
|
||||
# Export des données => mode 1 seule feuille -> supprimé
|
||||
@ -555,7 +580,7 @@ class JuryPE(object):
|
||||
|
||||
if onglets:
|
||||
self.add_file_to_zip(
|
||||
zipfile, f"synthese_jury_{self.diplome}_par_tag.xlsx", output.read()
|
||||
zipfile, f"synthese_jury_{self.diplome}.xlsx", output.read()
|
||||
)
|
||||
|
||||
def _gen_html_synthese_par_etudiant(self, zipfile: ZipFile):
|
||||
@ -565,12 +590,18 @@ class JuryPE(object):
|
||||
pe_affichage.pe_print("*** Synthèse finale étudiant par étudiant", info=True)
|
||||
pe_affichage.pe_print("**************************************************")
|
||||
|
||||
etudids = list(self.diplomes_ids)
|
||||
for etudid in etudids:
|
||||
nom, prenom, html = self.synthetise_jury_etudiant(etudid)
|
||||
self.add_file_to_zip(
|
||||
zipfile, f"{nom}_{prenom}.html", html, path="etudiants"
|
||||
)
|
||||
if (
|
||||
"moyennes_ues_rcues" not in self.options
|
||||
or self.options["moyennes_ues_rcues"]
|
||||
):
|
||||
etudids = list(self.diplomes_ids)
|
||||
for etudid in etudids:
|
||||
nom, prenom, html = self.synthetise_jury_etudiant(etudid)
|
||||
self.add_file_to_zip(
|
||||
zipfile, f"{nom}_{prenom}.html", html, path="etudiants"
|
||||
)
|
||||
else:
|
||||
pe_affichage.pe_print(" > Pas de synthèse étudiant/étudiant possible/prévu")
|
||||
|
||||
def _add_log_to_zip(self, zipfile):
|
||||
"""Add a text file with the log messages"""
|
||||
|
@ -117,7 +117,7 @@ class RCSsJuryPE:
|
||||
self.semXs_suivis[etudid][agregat] = semX
|
||||
self.etudiants.semXs[etudid][agregat] = semX
|
||||
|
||||
def cree_rcsemxs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
def cree_rcsemxs(self, options={"moyennes_ues_rcues": True}):
|
||||
"""Créé tous les RCSemXs, au regard du cursus des étudiants
|
||||
analysés (trajectoires traduisant son parcours dans les
|
||||
différents semestres) + les mémorise dans les données de l'étudiant
|
||||
@ -125,6 +125,11 @@ class RCSsJuryPE:
|
||||
self.rcsemxs_suivis = {}
|
||||
self.rcsemxs = {}
|
||||
|
||||
if "moyennes_ues_rcues" in options and options["moyennes_ues_rcues"] == False:
|
||||
# Pas de RCSemX généré
|
||||
pe_affichage.pe_print("⚠️ Pas de RCSemX générés")
|
||||
return
|
||||
|
||||
# Pour tous les étudiants du jury
|
||||
pas_de_semestres = []
|
||||
for etudid in self.trajectoires_suivies:
|
||||
@ -132,20 +137,11 @@ class RCSsJuryPE:
|
||||
nom_rcs: None for nom_rcs in pe_rcs.TOUS_LES_RCS_AVEC_PLUSIEURS_SEM
|
||||
}
|
||||
|
||||
# Recopie des SemX & des suivis associés => est-ce utile ?
|
||||
# for nom_rcs in pe_rcs.TOUS_LES_SEMESTRES:
|
||||
# trajectoire = self.semXs_suivis[etudid][nom_rcs]
|
||||
# if trajectoire:
|
||||
# self.rcsemxs[trajectoire.rcs_id] = trajectoire
|
||||
# self.rcsemxs_suivis[etudid][nom_rcs] = trajectoire
|
||||
|
||||
# Pour chaque aggréggat de type xA ou Sx
|
||||
tous_les_agregats = pe_rcs.TOUS_LES_RCS
|
||||
|
||||
for nom_rcs in tous_les_agregats:
|
||||
trajectoire = self.trajectoires_suivies[etudid][nom_rcs]
|
||||
# Pour chaque aggréggat de type xA ou Sx ou xS
|
||||
for agregat in pe_rcs.TOUS_LES_RCS:
|
||||
trajectoire = self.trajectoires_suivies[etudid][agregat]
|
||||
if not trajectoire:
|
||||
self.rcsemxs_suivis[etudid][nom_rcs] = None
|
||||
self.rcsemxs_suivis[etudid][agregat] = None
|
||||
else:
|
||||
# Identifiant de la trajectoire => donnera ceux du RCSemX
|
||||
tid = trajectoire.rcs_id
|
||||
@ -159,14 +155,14 @@ class RCSsJuryPE:
|
||||
# Par ex: dans S1+S2+S1+S2+S3 => les 2 S1 devient le SemX('S1'), les 2 S2 le SemX('S2'), etc..
|
||||
|
||||
# Les Sx pris en compte dans l'aggrégat
|
||||
noms_sems_aggregat = pe_rcs.TYPES_RCS[nom_rcs]["aggregat"]
|
||||
noms_sems_aggregat = pe_rcs.TYPES_RCS[agregat]["aggregat"]
|
||||
|
||||
semxs_a_aggreger = {}
|
||||
for Sx in noms_sems_aggregat:
|
||||
semestres_etudiants = etudiants.cursus[etudid][Sx]
|
||||
semestres_etudiants = self.etudiants.cursus[etudid][Sx]
|
||||
if not semestres_etudiants:
|
||||
pas_de_semestres += [
|
||||
f"{Sx} pour {etudiants.identites[etudid].nomprenom}"
|
||||
f"{Sx} pour {self.etudiants.identites[etudid].nomprenom}"
|
||||
]
|
||||
else:
|
||||
semx_id = get_semx_from_semestres_aggreges(
|
||||
@ -184,9 +180,10 @@ class RCSsJuryPE:
|
||||
rcsemx.add_semXs(semxs_a_aggreger)
|
||||
|
||||
# Mémoire du RCSemX aux informations de suivi de l'étudiant
|
||||
self.rcsemxs_suivis[etudid][nom_rcs] = rcsemx
|
||||
self.rcsemxs_suivis[etudid][agregat] = rcsemx
|
||||
self.etudiants.rcsemXs[etudid][agregat] = rcsemx
|
||||
|
||||
# Affichage des étudiants pour lesquels il manque un semestre
|
||||
# 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 :")
|
||||
@ -194,30 +191,6 @@ class RCSsJuryPE:
|
||||
"\n".join([" " * 10 + psd for psd in pas_de_semestres])
|
||||
)
|
||||
|
||||
def _aff_rcsemxs_suivis(self, etudiants):
|
||||
"""Affiche les RCSemX suivis par les étudiants"""
|
||||
# Affichage pour debug
|
||||
jeunes = list(enumerate(self.rcsemxs_suivis.keys()))
|
||||
for no_etud, etudid in jeunes:
|
||||
etat = "⛔" if etudid in etudiants.abandons_ids else "✅"
|
||||
pe_affichage.pe_print(
|
||||
f"-> {etat} {etudiants.identites[etudid].nomprenom} :"
|
||||
)
|
||||
for nom_rcs, rcs in self.rcsemxs_suivis[etudid].items():
|
||||
if rcs:
|
||||
pe_affichage.pe_print(f" > RCSemX ⏯️{nom_rcs}: {rcs.get_repr()}")
|
||||
|
||||
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(
|
||||
semestres: dict[int:FormSemestre], formsemestre_final: FormSemestre, nom_rcs: str
|
||||
|
Loading…
Reference in New Issue
Block a user