quelques annotations

This commit is contained in:
Emmanuel Viennet 2022-07-02 11:17:04 +02:00
parent 720e891f23
commit c5c7e9135b
6 changed files with 82 additions and 47 deletions

View File

@ -205,6 +205,19 @@ class Identite(db.Model):
d.update(adresse.to_dict(convert_nulls_to_str=True)) d.update(adresse.to_dict(convert_nulls_to_str=True))
return d return d
def inscriptions(self) -> list["FormSemestreInscription"]:
"Liste des inscriptions à des formsemestres, triée, la plus récente en tête"
from app.models.formsemestre import FormSemestre, FormSemestreInscription
return (
FormSemestreInscription.query.join(FormSemestreInscription.formsemestre)
.filter(
FormSemestreInscription.etudid == self.id,
)
.order_by(desc(FormSemestre.date_debut))
.all()
)
def inscription_courante(self): def inscription_courante(self):
"""La première inscription à un formsemestre _actuellement_ en cours. """La première inscription à un formsemestre _actuellement_ en cours.
None s'il n'y en a pas (ou plus, ou pas encore). None s'il n'y en a pas (ou plus, ou pas encore).
@ -216,7 +229,7 @@ class Identite(db.Model):
] ]
return r[0] if r else None return r[0] if r else None
def inscriptions_courantes(self) -> list: # -> list[FormSemestreInscription]: def inscriptions_courantes(self) -> list["FormSemestreInscription"]:
"""Liste des inscriptions à des semestres _courants_ """Liste des inscriptions à des semestres _courants_
(il est rare qu'il y en ai plus d'une, mais c'est possible). (il est rare qu'il y en ai plus d'une, mais c'est possible).
Triées par date de début de semestre décroissante (le plus récent en premier). Triées par date de début de semestre décroissante (le plus récent en premier).
@ -244,18 +257,6 @@ class Identite(db.Model):
] ]
return r[0] if r else None return r[0] if r else None
def inscription_etat(self, formsemestre_id):
"""État de l'inscription de cet étudiant au semestre:
False si pas inscrit, ou scu.INSCRIT, DEMISSION, DEF
"""
# voir si ce n'est pas trop lent:
ins = models.FormSemestreInscription.query.filter_by(
etudid=self.id, formsemestre_id=formsemestre_id
).first()
if ins:
return ins.etat
return False
def inscription_descr(self) -> dict: def inscription_descr(self) -> dict:
"""Description de l'état d'inscription""" """Description de l'état d'inscription"""
inscription_courante = self.inscription_courante() inscription_courante = self.inscription_courante()
@ -294,6 +295,18 @@ class Identite(db.Model):
"situation": situation, "situation": situation,
} }
def inscription_etat(self, formsemestre_id):
"""État de l'inscription de cet étudiant au semestre:
False si pas inscrit, ou scu.INSCRIT, DEMISSION, DEF
"""
# voir si ce n'est pas trop lent:
ins = models.FormSemestreInscription.query.filter_by(
etudid=self.id, formsemestre_id=formsemestre_id
).first()
if ins:
return ins.etat
return False
def descr_situation_etud(self) -> str: def descr_situation_etud(self) -> str:
"""Chaîne décrivant la situation _actuelle_ de l'étudiant. """Chaîne décrivant la situation _actuelle_ de l'étudiant.
Exemple: Exemple:

View File

@ -487,6 +487,19 @@ class FormSemestre(db.Model):
etudid, self.date_debut.isoformat(), self.date_fin.isoformat() etudid, self.date_debut.isoformat(), self.date_fin.isoformat()
) )
def get_codes_apogee(self, category=None) -> set[str]:
"""Les codes Apogée (codés en base comme "VRT1,VRT2")
category: None: tous, "etapes": étapes associées, "sem: code semestre", "annee": code annuel
"""
codes = set()
if category is None or category == "etapes":
codes |= {e.etape_apo for e in self.etapes if e}
if (category is None or category == "sem") and self.elt_sem_apo:
codes |= {x.strip() for x in self.elt_sem_apo.split(",") if x}
if (category is None or category == "annee") and self.elt_annee_apo:
codes |= {x.strip() for x in self.elt_annee_apo.split(",") if x}
return codes
def get_inscrits(self, include_demdef=False, order=False) -> list[Identite]: def get_inscrits(self, include_demdef=False, order=False) -> list[Identite]:
"""Liste des étudiants inscrits à ce semestre """Liste des étudiants inscrits à ce semestre
Si include_demdef, tous les étudiants, avec les démissionnaires Si include_demdef, tous les étudiants, avec les démissionnaires

View File

@ -178,7 +178,7 @@ class Module(db.Model):
def get_codes_apogee(self) -> set[str]: def get_codes_apogee(self) -> set[str]:
"""Les codes Apogée (codés en base comme "VRT1,VRT2")""" """Les codes Apogée (codés en base comme "VRT1,VRT2")"""
if self.code_apogee: if self.code_apogee:
return {x.strip() for x in self.code_apogee.split(",")} return {x.strip() for x in self.code_apogee.split(",") if x}
return set() return set()

View File

@ -124,5 +124,5 @@ class UniteEns(db.Model):
def get_codes_apogee(self) -> set[str]: def get_codes_apogee(self) -> set[str]:
"""Les codes Apogée (codés en base comme "VRT1,VRT2")""" """Les codes Apogée (codés en base comme "VRT1,VRT2")"""
if self.code_apogee: if self.code_apogee:
return {x.strip() for x in self.code_apogee.split(",")} return {x.strip() for x in self.code_apogee.split(",") if x}
return set() return set()

View File

@ -258,11 +258,16 @@ class ApoEtud(dict):
self["nom"] = nom self["nom"] = nom
self["prenom"] = prenom self["prenom"] = prenom
self["naissance"] = naissance self["naissance"] = naissance
self.cols = cols # { col_id : value } colid = 'apoL_c0001' self.cols = cols
"{ col_id : value } colid = 'apoL_c0001'"
self.col_elts = {}
"{'V1RT': {'R': 'ADM', 'J': '', 'B': 20, 'N': '12.14'}}"
self.new_cols = {} # { col_id : value to record in csv } self.new_cols = {} # { col_id : value to record in csv }
self.etud = None # etud ScoDoc self.etud: Identite = None
"etudiant ScoDoc associé"
self.etat = None # ETUD_OK, ... self.etat = None # ETUD_OK, ...
self.is_NAR = False # set to True si NARé dans un semestre self.is_NAR = False
"True si NARé dans un semestre"
self.log = [] self.log = []
self.has_logged_no_decision = False self.has_logged_no_decision = False
self.export_res_etape = export_res_etape # VET, ... self.export_res_etape = export_res_etape # VET, ...
@ -276,7 +281,7 @@ class ApoEtud(dict):
) )
def __repr__(self): def __repr__(self):
return "ApoEtud( nom='%s', nip='%s' )" % (self["nom"], self["nip"]) return f"""ApoEtud( nom='{self["nom"]}', nip='{self["nip"]}' )"""
def lookup_scodoc(self, etape_formsemestre_ids): def lookup_scodoc(self, etape_formsemestre_ids):
"""Cherche l'étudiant ScoDoc associé à cet étudiant Apogée. """Cherche l'étudiant ScoDoc associé à cet étudiant Apogée.
@ -284,6 +289,10 @@ class ApoEtud(dict):
met .etud à None. met .etud à None.
Sinon, cherche le semestre, et met l'état à ETUD_OK ou ETUD_NON_INSCRIT. Sinon, cherche le semestre, et met l'état à ETUD_OK ou ETUD_NON_INSCRIT.
""" """
# futur: #WIP
# etud: Identite = Identite.query.filter_by(code_nip=self["nip"]).first()
# self.etud = etud
etuds = sco_etud.get_etud_info(code_nip=self["nip"], filled=True) etuds = sco_etud.get_etud_info(code_nip=self["nip"], filled=True)
if not etuds: if not etuds:
# pas dans ScoDoc # pas dans ScoDoc
@ -291,13 +300,16 @@ class ApoEtud(dict):
self.log.append("non inscrit dans ScoDoc") self.log.append("non inscrit dans ScoDoc")
self.etat = ETUD_ORPHELIN self.etat = ETUD_ORPHELIN
else: else:
# futur: #WIP
# formsemestre_ids = {
# ins.formsemestre_id for ins in etud.formsemestre_inscriptions
# }
# in_formsemestre_ids = formsemestre_ids.intersection(etape_formsemestre_ids)
self.etud = etuds[0] self.etud = etuds[0]
# cherche le semestre ScoDoc correspondant à l'un de ceux de l'etape: # cherche le semestre ScoDoc correspondant à l'un de ceux de l'etape:
formsemestre_ids = {s["formsemestre_id"] for s in self.etud["sems"]} formsemestre_ids = {s["formsemestre_id"] for s in self.etud["sems"]}
self.in_formsemestre_ids = formsemestre_ids.intersection( in_formsemestre_ids = formsemestre_ids.intersection(etape_formsemestre_ids)
etape_formsemestre_ids if not in_formsemestre_ids:
)
if not self.in_formsemestre_ids:
self.log.append( self.log.append(
"connu dans ScoDoc, mais pas inscrit dans un semestre de cette étape" "connu dans ScoDoc, mais pas inscrit dans un semestre de cette étape"
) )
@ -305,7 +317,7 @@ class ApoEtud(dict):
else: else:
self.etat = ETUD_OK self.etat = ETUD_OK
def associate_sco(self, apo_data): def associate_sco(self, apo_data: "ApoData"):
"""Recherche les valeurs des éléments Apogée pour cet étudiant """Recherche les valeurs des éléments Apogée pour cet étudiant
Set .new_cols Set .new_cols
""" """
@ -327,7 +339,7 @@ class ApoEtud(dict):
cur_sem, autre_sem = self.etud_semestres_de_etape(apo_data) cur_sem, autre_sem = self.etud_semestres_de_etape(apo_data)
for sem in apo_data.sems_etape: for sem in apo_data.sems_etape:
el = self.search_elt_in_sem(code, sem, cur_sem, autre_sem) el = self.search_elt_in_sem(code, sem, cur_sem, autre_sem)
if el != None: if el is not None:
sco_elts[code] = el sco_elts[code] = el
break break
self.col_elts[code] = el self.col_elts[code] = el
@ -338,15 +350,15 @@ class ApoEtud(dict):
self.new_cols[col_id] = sco_elts[code][ self.new_cols[col_id] = sco_elts[code][
apo_data.cols[col_id]["Type Rés."] apo_data.cols[col_id]["Type Rés."]
] ]
except KeyError: except KeyError as exc:
log( log(
"associate_sco: missing key, etud=%s\ncode='%s'\netape='%s'" f"associate_sco: missing key, etud={self}\ncode='{code}'\netape='{apo_data.etape_apogee}'"
% (self, code, apo_data.etape_apogee)
) )
raise ScoValueError( raise ScoValueError(
"""L'élément %s n'a pas de résultat: peut-être une erreur dans les codes sur le programme pédagogique (vérifier qu'il est bien associé à une UE ou semestre)?""" f"""L'élément {code} n'a pas de résultat: peut-être une erreur
% code dans les codes sur le programme pédagogique
) (vérifier qu'il est bien associé à une UE ou semestre)?"""
) from exc
# recopie les 4 premieres colonnes (nom, ..., naissance): # recopie les 4 premieres colonnes (nom, ..., naissance):
for col_id in apo_data.col_ids[:4]: for col_id in apo_data.col_ids[:4]:
self.new_cols[col_id] = self.cols[col_id] self.new_cols[col_id] = self.cols[col_id]
@ -356,7 +368,7 @@ class ApoEtud(dict):
# codes = set([apo_data.cols[col_id].code for col_id in apo_data.col_ids]) # codes = set([apo_data.cols[col_id].code for col_id in apo_data.col_ids])
# return codes - set(sco_elts) # return codes - set(sco_elts)
def search_elt_in_sem(self, code, sem, cur_sem, autre_sem): def search_elt_in_sem(self, code, sem, cur_sem, autre_sem) -> dict:
""" """
VET code jury etape VET code jury etape
ELP élément pédagogique: UE, module ELP élément pédagogique: UE, module
@ -820,10 +832,8 @@ class ApoData(object):
elts[col["Code"]] = ApoElt([col]) elts[col["Code"]] = ApoElt([col])
return elts # { code apo : ApoElt } return elts # { code apo : ApoElt }
def apo_read_etuds(self, f): def apo_read_etuds(self, f) -> list[ApoEtud]:
"""Lecture des etudiants (et resultats) du fichier CSV Apogée """Lecture des etudiants (et resultats) du fichier CSV Apogée"""
-> liste de dicts
"""
L = [] L = []
while True: while True:
line = f.readline() line = f.readline()
@ -958,8 +968,11 @@ class ApoData(object):
""" """
codes_by_sem = {} codes_by_sem = {}
for sem in self.sems_etape: for sem in self.sems_etape:
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"]) formsemestre: FormSemestre = FormSemestre.query.get_or_404(
# L'ensemble des codes apo associés aux modules: sem["formsemestre_id"]
)
# L'ensemble des codes apo associés aux éléments:
codes_semestre = formsemestre.get_codes_apogee()
codes_modules = set().union( codes_modules = set().union(
*[ *[
modimpl.module.get_codes_apogee() modimpl.module.get_codes_apogee()
@ -976,12 +989,8 @@ class ApoData(object):
codes_by_sem[sem["formsemestre_id"]] = s codes_by_sem[sem["formsemestre_id"]] = s
for col_id in self.col_ids[4:]: for col_id in self.col_ids[4:]:
code = self.cols[col_id]["Code"] # 'V1RT' code = self.cols[col_id]["Code"] # 'V1RT'
# associé à l'étape, l'année ou les semestre: # associé à l'étape, l'année ou le semestre:
if ( if code in codes_semestre:
sco_formsemestre.sem_has_etape(sem, code)
or (code in {x.strip() for x in sem["elt_sem_apo"].split(",")})
or (code in {x.strip() for x in sem["elt_annee_apo"].split(",")})
):
s.add(code) s.add(code)
continue continue
# associé à une UE: # associé à une UE:

View File

@ -109,7 +109,7 @@ class DecisionSem(object):
# log('%s: %s %s %s %s %s' % (self.codechoice,code_etat,new_code_prev,formsemestre_id_utilise_pour_compenser,devenir,assiduite) ) # log('%s: %s %s %s %s %s' % (self.codechoice,code_etat,new_code_prev,formsemestre_id_utilise_pour_compenser,devenir,assiduite) )
def SituationEtudParcours(etud, formsemestre_id): def SituationEtudParcours(etud: dict, formsemestre_id: int):
"""renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)""" """renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)"""
formsemestre = FormSemestre.query.get_or_404(formsemestre_id) formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
@ -124,7 +124,7 @@ def SituationEtudParcours(etud, formsemestre_id):
class SituationEtudParcoursGeneric(object): class SituationEtudParcoursGeneric(object):
"Semestre dans un parcours" "Semestre dans un parcours"
def __init__(self, etud, formsemestre_id, nt): def __init__(self, etud: dict, formsemestre_id: int, nt: NotesTableCompat):
""" """
etud: dict filled by fill_etuds_info() etud: dict filled by fill_etuds_info()
""" """
@ -132,7 +132,7 @@ class SituationEtudParcoursGeneric(object):
self.etudid = etud["etudid"] self.etudid = etud["etudid"]
self.formsemestre_id = formsemestre_id self.formsemestre_id = formsemestre_id
self.sem = sco_formsemestre.get_formsemestre(formsemestre_id) self.sem = sco_formsemestre.get_formsemestre(formsemestre_id)
self.nt = nt self.nt: NotesTableCompat = nt
self.formation = self.nt.formsemestre.formation self.formation = self.nt.formsemestre.formation
self.parcours = self.nt.parcours self.parcours = self.nt.parcours
# Ce semestre est-il le dernier de la formation ? (e.g. semestre 4 du DUT) # Ce semestre est-il le dernier de la formation ? (e.g. semestre 4 du DUT)