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))
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):
"""La première inscription à un formsemestre _actuellement_ en cours.
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
def inscriptions_courantes(self) -> list: # -> list[FormSemestreInscription]:
def inscriptions_courantes(self) -> list["FormSemestreInscription"]:
"""Liste des inscriptions à des semestres _courants_
(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).
@ -244,18 +257,6 @@ class Identite(db.Model):
]
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:
"""Description de l'état d'inscription"""
inscription_courante = self.inscription_courante()
@ -294,6 +295,18 @@ class Identite(db.Model):
"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:
"""Chaîne décrivant la situation _actuelle_ de l'étudiant.
Exemple:

View File

@ -487,6 +487,19 @@ class FormSemestre(db.Model):
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]:
"""Liste des étudiants inscrits à ce semestre
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]:
"""Les codes Apogée (codés en base comme "VRT1,VRT2")"""
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()

View File

@ -124,5 +124,5 @@ class UniteEns(db.Model):
def get_codes_apogee(self) -> set[str]:
"""Les codes Apogée (codés en base comme "VRT1,VRT2")"""
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()

View File

@ -258,11 +258,16 @@ class ApoEtud(dict):
self["nom"] = nom
self["prenom"] = prenom
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.etud = None # etud ScoDoc
self.etud: Identite = None
"etudiant ScoDoc associé"
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.has_logged_no_decision = False
self.export_res_etape = export_res_etape # VET, ...
@ -276,7 +281,7 @@ class ApoEtud(dict):
)
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):
"""Cherche l'étudiant ScoDoc associé à cet étudiant Apogée.
@ -284,6 +289,10 @@ class ApoEtud(dict):
met .etud à None.
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)
if not etuds:
# pas dans ScoDoc
@ -291,13 +300,16 @@ class ApoEtud(dict):
self.log.append("non inscrit dans ScoDoc")
self.etat = ETUD_ORPHELIN
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]
# cherche le semestre ScoDoc correspondant à l'un de ceux de l'etape:
formsemestre_ids = {s["formsemestre_id"] for s in self.etud["sems"]}
self.in_formsemestre_ids = formsemestre_ids.intersection(
etape_formsemestre_ids
)
if not self.in_formsemestre_ids:
in_formsemestre_ids = formsemestre_ids.intersection(etape_formsemestre_ids)
if not in_formsemestre_ids:
self.log.append(
"connu dans ScoDoc, mais pas inscrit dans un semestre de cette étape"
)
@ -305,7 +317,7 @@ class ApoEtud(dict):
else:
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
Set .new_cols
"""
@ -327,7 +339,7 @@ class ApoEtud(dict):
cur_sem, autre_sem = self.etud_semestres_de_etape(apo_data)
for sem in apo_data.sems_etape:
el = self.search_elt_in_sem(code, sem, cur_sem, autre_sem)
if el != None:
if el is not None:
sco_elts[code] = el
break
self.col_elts[code] = el
@ -338,15 +350,15 @@ class ApoEtud(dict):
self.new_cols[col_id] = sco_elts[code][
apo_data.cols[col_id]["Type Rés."]
]
except KeyError:
except KeyError as exc:
log(
"associate_sco: missing key, etud=%s\ncode='%s'\netape='%s'"
% (self, code, apo_data.etape_apogee)
f"associate_sco: missing key, etud={self}\ncode='{code}'\netape='{apo_data.etape_apogee}'"
)
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)?"""
% code
)
f"""L'élément {code} 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)?"""
) from exc
# recopie les 4 premieres colonnes (nom, ..., naissance):
for col_id in apo_data.col_ids[:4]:
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])
# 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
ELP élément pédagogique: UE, module
@ -820,10 +832,8 @@ class ApoData(object):
elts[col["Code"]] = ApoElt([col])
return elts # { code apo : ApoElt }
def apo_read_etuds(self, f):
"""Lecture des etudiants (et resultats) du fichier CSV Apogée
-> liste de dicts
"""
def apo_read_etuds(self, f) -> list[ApoEtud]:
"""Lecture des etudiants (et resultats) du fichier CSV Apogée"""
L = []
while True:
line = f.readline()
@ -958,8 +968,11 @@ class ApoData(object):
"""
codes_by_sem = {}
for sem in self.sems_etape:
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
# L'ensemble des codes apo associés aux modules:
formsemestre: FormSemestre = FormSemestre.query.get_or_404(
sem["formsemestre_id"]
)
# L'ensemble des codes apo associés aux éléments:
codes_semestre = formsemestre.get_codes_apogee()
codes_modules = set().union(
*[
modimpl.module.get_codes_apogee()
@ -976,12 +989,8 @@ class ApoData(object):
codes_by_sem[sem["formsemestre_id"]] = s
for col_id in self.col_ids[4:]:
code = self.cols[col_id]["Code"] # 'V1RT'
# associé à l'étape, l'année ou les semestre:
if (
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(",")})
):
# associé à l'étape, l'année ou le semestre:
if code in codes_semestre:
s.add(code)
continue
# 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) )
def SituationEtudParcours(etud, formsemestre_id):
def SituationEtudParcours(etud: dict, formsemestre_id: int):
"""renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)"""
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
@ -124,7 +124,7 @@ def SituationEtudParcours(etud, formsemestre_id):
class SituationEtudParcoursGeneric(object):
"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()
"""
@ -132,7 +132,7 @@ class SituationEtudParcoursGeneric(object):
self.etudid = etud["etudid"]
self.formsemestre_id = formsemestre_id
self.sem = sco_formsemestre.get_formsemestre(formsemestre_id)
self.nt = nt
self.nt: NotesTableCompat = nt
self.formation = self.nt.formsemestre.formation
self.parcours = self.nt.parcours
# Ce semestre est-il le dernier de la formation ? (e.g. semestre 4 du DUT)