|
|
|
@ -57,11 +57,13 @@ class EtudiantsJuryPE:
|
|
|
|
|
|
|
|
|
|
"Les identités des étudiants traités pour le jury"
|
|
|
|
|
self.identites = {} # ex. ETUDINFO_DICT
|
|
|
|
|
"Les cursus (semestres suivis, abandons, ...) des étudiants"
|
|
|
|
|
"Les cursus (semestres suivis, abandons, dernier S1, S2, ...) des étudiants"
|
|
|
|
|
self.cursus = {}
|
|
|
|
|
"""Les aggrégats des semestres suivis (par ex: 3S=S1+S2+S3 à prendre en compte avec d'éventuels redoublements) des étudiants"""
|
|
|
|
|
self.aggregats = {}
|
|
|
|
|
|
|
|
|
|
"Les etudids des étudiants à considérer au jury (ceux qui seront effectivement diplômés)"
|
|
|
|
|
self.etudiants_jury_ids = {}
|
|
|
|
|
self.diplomes_ids = {}
|
|
|
|
|
"Les etudids des étudiants dont il faut calculer les moyennes/classements (même si d'éventuels abandons)"
|
|
|
|
|
self.etudiants_ids = {}
|
|
|
|
|
|
|
|
|
@ -83,6 +85,7 @@ class EtudiantsJuryPE:
|
|
|
|
|
"""
|
|
|
|
|
"Les cosemestres donnant lieu à même année de diplome"
|
|
|
|
|
cosemestres = pe_tools.get_cosemestres_diplomants(annee_diplome, None)
|
|
|
|
|
self.cosemestres = cosemestres
|
|
|
|
|
pe_tools.pe_print(
|
|
|
|
|
"1) Recherche des coSemestres -> %d trouvés" % len(cosemestres)
|
|
|
|
|
)
|
|
|
|
@ -116,23 +119,24 @@ class EtudiantsJuryPE:
|
|
|
|
|
pe_tools.pe_print()
|
|
|
|
|
|
|
|
|
|
"""Les étudiants à prendre dans le diplôme, étudiants ayant abandonnés non compris"""
|
|
|
|
|
self.etudiants_jury_ids = self.get_etudiants(annee_diplome)
|
|
|
|
|
self.diplomes_ids = self.get_etudiants(annee_diplome)
|
|
|
|
|
|
|
|
|
|
"""Les étudiants dont il faut calculer les moyennes"""
|
|
|
|
|
self.etudiants_ids = {etudid for etudid in self.cursus}
|
|
|
|
|
self.etudiants_ids = {etudid for etudid in self.identites}
|
|
|
|
|
|
|
|
|
|
"""Les formsemestres (des étudiants) dont il faut calculer les moyennes"""
|
|
|
|
|
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}"
|
|
|
|
|
f" => {len(self.diplomes_ids)} étudiants à diplômer en {annee_diplome}"
|
|
|
|
|
)
|
|
|
|
|
nbre_abandons = len(self.etudiants_ids) - len(self.etudiants_ids)
|
|
|
|
|
nbre_abandons = len(self.etudiants_ids) - len(self.diplomes_ids)
|
|
|
|
|
pe_tools.pe_print(f" => {nbre_abandons} étudiants éliminer pour abandon")
|
|
|
|
|
pe_tools.pe_print(f" => {len(self.formsemestres_jury_ids)} semestres dont il faut calculer la moyenne")
|
|
|
|
|
pe_tools.pe_print(
|
|
|
|
|
f" => quelques étudiants futurs diplômés : "
|
|
|
|
|
+ ", ".join([str(etudid) for etudid in list(self.etudiants_jury_ids)[:10]])
|
|
|
|
|
+ ", ".join([str(etudid) for etudid in list(self.diplomes_ids)[:10]])
|
|
|
|
|
)
|
|
|
|
|
pe_tools.pe_print(
|
|
|
|
|
f" => semestres dont il faut calculer les moyennes : "
|
|
|
|
@ -153,15 +157,13 @@ class EtudiantsJuryPE:
|
|
|
|
|
etudids = [
|
|
|
|
|
etudid
|
|
|
|
|
for etudid in self.cursus
|
|
|
|
|
if self.cursus[etudid]["diplome"] == annee_diplome and self.cursus[etudid]["abandon"]
|
|
|
|
|
if self.cursus[etudid]["diplome"] == annee_diplome
|
|
|
|
|
and self.cursus[etudid]["abandon"] == False
|
|
|
|
|
]
|
|
|
|
|
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é)
|
|
|
|
@ -192,33 +194,38 @@ class EtudiantsJuryPE:
|
|
|
|
|
self.cursus[etudid] = {
|
|
|
|
|
"etudid": etudid, # les infos sur l'étudiant
|
|
|
|
|
"etat_civil": identite.etat_civil, # Ajout à la table jury
|
|
|
|
|
"nom": identite.nom,
|
|
|
|
|
"diplome": annee_diplome(identite), # Le date prévisionnelle de son diplôme
|
|
|
|
|
"formsemestres": semestres_etudiant, # les semestres de l'étudiant
|
|
|
|
|
"semestres": {},
|
|
|
|
|
"aggregats": {},
|
|
|
|
|
"abandon": False, # va être traité en dessous
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
""" Est-il réorienté / démissionnaire ou a-t-il arrêté volontairement sa formation ?"""
|
|
|
|
|
self.cursus[etudid]["abandon"] = arret_de_formation(identite, cosemestres)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def analyse_parcours_etudiant_dans_semestres(self, etudid):
|
|
|
|
|
"""Structure les informations sur les semestres suivis par un
|
|
|
|
|
étudiant, pour identifier les semestres qui seront pris en compte lors de ses calculs
|
|
|
|
|
de moyennes PE.
|
|
|
|
|
|
|
|
|
|
La structure s'appuie sur les numéros de semestre: pour chaque Si, stocke :
|
|
|
|
|
* le (ou les) formsemestres de numéro i qu'a suivi un étudiant (2 si redoublant)
|
|
|
|
|
* le dernier semestre de numéro i qu'il a suivi (1 ou 0 si pas encore suivi)
|
|
|
|
|
Cette structuration (cf. attribut self.cursus) s'appuie sur les numéros de semestre: pour chaque Si, stocke :
|
|
|
|
|
le dernier semestre (en date) de numéro i qu'il a suivi (1 ou 0 si pas encore suivi). Ce semestre influera les
|
|
|
|
|
interclassement par semestre dans la promo.
|
|
|
|
|
|
|
|
|
|
Elle s'appuie également sur les aggrégats: pour chaque aggrégat (par ex, 3A=S1+S2+S3),
|
|
|
|
|
identifie les semestres que l'étudiant a suivi pour l'amener jusqu'au semestre terminal
|
|
|
|
|
de l'aggrégat. Ce parcours peut être :
|
|
|
|
|
* S1+S2+S1+S2+S3 si redoublement de la 1ère année
|
|
|
|
|
* S1+S2+(année de césure)+S3 si césure, ...
|
|
|
|
|
Elle calcule également sur les aggrégats (cf. attribut self.aggregats):
|
|
|
|
|
|
|
|
|
|
* pour un semestre de type Si, elle stocke le (ou les) formsemestres de numéro i qu'a suivi un étudiant
|
|
|
|
|
(2 si redoublant) dans self.aggregats
|
|
|
|
|
* pour des aggrégats de type iS ou iA (par ex, 3A=S1+S2+S3), elle identifie les semestres que l'étudiant
|
|
|
|
|
a suivi pour l'amener jusqu'au semestre terminal de l'aggrégat. Ce parcours peut être :
|
|
|
|
|
** S1+S2+S1+S2+S3 si redoublement de la 1ère année
|
|
|
|
|
** S1+S2+(année de césure)+S3 si césure, ...
|
|
|
|
|
"""
|
|
|
|
|
semestres_etudiant = self.cursus[etudid]["formsemestres"]
|
|
|
|
|
|
|
|
|
|
self.aggregats[etudid] = {}
|
|
|
|
|
|
|
|
|
|
"""Tri des semestres par numéro de semestre"""
|
|
|
|
|
for nom_sem in pe_tools.TOUS_LES_SEMESTRES:
|
|
|
|
|
i = int(nom_sem[1]) # le n° du semestre
|
|
|
|
|
semestres_i = {
|
|
|
|
@ -226,28 +233,28 @@ class EtudiantsJuryPE:
|
|
|
|
|
for fid in semestres_etudiant
|
|
|
|
|
if semestres_etudiant[fid].semestre_id == i
|
|
|
|
|
} # les semestres de n°i de l'étudiant
|
|
|
|
|
self.cursus[etudid]["aggregats"][nom_sem] = semestres_i
|
|
|
|
|
self.cursus[etudid]["semestres"][nom_sem] = get_dernier_semestre(semestres_i)
|
|
|
|
|
|
|
|
|
|
self.aggregats[etudid][nom_sem] = semestres_i
|
|
|
|
|
self.cursus[etudid][nom_sem] = get_dernier_semestre(semestres_i)
|
|
|
|
|
|
|
|
|
|
"""Tri des semestres par aggrégat et par semestre terminal"""
|
|
|
|
|
for aggregat in pe_tools.TOUS_LES_AGGREGATS:
|
|
|
|
|
self.cursus[etudid][aggregat] = {}
|
|
|
|
|
self.aggregats[etudid][aggregat] = {}
|
|
|
|
|
|
|
|
|
|
"""L'aggrégat considéré (par ex: 3S), son nom de son semestre terminal (par ex: S3) et son numéro (par ex: 3)"""
|
|
|
|
|
noms_semestre_de_aggregat = pe_tools.PARCOURS[aggregat]["aggregat"]
|
|
|
|
|
nom_semestre_terminal = noms_semestre_de_aggregat[-1]
|
|
|
|
|
numero_semestre_terminal = int(nom_semestre_terminal[-1])
|
|
|
|
|
|
|
|
|
|
"""Les semestres terminaux de l'aggrégat"""
|
|
|
|
|
# formsemestres_terminal = self.cursus[etudid]["aggregats"][nom_semestre_terminal]
|
|
|
|
|
# dernier_formsemestre_terminal = get_dernier_semestre(formsemestres_terminal) # le dernier en date
|
|
|
|
|
dernier_formsemestre_terminal = self.cursus[etudid]["semestres"][nom_semestre_terminal]
|
|
|
|
|
"""Le formsemestre terminal de l'aggrégat (par ex: son dernier S3 en date)"""
|
|
|
|
|
dernier_formsemestre_terminal = self.cursus[etudid][nom_semestre_terminal]
|
|
|
|
|
|
|
|
|
|
# for formsem_id_term in formsemestres_terminal:
|
|
|
|
|
if dernier_formsemestre_terminal: # ne considérant que le dernier
|
|
|
|
|
if dernier_formsemestre_terminal: # ne considérant que le dernier
|
|
|
|
|
formsem_id_term = list(dernier_formsemestre_terminal.keys())[0]
|
|
|
|
|
|
|
|
|
|
formsemestre_terminal = self.cursus[etudid]["formsemestres"][formsem_id_term]
|
|
|
|
|
formsemestre_terminal = self.cursus[etudid]["formsemestres"][
|
|
|
|
|
formsem_id_term
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
"""Semestres de n° inférieur (pax ex: des S1, S2, S3 pour un S3 terminal) et qui lui sont antérieurs"""
|
|
|
|
|
semestres_aggreges = {}
|
|
|
|
@ -259,7 +266,11 @@ class EtudiantsJuryPE:
|
|
|
|
|
):
|
|
|
|
|
semestres_aggreges[fid] = semestre
|
|
|
|
|
|
|
|
|
|
self.cursus[etudid][aggregat][formsem_id_term] = semestres_aggreges
|
|
|
|
|
self.aggregats[etudid][aggregat][formsem_id_term] = semestres_aggreges
|
|
|
|
|
|
|
|
|
|
"""Vérifications"""
|
|
|
|
|
dernier_semestre_aggregat = get_dernier_semestre(semestres_aggreges)
|
|
|
|
|
assert dernier_semestre_aggregat == dernier_formsemestre_terminal
|
|
|
|
|
|
|
|
|
|
def get_formsemestres_terminaux_aggregat(self, aggregat: str):
|
|
|
|
|
"""Pour un aggrégat donné, ensemble des formsemestres terminaux possibles pour l'aggrégat (pour l'aggrégat '3S'
|
|
|
|
@ -362,7 +373,7 @@ class EtudiantsJuryPE:
|
|
|
|
|
nom_sem = semestres_recherches
|
|
|
|
|
semestres = {}
|
|
|
|
|
for etudid in self.etudiants_ids:
|
|
|
|
|
semestres = semestres | self.cursus[etudid]["aggregats"][nom_sem]
|
|
|
|
|
semestres = semestres | self.aggregats[etudid][nom_sem]
|
|
|
|
|
return semestres
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError(
|
|
|
|
@ -420,19 +431,33 @@ def annee_diplome(identite: Identite) -> int:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def arret_de_formation(identite: Identite, cosemestres: list[FormSemestre]) -> bool:
|
|
|
|
|
"""Détermine si un étudiant a arrêté sa formation. Il peut s'agir :
|
|
|
|
|
"""Détermine si un étudiant a arrêté sa formation. Il peut s'agir :
|
|
|
|
|
|
|
|
|
|
* d'une réorientation à l'initiative du jury de semestre ou d'une démission ; dans ce cas, utilise les
|
|
|
|
|
décisions prises dans les jury de semestres (code NAR pour réorienté & DEM pour démissionnaire)
|
|
|
|
|
* d'une réorientation à l'initiative du jury de semestre ou d'une démission (on pourrait
|
|
|
|
|
utiliser les code NAR pour réorienté & DEM pour démissionnaire des résultats du jury renseigné dans la BDD,
|
|
|
|
|
mais pas nécessaire ici)
|
|
|
|
|
|
|
|
|
|
* d'un arrêt volontaire : l'étudiant disparait des listes d'inscrit, sans
|
|
|
|
|
pour autant avoir été indiqué NAR ou DEM. Dans ce cas, recherche son dernier semestre validé et
|
|
|
|
|
regarde s'il n'existe pas parmi les semestres existants dans Scodoc un semestre postérieur
|
|
|
|
|
(en terme de date de début)
|
|
|
|
|
de n° au moins égal à celui de son dernier semestre valide dans lequel il aurait pu
|
|
|
|
|
s'inscrire mais ne l'a pas fait.
|
|
|
|
|
* d'un arrêt volontaire : l'étudiant disparait des listes d'inscrits (sans pour autant avoir été indiqué NAR ou DEM).
|
|
|
|
|
|
|
|
|
|
Dans les cas, on considérera que l'étudiant a arrêté sa formation s'il n'est pas dans l'un des "derniers" cosemestres
|
|
|
|
|
(semestres conduisant à la même année de diplômation) connu dans Scodoc.
|
|
|
|
|
|
|
|
|
|
Par ex: au moment du jury PE en fin de S5 (pas de S6 renseigné dans Scodoc), l'étudiant doit appartenir à une
|
|
|
|
|
instance des S5 qui conduisent à la diplomation dans l'année visée. S'il n'est que dans un S4, il a sans doute
|
|
|
|
|
arrêté. A moins qu'il ne soit parti à l'étranger et là, pas de notes.
|
|
|
|
|
TODO:: Cas de l'étranger, à coder/tester
|
|
|
|
|
|
|
|
|
|
**Attention** : Cela suppose que toutes les instances d'un semestre donné (par ex: toutes les instances de S6
|
|
|
|
|
accueillant un étudiant soient créées ; sinon les étudiants non inscrits dans un S6 seront considérés comme
|
|
|
|
|
ayant abandonnés)
|
|
|
|
|
TODO:: Peut-être à mettre en regard avec les propositions d'inscriptions d'étudiants dans un nouveau semestre
|
|
|
|
|
|
|
|
|
|
Pour chaque étudiant, recherche son dernier semestre en date (validé ou non) et
|
|
|
|
|
regarde s'il n'existe pas parmi les semestres existants dans Scodoc un semestre :
|
|
|
|
|
* dont les dates sont postérieures (en terme de date de début)
|
|
|
|
|
* de n° au moins égal à celui de son dernier semestre valide (S5 -> S5 ou S5 -> S6)
|
|
|
|
|
dans lequel il aurait pu s'inscrire mais ne l'a pas fait.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
identite: L'identité d'un étudiant
|
|
|
|
@ -441,36 +466,37 @@ def arret_de_formation(identite: Identite, cosemestres: list[FormSemestre]) -> b
|
|
|
|
|
Returns:
|
|
|
|
|
Est-il réorienté, démissionnaire ou a-t-il arrêté de son propre chef sa formation ?
|
|
|
|
|
|
|
|
|
|
TODO:: A reprendre avec l'accès aux résultats des jury prévu par Scodoc9
|
|
|
|
|
TODO:: A reprendre pour le cas des étudiants à l'étranger
|
|
|
|
|
TODO:: A reprendre si BUT avec semestres décalés
|
|
|
|
|
"""
|
|
|
|
|
etudid = identite.etudid
|
|
|
|
|
reponse = False
|
|
|
|
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
|
|
|
|
(code, parcours) = sco_report.get_code_cursus_etud(etud)
|
|
|
|
|
|
|
|
|
|
# Est-il réorienté ou démissionnaire ?
|
|
|
|
|
if (
|
|
|
|
|
len(codes_cursus.CODES_SEM_REO & set(parcours.values())) > 0
|
|
|
|
|
): # Eliminé car NAR apparait dans le parcours
|
|
|
|
|
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
|
|
|
|
pe_tools.pe_print(" -> à éliminer car réorienté (NAR)")
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
if "DEM" in list(parcours.values()): # Eliminé car DEM
|
|
|
|
|
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
|
|
|
|
pe_tools.pe_print(" -> à éliminer car DEM")
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# A-t-il arrêté volontairement sa formation ?
|
|
|
|
|
"""Son dernier semestre en date"""
|
|
|
|
|
dernier_formsemestre = identite.get_formsemestres()[0]
|
|
|
|
|
numero_dernier_formsemestre = dernier_formsemestre.semestre_id
|
|
|
|
|
|
|
|
|
|
# Y-a-t-il des cosemestres dans lesquels il aurait pu s'incrire ?
|
|
|
|
|
"""Les numéro de semestres possible dans lesquels il pourrait s'incrire"""
|
|
|
|
|
# semestre impair => passage de droit en semestre pair suivant (effet de l'annualisation)
|
|
|
|
|
if numero_dernier_formsemestre % 2 == 1:
|
|
|
|
|
numeros_possibles = list(
|
|
|
|
|
range(numero_dernier_formsemestre + 1, pe_tools.NBRE_SEMESTRES_DIPLOMANT)
|
|
|
|
|
)
|
|
|
|
|
# semestre pair => passage en année supérieure ou redoublement
|
|
|
|
|
else: #
|
|
|
|
|
numeros_possibles = list(
|
|
|
|
|
range(
|
|
|
|
|
max(numero_dernier_formsemestre - 1, 1),
|
|
|
|
|
pe_tools.NBRE_SEMESTRES_DIPLOMANT,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
"""Y-a-t-il des cosemestres dans lesquels il aurait pu s'incrire ?"""
|
|
|
|
|
formsestres_superieurs_possibles = []
|
|
|
|
|
for fid, sem in cosemestres.items(): # Les semestres ayant des inscrits
|
|
|
|
|
if (
|
|
|
|
|
sem.formsemestre_id != dernier_formsemestre.formsemestre_id
|
|
|
|
|
fid != dernier_formsemestre.formsemestre_id
|
|
|
|
|
and sem.semestre_id in numeros_possibles
|
|
|
|
|
and sem.date_debut.year >= dernier_formsemestre.date_debut.year
|
|
|
|
|
and sem.semestre_id > dernier_formsemestre.semestre_id
|
|
|
|
|
): # date de debut des semestres possibles postérieur au dernier semestre de l'étudiant et de niveau plus élevé que le dernier semestre valide de l'étudiant
|
|
|
|
|
formsestres_superieurs_possibles.append(fid)
|
|
|
|
|
|
|
|
|
@ -481,7 +507,7 @@ def arret_de_formation(identite: Identite, cosemestres: list[FormSemestre]) -> b
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_dernier_semestre(semestres: dict[int, FormSemestre]):
|
|
|
|
|
"""Renvoie le dernier semestre en date d'un dictionnaire
|
|
|
|
|
"""Renvoie le dernier semestre en date (de fin) d'un dictionnaire
|
|
|
|
|
de semestres de la forme {fid: FormSemestre(fid)}.
|
|
|
|
|
La date prise en compte est celle marquant la **fin** des semestres.
|
|
|
|
|
|
|
|
|
|