ScoDoc/app/pe/pe_jurype.py

743 lines
31 KiB
Python
Raw Normal View History

2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# 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
"""
2024-01-20 16:34:38 +01:00
import datetime
2020-09-26 16:19:37 +02:00
# ----------------------------------------------------------
# Ensemble des fonctions et des classes
# permettant les calculs preliminaires (hors affichage)
# a l'edition d'un jury de poursuites d'etudes
# ----------------------------------------------------------
2021-08-31 20:18:50 +02:00
import io
2021-02-01 23:54:46 +01:00
import os
2021-08-31 20:18:50 +02:00
from zipfile import ZipFile
2020-09-26 16:19:37 +02:00
2024-01-20 16:34:38 +01:00
import app.pe.pe_etudiant
2024-01-21 18:55:21 +01:00
import app.pe.pe_settag_interclasse
2022-02-11 09:11:07 +01:00
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
2024-01-20 16:34:38 +01:00
from app.comp.res_sem import load_formsemestre_results
from app.models import Formation, FormSemestre
2024-01-20 16:34:38 +01:00
from app.models.etudiants import Identite
2024-01-21 18:55:21 +01:00
from app.pe.pe_semestretag import SemestreTag
2022-02-11 09:11:07 +01:00
from app.scodoc.gen_tables import GenTable, SeqGenTable
import app.scodoc.sco_utils as scu
2024-01-20 16:34:38 +01:00
from app.scodoc import (
codes_cursus,
sco_formsemestre_inscriptions,
) # codes_cursus.NEXT -> sem suivant
2021-06-21 10:17:16 +02:00
from app.scodoc import sco_etud
2024-01-20 16:34:38 +01:00
from app.scodoc import sco_report
2021-06-21 11:22:55 +02:00
from app.scodoc import sco_formsemestre
2021-09-26 10:01:20 +02:00
from app.pe import pe_tagtable
from app.pe import pe_tools
from app.pe import pe_semestretag
2024-01-24 15:37:50 +01:00
from app.pe import pe_trajectoiretag
2024-01-20 16:34:38 +01:00
from app.pe.pe_etudiant import EtudiantsJuryPE
2024-01-24 15:37:50 +01:00
from app.pe.pe_trajectoire import TrajectoiresJuryPE
2020-09-26 16:19:37 +02:00
2023-12-31 23:04:06 +01:00
2020-09-26 16:19:37 +02:00
# ----------------------------------------------------------------------------------------
def comp_nom_semestre_dans_parcours(sem):
2020-09-26 16:19:37 +02:00
"""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)
2020-09-26 16:19:37 +02:00
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
)
# ----------------------------------------------------------------------------------------
2021-07-09 23:31:16 +02:00
class JuryPE(object):
"""Classe mémorisant toutes les informations nécessaires pour établir un jury de PE.
Modèle basé sur NotesTable.
2020-09-26 16:19:37 +02:00
Attributs :
2021-01-01 18:40:47 +01:00
2024-01-20 16:34:38 +01:00
* 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
2020-09-26 16:19:37 +02:00
"""
# Variables de classe décrivant les aggrégats, leur ordre d'apparition temporelle et
# leur affichage dans les avis latex
2020-09-26 16:19:37 +02:00
# ------------------------------------------------------------------------------------------------------------------
2024-01-20 16:34:38 +01:00
def __init__(self, diplome, formation_id):
2020-09-26 16:19:37 +02:00
"""
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)
2020-09-26 16:19:37 +02:00
meme_programme: si True, impose un même programme pour tous les étudiants participant au jury,
si False, permet des programmes differents
"""
self.promoTagDict = {}
2024-01-20 16:34:38 +01:00
"L'année du diplome"
self.diplome = diplome
"La formation associée au diplome"
self.formation_id = formation_id
2020-09-26 16:19:37 +02:00
2024-01-20 16:34:38 +01:00
"Un zip où ranger les fichiers générés"
self.nom_export_zip = "Jury_PE_%s" % self.diplome
2021-08-31 20:18:50 +02:00
self.zipdata = io.BytesIO()
2020-09-26 16:19:37 +02:00
self.zipfile = ZipFile(self.zipdata, "w")
self.syntheseJury = {} # Le jury de synthèse
2024-01-20 16:34:38 +01:00
"""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(self.diplome) # Les infos sur les étudiants
self.etudiants.find_etudiants(self.formation_id)
2024-01-20 16:34:38 +01:00
2024-01-21 18:55:21 +01:00
"""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"
)
2024-01-24 15:37:50 +01:00
"""Génère les trajectoires (combinaison de semestres suivis
par un étudiant pour atteindre le semestre final d'un aggrégat)
"""
self.trajectoires = TrajectoiresJuryPE(self.diplome)
self.trajectoires.cree_trajectoires(self.etudiants)
2024-01-21 18:55:21 +01:00
"""Génère les aggrégats de semestre (par ex: 1A, 3S, 5S) avec calcul
des moyennes pour le jury"""
2024-01-24 15:37:50 +01:00
self.trajectoires_tagguees = compute_trajectoires_tag(
2024-01-23 19:08:54 +01:00
self.etudiants, self.semestres_taggues
)
2024-01-21 18:55:21 +01:00
if pe_tools.PE_DEBUG:
"""Intègre le bilan des aggrégats de semestres au zip final"""
2024-01-24 15:37:50 +01:00
for aggregat in self.trajectoires_tagguees:
for fid in self.trajectoires_tagguees[aggregat]:
set_tag = self.trajectoires_tagguees[aggregat][fid]
2024-01-21 18:55:21 +01:00
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"""
2024-01-23 19:08:54 +01:00
self.aggregats_taggues_interclasses = compute_interclassements(
self.etudiants, #
2024-01-24 15:37:50 +01:00
self.trajectoires_tagguees,
2024-01-23 19:08:54 +01:00
)
# 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"
)
2024-01-20 16:34:38 +01:00
"""Synthèse des éléments du jury PE"""
if False:
self.synthetise_juryPE()
2020-09-26 16:19:37 +02:00
# 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
2024-01-20 16:34:38 +01:00
if False:
filename = self.nom_export_zip + "_jurySyntheseDict" + scu.XLSX_SUFFIX
self.xlsV2 = self.table_syntheseJury(mode="multiplesheet")
if self.xlsV2:
2024-01-21 18:55:21 +01:00
pe_tools.add_file_to_zip(
self.nom_export_zip, filename, self.xlsV2.excel()
)
2020-09-26 16:19:37 +02:00
# Pour debug
# self.syntheseJury = pe_tools.JURY_SYNTHESE_POUR_DEBUG #Un dictionnaire fictif pour debug
2024-01-21 18:55:21 +01:00
def add_file_to_zip(self, filename: str, data, path=""):
2020-09-26 16:19:37 +02:00
"""Add a file to our zip
All files under NOM_EXPORT_ZIP/
path may specify a subdirectory
2024-01-21 18:55:21 +01:00
Args:
filename: Le nom du fichier à intégrer au zip
data: Les données du fichier
path: Un dossier dans l'arborescence du zip
2020-09-26 16:19:37 +02:00
"""
2024-01-20 16:34:38 +01:00
path_in_zip = os.path.join(self.nom_export_zip, path, filename)
2020-09-26 16:19:37 +02:00
self.zipfile.writestr(path_in_zip, data)
def get_zipped_data(self):
2021-08-31 20:18:50 +02:00
"""returns file-like data with a zip of all generated (CSV) files.
Reset file cursor at the beginning !
"""
2020-09-26 16:19:37 +02:00
if self.zipfile:
self.zipfile.close()
self.zipfile = None
2021-08-31 20:18:50 +02:00
self.zipdata.seek(0)
return self.zipdata
2020-09-26 16:19:37 +02:00
# **************************************************************************************************************** #
2024-01-20 16:34:38 +01:00
# Traitements des semestres impliqués dans le jury
2020-09-26 16:19:37 +02:00
# **************************************************************************************************************** #
# **************************************************************************************************************** #
# 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 = {}
2024-01-20 16:34:38 +01:00
for etudid in self.etudiants.get_etudids(self.diplome):
2020-09-26 16:19:37 +02:00
etudinfo = self.ETUDINFO_DICT[etudid]
self.syntheseJury[etudid] = {
"nom": etudinfo["nom"],
"prenom": etudinfo["prenom"],
"civilite": etudinfo["civilite"],
2021-02-16 15:18:06 +01:00
"civilite_str": etudinfo["civilite_str"],
2020-09-26 16:19:37 +02:00
"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
2020-09-26 16:19:37 +02:00
"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
2024-01-20 16:34:38 +01:00
for nom in pe_tools.PARCOURS: # S1, puis S2, puis 1A
2020-09-26 16:19:37 +02:00
# dans le groupe : la table tagguée dans les semtag ou les settag si aggrégat
self.syntheseJury[etudid][nom] = {"groupe": {}, "promo": {}}
if (
2024-01-20 16:34:38 +01:00
self.etudiants.cursus[etudid][nom] != None
2020-09-26 16:19:37 +02:00
): # Un parcours valide existe
2024-01-20 16:34:38 +01:00
if nom in pe_tools.TOUS_LES_SEMESTRES:
2024-01-21 18:55:21 +01:00
tagtable = self.semestres_taggues[
self.etudiants.cursus[etudid][nom]
]
2020-09-26 16:19:37 +02:00
else:
2024-01-24 15:37:50 +01:00
tagtable = self.trajectoires_tagguees[nom][
2024-01-20 16:34:38 +01:00
self.etudiants.cursus[etudid][nom]
2020-09-26 16:19:37 +02:00
]
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)
2024-01-16 15:51:22 +01:00
def get_dateEntree(self, etudid):
2020-09-26 16:19:37 +02:00
"""Renvoie l'année d'entrée de l'étudiant à l'IUT"""
2021-02-01 23:54:46 +01:00
# etudinfo = self.ETUDINFO_DICT[etudid]
semestres = self.get_semestresBUT_d_un_etudiant(etudid)
2022-08-30 11:09:13 +02:00
if semestres:
# le 1er sem à l'IUT
2022-09-08 09:48:19 +02:00
return semestres[0]["annee_debut"]
2022-08-30 11:09:13 +02:00
else:
return ""
2020-09-26 16:19:37 +02:00
2024-01-16 15:51:22 +01:00
def get_parcoursIUT(self, etudid):
2021-01-01 18:40:47 +01:00
"""Renvoie une liste d'infos sur les semestres du parcours d'un étudiant"""
2021-02-01 23:54:46 +01:00
# etudinfo = self.ETUDINFO_DICT[etudid]
2024-01-21 18:55:21 +01:00
sems = self.etudiants.semestres_etudiant(etudid)
2020-09-26 16:19:37 +02:00
infos = []
for sem in sems:
nomsem = comp_nom_semestre_dans_parcours(sem)
2020-09-26 16:19:37 +02:00
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
# **************************************************************************************************************** #
2024-01-16 15:51:22 +01:00
def str_etudiants_in_jury(self, delim=";"):
2020-09-26 16:19:37 +02:00
# En tete:
entete = ["Id", "Nom", "Abandon", "Diplome"]
2024-01-20 16:34:38 +01:00
for nom_sem in pe_tools.TOUS_LES_PARCOURS:
2020-09-26 16:19:37 +02:00
entete += [nom_sem, "descr"]
chaine = delim.join(entete) + "\n"
2024-01-20 16:34:38 +01:00
for etudid in self.etudiants.cursus:
donnees = self.etudiants.cursus[etudid]
2020-09-26 16:19:37 +02:00
# 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
2024-01-20 16:34:38 +01:00
for nom_sem in pe_tools.TOUS_LES_PARCOURS:
2020-09-26 16:19:37 +02:00
table = (
2024-01-21 18:55:21 +01:00
self.semestres_taggues[donnees[nom_sem]].nom
if donnees[nom_sem] in self.semestres_taggues
2020-09-26 16:19:37 +02:00
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)
2024-01-20 16:34:38 +01:00
filename = self.nom_export_zip + fichier + ".csv"
2020-09-26 16:19:37 +02:00
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
2023-12-31 23:04:06 +01:00
d'un aggrégat donné par son nom (S1, S2, S3 ou S4, 1A, ...). Renvoie [] si aucun tag.
"""
2020-09-26 16:19:37 +02:00
taglist = set()
2024-01-20 16:34:38 +01:00
for etudid in self.etudiants.get_etudids():
2020-09-26 16:19:37 +02:00
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"""
2020-09-26 16:19:37 +02:00
allTags = set()
2024-01-20 16:34:38 +01:00
for nom in pe_tools.TOUS_LES_PARCOURS:
2020-09-26 16:19:37 +02:00
allTags = allTags.union(set(self.get_allTagForAggregat(nom)))
return sorted(list(allTags)) if len(allTags) > 0 else []
2024-01-16 15:51:22 +01:00
def table_syntheseJury(self, mode="singlesheet"): # was str_syntheseJury
2020-09-26 16:19:37 +02:00
"""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",
2020-09-26 16:19:37 +02:00
)
sT.add_genTable("but", T)
2020-09-26 16:19:37 +02:00
return sT
# Si des étudiants
maxParcours = max(
[self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
)
infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
2020-09-26 16:19:37 +02:00
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
2024-01-20 16:34:38 +01:00
aggregats = list(pe_tools.PARCOURS.keys()) # ['S1', 'S2', ..., '1A', '4S']
# aggregats = sorted(
2024-01-20 16:34:38 +01:00
# aggregats, key=lambda t: pe_tools.PARCOURS[t]["ordre"]
# ) # Tri des aggrégats
2020-09-26 16:19:37 +02:00
if mode == "multiplesheet":
allSheets = (
self.get_allTagInSyntheseJury()
) # tous les tags de syntheseJuryDict
allSheets = sorted(allSheets) # Tri des tags par ordre alphabétique
2024-01-20 16:34:38 +01:00
for sem in pe_tools.TOUS_LES_PARCOURS:
2020-09-26 16:19:37 +02:00
entete.extend(["%s %s" % (sem, champ) for champ in champs])
else: # "singlesheet"
allSheets = ["singlesheet"]
2024-01-16 15:51:22 +01:00
for (
sem
) in (
2024-01-20 16:34:38 +01:00
pe_tools.TOUS_LES_PARCOURS
): # pe_tools.PARCOURS.keys() -> ['S1', 'S2', ..., '1A', '4S']
2020-09-26 16:19:37 +02:00
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"],
2020-09-26 16:19:37 +02:00
"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
2024-01-20 16:34:38 +01:00
for sem in aggregats: # pe_tools.PARCOURS.keys():
2020-09-26 16:19:37 +02:00
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)
)
2021-02-01 23:54:46 +01:00
row[champ + "note"] = scu.fmt_note(resgroupe[0])
2020-09-26 16:19:37 +02:00
row[champ + "class groupe"] = "%s / %s" % (
resgroupe[2] if resgroupe[2] else "-",
2024-01-16 15:51:22 +01:00
resgroupe[3] if resgroupe[3] else "-",
2020-09-26 16:19:37 +02:00
)
row[champ + "class promo"] = "%s / %s" % (
respromo[2] if respromo[2] else "-",
2024-01-16 15:51:22 +01:00
respromo[3] if respromo[3] else "-",
2020-09-26 16:19:37 +02:00
)
row[champ + "min/moy/max groupe"] = "%s / %s / %s" % tuple(
(scu.fmt_note(x) if x is not None else "-")
2024-01-16 15:51:22 +01:00
for x in (resgroupe[6], resgroupe[4], resgroupe[5])
2020-09-26 16:19:37 +02:00
)
row[champ + "min/moy/max promo"] = "%s / %s / %s" % tuple(
(scu.fmt_note(x) if x is not None else "-")
2021-02-01 23:54:46 +01:00
for x in (respromo[6], respromo[4], respromo[5])
2020-09-26 16:19:37 +02:00
)
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
# **************************************************************************************************************** #
# ------------------------------------------------------------------------------------------------------------------
2024-01-16 15:51:22 +01:00
def get_cache_etudInfo_d_un_etudiant(self, etudid):
2020-09-26 16:19:37 +02:00
"""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
2024-01-20 16:34:38 +01:00
TODO:: A supprimer à long terme
2020-09-26 16:19:37 +02:00
"""
if etudid not in self.ETUDINFO_DICT:
2024-01-20 16:34:38 +01:00
self.ETUDINFO_DICT[etudid] = Identite.get_etud(etudid=etudid)
# sco_etud.get_etud_info(
# etudid=etudid, filled=True
# ))[0]
2020-09-26 16:19:37 +02:00
return self.ETUDINFO_DICT[etudid]
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
2024-01-16 15:51:22 +01:00
def get_cache_notes_d_un_semestre(self, formsemestre_id: int) -> NotesTableCompat:
2021-01-01 18:40:47 +01:00
"""Charge la table des notes d'un formsemestre"""
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
return res_sem.load_formsemestre_results(formsemestre)
2020-09-26 16:19:37 +02:00
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
2024-01-20 16:34:38 +01:00
def get_semestresBUT_d_un_etudiant(self, identite: Identite, semestre_id=None):
"""cf. pe_etudiant.semestres_etudiant()"""
2020-09-26 16:19:37 +02:00
2024-01-20 16:34:38 +01:00
return None
2020-09-26 16:19:37 +02:00
# *********************************************
# Fonctions d'affichage pour debug
2024-01-16 15:51:22 +01:00
def get_resultat_d_un_etudiant(self, etudid):
2020-09-26 16:19:37 +02:00
chaine = ""
2024-01-20 16:34:38 +01:00
for nom_sem in pe_tools.TOUS_LES_SEMESTRES:
semtagid = self.etudiants.cursus[etudid][
2020-09-26 16:19:37 +02:00
nom_sem
] # le formsemestre_id du semestre taggué de l'étudiant
2024-01-21 18:55:21 +01:00
semtag = self.semestres_taggues[semtagid]
2021-08-10 17:12:10 +02:00
chaine += "Semestre " + nom_sem + str(semtagid) + "\n"
2020-09-26 16:19:37 +02:00
# 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
2022-04-20 12:23:43 +02:00
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 ""
2024-01-21 18:55:21 +01:00
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")
2024-01-24 15:37:50 +01:00
formsemestres = etudiants.get_formsemestres(
2024-01-21 18:55:21 +01:00
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
2024-01-24 15:37:50 +01:00
def compute_trajectoires_tag(trajectoires: TrajectoiresJuryPE,
etudiants: EtudiantsJuryPE,
semestres_taggues: dict[int, SemestreTag]):
"""Créée les trajectoires tagguées (combinaison aggrégeant plusieurs semestres au sens
d'un aggrégat (par ex: '3S')),
en calculant les moyennes et les classements par tag pour chacune.
Pour rappel : Chaque trajectoire est identifiée un nom d'aggrégat et par un formsemestre terminal.
2024-01-21 18:55:21 +01:00
Par exemple :
2024-01-24 15:37:50 +01:00
* combinaisons '3S' : S1+S2+S3 en prenant en compte tous les S3 qu'ont fréquenté les
2024-01-21 18:55:21 +01:00
é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)
2024-01-21 18:55:21 +01:00
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 ")
2024-01-24 15:37:50 +01:00
trajectoires_tagguees = {}
2024-01-21 18:55:21 +01:00
2024-01-24 15:37:50 +01:00
for trajectoire_id in trajectoires_tagguees:
trajectoire = trajectoires[trajectoire_id]
nom = trajectoire.get_repr()
2024-01-21 18:55:21 +01:00
2024-01-24 15:37:50 +01:00
pe_tools.pe_print(f" --> Fusion {nom}")
2024-01-21 18:55:21 +01:00
2024-01-24 15:37:50 +01:00
"""Création de la trajectoire_tagguee associée"""
trajectoire_tagguee = pe_trajectoiretag.TrajectoireTag(
nom, trajectoire, semestres_taggues, etudiants
2024-01-21 18:55:21 +01:00
)
2024-01-24 15:37:50 +01:00
"""Mémorise le résultat"""
trajectoires_tagguees[trajectoire_id] = trajectoire_tagguee
2024-01-21 18:55:21 +01:00
2024-01-24 15:37:50 +01:00
return trajectoires_tagguees
2024-01-21 18:55:21 +01:00
2024-01-23 19:08:54 +01:00
def compute_interclassements(
etudiants: EtudiantsJuryPE, aggregats_taggues: dict[str, dict]
):
"""Interclasse les étudiants, (nom d') aggrégat par aggrégat,
pour fournir un classement sur la promo. Le classement est établit au regard du nombre
d'étudiants ayant participé au même aggrégat.
"""
etudiants_diplomes = etudiants.get_etudiants_diplomes()
"""
for i, nom in enumerate(pe_tools.PARCOURS.keys()):
settag = app.pe.pe_settag_interclasse.SetTagInterClasse(nom, diplome=diplome)
nbreEtudInscrits = settag.set_Etudiants(
lesEtudids, self.etudiants.cursus, self.etudiants.identites
)
if nbreEtudInscrits > 0:
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)
)
"""