forked from ScoDoc/ScoDoc
Recode SemestreTag
This commit is contained in:
parent
c9336dd01c
commit
3e55391f7e
@ -98,7 +98,7 @@ class EtudiantsJuryPE:
|
||||
pe_tools.pe_print("3) Analyse des parcours individuels des étudiants")
|
||||
|
||||
no_etud = 0
|
||||
for (no_etud, etudid) in enumerate(self.etudiants_ids):
|
||||
for no_etud, etudid in enumerate(self.etudiants_ids):
|
||||
self.add_etudid(etudid, cosemestres)
|
||||
if (no_etud + 1) % 10 == 0:
|
||||
pe_tools.pe_print((no_etud + 1), " ", end="")
|
||||
@ -115,15 +115,27 @@ class EtudiantsJuryPE:
|
||||
self.formsemestres_jury_ids = self.get_formsemestres_jury()
|
||||
|
||||
# Synthèse
|
||||
pe_tools.pe_print(f" => {len(self.etudiants_jury_ids)} étudiants à diplômer en {annee_diplome}")
|
||||
pe_tools.pe_print(
|
||||
f" => {len(self.etudiants_jury_ids)} étudiants à diplômer en {annee_diplome}"
|
||||
)
|
||||
nbre_abandons = len(self.etudiants_ids) - len(self.etudiants_ids)
|
||||
pe_tools.pe_print(f" => {nbre_abandons} étudiants éliminer pour abandon")
|
||||
pe_tools.pe_print(f" => quelques étudiants futurs diplômés : " + ", ".join([str(etudid) for etudid in list(self.etudiants_jury_ids)[:10]]))
|
||||
pe_tools.pe_print(
|
||||
f" => quelques étudiants futurs diplômés : "
|
||||
+ ", ".join([str(etudid) for etudid in list(self.etudiants_jury_ids)[:10]])
|
||||
)
|
||||
pe_tools.pe_print(
|
||||
f" => semestres dont il faut calculer les moyennes : "
|
||||
+ ", ".join([str(fid) for fid in list(self.formsemestres_jury_ids)])
|
||||
)
|
||||
|
||||
def get_etudids(self, annee_diplome: int, ordre="aucun") -> list:
|
||||
def get_etudids(self, annee_diplome: int = None, ordre="aucun") -> list:
|
||||
"""Liste des etudid des étudiants qui vont être à traiter au jury PE pour
|
||||
l'année de diplômation donnée et n'ayant ni été réorienté, ni abandonné.
|
||||
|
||||
Si l'année de diplômation n'est pas précisée (None), inclus les étudiants réorientés
|
||||
ou ayant abandonné.
|
||||
|
||||
Si l'``ordre`` est précisé, trie la liste par ordre alphabétique de etat_civil
|
||||
|
||||
Args:
|
||||
@ -135,11 +147,17 @@ class EtudiantsJuryPE:
|
||||
|
||||
Note: ex JuryPE.get_etudids_du_jury()
|
||||
"""
|
||||
if annee_diplome:
|
||||
etudids = [
|
||||
etudid
|
||||
for (etudid, donnees) in self.cursus.items()
|
||||
if donnees["diplome"] == annee_diplome and not donnees["abandon"]
|
||||
]
|
||||
else:
|
||||
etudids = [
|
||||
etudid
|
||||
for (etudid, donnees) in self.cursus.items()
|
||||
]
|
||||
if ordre == "alphabetique": # Tri alphabétique
|
||||
etudidsAvecNom = [
|
||||
(etudid, etud["etat_civil"])
|
||||
@ -150,6 +168,24 @@ class EtudiantsJuryPE:
|
||||
etudids = [etud[0] for etud in etudidsAvecNomTrie]
|
||||
return etudids
|
||||
|
||||
def get_etudiants(self, annee_diplome: int = None) -> dict[Identite]:
|
||||
"""Identités des étudiants (sous forme d'un dictionnaire `{etudid: Identite(etudid)}`
|
||||
qui vont être à traiter au jury PE pour
|
||||
l'année de diplômation donnée et n'ayant ni été réorienté, ni abandonné.
|
||||
|
||||
Si l'année de diplômation n'est pas précisée (None), inclus les étudiants réorientés
|
||||
ou ayant abandonné.
|
||||
|
||||
Args:
|
||||
annee_diplome: Année de diplomation visée pour le jury
|
||||
|
||||
Returns:
|
||||
Un dictionnaire `{etudid: Identite(etudid)}`
|
||||
"""
|
||||
etudids = self.get_etudids(annee_diplome=annee_diplome)
|
||||
etudiants = {etudid: self.identites[etudids] for etudid in etudids}
|
||||
return etudiants
|
||||
|
||||
def add_etudid(self, etudid: int, cosemestres):
|
||||
"""Ajoute un étudiant à ceux qui devront être traités pendant le jury pouvant être :
|
||||
|
||||
@ -173,35 +209,37 @@ class EtudiantsJuryPE:
|
||||
Note: ex JuryPE.add_etudid_to_jury()
|
||||
"""
|
||||
|
||||
|
||||
"""L'identité de l'étudiant"""
|
||||
identite = Identite.get_etud(etudid)
|
||||
self.identites[etudid] = identite
|
||||
|
||||
"""Le cursus global de l'étudiant"""
|
||||
"""Le cursus global de l'étudiant (restreint aux semestres APC)"""
|
||||
semestres_etudiant = {
|
||||
frmsem.formsemestre_id: frmsem for frmsem in identite.get_formsemestres()
|
||||
frmsem.formsemestre_id: frmsem
|
||||
for frmsem in identite.get_formsemestres()
|
||||
if frmsem.formation.is_apc()
|
||||
}
|
||||
|
||||
self.cursus[etudid] = {
|
||||
"etudid": etudid, # les infos sur l'étudiant
|
||||
"etat_civil": identite.etat_civil, # Ajout à la table jury
|
||||
"diplome": annee_diplome(identite), # Le date prévisionnelle de son diplôme
|
||||
"formsemestres": semestres_etudiant # les semestres de l'étudiant
|
||||
"formsemestres": semestres_etudiant, # les semestres de l'étudiant
|
||||
}
|
||||
|
||||
""" Est-il réorienté / démissionnaire ou a-t-il arrêté volontairement sa formation ?"""
|
||||
self.cursus[etudid]["abandon"] = arret_de_formation(
|
||||
identite, cosemestres
|
||||
)
|
||||
self.cursus[etudid]["abandon"] = arret_de_formation(identite, cosemestres)
|
||||
|
||||
"""Tri des semestres par n° de semestre"""
|
||||
for nom_sem in pe_tools.TOUS_LES_SEMESTRES:
|
||||
numero_sem = int(nom_sem[1]) + 1
|
||||
self.cursus[etudid][nom_sem] = {fid: semestres_etudiant[fid]
|
||||
i = int(nom_sem[1]) + 1 # le n° du semestre
|
||||
semestres_i = {
|
||||
fid: semestres_etudiant[fid]
|
||||
for fid in semestres_etudiant
|
||||
if semestres_etudiant[fid].semestre_id == numero_sem}
|
||||
|
||||
if semestres_etudiant[fid].semestre_id == i
|
||||
} # les semestres de n°i de l'étudiant
|
||||
dernier_semestre_i = get_dernier_semestre(semestres_i)
|
||||
self.cursus[etudid][nom_sem] = dernier_semestre_i
|
||||
|
||||
"""Tri des semestres par aggrégat"""
|
||||
for parcours in pe_tools.TOUS_LES_AGGREGATS:
|
||||
@ -210,7 +248,9 @@ class EtudiantsJuryPE:
|
||||
|
||||
self.cursus[etudid][parcours] = {}
|
||||
for nom_sem in noms_semestre_de_aggregat:
|
||||
self.cursus[etudid][parcours] = self.cursus[etudid][parcours] | self.cursus[etudid][nom_sem]
|
||||
self.cursus[etudid][parcours] = (
|
||||
self.cursus[etudid][parcours] | self.cursus[etudid][nom_sem]
|
||||
)
|
||||
|
||||
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
||||
pe_tools.pe_print(
|
||||
@ -218,20 +258,64 @@ class EtudiantsJuryPE:
|
||||
end="",
|
||||
)
|
||||
|
||||
|
||||
def get_formsemestres_jury(self):
|
||||
def get_formsemestres_jury(self, semestres_recherches=None):
|
||||
"""Ayant connaissance des étudiants dont il faut calculer les moyennes pour
|
||||
le jury PE (attribut `self.etudiant_ids), renvoie l'ensemble des formsemestres
|
||||
de leur cursus, dont il faudra calculer la moyenne.
|
||||
le jury PE (attribut `self.etudiant_ids) et de leur cursus,
|
||||
renvoie un dictionnaire `{fid: FormSemestre(fid)}`
|
||||
contenant l'ensemble des formsemestres de leur cursus, dont il faudra calculer
|
||||
la moyenne. Les formsemestres sont limités à ceux indiqués dans ``semestres_recherches``.
|
||||
|
||||
Args:
|
||||
semestres_recherches: Une liste ou une chaine de caractères parmi :
|
||||
|
||||
* None : pour obtenir tous les formsemestres du jury
|
||||
* 'Si' : pour obtenir les semestres de n° i (par ex. 'S1')
|
||||
* 'iA' : pour obtenir les semestres de l'année i (par ex. '1A' donne ['S1, 'S2'])
|
||||
* '3S', '4S' : pour obtenir les combinaisons de semestres définies par les aggrégats
|
||||
|
||||
Returns:
|
||||
Un ensemble de formsemestres
|
||||
Un dictionnaire de la forme {fid: FormSemestre(fid)}
|
||||
|
||||
Remarque:
|
||||
Une liste de la forme `[ 'Si', 'iA' , ... ]` (combinant les formats précédents) est possible.
|
||||
"""
|
||||
formsemestres = {}
|
||||
if semestres_recherches is None:
|
||||
"""Appel récursif pour obtenir tous les semestres (validants)"""
|
||||
semestres = self.get_formsemestres_jury(pe_tools.AGGREGAT_DIPLOMANT)
|
||||
return semestres
|
||||
elif isinstance(semestres_recherches, list):
|
||||
"""Appel récursif sur tous les éléments de la liste"""
|
||||
semestres = {}
|
||||
for elmt in semestres_recherches:
|
||||
semestres_elmt = self.get_formsemestres_jury(elmt)
|
||||
semestres = semestres | semestres_elmt
|
||||
return semestres
|
||||
elif (
|
||||
isinstance(semestres_recherches, str)
|
||||
and semestres_recherches in pe_tools.TOUS_LES_AGGREGATS
|
||||
):
|
||||
"""Cas d'un aggrégat avec appel récursif sur toutes les entrées de l'aggrégat"""
|
||||
semestres = self.get_formsemestres_jury(
|
||||
pe_tools.PARCOURS[semestres_recherches]["aggregat"]
|
||||
)
|
||||
return semestres
|
||||
elif (
|
||||
isinstance(semestres_recherches, str)
|
||||
and semestres_recherches in pe_tools.TOUS_LES_SEMESTRES
|
||||
):
|
||||
"""semestres_recherches est un nom de semestre de type S1,
|
||||
pour une recherche parmi les étudiants à prendre en compte
|
||||
dans le jury (diplômé et redoublants non diplômé)
|
||||
"""
|
||||
nom_sem = semestres_recherches
|
||||
semestres = {}
|
||||
for etudid in self.etudiants_ids:
|
||||
formsem_etudid = set(self.cursus[etudid].keys())
|
||||
formsemestres = formsemestres | formsem_etudid
|
||||
return formsemestres
|
||||
semestres = semestres | self.cursus[etudid][nom_sem]
|
||||
return semestres
|
||||
else:
|
||||
raise ValueError(
|
||||
"Probleme de paramètres d'appel dans get_formsemestreids_du_jury"
|
||||
)
|
||||
|
||||
|
||||
def get_etudiants_dans_semestres(semestres: dict[FormSemestre]) -> set:
|
||||
@ -249,7 +333,7 @@ def get_etudiants_dans_semestres(semestres: dict[FormSemestre]) -> set:
|
||||
"""
|
||||
|
||||
etudiants_ids = set()
|
||||
for (fid, sem) in semestres.items(): # pour chacun des semestres de la liste
|
||||
for fid, sem in semestres.items(): # pour chacun des semestres de la liste
|
||||
etudiants_du_sem = {ins.etudid for ins in sem.inscriptions}
|
||||
|
||||
pe_print(f" --> {sem} : {len(etudiants_du_sem)} etudiants")
|
||||
@ -361,3 +445,28 @@ def arret_de_formation(identite: Identite, cosemestres: list[FormSemestre]) -> b
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_dernier_semestre(semestres: dict[FormSemestre]):
|
||||
"""Renvoie le dernier semestre en date d'un dictionnaire
|
||||
de semestres de la forme {fid: FormSemestre(fid)
|
||||
|
||||
Args:
|
||||
semestres: Un dictionnaire de semestres
|
||||
|
||||
Return:
|
||||
Un dictionnaire {fid: FormSemestre(fid)} contenant le semestre le plus récent
|
||||
"""
|
||||
if semestres:
|
||||
fid_dernier_semestre = list(semestres.keys())[0]
|
||||
dernier_semestre = {fid_dernier_semestre: semestres[fid_dernier_semestre]}
|
||||
for fid in semestres:
|
||||
if (
|
||||
semestres[fid].date_fin
|
||||
> dernier_semestre[fid_dernier_semestre].date_fin
|
||||
):
|
||||
dernier_semestre = {fid: semestres[fid]}
|
||||
fid_dernier_semestre = fid
|
||||
return dernier_semestre
|
||||
else:
|
||||
return {}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,110 +37,100 @@ Created on Fri Sep 9 09:15:05 2016
|
||||
"""
|
||||
|
||||
from app import db, log
|
||||
from app.comp import res_sem
|
||||
from app.comp import res_sem, inscr_mod, moy_ue, moy_sem
|
||||
from app.comp.res_common import ResultatsSemestre
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.models import FormSemestre
|
||||
from app.comp.res_sem import load_formsemestre_results
|
||||
from app.models import FormSemestre, Identite, DispenseUE
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
from app.pe import pe_tagtable
|
||||
from app.pe import pe_tools
|
||||
|
||||
from app.scodoc import codes_cursus
|
||||
from app.scodoc import codes_cursus, sco_preferences
|
||||
from app.scodoc import sco_tag_module
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.codes_cursus import UE_SPORT
|
||||
|
||||
|
||||
class SemestreTag(pe_tagtable.TableTag):
|
||||
"""Un SemestreTag représente un tableau de notes (basé sur notesTable)
|
||||
modélisant les résultats des étudiants sous forme de moyennes par tag.
|
||||
|
||||
Attributs récupérés via des NotesTables :
|
||||
- nt: le tableau de notes du semestre considéré
|
||||
- nt.inscrlist: étudiants inscrits à ce semestre, par ordre alphabétique (avec demissions)
|
||||
- nt.identdict: { etudid : ident }
|
||||
- liste des moduleimpl { ... 'module_id', ...}
|
||||
|
||||
Attributs supplémentaires :
|
||||
- inscrlist/identdict: étudiants inscrits hors démissionnaires ou défaillants
|
||||
- _tagdict : Dictionnaire résumant les tags et les modules du semestre auxquels ils sont liés
|
||||
|
||||
|
||||
Attributs hérités de TableTag :
|
||||
- nom :
|
||||
- resultats: {tag: { etudid: (note_moy, somme_coff), ...} , ...}
|
||||
- rang
|
||||
- statistiques
|
||||
|
||||
Redéfinition :
|
||||
- get_etudids() : les etudids des étudiants non défaillants ni démissionnaires
|
||||
"""Un SemestreTag représente les résultats des étudiants à un semestre, en donnant
|
||||
accès aux moyennes par tag.
|
||||
Il s'appuie principalement sur FormSemestre et sur ResultatsSemestreBUT.
|
||||
"""
|
||||
|
||||
DEBUG = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Fonctions d'initialisation
|
||||
# -----------------------------------------------------------------------------
|
||||
def __init__(self, notetable, sem): # Initialisation sur la base d'une notetable
|
||||
"""Instantiation d'un objet SemestreTag à partir d'un tableau de note
|
||||
et des informations sur le semestre pour le dater
|
||||
def __init__(self, nom: str, formsemestre_id: int):
|
||||
"""
|
||||
Args:
|
||||
nom: Nom à donner au SemestreTag
|
||||
formsemestre_id: Identifiant du FormSemestre sur lequel il se base
|
||||
"""
|
||||
pe_tagtable.TableTag.__init__(
|
||||
self,
|
||||
nom="S%d %s %s-%s"
|
||||
% (
|
||||
sem["semestre_id"],
|
||||
"ENEPS"
|
||||
if "ENEPS" in sem["titre"]
|
||||
else "UFA"
|
||||
if "UFA" in sem["titre"]
|
||||
else "FI",
|
||||
sem["annee_debut"],
|
||||
sem["annee_fin"],
|
||||
),
|
||||
nom=nom
|
||||
)
|
||||
"""Le semestre"""
|
||||
self.formsemestre_id = formsemestre_id
|
||||
self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
|
||||
# Les attributs spécifiques
|
||||
self.nt = notetable
|
||||
"""Les résultats du semestre"""
|
||||
self.nt = load_formsemestre_results(self.formsemestre)
|
||||
|
||||
# Les attributs hérités : la liste des étudiants
|
||||
self.inscrlist = [
|
||||
etud
|
||||
for etud in self.nt.inscrlist
|
||||
if self.nt.get_etud_etat(etud["etudid"]) == scu.INSCRIT
|
||||
]
|
||||
self.identdict = {
|
||||
etudid: ident
|
||||
for (etudid, ident) in self.nt.identdict.items()
|
||||
if etudid in self.get_etudids()
|
||||
} # Liste des étudiants non démissionnaires et non défaillants
|
||||
"""Les étudiants"""
|
||||
self.etuds = self.nt.etuds
|
||||
self.etudiants = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
||||
|
||||
# Les modules pris en compte dans le calcul des moyennes par tag => ceux des UE standards
|
||||
self.modimpls = [
|
||||
modimpl
|
||||
for modimpl in self.nt.formsemestre.modimpls_sorted
|
||||
if modimpl.module.ue.type == codes_cursus.UE_STANDARD
|
||||
] # la liste des modules (objet modimpl)
|
||||
self.somme_coeffs = sum(
|
||||
[
|
||||
modimpl.module.coefficient
|
||||
for modimpl in self.modimpls
|
||||
if modimpl.module.coefficient is not None
|
||||
]
|
||||
)
|
||||
"""Les notes, les modules implémentés triés, les étudiants, les coeffs,
|
||||
récupérés notamment de py:mod:`res_but`
|
||||
"""
|
||||
self.sem_cube = self.nt.sem_cube
|
||||
self.modimpls_sorted = self.nt.formsemestre.modimpls_sorted
|
||||
self.modimpl_coefs_df = self.nt.modimpl_coefs_df
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def comp_data_semtag(self):
|
||||
"""Calcule tous les données numériques associées au semtag"""
|
||||
# Attributs relatifs aux tag pour les modules pris en compte
|
||||
self.tagdict = (
|
||||
self.do_tagdict()
|
||||
) # Dictionnaire résumant les tags et les données (normalisées) des modules du semestre auxquels ils sont liés
|
||||
"""Les inscriptions au module et les dispenses d'UE"""
|
||||
self.modimpl_inscr_df = self.nt.modimpl_inscr_df
|
||||
self.ues = self.nt.ues
|
||||
self.ues_inscr_parcours_df = self.nt.load_ues_inscr_parcours()
|
||||
self.dispense_ues = self.nt.dispense_ues
|
||||
|
||||
# Calcul des moyennes de chaque étudiant puis ajoute la moyenne au sens "DUT"
|
||||
for tag in self.tagdict:
|
||||
self.add_moyennesTag(tag, self.comp_MoyennesTag(tag, force=True))
|
||||
self.add_moyennesTag("but", self.get_moyennes_DUT())
|
||||
self.taglist = sorted(
|
||||
list(self.tagdict.keys()) + ["but"]
|
||||
) # actualise la liste des tags
|
||||
"""Les tags"""
|
||||
self.tags = get_synthese_tags_semestre(self.nt.formsemestre)
|
||||
|
||||
"""Supprime les tags réservés"""
|
||||
for tag in pe_tagtable.TAGS_RESERVES:
|
||||
if tag in self.tags:
|
||||
del self.tags[tag]
|
||||
|
||||
"""Calcul des moyennes & les classements de chaque étudiant à chaque tag"""
|
||||
self.moyennes_tags = {}
|
||||
|
||||
for tag in self.tags:
|
||||
pe_tools.pe_print(f" -> Traitement du tag {tag}")
|
||||
moy_gen_tag = self.compute_moyenne_tag(tag)
|
||||
class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int
|
||||
self.moyennes_tags[tag] = {
|
||||
"notes": moy_gen_tag,
|
||||
"classements": class_gen_tag,
|
||||
"min": moy_gen_tag.min(),
|
||||
"max": moy_gen_tag.max(),
|
||||
"moy": moy_gen_tag.mean(),
|
||||
"nb_inscrits": len(moy_gen_tag),
|
||||
}
|
||||
|
||||
"""Ajoute les moyennes générales de BUT pour le semestre considéré"""
|
||||
pe_tools.pe_print(f" -> Traitement du tag but")
|
||||
moy_gen_but = self.nt.etud_moy_gen
|
||||
class_gen_but = self.nt.etud_moy_gen_ranks_int
|
||||
self.moyennes_tags["but"] = {
|
||||
"notes": moy_gen_but,
|
||||
"classements": class_gen_but,
|
||||
"min": moy_gen_but.min(),
|
||||
"max": moy_gen_but.max(),
|
||||
"moy": moy_gen_but.mean(),
|
||||
"nb_inscrits": len(moy_gen_but),
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_etudids(self):
|
||||
@ -148,89 +138,64 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
return [etud["etudid"] for etud in self.inscrlist]
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def do_tagdict(self):
|
||||
"""Parcourt les modimpl du semestre (instance des modules d'un programme) et synthétise leurs données sous la
|
||||
forme d'un dictionnaire reliant les tags saisis dans le programme aux
|
||||
données des modules qui les concernent, à savoir les modimpl_id, les module_id, le code du module, le coeff,
|
||||
la pondération fournie avec le tag (par défaut 1 si non indiquée).
|
||||
{ tagname1 : { modimpl_id1 : { 'module_id' : ..., 'coeff' : ..., 'coeff_norm' : ..., 'ponderation' : ..., 'module_code' : ..., 'ue_xxx' : ...},
|
||||
modimpl_id2 : ....
|
||||
},
|
||||
tagname2 : ...
|
||||
}
|
||||
Renvoie le dictionnaire ainsi construit.
|
||||
def compute_moyenne_tag(self, tag: str) -> list:
|
||||
"""Calcule la moyenne des étudiants pour le tag indiqué,
|
||||
pour ce SemestreTag.
|
||||
|
||||
Rq: choix fait de repérer les modules par rapport à leur modimpl_id (valable uniquement pour un semestre), car
|
||||
correspond à la majorité des calculs de moyennes pour les étudiants
|
||||
(seuls ceux qui ont capitalisé des ue auront un régime de calcul différent).
|
||||
"""
|
||||
tagdict = {}
|
||||
Sont pris en compte les modules implémentés associés au tag,
|
||||
avec leur éventuel coefficient de **repondération**, en utilisant les notes
|
||||
chargées pour ce SemestreTag.
|
||||
|
||||
for modimpl in []: # CB: désactive la recherche des tags -> self.modimpls:
|
||||
modimpl_id = modimpl.id
|
||||
# liste des tags pour le modimpl concerné:
|
||||
tags = sco_tag_module.module_tag_list(modimpl.module.id)
|
||||
|
||||
for (
|
||||
tag
|
||||
) in tags: # tag de la forme "mathématiques", "théorie", "pe:0", "maths:2"
|
||||
[tagname, ponderation] = sco_tag_module.split_tagname_coeff(
|
||||
tag
|
||||
) # extrait un tagname et un éventuel coefficient de pondération (par defaut: 1)
|
||||
# tagname = tagname
|
||||
if tagname not in tagdict: # Ajout d'une clé pour le tag
|
||||
tagdict[tagname] = {}
|
||||
|
||||
# Ajout du modimpl au tagname considéré
|
||||
tagdict[tagname][modimpl_id] = {
|
||||
"module_id": modimpl.module.id, # les données sur le module
|
||||
"coeff": modimpl.module.coefficient, # le coeff du module dans le semestre
|
||||
"ponderation": ponderation, # la pondération demandée pour le tag sur le module
|
||||
"module_code": modimpl.module.code, # le code qui doit se retrouver à l'identique dans des ue capitalisee
|
||||
"ue_id": modimpl.module.ue.id, # les données sur l'ue
|
||||
"ue_code": modimpl.module.ue.ue_code,
|
||||
"ue_acronyme": modimpl.module.ue.acronyme,
|
||||
}
|
||||
return tagdict
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def comp_MoyennesTag(self, tag, force=False) -> list:
|
||||
"""Calcule et renvoie les "moyennes" de tous les étudiants du SemTag
|
||||
(non défaillants) à un tag donné, en prenant en compte
|
||||
tous les modimpl_id concerné par le tag, leur coeff et leur pondération.
|
||||
Force ou non le calcul de la moyenne lorsque des notes sont manquantes.
|
||||
|
||||
Renvoie les informations sous la forme d'une liste
|
||||
[ (moy, somme_coeff_normalise, etudid), ...]
|
||||
"""
|
||||
lesMoyennes = []
|
||||
for etudid in self.get_etudids():
|
||||
(
|
||||
notes,
|
||||
coeffs_norm,
|
||||
ponderations,
|
||||
) = self.get_listesNotesEtCoeffsTagEtudiant(
|
||||
tag, etudid
|
||||
) # les notes associées au tag
|
||||
coeffs = comp_coeff_pond(
|
||||
coeffs_norm, ponderations
|
||||
) # les coeff pondérés par les tags
|
||||
(moyenne, somme_coeffs) = pe_tagtable.moyenne_ponderee_terme_a_terme(
|
||||
notes, coeffs, force=force
|
||||
)
|
||||
lesMoyennes += [
|
||||
(moyenne, somme_coeffs, etudid)
|
||||
] # Un tuple (pour classement résumant les données)
|
||||
return lesMoyennes
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_moyennes_DUT(self):
|
||||
"""Lit les moyennes DUT du semestre pour tous les étudiants
|
||||
et les renvoie au même format que comp_MoyennesTag"""
|
||||
return [
|
||||
(self.nt.etud_moy_gen[etudid], 1.0, etudid) for etudid in self.get_etudids()
|
||||
"""Adaptation du mask de calcul des moyennes au tag visé"""
|
||||
modimpls_mask = [
|
||||
modimpl.module.ue.type != UE_SPORT
|
||||
for modimpl in self.formsemestre.modimpls_sorted
|
||||
]
|
||||
|
||||
"""Désactive tous les modules qui ne sont pas pris en compte pour ce tag"""
|
||||
for i, modimpl in enumerate(self.formsemestre.modimpls_sorted):
|
||||
if modimpl.moduleimpl_id not in self.tags[tag]:
|
||||
modimpls_mask[i] = False
|
||||
|
||||
"""Applique la pondération des coefficients"""
|
||||
modimpl_coefs_ponderes_df = self.modimpl_coefs_df.copy()
|
||||
for modimpl_id in self.tags[tag]:
|
||||
ponderation = self.tags[tag][modimpl_id]["ponderation"]
|
||||
modimpl_coefs_ponderes_df[modimpl_id] *= ponderation
|
||||
|
||||
"""Calcule les moyennes pour le tag visé dans chaque UE (dataframe etudid x ues)"""
|
||||
moyennes_ues_tag = moy_ue.compute_ue_moys_apc(
|
||||
self.sem_cube,
|
||||
self.etuds,
|
||||
self.formsemestre.modimpls_sorted,
|
||||
self.modimpl_inscr_df,
|
||||
modimpl_coefs_ponderes_df,
|
||||
modimpls_mask,
|
||||
self.dispense_ues,
|
||||
block=self.formsemestre.block_moyennes,
|
||||
)
|
||||
|
||||
"""Les ects"""
|
||||
ects = self.ues_inscr_parcours_df.fillna(0.0) * [
|
||||
ue.ects for ue in self.ues if ue.type != UE_SPORT
|
||||
]
|
||||
|
||||
"""Calcule la moyenne générale dans le semestre (pondérée par le ECTS)"""
|
||||
moy_gen_tag = moy_sem.compute_sem_moys_apc_using_ects(
|
||||
moyennes_ues_tag,
|
||||
ects,
|
||||
formation_id=self.formsemestre.formation_id,
|
||||
skip_empty_ues=True,
|
||||
)
|
||||
|
||||
return moy_gen_tag
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
||||
"""Renvoie un couple donnant la note et le coeff normalisé d'un étudiant à un module d'id modimpl_id.
|
||||
@ -319,27 +284,6 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records")
|
||||
return []
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):
|
||||
"""Renvoie un triplet (notes, coeffs_norm, ponderations) où notes, coeff_norm et ponderation désignent trois listes
|
||||
donnant -pour un tag donné- les note, coeff et ponderation de chaque modimpl à prendre en compte dans
|
||||
le calcul de la moyenne du tag.
|
||||
Les notes et coeff_norm sont extraits grâce à SemestreTag.get_noteEtCoeff_modimpl (donc dans semestre courant ou UE capitalisée).
|
||||
Les pondérations sont celles déclarées avec le tag (cf. _tagdict)."""
|
||||
|
||||
notes = []
|
||||
coeffs_norm = []
|
||||
ponderations = []
|
||||
for moduleimpl_id, modimpl in self.tagdict[
|
||||
tag
|
||||
].items(): # pour chaque module du semestre relatif au tag
|
||||
(note, coeff_norm) = self.get_noteEtCoeff_modimpl(moduleimpl_id, etudid)
|
||||
if note != None:
|
||||
notes.append(note)
|
||||
coeffs_norm.append(coeff_norm)
|
||||
ponderations.append(modimpl["ponderation"])
|
||||
return (notes, coeffs_norm, ponderations)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Fonctions d'affichage (et d'export csv) des données du semestre en mode debug
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -435,8 +379,9 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
return chaine
|
||||
|
||||
def str_tagsModulesEtCoeffs(self):
|
||||
"""Renvoie une chaine affichant la liste des tags associés au semestre, les modules qui les concernent et les coeffs de pondération.
|
||||
Plus concrêtement permet d'afficher le contenu de self._tagdict"""
|
||||
"""Renvoie une chaine affichant la liste des tags associés au semestre,
|
||||
les modules qui les concernent et les coeffs de pondération.
|
||||
Plus concrètement permet d'afficher le contenu de self._tagdict"""
|
||||
chaine = "Semestre %s d'id %d" % (self.nom, id(self)) + "\n"
|
||||
chaine += " -> somme de coeffs: " + str(self.somme_coeffs) + "\n"
|
||||
taglist = self.get_all_tags()
|
||||
@ -463,25 +408,6 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
|
||||
|
||||
# *********************************************
|
||||
def comp_coeff_pond(coeffs, ponderations):
|
||||
"""
|
||||
Applique une ponderation (indiquée dans la liste ponderations) à une liste de coefficients :
|
||||
ex: coeff = [2, 3, 1, None], ponderation = [1, 2, 0, 1] => [2*1, 3*2, 1*0, None]
|
||||
Les coeff peuvent éventuellement être None auquel cas None est conservé ;
|
||||
Les pondérations sont des floattants
|
||||
"""
|
||||
if (
|
||||
coeffs == None
|
||||
or ponderations == None
|
||||
or not isinstance(coeffs, list)
|
||||
or not isinstance(ponderations, list)
|
||||
or len(coeffs) != len(ponderations)
|
||||
):
|
||||
raise ValueError("Erreur de paramètres dans comp_coeff_pond")
|
||||
return [
|
||||
(None if coeffs[i] == None else coeffs[i] * ponderations[i])
|
||||
for i in range(len(coeffs))
|
||||
]
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -509,3 +435,58 @@ def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float:
|
||||
if ue_status is None:
|
||||
return None
|
||||
return ue_status["moy"]
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_synthese_tags_semestre(formsemestre: FormSemestre):
|
||||
"""Etant données les implémentations des modules du semestre (modimpls),
|
||||
synthétise les tags les concernant (tags saisis dans le programme pédagogique)
|
||||
en les associant aux modimpls qui les concernent (modimpl_id, module_id,
|
||||
le code du module, coeff et pondération fournie avec le tag (par défaut 1 si non indiquée)).
|
||||
|
||||
{ tagname1: { modimpl_id1: { 'module_id': ...,
|
||||
'coeff': ...,
|
||||
'coeff_norm': ...,
|
||||
'ponderation': ...,
|
||||
'module_code': ...,
|
||||
'ue_xxx': ...},
|
||||
}
|
||||
}
|
||||
|
||||
Args:
|
||||
formsemestre: Le formsemestre à la base de la recherche des tags
|
||||
"""
|
||||
synthese_tags = {}
|
||||
|
||||
"""Instance des modules du semestre"""
|
||||
modimpls = formsemestre.modimpls_sorted
|
||||
|
||||
for modimpl in modimpls:
|
||||
modimpl_id = modimpl.id
|
||||
|
||||
"""Liste des tags pour le module concerné"""
|
||||
tags = sco_tag_module.module_tag_list(modimpl.module.id)
|
||||
|
||||
"""Traitement des tags recensés, chacun pouvant étant de la forme
|
||||
"mathématiques", "théorie", "pe:0", "maths:2"
|
||||
"""
|
||||
for tag in tags:
|
||||
"""Extraction du nom du tag et du coeff de pondération"""
|
||||
(tagname, ponderation) = sco_tag_module.split_tagname_coeff(tag)
|
||||
|
||||
"""Ajout d'une clé pour le tag"""
|
||||
if tagname not in synthese_tags:
|
||||
synthese_tags[tagname] = {}
|
||||
|
||||
"""Ajout du module (modimpl) au tagname considéré"""
|
||||
synthese_tags[tagname][modimpl_id] = {
|
||||
"modimpl": modimpl, # les données sur le module
|
||||
# "coeff": modimpl.module.coefficient, # le coeff du module dans le semestre
|
||||
"ponderation": ponderation, # la pondération demandée pour le tag sur le module
|
||||
# "module_code": modimpl.module.code, # le code qui doit se retrouver à l'identique dans des ue capitalisee
|
||||
# "ue_id": modimpl.module.ue.id, # les données sur l'ue
|
||||
# "ue_code": modimpl.module.ue.ue_code,
|
||||
# "ue_acronyme": modimpl.module.ue.acronyme,
|
||||
}
|
||||
|
||||
return synthese_tags
|
||||
|
@ -41,36 +41,52 @@ import datetime
|
||||
import numpy as np
|
||||
|
||||
from app.scodoc import sco_utils as scu
|
||||
import pandas as pd
|
||||
|
||||
|
||||
TAGS_RESERVES = ["but"]
|
||||
|
||||
|
||||
class TableTag(object):
|
||||
"""
|
||||
Classe mémorisant les moyennes des étudiants à différents tag et permettant de calculer les rangs et les statistiques :
|
||||
- nom : Nom représentatif des données de la Table
|
||||
- inscrlist : Les étudiants inscrits dans le TagTag avec leur information de la forme :
|
||||
Classe mémorisant les moyennes des étudiants à différents tags et permettant de
|
||||
calculer des rangs et des statistiques.
|
||||
|
||||
Ses attributs sont:
|
||||
|
||||
* nom : Nom représentatif des données de la Table
|
||||
* inscrlist : Les étudiants inscrits dans le TagTag avec leur information de la forme :
|
||||
{ etudid : dictionnaire d'info extrait de Scodoc, ...}
|
||||
- taglist : Liste triée des noms des tags
|
||||
- resultats : Dictionnaire donnant les notes-moyennes de chaque étudiant par tag et la somme commulée
|
||||
* taglist : Liste triée des noms des tags
|
||||
* resultats : Dictionnaire donnant les notes-moyennes de chaque étudiant par tag et la somme commulée
|
||||
des coeff utilisées dans le calcul de la moyenne pondérée, sous la forme :
|
||||
{ tag : { etudid: (note_moy, somme_coeff_norm),
|
||||
...}
|
||||
- rangs : Dictionnaire donnant les rang par tag de chaque étudiant de la forme :
|
||||
* rangs : Dictionnaire donnant les rang par tag de chaque étudiant de la forme :
|
||||
{ tag : {etudid: rang, ...} }
|
||||
- nbinscrits : Nombre d'inscrits dans le semestre (pas de distinction entre les tags)
|
||||
- statistiques : Dictionnaire donnant les stastitiques (moyenne, min, max) des résultats par tag de la forme :
|
||||
* nbinscrits : Nombre d'inscrits dans le semestre (pas de distinction entre les tags)
|
||||
* statistiques : Dictionnaire donnant les statistiques (moyenne, min, max) des résultats par tag de la forme :
|
||||
{ tag : (moy, min, max), ...}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, nom=""):
|
||||
def __init__(self, nom: str):
|
||||
"""Les attributs basiques des TagTable, qui seront initialisés
|
||||
dans les classes dérivées
|
||||
"""
|
||||
self.nom = nom
|
||||
self.inscrlist = []
|
||||
self.identdict = {}
|
||||
self.taglist = []
|
||||
"""Les étudiants"""
|
||||
self.etudiants = {}
|
||||
"""Les moyennes par tag"""
|
||||
self.moyennes_tags = {}
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
def get_all_tags(self):
|
||||
"""Renvoie la liste des tags du semestre triée par ordre alphabétique"""
|
||||
# return self.taglist
|
||||
return sorted(self.moyennes_tags.keys())
|
||||
|
||||
self.resultats = {}
|
||||
self.rangs = {}
|
||||
self.statistiques = {}
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# Accesseurs
|
||||
@ -80,8 +96,8 @@ class TableTag(object):
|
||||
def get_moy_from_resultats(self, tag, etudid):
|
||||
"""Renvoie la moyenne obtenue par un étudiant à un tag donné au regard du format de self.resultats"""
|
||||
return (
|
||||
self.resultats[tag][etudid][0]
|
||||
if tag in self.resultats and etudid in self.resultats[tag]
|
||||
self.moyennes_tags[tag][etudid][0]
|
||||
if tag in self.moyennes_tags and etudid in self.moyennes_tags[tag]
|
||||
else None
|
||||
)
|
||||
|
||||
@ -90,7 +106,7 @@ class TableTag(object):
|
||||
"""Renvoie le rang à un tag d'un étudiant au regard du format de self.resultats"""
|
||||
return (
|
||||
self.rangs[tag][etudid]
|
||||
if tag in self.resultats and etudid in self.resultats[tag]
|
||||
if tag in self.moyennes_tags and etudid in self.moyennes_tags[tag]
|
||||
else None
|
||||
)
|
||||
|
||||
@ -100,16 +116,11 @@ class TableTag(object):
|
||||
au regard du format de self.resultats.
|
||||
"""
|
||||
return (
|
||||
self.resultats[tag][etudid][1]
|
||||
if tag in self.resultats and etudid in self.resultats[tag]
|
||||
self.moyennes_tags[tag][etudid][1]
|
||||
if tag in self.moyennes_tags and etudid in self.moyennes_tags[tag]
|
||||
else None
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
def get_all_tags(self):
|
||||
"""Renvoie la liste des tags du semestre triée par ordre alphabétique"""
|
||||
# return self.taglist
|
||||
return sorted(self.resultats.keys())
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
def get_nbinscrits(self):
|
||||
@ -170,10 +181,12 @@ class TableTag(object):
|
||||
avec calcul du rang
|
||||
:param tag: Un tag
|
||||
:param listMoyEtCoeff: Une liste donnant [ (moy, coeff, etudid) ]
|
||||
|
||||
TODO:: Inutile maintenant ?
|
||||
"""
|
||||
# ajout des moyennes au dictionnaire résultat
|
||||
if listMoyEtCoeff:
|
||||
self.resultats[tag] = {
|
||||
self.moyennes_tags[tag] = {
|
||||
etudid: (moyenne, somme_coeffs)
|
||||
for (moyenne, somme_coeffs, etudid) in listMoyEtCoeff
|
||||
}
|
||||
@ -204,11 +217,12 @@ class TableTag(object):
|
||||
self.statistiques
|
||||
"""
|
||||
stats = ("-NA-", "-", "-")
|
||||
if tag not in self.resultats:
|
||||
if tag not in self.moyennes_tags:
|
||||
return stats
|
||||
|
||||
notes = [
|
||||
self.get_moy_from_resultats(tag, etudid) for etudid in self.resultats[tag]
|
||||
self.get_moy_from_resultats(tag, etudid)
|
||||
for etudid in self.moyennes_tags[tag]
|
||||
] # les notes du tag
|
||||
notes_valides = [
|
||||
note for note in notes if isinstance(note, float) and note != None
|
||||
@ -225,7 +239,7 @@ class TableTag(object):
|
||||
"""Renvoie une chaine de caractères (valable pour un csv)
|
||||
décrivant la moyenne et le rang d'un étudiant, pour un tag donné ;
|
||||
"""
|
||||
if tag not in self.get_all_tags() or etudid not in self.resultats[tag]:
|
||||
if tag not in self.get_all_tags() or etudid not in self.moyennes_tags[tag]:
|
||||
return ""
|
||||
|
||||
moystr = TableTag.str_moytag(
|
||||
@ -256,30 +270,18 @@ class TableTag(object):
|
||||
str_moytag = classmethod(str_moytag)
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
def str_tagtable(self, delim=";", decimal_sep=","):
|
||||
"""Renvoie une chaine de caractère listant toutes les moyennes, les rangs des étudiants pour tous les tags."""
|
||||
entete = ["etudid", "nom", "prenom"]
|
||||
def str_tagtable(self):
|
||||
"""Renvoie une chaine de caractère listant toutes les moyennes,
|
||||
les rangs des étudiants pour tous les tags."""
|
||||
|
||||
etudiants = self.etudiants
|
||||
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom"])
|
||||
|
||||
for tag in self.get_all_tags():
|
||||
entete += [titre + "_" + tag for titre in ["note", "rang", "nb_inscrit"]]
|
||||
chaine = delim.join(entete) + "\n"
|
||||
df = df.join(self.moyennes_tags[tag]["notes"].rename(f"moy {tag}"))
|
||||
df = df.join(self.moyennes_tags[tag]["classements"].rename(f"class {tag}"))
|
||||
|
||||
for etudid in self.identdict:
|
||||
descr = delim.join(
|
||||
[
|
||||
str(etudid),
|
||||
self.identdict[etudid]["nom"],
|
||||
self.identdict[etudid]["prenom"],
|
||||
]
|
||||
)
|
||||
descr += delim + self.str_res_d_un_etudiant(etudid, delim)
|
||||
chaine += descr + "\n"
|
||||
|
||||
# Ajout des stats ... à faire
|
||||
|
||||
if decimal_sep != ".":
|
||||
return chaine.replace(".", decimal_sep)
|
||||
else:
|
||||
return chaine
|
||||
return df.to_csv(sep=";")
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
@ -292,24 +292,35 @@ def get_etud_tagged_modules(etudid, tagname):
|
||||
return R
|
||||
|
||||
|
||||
def split_tagname_coeff(tag, separateur=":"):
|
||||
"""Découpe un tag saisi par un utilisateur pour en extraire un tagname
|
||||
(chaine de caractère correspondant au tag)
|
||||
et un éventuel coefficient de pondération, avec le séparateur fourni (par défaut ":").
|
||||
Renvoie le résultat sous la forme d'une liste [tagname, pond] où pond est un float
|
||||
def split_tagname_coeff(tag: str, separateur=":") -> tuple[str, float]:
|
||||
"""Découpage d'un tag, tel que saisi par un utilisateur dans le programme,
|
||||
pour en extraire :
|
||||
|
||||
Auteur: CB
|
||||
* son _nom de tag_ (tagname) (chaine de caractère correspondant au tag)
|
||||
* un éventuel coefficient de pondération, avec le séparateur fourni (par défaut ":").
|
||||
|
||||
Args:
|
||||
tag: La saisie utilisateur du tag dans le programme
|
||||
separateur: Le séparateur des informations dans la saisie utilisateur
|
||||
|
||||
Return:
|
||||
Tuple (tagname, coeff_de_ponderation) extrait de la saisie utilisateur
|
||||
(avec coeff_de_ponderation=1.0 si non mentionné)
|
||||
|
||||
Author:
|
||||
Cléo Baras
|
||||
"""
|
||||
if separateur in tag:
|
||||
temp = tag.split(":")
|
||||
try:
|
||||
pond = float(temp[1])
|
||||
return [temp[0], pond]
|
||||
return (temp[0], pond)
|
||||
except:
|
||||
return [tag, 1.0] # renvoie tout le tag si le découpage à échouer
|
||||
"""Renvoie tout le tag si le découpage à échouer"""
|
||||
return (tag, 1.0)
|
||||
else:
|
||||
# initialise le coeff de pondération à 1 lorsqu'aucun coeff de pondération n'est indiqué dans le tag
|
||||
return [tag, 1.0]
|
||||
"""initialise le coeff de pondération à 1 lorsqu'aucun coeff de pondération n'est indiqué dans le tag"""
|
||||
return (tag, 1.0)
|
||||
|
||||
|
||||
"""Tests:
|
||||
|
Loading…
Reference in New Issue
Block a user