Compare commits

...

2 Commits

7 changed files with 361 additions and 194 deletions

View File

@ -67,7 +67,8 @@ def get_code_latex_from_modele(fichier):
# ----------------------------------------------------------------------------------------
def get_code_latex_from_scodoc_preference(formsemestre_id, champ="pe_avis_latex_tmpl"):
def get_code_latex_from_scodoc_preference(formsemestre_id,
champ="pe_avis_latex_tmpl"):
"""
Extrait le template (ou le tag d'annotation au regard du champ fourni) des préférences LaTeX
et s'assure qu'il est renvoyé au format unicode
@ -94,7 +95,9 @@ def get_tags_latex(code_latex):
return []
def comp_latex_parcourstimeline(etudiant, promo, taille=17):
def comp_latex_parcourstimeline(etudiant,
promo,
taille=17):
"""Interprète un tag dans un avis latex **parcourstimeline**
et génère le code latex permettant de retracer le parcours d'un étudiant
sous la forme d'une frise temporelle.
@ -156,9 +159,11 @@ def interprete_tag_latex(tag):
# ----------------------------------------------------------------------------------------
def get_code_latex_avis_etudiant(
donnees_etudiant, un_avis_latex, annotationPE, footer_latex, prefs
):
def get_code_latex_avis_etudiant(donnees_etudiant,
un_avis_latex,
annotationPE,
footer_latex,
prefs):
"""
Renvoie le code latex permettant de générer l'avis d'un étudiant en utilisant ses
donnees_etudiant contenu dans le dictionnaire de synthèse du jury PE et en suivant un
@ -220,7 +225,8 @@ def get_code_latex_avis_etudiant(
# ----------------------------------------------------------------------------------------
def get_annotation_PE(etudid, tag_annotation_pe):
def get_annotation_PE(etudid,
tag_annotation_pe):
"""Renvoie l'annotation PE dans la liste de ces annotations ;
Cette annotation est reconnue par la présence d'un tag **PE**
(cf. .get_preferences -> pe_tag_annotation_avis_latex).
@ -261,7 +267,11 @@ def get_annotation_PE(etudid, tag_annotation_pe):
# ----------------------------------------------------------------------------------------
def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ):
def str_from_syntheseJury(donnees_etudiant,
aggregat,
groupe,
tag_scodoc,
champ):
"""Extrait du dictionnaire de synthèse du juryPE pour un étudiant donnée,
une valeur indiquée par un champ ;
si champ est une liste, renvoie la liste des valeurs extraites.
@ -312,7 +322,8 @@ def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ)
# ----------------------------------------------------------------------------------------
def get_bilanParTag(donnees_etudiant, groupe="groupe"):
def get_bilanParTag(donnees_etudiant,
groupe="groupe"):
"""Renvoie le code latex d'un tableau récapitulant, pour tous les tags trouvés dans
les données étudiants, ses résultats.
result: chaine unicode
@ -383,7 +394,12 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
# ----------------------------------------------------------------------------------------
def get_avis_poursuite_par_etudiant(
jury, etudid, template_latex, tag_annotation_pe, footer_latex, prefs
jury,
etudid,
template_latex,
tag_annotation_pe,
footer_latex,
prefs
):
"""Renvoie un nom de fichier et le contenu de l'avis latex d'un étudiant dont l'etudid est fourni.
result: [ chaine unicode, chaine unicode ]
@ -444,7 +460,8 @@ def get_templates_from_distrib(template="avis"):
# ----------------------------------------------------------------------------------------
def table_syntheseAnnotationPE(syntheseJury, tag_annotation_pe):
def table_syntheseAnnotationPE(syntheseJury,
tag_annotation_pe):
"""Génère un fichier excel synthétisant les annotations PE telles qu'inscrites dans les fiches de chaque étudiant"""
sT = SeqGenTable() # le fichier excel à générer

View File

@ -78,20 +78,24 @@ def comp_nom_semestre_dans_parcours(sem):
# ----------------------------------------------------------------------------------------
class JuryPE(object):
"""Classe memorisant toutes les informations necessaires pour etablir un jury de PE. Modele
base sur NotesTable
"""Classe mémorisant toutes les informations nécessaires pour établir un jury de PE.
Modèle basé sur NotesTable.
Attributs : - diplome : l'annee d'obtention du diplome DUT et du jury de PE (generalement fevrier XXXX)
- juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives +
celles des semestres valides à prendre en compte permettant le calcul des moyennes ...
{'etudid : { 'nom', 'prenom', 'civilite', 'diplome', '', }}
Rq: il contient à la fois les étudiants qui vont être diplomés à la date prévue
et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif
Attributs :
* diplome : l'annee d'obtention du diplome BUT et du jury de PE (generalement fevrier XXXX)
* juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives +
celles des semestres valides à prendre en compte permettant le calcul des moyennes ...
``{'etudid : { 'nom', 'prenom', 'civilite', 'diplome', '', }}``
Rq: il contient à la fois les étudiants qui vont être diplomés à la date prévue
et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif
"""
# Variables de classe décrivant les aggrégats, leur ordre d'apparition temporelle et
# leur affichage dans les avis latex
NBRE_SEMESTRES_PARCOURS = 6
PARCOURS = {
"S1": {
"aggregat": ["S1"],
@ -105,6 +109,12 @@ class JuryPE(object):
"affichage_court": "S2",
"affichage_long": "Semestre 2",
},
"1A": {
"aggregat": ["S1", "S2"],
"ordre": 3,
"affichage_court": "1A",
"affichage_long": "1ère année",
},
"S3": {
"aggregat": ["S3"],
"ordre": 4,
@ -117,12 +127,6 @@ class JuryPE(object):
"affichage_court": "S4",
"affichage_long": "Semestre 4",
},
"1A": {
"aggregat": ["S1", "S2"],
"ordre": 3,
"affichage_court": "1A",
"affichage_long": "1ère année",
},
"2A": {
"aggregat": ["S3", "S4"],
"ordre": 6,
@ -133,16 +137,52 @@ class JuryPE(object):
"aggregat": ["S1", "S2", "S3"],
"ordre": 7,
"affichage_court": "S1+S2+S3",
"affichage_long": "DUT du semestre 1 au semestre 3",
"affichage_long": "BUT du semestre 1 au semestre 3",
},
"4S": {
"aggregat": ["S1", "S2", "S3", "S4"],
"ordre": 8,
"affichage_court": "DUT",
"affichage_long": "DUT (tout semestre inclus)",
"affichage_court": "BUT",
"affichage_long": "BUT du semestre 1 au semestre 4",
},
"S5": {
"aggregat": ["S5"],
"ordre": 9,
"affichage_court": "S5",
"affichage_long": "Semestre 5",
},
"S6": {
"aggregat": ["S6"],
"ordre": 10,
"affichage_court": "S6",
"affichage_long": "Semestre 6",
},
"3A": {
"aggregat": ["S5", "S6"],
"ordre": 11,
"affichage_court": "3A",
"affichage_long": "3ème année",
},
"5S": {
"aggregat": ["S1", "S2", "S3", "S4", "S5"],
"ordre": 12,
"affichage_court": "S1+S2+S3+S4+S5",
"affichage_long": "BUT du semestre 1 au semestre 5",
},
"6S": {
"aggregat": ["S1", "S2", "S3", "S4", "S5", "S6"],
"ordre": 13,
"affichage_court": "BUT",
"affichage_long": "BUT (tout semestre inclus)",
},
}
AGGREGAT_DIPLOMANT = "6S" # aggrégat correspondant à la totalité des notes pour le diplôme
TOUS_LES_SEMESTRES = PARCOURS["6S"]["aggregat"]
TOUS_LES_AGGREGATS = [cle for cle in PARCOURS.keys() if not cle.startswith("S")]
TOUS_LES_PARCOURS = list(PARCOURS.keys())
# ------------------------------------------------------------------------------------------------------------------
def __init__(self, semBase):
"""
@ -268,7 +308,9 @@ class JuryPE(object):
# **************************************************************************************************************** #
# ------------------------------------------------------------------------------------------------------------------
def get_etudiants_in_jury(self, semBase, avec_meme_formation=False):
def get_etudiants_in_jury(self,
semBase,
avec_meme_formation=False):
"""
Calcule la liste des étudiants à prendre en compte dans le jury et la renvoie sous la forme
"""
@ -314,7 +356,8 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_etudiants_dans_semestres(self, semsListe):
def get_etudiants_dans_semestres(self,
semsListe):
"""Renvoie la liste des etudid des etudiants inscrits à l'un des semestres de la liste fournie en paramètre
en supprimant les doublons (i.e. un même étudiant qui apparaîtra 2 fois)"""
@ -322,7 +365,7 @@ class JuryPE(object):
for sem in semsListe: # pour chacun des semestres de la liste
nt = self.get_cache_notes_d_un_semestre(sem["formsemestre_id"])
etudiantsDuSemestre = (
nt.get_etudids()
[ins.etudid for ins in nt.formsemestre.inscriptions] # nt.get_etudids()
) # identification des etudiants du semestre
if pe_tools.PE_DEBUG:
@ -335,9 +378,10 @@ class JuryPE(object):
return list(set(etudiants)) # suppression des doublons
# ------------------------------------------------------------------------------------------------------------------
def get_etudids_du_jury(self, ordre="aucun"):
def get_etudids_du_jury(self,
ordre="aucun"):
"""Renvoie la liste de tous les étudiants (concrètement leur etudid)
participant au jury c'est à dire, ceux dont la date du 'jury' est self.diplome
participant au jury c'est-à-dire, ceux dont la date du 'jury' est self.diplome
et n'ayant pas abandonné.
Si l'ordre est précisé, donne une liste etudid dont le nom, prenom trié par ordre alphabétique
"""
@ -359,14 +403,20 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def add_etudiants(self, etudid):
"""Ajoute un étudiant (via son etudid) au dictionnaire de synthèse jurydict.
def add_etudiants(self,
etudid):
"""Ajoute un étudiant connaissant son etudid au dictionnaire de synthèse jurydict.
L'ajout consiste à :
> insérer une entrée pour l'étudiant en mémorisant ses infos (get_etudInfo),
avec son nom, prénom, etc...
> à analyser son parcours, pour vérifier s'il n'a pas abandonné l'IUT en cours de route => clé abandon
> à chercher ses semestres valides (formsemestre_id) et ses années valides (formannee_id),
c'est à dire ceux pour lesquels il faudra prendre en compte ses notes dans les calculs de moyenne (type 1A=S1+S2/2)
* insérer une entrée pour l'étudiant en mémorisant ses infos (get_etudInfo),
avec son nom, prénom, etc...
* à analyser son parcours, pour vérifier s'il n'a pas abandonné l'IUT en cours de
route (cf. clé abandon)
* à chercher ses semestres valides (formsemestre_id) et ses années valides (formannee_id),
c'est-à-dire ceux pour lesquels il faudra prendre en compte ses notes dans les calculs de
moyenne (type 1A=S1+S2/2)
Args:
etudid: L'etudid d'un étudiant, à ajouter au jury s'il respecte les critères précédents
"""
if etudid not in self.PARCOURSINFO_DICT:
@ -386,7 +436,7 @@ class JuryPE(object):
# Sa date prévisionnelle de diplome
self.PARCOURSINFO_DICT[etudid][
"diplome"
] = self.calcul_anneePromoDUT_d_un_etudiant(etudid)
] = self.calcul_anneePromoBUT_d_un_etudiant(etudid)
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
pe_tools.pe_print(
"promo=" + str(self.PARCOURSINFO_DICT[etudid]["diplome"]), end=""
@ -407,11 +457,10 @@ class JuryPE(object):
# et s'ils existent quelles sont ses notes utiles ?
sesFormsemestre_idValidants = [
self.get_Fid_d_un_Si_valide_d_un_etudiant(etudid, nom_sem)
for nom_sem in JuryPE.PARCOURS["4S"][
"aggregat"
] # Recherche du formsemestre_id de son Si valide (ou a défaut en cours)
for nom_sem in JuryPE.TOUS_LES_SEMESTRES
# Recherche du formsemestre_id de son Si valide (ou a défaut en cours)
]
for i, nom_sem in enumerate(JuryPE.PARCOURS["4S"]["aggregat"]):
for i, nom_sem in enumerate(JuryPE.TOUS_LES_SEMESTRES):
fid = sesFormsemestre_idValidants[i]
self.PARCOURSINFO_DICT[etudid][nom_sem] = fid # ['formsemestre_id']
if fid != None and pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
@ -419,13 +468,11 @@ class JuryPE(object):
# self.get_moyennesEtClassements_par_semestre_d_un_etudiant( etudid, fid )
# Quelles sont ses années validantes ('1A', '2A') et ses parcours (3S, 4S) validants ?
for parcours in ["1A", "2A", "3S", "4S"]:
lesSemsDuParcours = JuryPE.PARCOURS[parcours][
"aggregat"
] # les semestres du parcours : par ex. ['S1', 'S2', 'S3']
for parcours in JuryPE.TOUS_LES_AGGREGATS:
lesSemsDuParcours = JuryPE.PARCOURS[parcours]["aggregat"] # les semestres du parcours : par ex. ['S1', 'S2', 'S3']
lesFidsValidantDuParcours = [
sesFormsemestre_idValidants[
JuryPE.PARCOURS["4S"]["aggregat"].index(nom_sem)
JuryPE.TOUS_LES_SEMESTRES.index(nom_sem)
]
for nom_sem in lesSemsDuParcours # par ex. ['SEM4532', 'SEM567', ...]
]
@ -449,7 +496,8 @@ class JuryPE(object):
# print
# ------------------------------------------------------------------------------------------------------------------
def est_un_etudiant_reoriente_ou_demissionnaire(self, etudid):
def est_un_etudiant_reoriente_ou_demissionnaire(self,
etudid):
"""Renvoie True si l'étudiant est réorienté (NAR) ou démissionnaire (DEM)"""
from app.scodoc import sco_report
@ -469,13 +517,14 @@ class JuryPE(object):
return reponse
# ------------------------------------------------------------------------------------------------------------------
def est_un_etudiant_disparu(self, etudid):
def est_un_etudiant_disparu(self,
etudid):
"""Renvoie True si l'étudiant n'a pas achevé la formation à l'IUT et a disparu des listes, sans
pour autant avoir été indiqué NAR ou DEM ; 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."""
sessems = self.get_semestresDUT_d_un_etudiant(
sessems = self.get_semestresBUT_d_un_etudiant(
etudid
) # les semestres de l'étudiant
sonDernierSidValide = self.get_dernier_semestre_id_valide_d_un_etudiant(etudid)
@ -519,7 +568,8 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_dernier_semestre_id_valide_d_un_etudiant(self, etudid):
def get_dernier_semestre_id_valide_d_un_etudiant(self,
etudid):
"""Renvoie le n° (semestre_id) du dernier semestre validé par un étudiant fourni par son etudid
et None si aucun semestre n'a été validé
"""
@ -542,12 +592,14 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_Fid_d_un_Si_valide_d_un_etudiant(self, etudid, nom_semestre):
def get_Fid_d_un_Si_valide_d_un_etudiant(self,
etudid,
nom_semestre):
"""Récupère le formsemestre_id valide d'un étudiant fourni son etudid à un semestre DUT de n° semestre_id
donné. Si le semestre est en cours (pas encore de jury), renvoie le formsemestre_id actuel.
"""
semestre_id = JuryPE.PARCOURS["4S"]["aggregat"].index(nom_semestre) + 1
sesSi = self.get_semestresDUT_d_un_etudiant(
semestre_id = JuryPE.TOUS_LES_SEMESTRES.index(nom_semestre) + 1
sesSi = self.get_semestresBUT_d_un_etudiant(
etudid, semestre_id
) # extrait uniquement les Si par ordre temporel décroissant
@ -580,7 +632,8 @@ class JuryPE(object):
Calcule les moyennes et les classements de chaque semestre par tag et les statistiques de ces semestres.
"""
lesFids = self.get_formsemestreids_du_jury(
self.get_etudids_du_jury(), liste_semestres=["S1", "S2", "S3", "S4"]
self.get_etudids_du_jury(),
liste_semestres=JuryPE.TOUS_LES_SEMESTRES
)
for i, fid in enumerate(lesFids):
if pe_tools.PE_DEBUG:
@ -591,7 +644,8 @@ class JuryPE(object):
self.add_semtags_in_jury(fid)
# ------------------------------------------------------------------------------------------------------------------
def add_semtags_in_jury(self, fid):
def add_semtags_in_jury(self,
fid):
"""Crée si nécessaire un semtag et le mémorise dans self.semTag ;
charge également les données des nouveaux étudiants qui en font partis.
"""
@ -623,7 +677,7 @@ class JuryPE(object):
" - %d étudiants classés " % (nbinscrit)
+ ": "
+ ",".join(
[etudid for etudid in self.semTagDict[fid].get_etudids()]
[str(etudid) for etudid in self.semTagDict[fid].get_etudids()]
)
)
if lesEtudidsManquants:
@ -631,14 +685,16 @@ class JuryPE(object):
" - dont %d étudiants manquants ajoutés aux données du jury"
% (len(lesEtudidsManquants))
+ ": "
+ ", ".join(lesEtudidsManquants)
+ ", ".join([str(etudid) for etudid in lesEtudidsManquants])
)
pe_tools.pe_print(" - Export csv")
filename = self.NOM_EXPORT_ZIP + self.semTagDict[fid].nom + ".csv"
self.zipfile.writestr(filename, self.semTagDict[fid].str_tagtable())
# ----------------------------------------------------------------------------------------------------------------
def get_formsemestreids_du_jury(self, etudids, liste_semestres="4S"):
def get_formsemestreids_du_jury(self,
etudids,
liste_semestres="6S"):
"""Renvoie la liste des formsemestre_id validants des étudiants en parcourant les semestres valides des étudiants mémorisés dans
self.PARCOURSINFO_DICT.
Les étudiants sont identifiés par leur etudic donnés dans la liste etudids (généralement self.get_etudids_in_jury() ).
@ -723,8 +779,8 @@ class JuryPE(object):
# '3S' : ['S1', 'S2', 'S3'], '4S' : ['S1', 'S2', 'S3', 'S4'] }
# ---> sur 2 parcours DUT (cas S3 fini, cas S4 fini)
combinaisons = ["1A", "2A", "3S", "4S"]
for i, nom in enumerate(combinaisons):
for i, nom in enumerate(JuryPE.TOUS_LES_AGGREGATS):
parcours = JuryPE.PARCOURS[nom][
"aggregat"
] # La liste des noms de semestres (S1, S2, ...) impliqués dans l'aggrégat
@ -793,7 +849,7 @@ class JuryPE(object):
pe_tools.pe_print(
"%d) %s avec interclassement sur la promo" % (i + 1, nom)
)
if nom in ["S1", "S2", "S3", "S4"]:
if nom in JuryPE.TOUS_LES_SEMESTRES:
settag.set_SetTagDict(self.semTagDict)
else: # cas des aggrégats
settag.set_SetTagDict(self.setTagDict[nom])
@ -846,7 +902,7 @@ class JuryPE(object):
if (
self.PARCOURSINFO_DICT[etudid][nom] != None
): # Un parcours valide existe
if nom in ["S1", "S2", "S3", "S4"]:
if nom in JuryPE.TOUS_LES_SEMESTRES:
tagtable = self.semTagDict[self.PARCOURSINFO_DICT[etudid][nom]]
else:
tagtable = self.setTagDict[nom][
@ -866,20 +922,22 @@ class JuryPE(object):
tag
] = tagtable.get_resultatsEtud(tag, etudid)
def get_dateEntree(self, etudid):
def get_dateEntree(self,
etudid):
"""Renvoie l'année d'entrée de l'étudiant à l'IUT"""
# etudinfo = self.ETUDINFO_DICT[etudid]
semestres = self.get_semestresDUT_d_un_etudiant(etudid)
semestres = self.get_semestresBUT_d_un_etudiant(etudid)
if semestres:
# le 1er sem à l'IUT
return semestres[0]["annee_debut"]
else:
return ""
def get_parcoursIUT(self, etudid):
def get_parcoursIUT(self,
etudid):
"""Renvoie une liste d'infos sur les semestres du parcours d'un étudiant"""
# etudinfo = self.ETUDINFO_DICT[etudid]
sems = self.get_semestresDUT_d_un_etudiant(etudid)
sems = self.get_semestresBUT_d_un_etudiant(etudid)
infos = []
for sem in sems:
@ -896,10 +954,11 @@ class JuryPE(object):
# **************************************************************************************************************** #
# Méthodes d'affichage pour debug
# **************************************************************************************************************** #
def str_etudiants_in_jury(self, delim=";"):
def str_etudiants_in_jury(self,
delim=";"):
# En tete:
entete = ["Id", "Nom", "Abandon", "Diplome"]
for nom_sem in ["S1", "S2", "S3", "S4", "1A", "2A", "3S", "4S"]:
for nom_sem in JuryPE.TOUS_LES_PARCOURS:
entete += [nom_sem, "descr"]
chaine = delim.join(entete) + "\n"
@ -914,8 +973,8 @@ class JuryPE(object):
str(donnees["diplome"]),
]
# les semestres
for nom_sem in ["S1", "S2", "S3", "S4", "1A", "2A", "3S", "4S"]:
# les semestres et les aggrégats
for nom_sem in JuryPE.TOUS_LES_PARCOURS:
table = (
self.semTagDict[donnees[nom_sem]].nom
if donnees[nom_sem] in self.semTagDict
@ -952,13 +1011,15 @@ class JuryPE(object):
return list(taglist)
def get_allTagInSyntheseJury(self):
"""Extrait tous les tags du dictionnaire syntheseJury trié par ordre alphabétique. [] si aucun tag"""
"""Extrait tous les tags du dictionnaire syntheseJury trié par
ordre alphabétique. [] si aucun tag"""
allTags = set()
for nom in JuryPE.PARCOURS.keys():
for nom in JuryPE.TOUS_LES_PARCOURS:
allTags = allTags.union(set(self.get_allTagForAggregat(nom)))
return sorted(list(allTags)) if len(allTags) > 0 else []
def table_syntheseJury(self, mode="singlesheet"): # was str_syntheseJury
def table_syntheseJury(self,
mode="singlesheet"): # was str_syntheseJury
"""Table(s) du jury
mode: singlesheet ou multiplesheet pour export excel
"""
@ -984,9 +1045,9 @@ class JuryPE(object):
rows=[],
titles={"pas d'étudiants": "pas d'étudiants"},
html_sortable=True,
xls_sheet_name="but",
xls_sheet_name="dut",
)
sT.add_genTable("but", T)
sT.add_genTable("dut", T)
return sT
# Si des étudiants
@ -1120,7 +1181,8 @@ class JuryPE(object):
# **************************************************************************************************************** #
# ------------------------------------------------------------------------------------------------------------------
def get_cache_etudInfo_d_un_etudiant(self, etudid):
def get_cache_etudInfo_d_un_etudiant(self,
etudid):
"""Renvoie les informations sur le parcours d'un étudiant soit en les relisant depuis
ETUDINFO_DICT si mémorisée soit en les chargeant et en les mémorisant
"""
@ -1133,7 +1195,8 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_cache_notes_d_un_semestre(self, formsemestre_id: int) -> NotesTableCompat:
def get_cache_notes_d_un_semestre(self,
formsemestre_id: int) -> NotesTableCompat:
"""Charge la table des notes d'un formsemestre"""
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
return res_sem.load_formsemestre_results(formsemestre)
@ -1141,24 +1204,28 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------
def get_semestresDUT_d_un_etudiant(self, etudid, semestre_id=None):
def get_semestresBUT_d_un_etudiant(self,
etudid,
semestre_id=None):
"""Renvoie la liste des semestres DUT d'un étudiant
pour un semestre_id (parmi 1,2,3,4) donné
en fonction de ses infos d'etud (cf. sco_etud.get_etud_info( etudid=etudid, filled=True)[0]),
les semestres étant triés par ordre décroissant.
Si semestre_id == None renvoie tous les semestres"""
etud = self.get_cache_etudInfo_d_un_etudiant(etudid)
nbre_semestres = int(JuryPE.AGGREGAT_DIPLOMANT[0]) # 6
if semestre_id == None:
sesSems = [sem for sem in etud["sems"] if 1 <= sem["semestre_id"] <= 4]
sesSems = [sem for sem in etud["sems"] if 1 <= sem["semestre_id"] <= nbre_semestres]
else:
sesSems = [sem for sem in etud["sems"] if sem["semestre_id"] == semestre_id]
return sesSems
# **********************************************
def calcul_anneePromoDUT_d_un_etudiant(self, etudid) -> int:
def calcul_anneePromoBUT_d_un_etudiant(self,
etudid) -> int:
"""Calcule et renvoie la date de diplome prévue pour un étudiant fourni avec son etudid
en fonction de ses semestres de scolarisation"""
semestres = self.get_semestresDUT_d_un_etudiant(etudid)
semestres = self.get_semestresBUT_d_un_etudiant(etudid)
if semestres:
return max([get_annee_diplome_semestre(sem) for sem in semestres])
else:
@ -1166,9 +1233,10 @@ class JuryPE(object):
# *********************************************
# Fonctions d'affichage pour debug
def get_resultat_d_un_etudiant(self, etudid):
def get_resultat_d_un_etudiant(self,
etudid):
chaine = ""
for nom_sem in ["S1", "S2", "S3", "S4"]:
for nom_sem in JuryPE.TOUS_LES_SEMESTRES:
semtagid = self.PARCOURSINFO_DICT[etudid][
nom_sem
] # le formsemestre_id du semestre taggué de l'étudiant
@ -1207,27 +1275,37 @@ class JuryPE(object):
# ----------------------------------------------------------------------------------------
def get_annee_diplome_semestre(sem) -> int:
"""Pour un semestre donne, décrit par le biais du dictionnaire sem usuel :
sem = {'formestre_id': ..., 'semestre_id': ..., 'annee_debut': ...},
à condition qu'il soit un semestre de formation DUT,
predit l'annee à laquelle sera remis le diplome DUT des etudiants scolarisés dans le semestre
sem = {'formestre_id': ..., 'semestre_id': ..., 'annee_debut': ...}
à condition qu'il soit un semestre de formation BUT,
predit l'annee à laquelle sera remis le diplome BUT des etudiants scolarisés dans le semestre
(en supposant qu'il n'y ait plus de redoublement) et la renvoie sous la forme d'un int.
Hypothese : les semestres de 1ere partie d'annee universitaire (comme des S1 ou des S3) s'etalent
sur deux annees civiles - contrairement au semestre de seconde partie d'annee universitaire (comme
des S2 ou des S4).
Les semestres de 1ère partie d'année (S1, S3, S5 ou S4, S6 pour des semestres décalés)
s'étalent sur deux années civiles ; contrairement au semestre de seconde partie d'annee universitaire.
Par exemple :
> S4 debutant en 2016 finissant en 2016 => diplome en 2016
> S3 debutant en 2015 et finissant en 2016 => diplome en 2016
> S3 (decale) debutant en 2015 et finissant en 2015 => diplome en 2016
La regle de calcul utilise l'annee_fin du semestre sur le principe suivant :
nbreSemRestant = nombre de semestres restant avant diplome
nbreAnneeRestant = nombre d'annees restant avant diplome
1 - delta = 0 si semestre de 1ere partie d'annee / 1 sinon
decalage = active ou desactive un increment a prendre en compte en cas de semestre decale
* S5 débutant en 2025 finissant en 2026 => diplome en 2026
* S3 debutant en 2025 et finissant en 2026 => diplome en 2027
* S5 décalé débutant en 2025 et finissant en 2025 => diplome en 2026
* S3 decale débutant en 2025 et finissant en 2025 => diplome en 2027
La règle de calcul utilise l'``annee_fin`` du semestre sur le principe suivant :
* nbreSemRestant = nombre de semestres restant avant diplome
* nbreAnneeRestant = nombre d'annees restant avant diplome
* 1 - delta = 0 si semestre de 1ere partie d'annee / 1 sinon
* decalage = active ou désactive un increment à prendre en compte en cas de semestre decale
Args:
sem: Le semestre
"""
nbre_semestres = int(JuryPE.AGGREGAT_DIPLOMANT[0]) # 6
if (
1 <= sem["semestre_id"] <= 4
): # Si le semestre est un semestre DUT => problème si formation DUT en 1 an ??
nbreSemRestant = 4 - sem["semestre_id"]
1 <= sem["semestre_id"] <= nbre_semestres
): # Si le semestre est un semestre BUT => problème si formation BUT en 1 an ??
nbreSemRestant = nbre_semestres - sem["semestre_id"]
nbreAnRestant = nbreSemRestant // 2
delta = int(sem["annee_fin"]) - int(sem["annee_debut"])
decalage = nbreSemRestant % 2 # 0 si S4, 1 si S3, 0 si S2, 1 si S1
@ -1239,7 +1317,8 @@ def get_annee_diplome_semestre(sem) -> int:
# ----------------------------------------------------------------------------------
def get_cosemestres_diplomants(semBase, avec_meme_formation=False):
def get_cosemestres_diplomants(semBase,
avec_meme_formation=False):
"""Partant d'un semestre de Base = {'formsemestre_id': ..., 'semestre_id': ..., 'annee_debut': ...},
renvoie la liste de tous ses co-semestres (lui-meme inclus)
Par co-semestre, s'entend les semestres :

View File

@ -78,7 +78,9 @@ class SemestreTag(pe_tagtable.TableTag):
# -----------------------------------------------------------------------------
# Fonctions d'initialisation
# -----------------------------------------------------------------------------
def __init__(self, notetable, sem): # Initialisation sur la base d'une notetable
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
"""
@ -194,7 +196,9 @@ class SemestreTag(pe_tagtable.TableTag):
return tagdict
# -----------------------------------------------------------------------------
def comp_MoyennesTag(self, tag, force=False) -> list:
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.
@ -232,7 +236,10 @@ class SemestreTag(pe_tagtable.TableTag):
]
# -----------------------------------------------------------------------------
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
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.
La note et le coeff sont extraits :
1) soit des données du semestre en normalisant le coefficient par rapport à la somme des coefficients des modules du semestre,
@ -313,14 +320,17 @@ class SemestreTag(pe_tagtable.TableTag):
return (note, coeff_norm)
# -----------------------------------------------------------------------------
def get_ue_capitalisees(self, etudid) -> list[dict]:
def get_ue_capitalisees(self,
etudid) -> list[dict]:
"""Renvoie la liste des capitalisation effectivement capitalisées par un étudiant"""
if etudid in self.nt.validations.ue_capitalisees.index:
return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records")
return []
# -----------------------------------------------------------------------------
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):
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.
@ -343,7 +353,10 @@ class SemestreTag(pe_tagtable.TableTag):
# -----------------------------------------------------------------------------
# Fonctions d'affichage (et d'export csv) des données du semestre en mode debug
# -----------------------------------------------------------------------------
def str_detail_resultat_d_un_tag(self, tag, etudid=None, delim=";"):
def str_detail_resultat_d_un_tag(self,
tag,
etudid=None,
delim=";"):
"""Renvoie une chaine de caractère décrivant les résultats d'étudiants à un tag :
rappelle les notes obtenues dans les modules à prendre en compte, les moyennes et les rangs calculés.
Si etudid=None, tous les étudiants inscrits dans le semestre sont pris en compte. Sinon seuls les étudiants indiqués sont affichés.
@ -463,7 +476,8 @@ class SemestreTag(pe_tagtable.TableTag):
# *********************************************
def comp_coeff_pond(coeffs, ponderations):
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]
@ -499,7 +513,9 @@ def get_moduleimpl(modimpl_id) -> dict:
# **********************************************
def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float:
def get_moy_ue_from_nt(nt,
etudid,
modimpl_id) -> float:
"""Renvoie la moyenne de l'UE d'un etudid dans laquelle se trouve
le module de modimpl_id
"""

View File

@ -51,15 +51,19 @@ class SetTag(pe_tagtable.TableTag):
"""
# -------------------------------------------------------------------------------------------------------------------
def __init__(self, nom_combinaison, parcours):
def __init__(self,
nom_combinaison,
parcours):
pe_tagtable.TableTag.__init__(self, nom=nom_combinaison)
self.combinaison = nom_combinaison
self.parcours = parcours # Le groupe de semestres/parcours à aggréger
# -------------------------------------------------------------------------------------------
def set_Etudiants(
self, etudiants: list[dict], juryPEDict, etudInfoDict, nom_sem_final=None
):
def set_Etudiants(self,
etudiants: list[dict],
juryPEDict,
etudInfoDict,
nom_sem_final=None):
"""Détermine la liste des étudiants à prendre en compte, en partant de
la liste en paramètre et en vérifiant qu'ils ont tous un parcours valide."""
if nom_sem_final:
@ -94,7 +98,8 @@ class SetTag(pe_tagtable.TableTag):
)
# ---------------------------------------------------------------------------------------------
def set_SemTagDict(self, SemTagDict):
def set_SemTagDict(self,
SemTagDict):
"""Mémorise les semtag nécessaires au jury."""
self.SemTagDict = {fid: SemTagDict[fid] for fid in self.get_Fids_in_settag()}
if PE_DEBUG >= 1:
@ -152,7 +157,9 @@ class SetTag(pe_tagtable.TableTag):
self.tagdict[tag][mod] = semtag.tagdict[tag][mod]
# -------------------------------------------------------------------------------------------------------------------
def get_NotesEtCoeffsSetTagEtudiant(self, tag, etudid):
def get_NotesEtCoeffsSetTagEtudiant(self,
tag,
etudid):
"""Récupère tous les notes et les coeffs d'un étudiant relatives à un tag dans ses semestres valides et les renvoie dans un tuple (notes, coeffs)
avec notes et coeffs deux listes"""
lesSemsDeLEtudiant = [
@ -172,7 +179,9 @@ class SetTag(pe_tagtable.TableTag):
return (notes, coeffs)
# -------------------------------------------------------------------------------------------------------------------
def comp_MoyennesSetTag(self, tag, force=False):
def comp_MoyennesSetTag(self,
tag,
force=False):
"""Calcule et renvoie les "moyennes" des étudiants à un tag donné, en prenant en compte tous les semestres taggués
de l'aggrégat, et leur coeff Par moyenne, s'entend une note moyenne, la somme des coefficients de pondération
appliqué dans cette moyenne.
@ -203,19 +212,25 @@ class SetTag(pe_tagtable.TableTag):
class SetTagInterClasse(pe_tagtable.TableTag):
"""Récupère les moyennes de SetTag aggrégant un même parcours (par ex un ['S1', 'S2'] n'ayant pas fini au même S2
"""Récupère les moyennes de SetTag aggrégeant un même parcours (par ex un ['S1', 'S2'] n'ayant pas fini au même S2
pour fournir un interclassement sur un groupe d'étudiant => seul compte alors la promo
nom_combinaison = 'S1' ou '1A'
"""
# -------------------------------------------------------------------------------------------------------------------
def __init__(self, nom_combinaison, diplome):
def __init__(self,
nom_combinaison,
diplome):
pe_tagtable.TableTag.__init__(self, nom=f"{nom_combinaison}_{diplome or ''}")
self.combinaison = nom_combinaison
self.parcoursDict = {}
# -------------------------------------------------------------------------------------------
def set_Etudiants(self, etudiants, juryPEDict, etudInfoDict, nom_sem_final=None):
def set_Etudiants(self,
etudiants,
juryPEDict,
etudInfoDict,
nom_sem_final=None):
"""Détermine la liste des étudiants à prendre en compte, en partant de
la liste fournie en paramètre et en vérifiant que l'étudiant dispose bien d'un parcours valide pour la combinaison demandée.
Renvoie le nombre d'étudiants effectivement inscrits."""
@ -237,7 +252,8 @@ class SetTagInterClasse(pe_tagtable.TableTag):
)
# ---------------------------------------------------------------------------------------------
def set_SetTagDict(self, SetTagDict):
def set_SetTagDict(self,
SetTagDict):
"""Mémorise les settag nécessaires au jury."""
self.SetTagDict = {
fid: SetTagDict[fid] for fid in self.get_Fids_in_settag() if fid != None
@ -285,7 +301,9 @@ class SetTagInterClasse(pe_tagtable.TableTag):
return sorted(list(set(ensemble)))
# -------------------------------------------------------------------------------------------------------------------
def get_NotesEtCoeffsSetTagEtudiant(self, tag, etudid):
def get_NotesEtCoeffsSetTagEtudiant(self,
tag,
etudid):
"""Récupère tous les notes et les coeffs d'un étudiant relatives à un tag dans ses semestres valides et les renvoie dans un tuple (notes, coeffs)
avec notes et coeffs deux listes"""
leSetTagDeLetudiant = self.parcoursDict[etudid][self.combinaison]
@ -297,7 +315,9 @@ class SetTagInterClasse(pe_tagtable.TableTag):
return (note, coeff)
# -------------------------------------------------------------------------------------------------------------------
def get_MoyennesSetTag(self, tag, force=False):
def get_MoyennesSetTag(self,
tag,
force=False):
"""Renvoie les "moyennes" des étudiants à un tag donné, en prenant en compte tous les settag de l'aggrégat,
et leur coeff Par moyenne, s'entend une note moyenne, la somme des coefficients de pondération
appliqué dans cette moyenne.

View File

@ -77,7 +77,9 @@ class TableTag(object):
# *****************************************************************************************************************
# -----------------------------------------------------------------------------------------------------------
def get_moy_from_resultats(self, tag, etudid):
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]
@ -86,7 +88,9 @@ class TableTag(object):
)
# -----------------------------------------------------------------------------------------------------------
def get_rang_from_resultats(self, tag, etudid):
def get_rang_from_resultats(self,
tag,
etudid):
"""Renvoie le rang à un tag d'un étudiant au regard du format de self.resultats"""
return (
self.rangs[tag][etudid]
@ -95,7 +99,9 @@ class TableTag(object):
)
# -----------------------------------------------------------------------------------------------------------
def get_coeff_from_resultats(self, tag, etudid):
def get_coeff_from_resultats(self,
tag,
etudid):
"""Renvoie la somme des coeffs de pondération normalisée utilisés dans le calcul de la moyenne à un tag d'un étudiant
au regard du format de self.resultats.
"""
@ -117,15 +123,18 @@ class TableTag(object):
return len(self.inscrlist)
# -----------------------------------------------------------------------------------------------------------
def get_moy_from_stats(self, tag):
def get_moy_from_stats(self,
tag):
"""Renvoie la moyenne des notes calculées pour d'un tag donné"""
return self.statistiques[tag][0] if tag in self.statistiques else None
def get_min_from_stats(self, tag):
def get_min_from_stats(self,
tag):
"""Renvoie la plus basse des notes calculées pour d'un tag donné"""
return self.statistiques[tag][1] if tag in self.statistiques else None
def get_max_from_stats(self, tag):
def get_max_from_stats(self,
tag):
"""Renvoie la plus haute des notes calculées pour d'un tag donné"""
return self.statistiques[tag][2] if tag in self.statistiques else None
@ -142,7 +151,9 @@ class TableTag(object):
"min",
)
def get_resultatsEtud(self, tag, etudid):
def get_resultatsEtud(self,
tag,
etudid):
"""Renvoie un tuple (note, coeff, rang, nb_inscrit, moy, min, max) synthétisant les résultats d'un étudiant
à un tag donné. None sinon"""
return (
@ -164,7 +175,9 @@ class TableTag(object):
# *****************************************************************************************************************
# -----------------------------------------------------------------------------------------------------------
def add_moyennesTag(self, tag, listMoyEtCoeff) -> bool:
def add_moyennesTag(self,
tag,
listMoyEtCoeff) -> bool:
"""
Mémorise les moyennes, les coeffs de pondération et les etudid dans resultats
avec calcul du rang
@ -197,7 +210,8 @@ class TableTag(object):
# Méthodes dévolues aux calculs de statistiques (min, max, moy) sur chaque moyenne taguée
# *****************************************************************************************************************
def comp_stats_d_un_tag(self, tag):
def comp_stats_d_un_tag(self,
tag):
"""
Calcule la moyenne generale, le min, le max pour un tag donné,
en ne prenant en compte que les moyennes significatives. Mémorise le resultat dans
@ -221,7 +235,10 @@ class TableTag(object):
# ************************************************************************
# Méthodes dévolues aux affichages -> a revoir
# ************************************************************************
def str_resTag_d_un_etudiant(self, tag, etudid, delim=";"):
def str_resTag_d_un_etudiant(self,
tag,
etudid,
delim=";"):
"""Renvoie une chaine de caractères (valable pour un csv)
décrivant la moyenne et le rang d'un étudiant, pour un tag donné ;
"""
@ -236,14 +253,20 @@ class TableTag(object):
)
return moystr
def str_res_d_un_etudiant(self, etudid, delim=";"):
def str_res_d_un_etudiant(self,
etudid,
delim=";"):
"""Renvoie sur une ligne les résultats d'un étudiant à tous les tags (par ordre alphabétique)."""
return delim.join(
[self.str_resTag_d_un_etudiant(tag, etudid) for tag in self.get_all_tags()]
)
# -----------------------------------------------------------------------
def str_moytag(cls, moyenne, rang, nbinscrit, delim=";"):
def str_moytag(cls,
moyenne,
rang,
nbinscrit,
delim=";"):
"""Renvoie une chaine de caractères représentant une moyenne (float ou string) et un rang
pour différents formats d'affichage : HTML, debug ligne de commande, csv"""
moystr = (
@ -256,7 +279,9 @@ class TableTag(object):
str_moytag = classmethod(str_moytag)
# -----------------------------------------------------------------------
def str_tagtable(self, delim=";", decimal_sep=","):
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"]
for tag in self.get_all_tags():
@ -266,7 +291,7 @@ class TableTag(object):
for etudid in self.identdict:
descr = delim.join(
[
etudid,
str(etudid),
self.identdict[etudid]["nom"],
self.identdict[etudid]["prenom"],
]
@ -288,7 +313,9 @@ class TableTag(object):
# *********************************************
def moyenne_ponderee_terme_a_terme(notes, coefs=None, force=False):
def moyenne_ponderee_terme_a_terme(notes,
coefs=None,
force=False):
"""
Calcule la moyenne pondérée d'une liste de notes avec d'éventuels coeffs de pondération.
Renvoie le résultat sous forme d'un tuple (moy, somme_coeff)

View File

@ -76,7 +76,8 @@ PE_LOCAL_FOOTER_TMPL = REP_LOCAL_AVIS + "local/modeles/un_footer.tex"
# ----------------------------------------------------------------------------------------
def print_semestres_description(sems, avec_affichage_debug=False):
def print_semestres_description(sems,
avec_affichage_debug=False):
"""Dediee a l'affichage d'un semestre pour debug du module"""
def chaine_semestre(sem):
@ -119,7 +120,6 @@ def calcul_age(born):
)
# ----------------------------------------------------------------------------------------
def remove_accents(input_unicode_str):
"""Supprime les accents d'une chaine unicode"""
nfkd_form = unicodedata.normalize("NFKD", input_unicode_str)
@ -166,7 +166,10 @@ def list_directory_filenames(path):
return R
def add_local_file_to_zip(zipfile, ziproot, pathname, path_in_zip):
def add_local_file_to_zip(zipfile,
ziproot,
pathname,
path_in_zip):
"""Read pathname server file and add content to zip under path_in_zip"""
rooted_path_in_zip = os.path.join(ziproot, path_in_zip)
zipfile.write(filename=pathname, arcname=rooted_path_in_zip)
@ -174,7 +177,8 @@ def add_local_file_to_zip(zipfile, ziproot, pathname, path_in_zip):
# zipfile.writestr(rooted_path_in_zip, data)
def add_refs_to_register(register, directory):
def add_refs_to_register(register,
directory):
"""Ajoute les fichiers trouvés dans directory au registre (dictionaire) sous la forme
filename => pathname
"""
@ -184,7 +188,8 @@ def add_refs_to_register(register, directory):
register[filename] = pathname
def add_pe_stuff_to_zip(zipfile, ziproot):
def add_pe_stuff_to_zip(zipfile,
ziproot):
"""Add auxiliary files to (already opened) zip
Put all local files found under config/doc_poursuites_etudes/local
and config/doc_poursuites_etudes/distrib

View File

@ -106,39 +106,40 @@ def pe_view_sem_recap(
# (chaines unicodes, html non quoté)
template_latex = ""
# template fourni via le formulaire Web
if avis_tmpl_file:
try:
template_latex = avis_tmpl_file.read().decode("utf-8")
except UnicodeDecodeError as e:
raise ScoValueError(
"Données (template) invalides (caractères non UTF8 ?)"
) from e
else:
# template indiqué dans préférences ScoDoc ?
template_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
formsemestre_id, champ="pe_avis_latex_tmpl"
)
if False:
if avis_tmpl_file:
try:
template_latex = avis_tmpl_file.read().decode("utf-8")
except UnicodeDecodeError as e:
raise ScoValueError(
"Données (template) invalides (caractères non UTF8 ?)"
) from e
else:
# template indiqué dans préférences ScoDoc ?
template_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
formsemestre_id, champ="pe_avis_latex_tmpl"
)
template_latex = template_latex.strip()
if not template_latex:
# pas de preference pour le template: utilise fichier du serveur
template_latex = pe_avislatex.get_templates_from_distrib("avis")
template_latex = template_latex.strip()
if not template_latex:
# pas de preference pour le template: utilise fichier du serveur
template_latex = pe_avislatex.get_templates_from_distrib("avis")
# Footer:
footer_latex = ""
# template fourni via le formulaire Web
if footer_tmpl_file:
footer_latex = footer_tmpl_file.read().decode("utf-8")
else:
footer_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
formsemestre_id, champ="pe_avis_latex_footer"
)
footer_latex = footer_latex.strip()
if not footer_latex:
# pas de preference pour le footer: utilise fichier du serveur
footer_latex = pe_avislatex.get_templates_from_distrib(
"footer"
) # fallback: footer vides
# Footer:
footer_latex = ""
# template fourni via le formulaire Web
if footer_tmpl_file:
footer_latex = footer_tmpl_file.read().decode("utf-8")
else:
footer_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
formsemestre_id, champ="pe_avis_latex_footer"
)
footer_latex = footer_latex.strip()
if not footer_latex:
# pas de preference pour le footer: utilise fichier du serveur
footer_latex = pe_avislatex.get_templates_from_distrib(
"footer"
) # fallback: footer vides
tag_annotation_pe = pe_avislatex.get_code_latex_from_scodoc_preference(
formsemestre_id, champ="pe_tag_annotation_avis_latex"
@ -151,27 +152,29 @@ def pe_view_sem_recap(
jury.NOM_EXPORT_ZIP + "_annotationsPE" + scu.XLSX_SUFFIX, sT.excel()
)
latex_pages = {} # Dictionnaire de la forme nom_fichier => contenu_latex
for etudid in etudids:
[nom_fichier, contenu_latex] = pe_avislatex.get_avis_poursuite_par_etudiant(
jury,
etudid,
template_latex,
tag_annotation_pe,
footer_latex,
prefs,
if False:
latex_pages = {} # Dictionnaire de la forme nom_fichier => contenu_latex
for etudid in etudids:
[nom_fichier, contenu_latex] = pe_avislatex.get_avis_poursuite_par_etudiant(
jury,
etudid,
template_latex,
tag_annotation_pe,
footer_latex,
prefs,
)
jury.add_file_to_zip("avis/" + nom_fichier + ".tex", contenu_latex)
latex_pages[nom_fichier] = contenu_latex # Sauvegarde dans un dico
# Nouvelle version : 1 fichier par étudiant avec 1 fichier appelant créée ci-dessous
doc_latex = "\n% -----\n".join(
["\\include{" + nom + "}" for nom in sorted(latex_pages.keys())]
)
jury.add_file_to_zip("avis/" + nom_fichier + ".tex", contenu_latex)
latex_pages[nom_fichier] = contenu_latex # Sauvegarde dans un dico
jury.add_file_to_zip("avis/avis_poursuite.tex", doc_latex)
# Nouvelle version : 1 fichier par étudiant avec 1 fichier appelant créée ci-dessous
doc_latex = "\n% -----\n".join(
["\\include{" + nom + "}" for nom in sorted(latex_pages.keys())]
)
jury.add_file_to_zip("avis/avis_poursuite.tex", doc_latex)
# Ajoute image, LaTeX class file(s) and modeles
pe_tools.add_pe_stuff_to_zip(jury.zipfile, jury.NOM_EXPORT_ZIP)
# Ajoute image, LaTeX class file(s) and modeles
pe_tools.add_pe_stuff_to_zip(jury.zipfile, jury.NOM_EXPORT_ZIP)
data = jury.get_zipped_data()
return send_file(