forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -47,7 +47,7 @@ from flask import g
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
from app.models import FormSemestre
|
||||
from app.pe.rcss.rcss_constantes import TYPES_RCS
|
||||
from app.pe.rcss.pe_rcs import TYPES_RCS
|
||||
from app.scodoc import sco_formsemestre
|
||||
from app.scodoc.sco_logos import find_logo
|
||||
|
||||
@ -317,3 +317,23 @@ def find_index_and_columns_communs(
|
||||
colonnes2 = df2.columns
|
||||
colonnes_communes = list(set(colonnes1) & set(colonnes2))
|
||||
return indices_communs, colonnes_communes
|
||||
|
||||
|
||||
def get_dernier_semestre_en_date(semestres: dict[int, FormSemestre]) -> FormSemestre:
|
||||
"""Renvoie le dernier semestre en **date de fin** d'un dictionnaire
|
||||
de semestres (potentiellement non trié) de la forme ``{fid: FormSemestre(fid)}``.
|
||||
|
||||
Args:
|
||||
semestres: Un dictionnaire de semestres
|
||||
|
||||
Return:
|
||||
Le FormSemestre du semestre le plus récent
|
||||
"""
|
||||
if semestres:
|
||||
fid_dernier_semestre = list(semestres.keys())[0]
|
||||
dernier_semestre: FormSemestre = semestres[fid_dernier_semestre]
|
||||
for fid in semestres:
|
||||
if semestres[fid].date_fin > dernier_semestre.date_fin:
|
||||
dernier_semestre = semestres[fid]
|
||||
return dernier_semestre
|
||||
return None
|
||||
|
@ -59,10 +59,10 @@ class EtudiantsJuryPE:
|
||||
self.identites: dict[int, Identite] = {} # ex. ETUDINFO_DICT
|
||||
"Les identités des étudiants traités pour le jury"
|
||||
|
||||
self.trajectoires: dict[int, dict] = {}
|
||||
self.cursus: dict[int, dict] = {}
|
||||
"Les cursus (semestres suivis, abandons) des étudiants"
|
||||
|
||||
self.trajectoires = {}
|
||||
self.cursus = {}
|
||||
"""Les trajectoires/chemins de semestres suivis par les étudiants
|
||||
pour atteindre un aggrégat donné
|
||||
(par ex: 3S=S1+S2+S3 à prendre en compte avec d'éventuels redoublements)"""
|
||||
@ -164,7 +164,7 @@ class EtudiantsJuryPE:
|
||||
"""
|
||||
etudids = [
|
||||
etudid
|
||||
for etudid, cursus_etud in self.trajectoires.items()
|
||||
for etudid, cursus_etud in self.cursus.items()
|
||||
if cursus_etud["diplome"] == self.annee_diplome
|
||||
and cursus_etud["abandon"] is False
|
||||
]
|
||||
@ -181,18 +181,14 @@ class EtudiantsJuryPE:
|
||||
"""
|
||||
etudids = [
|
||||
etudid
|
||||
for etudid, cursus_etud in self.trajectoires.items()
|
||||
for etudid, cursus_etud in self.cursus.items()
|
||||
if cursus_etud["diplome"] != self.annee_diplome
|
||||
or cursus_etud["abandon"] is True
|
||||
]
|
||||
etudiants = {etudid: self.identites[etudid] for etudid in etudids}
|
||||
return etudiants
|
||||
|
||||
def analyse_etat_etudiant(
|
||||
self,
|
||||
etudid: int,
|
||||
cosemestres: dict[int, FormSemestre]
|
||||
):
|
||||
def analyse_etat_etudiant(self, etudid: int, cosemestres: dict[int, FormSemestre]):
|
||||
"""Analyse le cursus d'un étudiant pouvant être :
|
||||
|
||||
* l'un de ceux sur lesquels le jury va statuer (année de diplômation du jury considéré)
|
||||
@ -225,7 +221,7 @@ class EtudiantsJuryPE:
|
||||
if formsemestre.formation.is_apc()
|
||||
}
|
||||
|
||||
self.trajectoires[etudid] = {
|
||||
self.cursus[etudid] = {
|
||||
"etudid": etudid, # les infos sur l'étudiant
|
||||
"etat_civil": identite.etat_civil, # Ajout à la table jury
|
||||
"nom": identite.nom,
|
||||
@ -241,16 +237,16 @@ class EtudiantsJuryPE:
|
||||
}
|
||||
|
||||
# Si l'étudiant est succeptible d'être diplomé
|
||||
if self.trajectoires[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 ?
|
||||
dernier_semes_etudiant = formsemestres[0]
|
||||
res = load_formsemestre_results(dernier_semes_etudiant)
|
||||
etud_etat = res.get_etud_etat(etudid)
|
||||
if etud_etat == scu.DEMISSION:
|
||||
self.trajectoires[etudid]["abandon"] = True
|
||||
self.cursus[etudid]["abandon"] = True
|
||||
else:
|
||||
# Est-il réorienté ou a-t-il arrêté (volontairement) sa formation ?
|
||||
self.trajectoires[etudid]["abandon"] = arret_de_formation(
|
||||
self.cursus[etudid]["abandon"] = arret_de_formation(
|
||||
identite, cosemestres
|
||||
)
|
||||
|
||||
@ -270,7 +266,7 @@ class EtudiantsJuryPE:
|
||||
Un dictionnaire ``{fid: FormSemestre(fid)}`` dans lequel les semestres
|
||||
amènent à une diplômation antérieur à celle de la diplômation visée par le jury jury
|
||||
"""
|
||||
semestres_etudiant = self.trajectoires[etudid]["formsemestres"]
|
||||
semestres_etudiant = self.cursus[etudid]["formsemestres"]
|
||||
semestres_significatifs = {}
|
||||
for fid in semestres_etudiant:
|
||||
semestre = semestres_etudiant[fid]
|
||||
@ -297,11 +293,9 @@ class EtudiantsJuryPE:
|
||||
for fid, sem_sig in semestres_significatifs.items()
|
||||
if sem_sig.semestre_id == i
|
||||
}
|
||||
self.trajectoires[etudid][f"S{i}"] = semestres_i
|
||||
self.cursus[etudid][f"S{i}"] = semestres_i
|
||||
|
||||
def get_formsemestres_finals_des_rcs(
|
||||
self, nom_rcs: str
|
||||
) -> dict[int, FormSemestre]:
|
||||
def get_formsemestres_finals_des_rcs(self, nom_rcs: str) -> dict[int, FormSemestre]:
|
||||
"""Pour un nom de RCS donné, ensemble des formsemestres finals possibles
|
||||
pour les RCS. Par ex. un RCS '3S' incluant S1+S2+S3 a pour semestre final un S3.
|
||||
Les formsemestres finals obtenus traduisent :
|
||||
@ -321,7 +315,7 @@ class EtudiantsJuryPE:
|
||||
Un dictionnaire ``{fid: FormSemestre(fid)}``
|
||||
"""
|
||||
formsemestres_terminaux = {}
|
||||
for trajectoire_aggr in self.trajectoires.values():
|
||||
for trajectoire_aggr in self.cursus.values():
|
||||
trajectoire = trajectoire_aggr[nom_rcs]
|
||||
if trajectoire:
|
||||
# Le semestre terminal de l'étudiant de l'aggrégat
|
||||
@ -338,7 +332,7 @@ class EtudiantsJuryPE:
|
||||
"""
|
||||
nbres_semestres = []
|
||||
for etudid in etudids:
|
||||
nbres_semestres.append(self.trajectoires[etudid]["nb_semestres"])
|
||||
nbres_semestres.append(self.cursus[etudid]["nb_semestres"])
|
||||
if not nbres_semestres:
|
||||
return 0
|
||||
return max(nbres_semestres)
|
||||
@ -359,7 +353,7 @@ class EtudiantsJuryPE:
|
||||
|
||||
for etudid in etudids:
|
||||
etudiant = self.identites[etudid]
|
||||
cursus = self.trajectoires[etudid]
|
||||
cursus = self.cursus[etudid]
|
||||
formsemestres = cursus["formsemestres"]
|
||||
|
||||
if cursus["diplome"]:
|
||||
@ -549,9 +543,9 @@ def arret_de_formation(etud: Identite, cosemestres: dict[int, FormSemestre]) ->
|
||||
non_inscrit_a = [
|
||||
rang for rang in etat_inscriptions if not etat_inscriptions[rang]
|
||||
]
|
||||
affichage = ",".join([f"S{val}" for val in non_inscrit_a])
|
||||
affichage = ", ".join([f"S{val}" for val in non_inscrit_a])
|
||||
pe_affichage.pe_print(
|
||||
f"{etud.etat_civil} ({etud.etudid}) considéré en abandon car non inscrit dans un (ou des) semestre(s) {affichage} amenant à diplômation"
|
||||
f"--> ⛔ {etud.etat_civil} ({etud.etudid}), non inscrit dans {affichage} amenant à diplômation"
|
||||
)
|
||||
|
||||
return est_demissionnaire
|
||||
@ -593,26 +587,6 @@ def arret_de_formation(etud: Identite, cosemestres: dict[int, FormSemestre]) ->
|
||||
# return False
|
||||
|
||||
|
||||
def get_dernier_semestre_en_date(semestres: dict[int, FormSemestre]) -> FormSemestre:
|
||||
"""Renvoie le dernier semestre en **date de fin** d'un dictionnaire
|
||||
de semestres (potentiellement non trié) de la forme ``{fid: FormSemestre(fid)}``.
|
||||
|
||||
Args:
|
||||
semestres: Un dictionnaire de semestres
|
||||
|
||||
Return:
|
||||
Le FormSemestre du semestre le plus récent
|
||||
"""
|
||||
if semestres:
|
||||
fid_dernier_semestre = list(semestres.keys())[0]
|
||||
dernier_semestre: FormSemestre = semestres[fid_dernier_semestre]
|
||||
for fid in semestres:
|
||||
if semestres[fid].date_fin > dernier_semestre.date_fin:
|
||||
dernier_semestre = semestres[fid]
|
||||
return dernier_semestre
|
||||
return None
|
||||
|
||||
|
||||
def etapes_du_cursus(
|
||||
semestres: dict[int, FormSemestre], nbre_etapes_max: int
|
||||
) -> list[str]:
|
||||
@ -679,4 +653,3 @@ def nom_semestre_etape(semestre: FormSemestre, avec_fid=False) -> str:
|
||||
description.append(f"({semestre.formsemestre_id})")
|
||||
|
||||
return " ".join(description)
|
||||
|
||||
|
@ -83,8 +83,8 @@ class RCSInterclasseTag(TableTag):
|
||||
# celles associées à l'aggrégat
|
||||
self.rcss: dict[int, pe_rcs.RCS] = {}
|
||||
"""Ensemble des trajectoires associées à l'aggrégat"""
|
||||
for trajectoire_id in rcss_jury_pe.rcss:
|
||||
trajectoire = rcss_jury_pe.rcss[trajectoire_id]
|
||||
for trajectoire_id in rcss_jury_pe.trajectoires:
|
||||
trajectoire = rcss_jury_pe.trajectoires[trajectoire_id]
|
||||
if trajectoire_id[0] == nom_rcs:
|
||||
self.rcss[trajectoire_id] = trajectoire
|
||||
|
||||
@ -99,7 +99,7 @@ class RCSInterclasseTag(TableTag):
|
||||
"""Association entre chaque étudiant et la trajectoire tagguée à prendre en
|
||||
compte pour l'aggrégat"""
|
||||
for etudid in self.diplomes_ids:
|
||||
self.suivi[etudid] = rcss_jury_pe.rcss_suivis[etudid][nom_rcs]
|
||||
self.suivi[etudid] = rcss_jury_pe.trajectoires_suivies[etudid][nom_rcs]
|
||||
|
||||
self.tags_sorted = self.do_taglist()
|
||||
"""Liste des tags (triés par ordre alphabétique)"""
|
||||
|
@ -50,17 +50,15 @@ from zipfile import ZipFile
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
import app.pe.rcss.rcss_constantes as rcss_constants
|
||||
from app.pe.rcss import pe_rcs
|
||||
from app.pe import pe_sxtag
|
||||
from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE
|
||||
import app.pe.pe_affichage as pe_affichage
|
||||
import app.pe.pe_etudiant as pe_etudiant
|
||||
import app.pe.rcss.pe_rcs as pe_rcs
|
||||
from app.pe.pe_rcstag import RCSTag
|
||||
from app.pe.pe_ressemtag import ResSemBUTTag
|
||||
from app.pe.pe_interclasstag import RCSInterclasseTag
|
||||
import app.pe.pe_rcss_jury as pe_rcss_jury
|
||||
import app.pe.rcss.rcss_constantes as rcss_constantes
|
||||
|
||||
|
||||
class JuryPE(object):
|
||||
@ -107,11 +105,11 @@ class JuryPE(object):
|
||||
try:
|
||||
self._gen_xls_diplomes(zipfile)
|
||||
self._gen_xls_ressembuttags(zipfile)
|
||||
self._gen_rcss()
|
||||
self._gen_rcsf()
|
||||
self._gen_trajectoires()
|
||||
self._gen_semXs()
|
||||
self._gen_xls_sxtags(zipfile)
|
||||
self._gen_rcrcfs()
|
||||
self._gen_xls_rcrcss_tags(zipfile)
|
||||
# self._gen_rcsemxs()
|
||||
# self._gen_xls_rcrcss_tags(zipfile)
|
||||
# self._gen_xls_interclassements_rcss(zipfile)
|
||||
# self._gen_xls_synthese_jury_par_tag(zipfile)
|
||||
# self._gen_xls_synthese_par_etudiant(zipfile)
|
||||
@ -185,35 +183,40 @@ class JuryPE(object):
|
||||
path="details",
|
||||
)
|
||||
|
||||
def _gen_rcss(self):
|
||||
"""Génère les RCS (attribut `rcss_jury`), combinaisons de semestres
|
||||
suivis par les étudiants au sens d'un nom de RCS (par ex: 'S2' ou '3S').
|
||||
def _gen_trajectoires(self):
|
||||
"""Génère l'ensemble des trajectoires (RCS), qui traduisent les différents
|
||||
chemins au sein des (form)semestres pour atteindre la cible d'un
|
||||
RCS (par ex: 'S2' ou '3S').
|
||||
"""
|
||||
pe_affichage.pe_print(
|
||||
"*** Génère les RCS (différentes combinaisons de semestres) des étudiants"
|
||||
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants"
|
||||
)
|
||||
|
||||
self.rcss_jury.cree_rcss(self.etudiants)
|
||||
self.rcss_jury.cree_trajectoires(self.etudiants)
|
||||
|
||||
def _gen_rcsf(self):
|
||||
"""Génère les RCF, regroupement de semestres de type Sx pour préparer
|
||||
le calcul des moyennes par Sx"""
|
||||
def _gen_semXs(self):
|
||||
"""Génère les SemXs (trajectoires/combinaisons de semestre de même rang x)
|
||||
qui traduisent les différents chemins des étudiants pour valider un semestre Sx.
|
||||
"""
|
||||
# Génère les regroupements de semestres de type Sx
|
||||
pe_affichage.pe_print(
|
||||
"*** Génère les RCSValid (RCS de même Sx donnant lieu à validation du semestre)"
|
||||
"*** Génère les SemXs (RCS de même Sx donnant lieu à validation du semestre)"
|
||||
)
|
||||
self.rcss_jury.cree_rcfs(self.etudiants)
|
||||
self.rcss_jury.cree_semxs(self.etudiants)
|
||||
self.rcss_jury._aff_semxs_suivis(self.etudiants)
|
||||
|
||||
def _gen_xls_sxtags(self, zipfile: ZipFile):
|
||||
"""Génère les semestres taggués en s'appuyant sur les RCF de type Sx (pour
|
||||
identifier les redoublements impactant les semestres taggués).
|
||||
"""
|
||||
# Génère les moyennes des RCS de type Sx
|
||||
pe_affichage.pe_print("*** Calcule les moyennes des SxTag")
|
||||
pe_affichage.pe_print(
|
||||
"*** Calcule les moyennes des SxTag (moyennes d'un SemX/RCS de type Sx)"
|
||||
)
|
||||
|
||||
# Les SxTag (moyenne de Sx par UE)
|
||||
self.sxtags = {}
|
||||
for rcf_id, rcf in self.rcss_jury.rcfs.items():
|
||||
for rcf_id, rcf in self.rcss_jury.semXs.items():
|
||||
# SxTag traduisant le RCF
|
||||
sxtag_id = rcf_id
|
||||
|
||||
@ -242,13 +245,15 @@ class JuryPE(object):
|
||||
path="details",
|
||||
)
|
||||
|
||||
def _gen_rcrcfs(self):
|
||||
def _gen_rcsemxs(self):
|
||||
"""Génère les regroupements cohérents de RCFs qu'ont suivi chaque étudiant"""
|
||||
|
||||
pe_affichage.pe_print(
|
||||
"*** Génère les RCRCF (regroupements de RCF de type Sx) amenant du S1 à un semestre final***"
|
||||
"*** Génère les RCSemX (regroupements cohérents de données"
|
||||
" extraites des SemX) amenant du S1 à un semestre final***"
|
||||
)
|
||||
self.rcss_jury.cree_rcrcfs(self.etudiants)
|
||||
self.rcss_jury.cree_rcsemxs(self.etudiants)
|
||||
self.rcss_jury._aff_rcsemxs_suivis(self.etudiants)
|
||||
|
||||
def _gen_xls_rcrcss_tags(self, zipfile: ZipFile):
|
||||
"""Génère les RCS taggués traduisant les moyennes (orientées compétences)
|
||||
@ -273,7 +278,7 @@ class JuryPE(object):
|
||||
pe_affichage.pe_print("*** Calcule les moyennes des RC de RCFS")
|
||||
|
||||
self.rcss_tags = {}
|
||||
for rcs_id, rcrcf in self.rcss_jury.rcrcfs.items():
|
||||
for rcs_id, rcrcf in self.rcss_jury.rcsemxs.items():
|
||||
self.rcss_tags[rcs_id] = RCSTag(rcrcf, self.sxtags)
|
||||
|
||||
# Intègre le bilan des trajectoires tagguées au zip final
|
||||
@ -458,13 +463,13 @@ class JuryPE(object):
|
||||
|
||||
# Ajout des aggrégats
|
||||
for aggregat in pe_rcs.TOUS_LES_RCS:
|
||||
descr = rcss_constantes.TYPES_RCS[aggregat]["descr"]
|
||||
descr = app.pe.rcss.pe_rcs.TYPES_RCS[aggregat]["descr"]
|
||||
|
||||
# Les trajectoires (tagguées) suivies par les étudiants pour l'aggrégat et le tag
|
||||
# considéré
|
||||
trajectoires_tagguees = []
|
||||
for etudid in etudids:
|
||||
trajectoire = self.rcss_jury.rcss_suivis[etudid][aggregat]
|
||||
trajectoire = self.rcss_jury.trajectoires_suivies[etudid][aggregat]
|
||||
if trajectoire:
|
||||
tid = trajectoire.sxtag_id
|
||||
trajectoire_tagguee = self.rcss_tags[tid]
|
||||
@ -610,7 +615,7 @@ class JuryPE(object):
|
||||
)
|
||||
|
||||
# La trajectoire de l'étudiant sur l'aggrégat
|
||||
trajectoire = self.rcss_jury.rcss_suivis[etudid][aggregat]
|
||||
trajectoire = self.rcss_jury.trajectoires_suivies[etudid][aggregat]
|
||||
if trajectoire:
|
||||
trajectoire_tagguee = self.rcss_tags[trajectoire.sxtag_id]
|
||||
if tag in trajectoire_tagguee.moyennes_tags:
|
||||
@ -651,9 +656,9 @@ def get_formsemestres_etudiants(etudiants: pe_etudiant.EtudiantsJuryPE) -> dict:
|
||||
"""
|
||||
semestres = {}
|
||||
for etudid in etudiants.etudiants_ids:
|
||||
for cle in etudiants.trajectoires[etudid]:
|
||||
for cle in etudiants.cursus[etudid]:
|
||||
if cle.startswith("S"):
|
||||
semestres = semestres | etudiants.trajectoires[etudid][cle]
|
||||
semestres = semestres | etudiants.cursus[etudid][cle]
|
||||
return semestres
|
||||
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
|
||||
import app.pe.rcss.pe_rcf as pe_rcf
|
||||
import app.pe.rcss.pe_rcrcf as pe_rcrcf
|
||||
import app.pe.pe_comp
|
||||
from app.pe.rcss import pe_rcs, pe_trajectoires, pe_rcsemx
|
||||
import app.pe.pe_etudiant as pe_etudiant
|
||||
import app.pe.pe_comp as pe_comp
|
||||
import app.pe.rcss.rcss_constantes as rcss_constantes
|
||||
from app.models import FormSemestre
|
||||
from app.pe import pe_affichage
|
||||
|
||||
@ -20,159 +18,198 @@ class RCSsJuryPE:
|
||||
self.annee_diplome = annee_diplome
|
||||
"""Année de diplômation"""
|
||||
|
||||
self.rcss: dict[tuple(int, str): pe_rcf.RCF] = {}
|
||||
"""Ensemble des RCS recensés"""
|
||||
self.trajectoires: dict[tuple(int, str) : pe_trajectoires.Trajectoire] = {}
|
||||
"""Ensemble des trajectoires recensées (regroupement de (form)semestres BUT)"""
|
||||
|
||||
self.rcss_suivis: dict[int:dict] = {}
|
||||
self.trajectoires_suivies: dict[int:dict] = {}
|
||||
"""Dictionnaire associant, pour chaque étudiant et pour chaque type de RCS,
|
||||
son RCS : {etudid: {nom_RCS: RCS}}"""
|
||||
sa Trajectoire : {etudid: {nom_RCS: Trajectoire}}"""
|
||||
|
||||
self.rcfs: dict[tuple(int, str) : pe_rcf.RCF] = {}
|
||||
"""Ensemble des RCF recensés : {(nom_RCS, fid_terminal): RCF}"""
|
||||
self.semXs: dict[tuple(int, str) : pe_trajectoires.SemX] = {}
|
||||
"""Ensemble des SemX recensés (regroupement de (form)semestre BUT de rang x) :
|
||||
{(nom_RCS, fid_terminal): SemX}"""
|
||||
|
||||
self.rcfs_suivis: dict[int:dict] = {}
|
||||
self.semXs_suivis: dict[int:dict] = {}
|
||||
"""Dictionnaire associant, pour chaque étudiant et pour chaque RCS de type Sx,
|
||||
son SemX : {etudid: {nom_RCS_de_type_Sx: SemX}}"""
|
||||
|
||||
self.rcsemxs: dict[tuple(int, str) : pe_rcsemx.RCSemX] = {}
|
||||
"""Ensemble des RCSemX (regroupement de SemX donnant les résultats aux sems de rang x)
|
||||
recensés : {(nom_RCS, fid_terminal): RCSemX}"""
|
||||
|
||||
self.rcsemxs_suivis: dict[int:str] = {}
|
||||
"""Dictionnaire associant, pour chaque étudiant et pour chaque type de RCS,
|
||||
son RCS : {etudid: {nom_RCS: RCF}}"""
|
||||
son RCSemX : {etudid: {nom_RCS: RCSemX}}"""
|
||||
|
||||
self.rcrcfs: dict[tuple(int, str) : pe_rcrcf.RCRCF] = {}
|
||||
"""Ensemble des RCS recensés : {(nom_RCS, fid_terminal): RCRCF}"""
|
||||
|
||||
self.rcrcfs_suivis: dict[int:str] = {}
|
||||
"""Dictionnaire associant, pour chaque étudiant et pour chaque type de RCS,
|
||||
son RCRCF : {etudid: {nom_RCS: RCSx}}"""
|
||||
|
||||
def cree_rcss(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""Créé tous les RCS, au regard du cursus des étudiants
|
||||
def cree_trajectoires(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""Créé toutes les trajectoires, au regard du cursus des étudiants
|
||||
analysés + les mémorise dans les données de l'étudiant
|
||||
|
||||
Args:
|
||||
etudiants: Les étudiants à prendre en compte dans le Jury PE
|
||||
"""
|
||||
|
||||
tous_les_aggregats = rcss_constantes.TOUS_LES_SEMESTRES + rcss_constantes.TOUS_LES_RCS_AVEC_PLUSIEURS_SEM
|
||||
for etudid in etudiants.trajectoires:
|
||||
self.rcss_suivis[etudid] = {
|
||||
aggregat: None
|
||||
for aggregat in tous_les_aggregats
|
||||
tous_les_aggregats = (
|
||||
pe_rcs.TOUS_LES_SEMESTRES + pe_rcs.TOUS_LES_RCS_AVEC_PLUSIEURS_SEM
|
||||
)
|
||||
for etudid in etudiants.cursus:
|
||||
self.trajectoires_suivies[etudid] = {
|
||||
aggregat: None for aggregat in tous_les_aggregats
|
||||
}
|
||||
|
||||
for nom_rcs in tous_les_aggregats:
|
||||
# L'aggrégat considéré (par ex: 3S=S1+S2+S3), son nom de son semestre
|
||||
# terminal (par ex: S3) et son numéro (par ex: 3)
|
||||
noms_semestre_de_aggregat = rcss_constantes.TYPES_RCS[nom_rcs]["aggregat"]
|
||||
noms_semestre_de_aggregat = pe_rcs.TYPES_RCS[nom_rcs]["aggregat"]
|
||||
nom_semestre_terminal = noms_semestre_de_aggregat[-1]
|
||||
|
||||
for etudid in etudiants.trajectoires:
|
||||
for etudid in etudiants.cursus:
|
||||
# Le formsemestre terminal (dernier en date) associé au
|
||||
# semestre marquant la fin de l'aggrégat
|
||||
# (par ex: son dernier S3 en date)
|
||||
trajectoire = etudiants.trajectoires[etudid][nom_semestre_terminal]
|
||||
trajectoire = etudiants.cursus[etudid][nom_semestre_terminal]
|
||||
if trajectoire:
|
||||
formsemestre_final = pe_etudiant.get_dernier_semestre_en_date(trajectoire)
|
||||
formsemestre_final = app.pe.pe_comp.get_dernier_semestre_en_date(
|
||||
trajectoire
|
||||
)
|
||||
|
||||
# Ajout ou récupération du RCS associé
|
||||
rcs_id = (nom_rcs, formsemestre_final.formsemestre_id)
|
||||
if rcs_id not in self.rcss:
|
||||
self.rcss[rcs_id] = pe_rcf.RCF(nom_rcs, formsemestre_final)
|
||||
rcs = self.rcss[rcs_id]
|
||||
if rcs_id not in self.trajectoires:
|
||||
self.trajectoires[rcs_id] = pe_trajectoires.Trajectoire(
|
||||
nom_rcs, formsemestre_final
|
||||
)
|
||||
rcs = self.trajectoires[rcs_id]
|
||||
|
||||
# La liste des semestres de l'étudiant à prendre en compte
|
||||
# pour cette trajectoire
|
||||
semestres_a_aggreger = get_rcs_etudiant(
|
||||
etudiants.trajectoires[etudid], formsemestre_final, nom_rcs
|
||||
etudiants.cursus[etudid], formsemestre_final, nom_rcs
|
||||
)
|
||||
|
||||
# Ajout des semestres au RCS
|
||||
rcs.add_semestres_a_aggreger(semestres_a_aggreger)
|
||||
rcs.add_semestres(semestres_a_aggreger)
|
||||
|
||||
# Mémorise le RCS suivi par l'étudiant
|
||||
self.rcss_suivis[etudid][nom_rcs] = rcs
|
||||
self.trajectoires_suivies[etudid][nom_rcs] = rcs
|
||||
|
||||
# Affichage pour debug
|
||||
jeunes = list(enumerate(self.rcss_suivis))
|
||||
jeunes = list(enumerate(self.trajectoires_suivies))
|
||||
for no_etud, etudid in jeunes[:20]:
|
||||
pe_affichage.pe_print(f"--> {etudiants.identites[etudid].nomprenom} (#{etudid}) :")
|
||||
for nom_rcs, rcs in self.rcss_suivis[etudid].items():
|
||||
pe_affichage.pe_print(
|
||||
f"--> {etudiants.identites[etudid].nomprenom} (#{etudid}) :"
|
||||
)
|
||||
for nom_rcs, rcs in self.trajectoires_suivies[etudid].items():
|
||||
if rcs:
|
||||
pe_affichage.pe_print(f" > RCS {nom_rcs}: {rcs.get_repr()}")
|
||||
|
||||
def cree_rcfs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""Créé les RCFs en ne conservant dans les RCS que les regroupements
|
||||
def cree_semxs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""Créé les les SemXs (trajectoires/combinaisons de semestre de même rang x),
|
||||
en ne conservant dans les trajectoires que les regroupements
|
||||
de type Sx"""
|
||||
self.rcfs = {}
|
||||
for rcs_id, rcs in self.rcss.items():
|
||||
if rcs and rcs.nom in rcss_constantes.TOUS_LES_SEMESTRES:
|
||||
self.rcfs[rcs_id] = rcs
|
||||
self.semXs = {}
|
||||
for rcs_id, trajectoire in self.trajectoires.items():
|
||||
if trajectoire and trajectoire.nom in pe_rcs.TOUS_LES_SEMESTRES:
|
||||
self.semXs[rcs_id] = pe_trajectoires.SemX(trajectoire)
|
||||
|
||||
for etudid in self.rcss_suivis:
|
||||
for nom_rcs, rcs in self.rcss_suivis[etudid].items():
|
||||
if rcs and nom_rcs in rcss_constantes.TOUS_LES_SEMESTRES:
|
||||
if etudid not in self.rcfs_suivis:
|
||||
self.rcfs_suivis[etudid] = {}
|
||||
self.rcfs_suivis[etudid][nom_rcs] = rcs
|
||||
self.semXs_suivis = {}
|
||||
for etudid in self.trajectoires_suivies:
|
||||
self.semXs_suivis[etudid] = {
|
||||
nom_rcs: None for nom_rcs in pe_rcs.TOUS_LES_SEMESTRES
|
||||
}
|
||||
|
||||
# Affichage pour debug
|
||||
jeunes = list(enumerate(self.rcfs_suivis))
|
||||
for nom_rcs, trajectoire in self.trajectoires_suivies[etudid].items():
|
||||
if trajectoire and nom_rcs in pe_rcs.TOUS_LES_SEMESTRES:
|
||||
rcs_id = trajectoire.rcs_id
|
||||
self.semXs_suivis[etudid][nom_rcs] = self.semXs[rcs_id]
|
||||
|
||||
def _aff_semxs_suivis(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""Affichage des SemX pour debug"""
|
||||
jeunes = list(enumerate(self.semXs_suivis))
|
||||
vides = []
|
||||
for no_etud, etudid in jeunes[:20]:
|
||||
pe_affichage.pe_print(f"-> {etudiants.identites[etudid].nomprenom} :")
|
||||
for nom_rcs, rcs in self.rcfs_suivis[etudid].items():
|
||||
for nom_rcs, rcs in self.semXs_suivis[etudid].items():
|
||||
if rcs:
|
||||
pe_affichage.pe_print(f" > RCSValid {nom_rcs}: {rcs.get_repr()}")
|
||||
pe_affichage.pe_print(f" > SemX {nom_rcs}: {rcs.get_repr()}")
|
||||
else:
|
||||
pe_affichage.pe_print(f" > RCSValid {nom_rcs}: <vide>")
|
||||
vides += [nom_rcs]
|
||||
vides = sorted(list(set(vides)))
|
||||
pe_affichage.pe_print(f"-> ⚠ SemX vides : {', '.join(vides)}")
|
||||
|
||||
def cree_rcrcfs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""Créé tous les RCRCF, au regard du cursus des étudiants
|
||||
def cree_rcsemxs(self, etudiants: pe_etudiant.EtudiantsJuryPE):
|
||||
"""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
|
||||
"""
|
||||
self.rcsemxs_suivis = {nom_rcs: None for nom_rcs in pe_rcs.TOUS_LES_RCS}
|
||||
self.rcsemxs = {}
|
||||
|
||||
# Pour tous les étudiants du jury
|
||||
for etudid in self.rcss_suivis:
|
||||
self.rcrcfs_suivis[etudid] = {}
|
||||
for etudid in self.trajectoires_suivies:
|
||||
self.rcsemxs_suivis[etudid] = {}
|
||||
|
||||
for nom_rcs, rcf in self.rcfs_suivis[etudid].items(): # Pour chaque RCS
|
||||
semestres_a_aggreger = rcf.semestres_aggreges
|
||||
# Recopie des SemX & des suivis associés
|
||||
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
|
||||
|
||||
# Tri des semestres par rang
|
||||
semestres_tries = pe_comp.tri_semestres_par_rang(semestres_a_aggreger)
|
||||
|
||||
# Récupére les RCFs de type Sx traduisant sa trajectoire
|
||||
rcfs_a_aggreger = {}
|
||||
for semestres_du_rang in semestres_tries.values():
|
||||
if semestres_du_rang:
|
||||
rcf_id = get_rcf_from_semestres_aggreges(
|
||||
self.rcfs, semestres_du_rang
|
||||
# Pour chaque aggréggat de type xA ou Sx
|
||||
for nom_rcs in pe_rcs.TOUS_LES_RCS_AVEC_PLUSIEURS_SEM:
|
||||
trajectoire = self.trajectoires_suivies[etudid][nom_rcs]
|
||||
if not trajectoire:
|
||||
self.rcsemxs_suivis[etudid][nom_rcs] = None
|
||||
else:
|
||||
# Identifiant de la trajectoire => donnera ceux du RCSemX
|
||||
tid = trajectoire.rcs_id
|
||||
# Ajout du RCSemX
|
||||
if tid not in self.rcsemxs:
|
||||
self.rcsemxs[tid] = pe_rcsemx.RCSemX(
|
||||
trajectoire.nom, trajectoire.formsemestre_final
|
||||
)
|
||||
if not rcf_id:
|
||||
raise ValueError(
|
||||
"Il manque un RCF pour créer les RCRCFs dans cree_rcrcfs"
|
||||
|
||||
# Récupére les SemX (RC de type Sx) associés aux semestres de son cursus
|
||||
# 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"]
|
||||
|
||||
semxs_a_aggreger = {}
|
||||
for Sx in noms_sems_aggregat:
|
||||
semestres_etudiants = etudiants.cursus[etudid][Sx]
|
||||
|
||||
semx_id = get_semx_from_semestres_aggreges(
|
||||
self.semXs, semestres_etudiants
|
||||
)
|
||||
rcfs_a_aggreger[rcf_id] = self.rcfs[rcf_id]
|
||||
if not semx_id:
|
||||
raise (
|
||||
"Il manque un SemX pour créer les RCSemX dans cree_rcsemxs"
|
||||
)
|
||||
# Les SemX à ajouter au RCSemX
|
||||
semxs_a_aggreger[semx_id] = self.semXs[semx_id]
|
||||
|
||||
# Ajout du RCRCF
|
||||
if rcf_id not in self.rcrcfs:
|
||||
rcf_nom = rcf_id[0]
|
||||
self.rcrcfs[rcf_id] = pe_rcrcf.RCRCF(rcf_nom, rcf.formsemestre_final)
|
||||
rcrcf = self.rcrcfs[rcf_id]
|
||||
# Ajout des SemX à ceux à aggréger dans le RCSemX
|
||||
rcsemx = self.rcsemxs[tid]
|
||||
rcsemx.add_semXs(semxs_a_aggreger)
|
||||
|
||||
# Ajout des RCFs au RCRCF
|
||||
rcrcf.add_rcfs_a_aggreger(rcfs_a_aggreger)
|
||||
|
||||
# Mémoire la trajectoire RCRCF suivie par l'étudiant
|
||||
nom_rcs = rcrcf.nom
|
||||
self.rcrcfs_suivis[etudid][nom_rcs] = rcrcf
|
||||
# Mémoire du RCSemX aux informations de suivi de l'étudiant
|
||||
self.rcsemxs_suivis[etudid][nom_rcs] = rcsemx
|
||||
|
||||
def _aff_rcsemxs_suivis(self, etudiants):
|
||||
"""Affiche les RCSemX suivis par les étudiants"""
|
||||
# Affichage pour debug
|
||||
jeunes = list(enumerate(self.rcrcfs_suivis))
|
||||
jeunes = list(enumerate(self.rcsemxs_suivis))
|
||||
vides = []
|
||||
for no_etud, etudid in jeunes[:20]:
|
||||
pe_affichage.pe_print(f"-> {etudiants.identites[etudid].nomprenom} :")
|
||||
for nom_rcs, rcs in self.rcrcfs_suivis[etudid].items():
|
||||
for nom_rcs, rcs in self.rcsemxs_suivis[etudid].items():
|
||||
if rcs:
|
||||
pe_affichage.pe_print(f" > RCRCF {nom_rcs}: {rcs.get_repr()}")
|
||||
pe_affichage.pe_print(f" > RCSemX {nom_rcs}: {rcs.get_repr()}")
|
||||
else:
|
||||
pe_affichage.pe_print(f" > RCRCF {nom_rcs}: <vide> !!! ")
|
||||
|
||||
vides += [f"{nom_rcs}"]
|
||||
pe_affichage.pe_print(f"-> ⚠ RCSemX vides : {', '.join(list(set(vides)))}")
|
||||
|
||||
|
||||
def get_rcs_etudiant(
|
||||
@ -204,7 +241,7 @@ def get_rcs_etudiant(
|
||||
numero_semestres_possibles = [numero_semestre_terminal]
|
||||
elif nom_rcs.endswith("A"): # les années
|
||||
numero_semestres_possibles = [
|
||||
int(sem[-1]) for sem in rcss_constantes.TYPES_RCS[nom_rcs]["aggregat"]
|
||||
int(sem[-1]) for sem in pe_rcs.TYPES_RCS[nom_rcs]["aggregat"]
|
||||
]
|
||||
assert numero_semestre_terminal in numero_semestres_possibles
|
||||
else: # les xS = tous les semestres jusqu'à Sx (eg S1, S2, S3 pour un S3 terminal)
|
||||
@ -221,25 +258,52 @@ def get_rcs_etudiant(
|
||||
return semestres_aggreges
|
||||
|
||||
|
||||
def get_rcf_from_semestres_aggreges(
|
||||
rcfs: dict[(str, int):pe_rcf.RCF], semestres_a_aggreges: list[FormSemestre]
|
||||
) -> (str, int):
|
||||
"""Partant d'un dictionnaire de RCFs (de la forme
|
||||
``{ (nom_rcs, fid): RCF }, et connaissant une liste
|
||||
de (form)semestres à aggréger, renvoie l'identifiant
|
||||
(nom_rcs, fid) du RCFs qui lui correspond (c'est à dire celui dont
|
||||
les semestres_aggregés par le RCF sont les même que les
|
||||
semestres_a_aggreger.
|
||||
def get_semx_from_semestres_aggreges(
|
||||
semXs: dict[(str, int) : pe_trajectoires.SemX],
|
||||
semestres_a_aggreger: dict[(str, int):FormSemestre],
|
||||
) -> (str, int):
|
||||
"""Partant d'un dictionnaire de SemX (de la forme
|
||||
``{ (nom_rcs, fid): SemX }, et connaissant une liste
|
||||
de (form)semestres suivis, renvoie l'identifiant
|
||||
(nom_rcs, fid) du SemX qui lui correspond.
|
||||
|
||||
Le SemX qui correspond est tel que :
|
||||
|
||||
* le semestre final du SemX correspond au dernier semestre en date des
|
||||
semestres_a_aggreger
|
||||
* le rang du SemX est le même que celui des semestres_aggreges
|
||||
* les semestres_a_aggreger (plus large, car contenant plusieurs
|
||||
parcours), matchent avec les semestres aggrégés
|
||||
par le SemX
|
||||
|
||||
|
||||
Returns:
|
||||
rcf_id: L'identifiant du RCF trouvé
|
||||
"""
|
||||
fids_semestres_a_aggreger = set(
|
||||
[frms.formsemestre_id for frms in semestres_a_aggreges]
|
||||
)
|
||||
for rcf_id, rcf in rcfs.items():
|
||||
fids_rcf = set(rcf.semestres_aggreges)
|
||||
if fids_rcf == fids_semestres_a_aggreger:
|
||||
return rcf_id
|
||||
return None
|
||||
assert semestres_a_aggreger, "Pas de semestres à aggréger"
|
||||
rangs_a_aggreger = [sem.semestre_id for fid, sem in semestres_a_aggreger.items()]
|
||||
assert (
|
||||
len(set(rangs_a_aggreger)) == 1
|
||||
), "Tous les sem à aggréger doivent être de même rang"
|
||||
|
||||
# Le dernier semestre des semestres à regrouper
|
||||
dernier_sem_a_aggreger = pe_comp.get_dernier_semestre_en_date(semestres_a_aggreger)
|
||||
|
||||
semxs_ids = [] # Au cas où il y ait plusieurs solutions
|
||||
for semx_id, semx in semXs.items():
|
||||
# Même semestre final ?
|
||||
if semx.get_formsemestre_id_final() == dernier_sem_a_aggreger.formsemestre_id:
|
||||
# Les fids
|
||||
fids_a_aggreger = set(semestres_a_aggreger.keys())
|
||||
# Ceux du semx
|
||||
fids_semx = set(semx.semestres_aggreges.keys())
|
||||
if fids_a_aggreger.issubset(
|
||||
fids_semx
|
||||
): # tous les semestres du semx correspond à des sems de la trajectoire
|
||||
semxs_ids += [semx_id]
|
||||
if len(semxs_ids) == 0:
|
||||
return None # rien trouvé
|
||||
elif len(semxs_ids) == 1:
|
||||
return semxs_ids[0]
|
||||
else:
|
||||
raise "Plusieurs solutions :)"
|
||||
|
@ -42,7 +42,7 @@ from app.pe import pe_affichage
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import app.pe.rcss.pe_rcs as pe_rcs
|
||||
import app.pe.rcss.pe_rcrcf as pe_rcrcf
|
||||
import app.pe.rcss.pe_rcsemx as pe_rcrcf
|
||||
import app.pe.pe_sxtag as pe_sxtag
|
||||
import app.pe.pe_comp as pe_comp
|
||||
from app.pe.pe_tabletags import TableTag
|
||||
@ -66,7 +66,7 @@ class RCSTag(TableTag):
|
||||
self.rcs_id: tuple(str, int) = rcrcf.rcs_id
|
||||
"""Identifiant du RCS taggué (identique au RCS sur lequel il s'appuie)"""
|
||||
|
||||
self.rcrcf: pe_rcrcf.RCRCF = rcrcf
|
||||
self.rcrcf: pe_rcrcf.RCSemX = rcrcf
|
||||
"""RCRCF associé au RCS taggué"""
|
||||
|
||||
self.nom = self.get_repr()
|
||||
@ -82,12 +82,12 @@ class RCSTag(TableTag):
|
||||
pe_affichage.pe_print(f"-> {self.get_repr(verbose=True)}")
|
||||
|
||||
# Les données aggrégés (RCRCF + SxTags
|
||||
self.rcfs_aggreges = rcrcf.rcfs_aggreges
|
||||
self.rcsemxs_aggreges = rcrcf.rcsemxs_aggreges
|
||||
"""Les RCFs aggrégés"""
|
||||
self.sxstags = {}
|
||||
"""Les SxTag associés aux RCF aggrégés"""
|
||||
try:
|
||||
for rcf_id in self.rcfs_aggreges:
|
||||
for rcf_id in self.rcsemxs_aggreges:
|
||||
self.sxstags[rcf_id] = sxstags[rcf_id]
|
||||
except:
|
||||
raise ValueError("Semestres SxTag manquants")
|
||||
|
@ -43,14 +43,14 @@ import numpy as np
|
||||
|
||||
from app.pe.pe_tabletags import TableTag
|
||||
from app.pe.pe_moytag import MoyennesTag
|
||||
import app.pe.rcss.pe_rcf as pe_rcf
|
||||
import app.pe.rcss.pe_trajectoires as pe_trajectoires
|
||||
|
||||
|
||||
class SxTag(TableTag):
|
||||
def __init__(
|
||||
self,
|
||||
sxtag_id: (str, int),
|
||||
rcf: pe_rcf.RCF,
|
||||
semx: pe_trajectoires.SemX,
|
||||
ressembuttags: dict[int, pe_ressemtag.ResSemBUTTag],
|
||||
):
|
||||
"""Calcule les moyennes/classements par tag d'un semestre de type 'Sx'
|
||||
@ -86,13 +86,22 @@ class SxTag(TableTag):
|
||||
|
||||
self.sxtag_id: (str, int) = sxtag_id
|
||||
"""Identifiant du SxTag de la forme (nom_Sx, fid_semestre_final)"""
|
||||
assert (
|
||||
len(self.sxtag_id) == 2
|
||||
and isinstance(self.sxtag_id[0], str)
|
||||
and isinstance(self.sxtag_id[1], int)
|
||||
), "Format de l'identifiant du SxTag non respecté"
|
||||
|
||||
self.rcf = rcf
|
||||
"""Le RCF sur lequel il s'appuie"""
|
||||
assert rcf.rcs_id == sxtag_id, "Problème de correspondance SxTag/RCF"
|
||||
self.nom_rcs = sxtag_id[0]
|
||||
|
||||
# Les resultats des semestres taggués à prendre en compte dans le RCF
|
||||
self.ressembuttags = {fid: ressembuttags[fid] for fid in rcf.semestres_aggreges}
|
||||
self.semx = semx
|
||||
"""Le SemX sur lequel il s'appuie"""
|
||||
assert semx.rcs_id == sxtag_id, "Problème de correspondance SxTag/SemX"
|
||||
|
||||
# Les resultats des semestres taggués à prendre en compte dans le SemX
|
||||
self.ressembuttags = {
|
||||
fid: ressembuttags[fid] for fid in semx.semestres_aggreges
|
||||
}
|
||||
"""Les ResSemBUTTags à regrouper dans le SxTag"""
|
||||
|
||||
# Les données du semestre final
|
||||
@ -108,7 +117,7 @@ class SxTag(TableTag):
|
||||
"""Les etudids triés"""
|
||||
|
||||
# Affichage
|
||||
pe_affichage.pe_print(f"--> {self.get_repr()}")
|
||||
pe_affichage.pe_print(f"--> {self.get_repr(verbose=True)}")
|
||||
|
||||
# Les tags
|
||||
self.tags_sorted = self.ressembuttag_final.tags_sorted
|
||||
@ -227,10 +236,10 @@ class SxTag(TableTag):
|
||||
"""Renvoie une représentation textuelle (celle de la trajectoire sur laquelle elle
|
||||
est basée)"""
|
||||
if verbose:
|
||||
return f"{self.sxtag_id[0]}Tag basé sur {self.rcf.get_repr()}"
|
||||
return f"SXTag basé sur {self.semx.get_repr()}"
|
||||
else:
|
||||
# affichage = [str(fid) for fid in self.ressembuttags]
|
||||
return f"{self.sxtag_id[0]}Tag (#{self.fid_final})"
|
||||
return f"SXTag {self.nom_rcs}#{self.fid_final}"
|
||||
|
||||
def _aff_capitalisations(self):
|
||||
"""Affichage des capitalisations du sxtag pour debug"""
|
||||
|
@ -1,57 +0,0 @@
|
||||
|
||||
from app.models import FormSemestre
|
||||
import app.pe.rcss.pe_rcs as pe_rcs
|
||||
|
||||
|
||||
class RCF(pe_rcs.RCS):
|
||||
"""Modélise un ensemble de (form)semestres d'étudiants
|
||||
associé à un type de regroupement cohérent de semestres
|
||||
donné (par ex: 'S2', '3S', '2A').
|
||||
|
||||
Si le RCF est un semestre de type Si, stocke les
|
||||
formsemestres de numéro i qu'ont suivi l'étudiant pour atteindre le Si
|
||||
(en général 1 si personnes n'a redoublé, mais 2 s'il y a des redoublants)
|
||||
|
||||
Pour le RCF de type iS ou iA (par ex, 3A=S1+S2+S3), identifie
|
||||
les semestres que les étudiants ont suivis pour les amener jusqu'au semestre
|
||||
terminal du RCS (par ex: ici un S3).
|
||||
|
||||
Ces semestres peuvent être :
|
||||
|
||||
* des S1+S2+S1+S2+S3 si redoublement de la 1ère année
|
||||
* des S1+S2+(année de césure)+S3 si césure, ...
|
||||
|
||||
Args:
|
||||
nom_rcs: Un nom du RCS (par ex: '5S')
|
||||
semestre_final: Le formsemestre final du RCS
|
||||
"""
|
||||
|
||||
def __init__(self, nom_rcs: str, semestre_final: FormSemestre):
|
||||
pe_rcs.RCS.__init__(self, nom_rcs, semestre_final)
|
||||
|
||||
self.semestres_aggreges: dict[int:FormSemestre] = {}
|
||||
"""Formsemestres regroupés dans le RCS"""
|
||||
|
||||
def add_semestres_a_aggreger(self, semestres: dict[int:FormSemestre]):
|
||||
"""Ajout de semestres aux semestres à regrouper
|
||||
|
||||
Args:
|
||||
semestres: Dictionnaire ``{fid: Formsemestre)``
|
||||
"""
|
||||
self.semestres_aggreges = self.semestres_aggreges | semestres
|
||||
|
||||
def get_repr(self, verbose=True) -> str:
|
||||
"""Représentation textuelle d'un RCS
|
||||
basé sur ses semestres aggrégés"""
|
||||
title = f"""{self.__class__.__name__} {pe_rcs.RCS.__str__(self)}"""
|
||||
if verbose:
|
||||
noms = []
|
||||
for fid in self.semestres_aggreges:
|
||||
semestre = self.semestres_aggreges[fid]
|
||||
noms.append(f"S{semestre.semestre_id}(#{fid})")
|
||||
noms = sorted(noms)
|
||||
if noms:
|
||||
title += " <" + "+".join(noms) + ">"
|
||||
else:
|
||||
title += " <vide>"
|
||||
return title
|
@ -1,69 +0,0 @@
|
||||
##############################################################################
|
||||
# Module "Avis de poursuite d'étude"
|
||||
# conçu et développé par Cléo Baras (IUT de Grenoble)
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Created on 01-2024
|
||||
|
||||
@author: barasc
|
||||
"""
|
||||
|
||||
import app.pe.pe_comp as pe_comp
|
||||
import app.pe.rcss.pe_rcf
|
||||
import app.pe.rcss.rcss_constantes
|
||||
|
||||
from app.models import FormSemestre
|
||||
from app.pe import pe_sxtag, pe_affichage
|
||||
from app.pe.pe_etudiant import EtudiantsJuryPE, get_dernier_semestre_en_date
|
||||
import app.pe.rcss.pe_rcs as pe_rcs
|
||||
import app.pe.rcss.pe_rcf as pe_rcf
|
||||
|
||||
|
||||
|
||||
class RCRCF:
|
||||
"""Modélise les RCF d'étudiants suivis par un étudiant dans
|
||||
le cadre d'un RCS donné (par ex: 3S=S1+S2+S3).
|
||||
|
||||
Pour rappel : un RCF (par ex. S1) combine les semestres 1 qu'a suivi
|
||||
l'étudiant pour valider son S1 (1 si étudiant standard, 2 si redoublant).
|
||||
|
||||
Le RCRCF 3S est donc le regroupement du RCF S1 + RCF S2 + RCF S3.
|
||||
|
||||
Il est identifié par le formsemestre de S3 marquant la fin du regroupement.
|
||||
|
||||
|
||||
Args:
|
||||
nom_rcs: Un nom du RCS (par ex: '5S')
|
||||
semestre_final: Le semestre final du RCS
|
||||
"""
|
||||
|
||||
def __init__(self, nom_rcs: str, semestre_final: FormSemestre):
|
||||
pe_rcs.RCS.__init__(self, nom_rcs, semestre_final)
|
||||
|
||||
self.rcfs_aggreges: dict[(str, int) : pe_sxtag.SxTag] = {}
|
||||
"""Les RCFs à aggréger"""
|
||||
|
||||
def add_rcfs_a_aggreger(self, rcfs: dict[(str, int): app.pe.rcss.pe_rcf.RCF]):
|
||||
"""Ajout des RCFs aux RCFS à regrouper
|
||||
|
||||
Args:
|
||||
rcfs: Dictionnaire ``{(str,fid): RCF}`` à ajouter
|
||||
"""
|
||||
self.rcfs_aggreges = self.rcfs_aggreges | rcfs
|
||||
|
||||
def get_repr(self, verbose=True) -> str:
|
||||
"""Représentation textuelle d'un RCSF
|
||||
basé sur ses RCF aggrégés"""
|
||||
title = f"""{self.__class__.__name__}{pe_rcs.RCS.__str__(self)}"""
|
||||
if verbose:
|
||||
noms = []
|
||||
for rcf_id, rcf in self.rcfs_aggreges.items():
|
||||
noms.append(rcf.get_repr(verbose=False))
|
||||
if noms:
|
||||
title += " <<" + "+".join(noms) + ">>"
|
||||
else:
|
||||
title += " <<vide>>"
|
||||
return title
|
||||
|
||||
|
@ -10,32 +10,100 @@ Created on 01-2024
|
||||
"""
|
||||
|
||||
from app.models import FormSemestre
|
||||
import app.pe.rcss.rcss_constantes as rcss_constantes
|
||||
|
||||
TYPES_RCS = {
|
||||
"S1": {
|
||||
"aggregat": ["S1"],
|
||||
"descr": "Semestre 1 (S1)",
|
||||
},
|
||||
"S2": {
|
||||
"aggregat": ["S2"],
|
||||
"descr": "Semestre 2 (S2)",
|
||||
},
|
||||
"1A": {
|
||||
"aggregat": ["S1", "S2"],
|
||||
"descr": "BUT1 (S1+S2)",
|
||||
},
|
||||
"S3": {
|
||||
"aggregat": ["S3"],
|
||||
"descr": "Semestre 3 (S3)",
|
||||
},
|
||||
"S4": {
|
||||
"aggregat": ["S4"],
|
||||
"descr": "Semestre 4 (S4)",
|
||||
},
|
||||
"2A": {
|
||||
"aggregat": ["S3", "S4"],
|
||||
"descr": "BUT2 (S3+S4)",
|
||||
},
|
||||
"3S": {
|
||||
"aggregat": ["S1", "S2", "S3"],
|
||||
"descr": "Moyenne du semestre 1 au semestre 3 (S1+S2+S3)",
|
||||
},
|
||||
"4S": {
|
||||
"aggregat": ["S1", "S2", "S3", "S4"],
|
||||
"descr": "Moyenne du semestre 1 au semestre 4 (S1+S2+S3+S4)",
|
||||
},
|
||||
"S5": {
|
||||
"aggregat": ["S5"],
|
||||
"descr": "Semestre 5 (S5)",
|
||||
},
|
||||
"S6": {
|
||||
"aggregat": ["S6"],
|
||||
"descr": "Semestre 6 (S6)",
|
||||
},
|
||||
"3A": {
|
||||
"aggregat": ["S5", "S6"],
|
||||
"descr": "3ème année (S5+S6)",
|
||||
},
|
||||
"5S": {
|
||||
"aggregat": ["S1", "S2", "S3", "S4", "S5"],
|
||||
"descr": "Moyenne du semestre 1 au semestre 5 (S1+S2+S3+S4+S5)",
|
||||
},
|
||||
"6S": {
|
||||
"aggregat": ["S1", "S2", "S3", "S4", "S5", "S6"],
|
||||
"descr": "Moyenne globale (S1+S2+S3+S4+S5+S6)",
|
||||
},
|
||||
}
|
||||
"""Dictionnaire détaillant les différents regroupements cohérents
|
||||
de semestres (RCS), en leur attribuant un nom et en détaillant
|
||||
le nom des semestres qu'ils regroupent et l'affichage qui en sera fait
|
||||
dans les tableurs de synthèse.
|
||||
"""
|
||||
|
||||
TOUS_LES_RCS_AVEC_PLUSIEURS_SEM = [cle for cle in TYPES_RCS if not cle.startswith("S")]
|
||||
TOUS_LES_RCS = list(TYPES_RCS.keys())
|
||||
TOUS_LES_SEMESTRES = [cle for cle in TYPES_RCS if cle.startswith("S")]
|
||||
|
||||
|
||||
def get_descr_rcs(nom_rcs: str) -> str:
|
||||
"""Renvoie la description pour les tableurs de synthèse
|
||||
Excel d'un nom de RCS"""
|
||||
return rcss_constantes.TYPES_RCS[nom_rcs]["descr"]
|
||||
return TYPES_RCS[nom_rcs]["descr"]
|
||||
|
||||
|
||||
class RCS:
|
||||
"""Modélise un regroupement cohérent de semestres (formsemestre ou de Sx)"""
|
||||
"""Modélise un regroupement cohérent de semestres,
|
||||
tous se terminant par un (form)semestre final.
|
||||
"""
|
||||
|
||||
def __init__(self, nom_rcs: str, semestre_final: FormSemestre):
|
||||
self.nom: str = nom_rcs
|
||||
"""Nom du RCS"""
|
||||
assert self.nom in TOUS_LES_RCS, "Le nom d'un RCS doit être un aggrégat"
|
||||
|
||||
self.formsemestre_final: FormSemestre = semestre_final
|
||||
"""FormSemestre terminal du RCS"""
|
||||
"""(Form)Semestre final du RCS"""
|
||||
|
||||
self.rang_final = self.formsemestre_final.semestre_id
|
||||
"""Le rang du formsemestre final"""
|
||||
"""Rang du formsemestre final"""
|
||||
|
||||
self.rcs_id: (str, int) = (nom_rcs, semestre_final.formsemestre_id)
|
||||
"""Identifiant du RCS sous forme (nom_rcs, id du semestre_terminal)"""
|
||||
|
||||
self.fid_final: int = self.formsemestre_final.formsemestre_id
|
||||
"""Identifiant du (Form)Semestre final"""
|
||||
|
||||
def get_formsemestre_id_final(self) -> int:
|
||||
"""Renvoie l'identifiant du formsemestre final du RCS
|
||||
|
||||
@ -58,5 +126,3 @@ class RCS:
|
||||
self.nom == other.nom
|
||||
and self.formsemestre_final == other.formsemestre_final
|
||||
)
|
||||
|
||||
|
||||
|
59
app/pe/rcss/pe_rcsemx.py
Normal file
59
app/pe/rcss/pe_rcsemx.py
Normal file
@ -0,0 +1,59 @@
|
||||
##############################################################################
|
||||
# Module "Avis de poursuite d'étude"
|
||||
# conçu et développé par Cléo Baras (IUT de Grenoble)
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Created on 01-2024
|
||||
|
||||
@author: barasc
|
||||
"""
|
||||
|
||||
from app.models import FormSemestre
|
||||
from app.pe import pe_sxtag, pe_affichage
|
||||
from app.pe.rcss import pe_rcs, pe_trajectoires
|
||||
|
||||
|
||||
class RCSemX(pe_rcs.RCS):
|
||||
"""Modélise un regroupement cohérent de SemX (en même regroupant
|
||||
des semestres Sx combinés pour former les résultats des étudiants
|
||||
au semestre de rang x) dans le but de synthétiser les résultats
|
||||
du S1 jusqu'au semestre final ciblé par le RCSemX (dépendant de l'aggrégat
|
||||
visé).
|
||||
|
||||
Par ex: Si l'aggrégat du RCSemX est '3S' (=S1+S2+S3),
|
||||
regroupement le SemX du S1 + le SemX du S2 + le SemX du S3 (chacun
|
||||
incluant des infos sur les redoublements).
|
||||
|
||||
Args:
|
||||
nom_rcs: Un nom du RCS (par ex: '5S')
|
||||
semestre_final: Le semestre final du RCS
|
||||
"""
|
||||
|
||||
def __init__(self, nom_rcs: str, semestre_final: FormSemestre):
|
||||
pe_rcs.RCS.__init__(self, nom_rcs, semestre_final)
|
||||
|
||||
self.semXs_aggreges: dict[(str, int) : pe_sxtag.SxTag] = {}
|
||||
"""Les semX à aggréger"""
|
||||
|
||||
def add_semXs(self, semXs: dict[(str, int) : pe_trajectoires.SemX]):
|
||||
"""Ajoute des semXs aux semXs à regrouper dans le RCSemX
|
||||
|
||||
Args:
|
||||
semXs: Dictionnaire ``{(str,fid): RCF}`` à ajouter
|
||||
"""
|
||||
self.semXs_aggreges = self.semXs_aggreges | semXs
|
||||
|
||||
def get_repr(self, verbose=True) -> str:
|
||||
"""Représentation textuelle d'un RCSF
|
||||
basé sur ses RCF aggrégés"""
|
||||
title = f"""{self.__class__.__name__} {pe_rcs.RCS.__str__(self)}"""
|
||||
if verbose:
|
||||
noms = []
|
||||
for semx_id, semx in self.semXs_aggreges.items():
|
||||
noms.append(semx.get_repr(verbose=False))
|
||||
if noms:
|
||||
title += " <<" + "+".join(noms) + ">>"
|
||||
else:
|
||||
title += " <<vide>>"
|
||||
return title
|
87
app/pe/rcss/pe_trajectoires.py
Normal file
87
app/pe/rcss/pe_trajectoires.py
Normal file
@ -0,0 +1,87 @@
|
||||
from app.models import FormSemestre
|
||||
import app.pe.rcss.pe_rcs as pe_rcs
|
||||
|
||||
|
||||
class Trajectoire(pe_rcs.RCS):
|
||||
"""Regroupement Cohérent de Semestres ciblant un type d'aggrégat (par ex.
|
||||
'S2', '3S', '1A') et un semestre final, et dont les données regroupées
|
||||
sont des **FormSemestres** suivis par les étudiants.
|
||||
|
||||
Une *Trajectoire* traduit la succession de semestres
|
||||
qu'ont pu suivre des étudiants pour aller d'un semestre S1 jusqu'au semestre final
|
||||
de l'aggrégat.
|
||||
|
||||
Une *Trajectoire* peut être :
|
||||
|
||||
* un RCS de semestre de type "Sx" (cf. classe "SemX"), qui stocke les
|
||||
formsemestres de rang x qu'ont suivi l'étudiant pour valider le Sx
|
||||
(en général 1 formsemestre pour les non-redoublants et 2 pour les redoublants)
|
||||
|
||||
* un RCS de type iS ou iA (par ex, 3A=S1+S2+S3), qui identifie
|
||||
les formsemestres que des étudiants ont suivis pour les amener jusqu'au semestre
|
||||
terminal du RCS. Par ex: si le RCS est un 3S:
|
||||
|
||||
* des S1+S2+S1+S2+S3 si redoublement de la 1ère année
|
||||
* des S1+S2+(année de césure)+S3 si césure, ...
|
||||
|
||||
Args:
|
||||
nom_rcs: Un nom du RCS (par ex: '5S')
|
||||
semestre_final: Le formsemestre final du RCS
|
||||
"""
|
||||
|
||||
def __init__(self, nom_rcs: str, semestre_final: FormSemestre):
|
||||
pe_rcs.RCS.__init__(self, nom_rcs, semestre_final)
|
||||
|
||||
self.semestres_aggreges: dict[int:FormSemestre] = {}
|
||||
"""Formsemestres regroupés dans le RCS"""
|
||||
|
||||
def add_semestres(self, semestres: dict[int:FormSemestre]):
|
||||
"""Ajout de semestres aux semestres à regrouper
|
||||
|
||||
Args:
|
||||
semestres: Dictionnaire ``{fid: Formsemestre)``
|
||||
"""
|
||||
for sem in semestres.values():
|
||||
assert isinstance(
|
||||
sem, FormSemestre
|
||||
), "Les données aggrégées d'une Trajectoire doivent être des FormSemestres"
|
||||
self.semestres_aggreges = self.semestres_aggreges | semestres
|
||||
|
||||
def get_repr(self, verbose=True) -> str:
|
||||
"""Représentation textuelle d'un RCS
|
||||
basé sur ses semestres aggrégés"""
|
||||
title = f"""{self.__class__.__name__} {pe_rcs.RCS.__str__(self)}"""
|
||||
if verbose:
|
||||
noms = []
|
||||
for fid in self.semestres_aggreges:
|
||||
semestre = self.semestres_aggreges[fid]
|
||||
noms.append(f"S{semestre.semestre_id}#{fid}")
|
||||
noms = sorted(noms)
|
||||
if noms:
|
||||
title += " <" + "+".join(noms) + ">"
|
||||
else:
|
||||
title += " <vide>"
|
||||
return title
|
||||
|
||||
|
||||
class SemX(Trajectoire):
|
||||
"""Trajectoire (regroupement cohérent de (form)semestres
|
||||
dans laquelle tous les semestres regroupés sont de même rang `x`.
|
||||
|
||||
Les SemX stocke les
|
||||
formsemestres de rang x qu'ont suivi l'étudiant pour valider le Sx
|
||||
(en général 1 formsemestre pour les non-redoublants et 2 pour les redoublants).
|
||||
|
||||
Ils servent à calculer les SemXTag (moyennes par tag des RCS de type `Sx`).
|
||||
"""
|
||||
|
||||
def __init__(self, trajectoire: Trajectoire):
|
||||
Trajectoire.__init__(self, trajectoire.nom, trajectoire.formsemestre_final)
|
||||
|
||||
semestres_aggreges = trajectoire.semestres_aggreges
|
||||
for sem in semestres_aggreges.values():
|
||||
assert (
|
||||
sem.semestre_id == trajectoire.rang_final
|
||||
), "Tous les semestres aggrégés d'un SemX doivent être de même rang"
|
||||
|
||||
self.semestres_aggreges = trajectoire.semestres_aggreges
|
@ -1,64 +0,0 @@
|
||||
|
||||
TYPES_RCS = {
|
||||
"S1": {
|
||||
"aggregat": ["S1"],
|
||||
"descr": "Semestre 1 (S1)",
|
||||
},
|
||||
"S2": {
|
||||
"aggregat": ["S2"],
|
||||
"descr": "Semestre 2 (S2)",
|
||||
},
|
||||
"1A": {
|
||||
"aggregat": ["S1", "S2"],
|
||||
"descr": "BUT1 (S1+S2)",
|
||||
},
|
||||
"S3": {
|
||||
"aggregat": ["S3"],
|
||||
"descr": "Semestre 3 (S3)",
|
||||
},
|
||||
"S4": {
|
||||
"aggregat": ["S4"],
|
||||
"descr": "Semestre 4 (S4)",
|
||||
},
|
||||
"2A": {
|
||||
"aggregat": ["S3", "S4"],
|
||||
"descr": "BUT2 (S3+S4)",
|
||||
},
|
||||
"3S": {
|
||||
"aggregat": ["S1", "S2", "S3"],
|
||||
"descr": "Moyenne du semestre 1 au semestre 3 (S1+S2+S3)",
|
||||
},
|
||||
"4S": {
|
||||
"aggregat": ["S1", "S2", "S3", "S4"],
|
||||
"descr": "Moyenne du semestre 1 au semestre 4 (S1+S2+S3+S4)",
|
||||
},
|
||||
"S5": {
|
||||
"aggregat": ["S5"],
|
||||
"descr": "Semestre 5 (S5)",
|
||||
},
|
||||
"S6": {
|
||||
"aggregat": ["S6"],
|
||||
"descr": "Semestre 6 (S6)",
|
||||
},
|
||||
"3A": {
|
||||
"aggregat": ["S5", "S6"],
|
||||
"descr": "3ème année (S5+S6)",
|
||||
},
|
||||
"5S": {
|
||||
"aggregat": ["S1", "S2", "S3", "S4", "S5"],
|
||||
"descr": "Moyenne du semestre 1 au semestre 5 (S1+S2+S3+S4+S5)",
|
||||
},
|
||||
"6S": {
|
||||
"aggregat": ["S1", "S2", "S3", "S4", "S5", "S6"],
|
||||
"descr": "Moyenne globale (S1+S2+S3+S4+S5+S6)",
|
||||
},
|
||||
}
|
||||
"""Dictionnaire détaillant les différents regroupements cohérents
|
||||
de semestres (RCS), en leur attribuant un nom et en détaillant
|
||||
le nom des semestres qu'ils regroupent et l'affichage qui en sera fait
|
||||
dans les tableurs de synthèse.
|
||||
"""
|
||||
|
||||
TOUS_LES_RCS_AVEC_PLUSIEURS_SEM = [cle for cle in TYPES_RCS if not cle.startswith("S")]
|
||||
TOUS_LES_RCS = list(TYPES_RCS.keys())
|
||||
TOUS_LES_SEMESTRES = [cle for cle in TYPES_RCS if cle.startswith("S")]
|
Loading…
Reference in New Issue
Block a user