1
0
forked from ScoDoc/ScoDoc

Modernisation code: remplace DictDefault

This commit is contained in:
Emmanuel Viennet 2023-03-08 22:23:55 +01:00
parent 40978f30ee
commit fc786db83e
9 changed files with 80 additions and 89 deletions

View File

@ -28,6 +28,7 @@
"""Génération des bulletins de notes """Génération des bulletins de notes
""" """
import collections
import email import email
import time import time
import numpy as np import numpy as np
@ -143,7 +144,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
if not nt.get_etud_etat(etudid): if not nt.get_etud_etat(etudid):
raise ScoValueError("Étudiant non inscrit à ce semestre") raise ScoValueError("Étudiant non inscrit à ce semestre")
I = scu.DictDefault(defaultvalue="") I = collections.defaultdict(str)
I["etudid"] = etudid I["etudid"] = etudid
I["formsemestre_id"] = formsemestre_id I["formsemestre_id"] = formsemestre_id
I["sem"] = formsemestre.get_infos_dict() I["sem"] = formsemestre.get_infos_dict()
@ -260,7 +261,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
# n'affiche pas le rang sur le bulletin s'il y a des # n'affiche pas le rang sur le bulletin s'il y a des
# notes en attente dans ce semestre # notes en attente dans ce semestre
rang = scu.RANG_ATTENTE_STR rang = scu.RANG_ATTENTE_STR
rang_gr = scu.DictDefault(defaultvalue=scu.RANG_ATTENTE_STR) rang_gr = collections.defaultdict(lambda: scu.RANG_ATTENTE_STR)
inscriptions_counts = nt.get_inscriptions_counts() inscriptions_counts = nt.get_inscriptions_counts()
I["rang"] = rang I["rang"] = rang
I["rang_gr"] = rang_gr I["rang_gr"] = rang_gr
@ -710,50 +711,15 @@ def etud_descr_situation_semestre(
decisions_ue : noms (acronymes) des UE validées, séparées par des virgules. decisions_ue : noms (acronymes) des UE validées, séparées par des virgules.
descr_decisions_ue : ' UE acquises: UE1, UE2', ou vide si pas de dec. ou si pas show_uevalid descr_decisions_ue : ' UE acquises: UE1, UE2', ou vide si pas de dec. ou si pas show_uevalid
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
descr_parcours : le nom (libelle) du parcours dans lequel est inscrit l'étudiant en BUT (vide ailleurs)
""" """
# Fonction utilisée par tous les bulletins (APC ou classiques) # Fonction utilisée par tous les bulletins (APC ou classiques)
cnx = ndb.GetDBConnexion() infos = collections.defaultdict(str)
infos = scu.DictDefault(defaultvalue="")
# --- Situation et décisions jury # --- Situation et décisions jury
# démission/inscription ?
events = sco_etud.scolar_events_list( date_inscr, date_dem, date_def = _dates_insc_dem_def(etudid, formsemestre_id)
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
)
date_inscr = None
date_dem = None
date_def = None
for event in events:
event_type = event["event_type"]
if event_type == "INSCRIPTION":
if date_inscr:
# plusieurs inscriptions ???
# date_inscr += ', ' + event['event_date'] + ' (!)'
# il y a eu une erreur qui a laissé un event 'inscription'
# on l'efface:
log(
f"etud_descr_situation_semestre: removing duplicate INSCRIPTION event for etudid={etudid} !"
)
sco_etud.scolar_events_delete(cnx, event["event_id"])
else:
date_inscr = event["event_date"]
elif event_type == "DEMISSION":
# assert date_dem == None, 'plusieurs démissions !'
if date_dem: # cela ne peut pas arriver sauf bug (signale a Evry 2013?)
log(
f"etud_descr_situation_semestre: removing duplicate DEMISSION event for etudid={etudid} !"
)
sco_etud.scolar_events_delete(cnx, event["event_id"])
else:
date_dem = event["event_date"]
elif event_type == "DEFAILLANCE":
if date_def:
log(
f"etud_descr_situation_semestre: removing duplicate DEFAILLANCE event for etudid={etudid} !"
)
sco_etud.scolar_events_delete(cnx, event["event_id"])
else:
date_def = event["event_date"]
if show_date_inscr: if show_date_inscr:
if not date_inscr: if not date_inscr:
infos["date_inscription"] = "" infos["date_inscription"] = ""
@ -851,6 +817,49 @@ def etud_descr_situation_semestre(
return infos, dpv return infos, dpv
def _dates_insc_dem_def(etudid, formsemestre_id) -> tuple:
"Cherche les dates d'inscription, démission et défaillance de l'étudiant"
cnx = ndb.GetDBConnexion()
events = sco_etud.scolar_events_list(
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
)
date_inscr = None
date_dem = None
date_def = None
for event in events:
event_type = event["event_type"]
if event_type == "INSCRIPTION":
if date_inscr:
# plusieurs inscriptions ???
# date_inscr += ', ' + event['event_date'] + ' (!)'
# il y a eu une erreur qui a laissé un event 'inscription'
# on l'efface:
log(
f"etud_descr_situation_semestre: removing duplicate INSCRIPTION event for etudid={etudid} !"
)
sco_etud.scolar_events_delete(cnx, event["event_id"])
else:
date_inscr = event["event_date"]
elif event_type == "DEMISSION":
# assert date_dem == None, 'plusieurs démissions !'
if date_dem: # cela ne peut pas arriver sauf bug (signale a Evry 2013?)
log(
f"etud_descr_situation_semestre: removing duplicate DEMISSION event for etudid={etudid} !"
)
sco_etud.scolar_events_delete(cnx, event["event_id"])
else:
date_dem = event["event_date"]
elif event_type == "DEFAILLANCE":
if date_def:
log(
f"etud_descr_situation_semestre: removing duplicate DEFAILLANCE event for etudid={etudid} !"
)
sco_etud.scolar_events_delete(cnx, event["event_id"])
else:
date_def = event["event_date"]
return date_inscr, date_dem, date_def
def _format_situation_fields( def _format_situation_fields(
infos, field_names: list[str], extra_values: list[str] infos, field_names: list[str], extra_values: list[str]
) -> None: ) -> None:

View File

@ -27,6 +27,7 @@
"""Evaluations """Evaluations
""" """
import collections
import datetime import datetime
import operator import operator
import time import time
@ -171,8 +172,8 @@ def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=
# On considere une note "manquante" lorsqu'elle n'existe pas # On considere une note "manquante" lorsqu'elle n'existe pas
# ou qu'elle est en attente (ATT) # ou qu'elle est en attente (ATT)
GrNbMissing = scu.DictDefault() # group_id : nb notes manquantes GrNbMissing = collections.defaultdict(int) # group_id : nb notes manquantes
GrNotes = scu.DictDefault(defaultvalue=[]) # group_id: liste notes valides GrNotes = collections.defaultdict(list) # group_id: liste notes valides
TotalNbMissing = 0 TotalNbMissing = 0
TotalNbAtt = 0 TotalNbAtt = 0
groups = {} # group_id : group groups = {} # group_id : group

View File

@ -27,6 +27,7 @@
"""Opérations d'inscriptions aux semestres et modules """Opérations d'inscriptions aux semestres et modules
""" """
import collections
import time import time
import flask import flask
@ -543,10 +544,8 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
mods = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id) mods = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(etudid=etudid) inscr = sco_moduleimpl.do_moduleimpl_inscription_list(etudid=etudid)
# Formulaire # Formulaire
modimpls_by_ue_ids = scu.DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ] modimpls_by_ue_ids = collections.defaultdict(list) # ue_id : [ moduleimpl_id ]
modimpls_by_ue_names = scu.DictDefault( modimpls_by_ue_names = collections.defaultdict(list) # ue_id : [ moduleimpl_name ]
defaultvalue=[]
) # ue_id : [ moduleimpl_name ]
ues = [] ues = []
ue_ids = set() ue_ids = set()
initvalues = {} initvalues = {}

View File

@ -33,8 +33,8 @@ Elle n'est pas utilisée pour les parcours, ni pour rien d'autre
(c'est donc un attribut "cosmétique"). (c'est donc un attribut "cosmétique").
""" """
import collections
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import log from app import log
@ -54,7 +54,7 @@ def group_sems_by_modalite(sems):
"""Given the list of fromsemestre, group them by modalite, """Given the list of fromsemestre, group them by modalite,
sorted in each one by semestre id and date sorted in each one by semestre id and date
""" """
sems_by_mod = scu.DictDefault(defaultvalue=[]) sems_by_mod = collections.defaultdict(list)
modalites = list_formsemestres_modalites(sems) modalites = list_formsemestres_modalites(sems)
for modalite in modalites: for modalite in modalites:
for sem in sems: for sem in sems:

View File

@ -27,6 +27,7 @@
"""Opérations d'inscriptions aux modules (interface pour gérer options ou parcours) """Opérations d'inscriptions aux modules (interface pour gérer options ou parcours)
""" """
import collections
from operator import itemgetter from operator import itemgetter
import flask import flask
@ -676,7 +677,7 @@ def get_etuds_with_capitalized_ue(formsemestre_id: int) -> list[dict]:
"""For each UE, computes list of students capitalizing the UE. """For each UE, computes list of students capitalizing the UE.
returns { ue_id : [ { infos } ] } returns { ue_id : [ { infos } ] }
""" """
ues_cap_info = scu.DictDefault(defaultvalue=[]) ues_cap_info = collections.defaultdict(list)
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)

View File

@ -27,6 +27,7 @@
"""Feuille excel pour préparation des jurys classiques (non BUT) """Feuille excel pour préparation des jurys classiques (non BUT)
""" """
import collections
import time import time
from openpyxl.styles.numbers import FORMAT_NUMBER_00 from openpyxl.styles.numbers import FORMAT_NUMBER_00
@ -64,10 +65,10 @@ def feuille_preparation_jury(formsemestre_id):
"partition_id" "partition_id"
] ]
prev_moy_ue = scu.DictDefault(defaultvalue={}) # ue_code_s : { etudid : moy ue } prev_moy_ue = collections.defaultdict(dict) # ue_code_s : { etudid : moy ue }
prev_ue_acro = {} # ue_code_s : acronyme (à afficher) prev_ue_acro = {} # ue_code_s : acronyme (à afficher)
prev_moy = {} # moyennes gen sem prec prev_moy = {} # moyennes gen sem prec
moy_ue = scu.DictDefault(defaultvalue={}) # ue_acro : moyennes { etudid : moy ue } moy_ue = collections.defaultdict(dict) # ue_acro : moyennes { etudid : moy ue }
ue_acro = {} # ue_code_s : acronyme (à afficher) ue_acro = {} # ue_code_s : acronyme (à afficher)
moy = {} # moyennes gen moy = {} # moyennes gen
moy_inter = {} # moyenne gen. sur les 2 derniers semestres moy_inter = {} # moyenne gen. sur les 2 derniers semestres

View File

@ -29,7 +29,7 @@
Formulaires paramétrage PV et génération des tables Formulaires paramétrage PV et génération des tables
""" """
import collections
import time import time
from reportlab.platypus import Paragraph from reportlab.platypus import Paragraph
from reportlab.lib import styles from reportlab.lib import styles
@ -283,7 +283,7 @@ def formsemestre_pvjury(formsemestre_id, format="html", publish=True):
H.append(tab.html()) H.append(tab.html())
# Count number of cases for each decision # Count number of cases for each decision
counts = scu.DictDefault() counts = collections.defaultdict(int)
for row in rows: for row in rows:
counts[row["decision"]] += 1 counts[row["decision"]] += 1
# add codes for previous (for explanation, without count) # add codes for previous (for explanation, without count)

View File

@ -29,6 +29,7 @@
- statistiques decisions - statistiques decisions
- suivi cohortes - suivi cohortes
""" """
import collections
import os import os
import tempfile import tempfile
import re import re
@ -178,7 +179,8 @@ def _results_by_category(
if etud[category] in Count: if etud[category] in Count:
Count[etud[category]][etud[result]] += 1 Count[etud[category]][etud[result]] += 1
else: else:
Count[etud[category]] = scu.DictDefault(kv_dict={etud[result]: 1}) Count[etud[category]] = collections.defaultdict(int, {etud[result]: 1})
# conversion en liste de dict # conversion en liste de dict
C = [Count[cat] for cat in categories] C = [Count[cat] for cat in categories]
# Totaux par lignes et colonnes # Totaux par lignes et colonnes
@ -551,7 +553,7 @@ def table_suivi_cohorte(
indices_sems.sort() indices_sems.sort()
for p in P: for p in P:
p.nb_etuds = 0 # nombre total d'etudiants dans la periode p.nb_etuds = 0 # nombre total d'etudiants dans la periode
p.sems_by_id = scu.DictDefault(defaultvalue=[]) p.sems_by_id = collections.defaultdict(list)
for s in p.sems: for s in p.sems:
p.sems_by_id[s["semestre_id"]].append(s) p.sems_by_id[s["semestre_id"]].append(s)
p.nb_etuds += len(s["members"]) p.nb_etuds += len(s["members"])
@ -1162,7 +1164,7 @@ def table_suivi_cursus(formsemestre_id, only_primo=False, grouped_parcours=True)
civilites, civilites,
statuts, statuts,
) = tsp_etud_list(formsemestre_id, only_primo=only_primo) ) = tsp_etud_list(formsemestre_id, only_primo=only_primo)
codes_etuds = scu.DictDefault(defaultvalue=[]) codes_etuds = collections.defaultdict(list)
for etud in etuds: for etud in etuds:
etud["code_cursus"], etud["decisions_jury"] = get_code_cursus_etud(etud) etud["code_cursus"], etud["decisions_jury"] = get_code_cursus_etud(etud)
codes_etuds[etud["code_cursus"]].append(etud) codes_etuds[etud["code_cursus"]].append(etud)
@ -1350,17 +1352,16 @@ def graph_cursus(
civilites, civilites,
statuts, statuts,
) )
edges = scu.DictDefault( edges = collections.defaultdict(set)
defaultvalue=set() # {("SEM"formsemestre_id_origin, "SEM"formsemestre_id_dest) : etud_set}
) # {("SEM"formsemestre_id_origin, "SEM"formsemestre_id_dest) : etud_set}
def sem_node_name(sem, prefix="SEM"): def sem_node_name(sem, prefix="SEM"):
"pydot node name for this integer id" "pydot node name for this integer id"
return prefix + str(sem["formsemestre_id"]) return prefix + str(sem["formsemestre_id"])
sems = {} sems = {}
effectifs = scu.DictDefault(defaultvalue=set()) # formsemestre_id : etud_set effectifs = collections.defaultdict(set) # formsemestre_id : etud_set
decisions = scu.DictDefault(defaultvalue={}) # formsemestre_id : { code : nb_etud } decisions = collections.defaultdict(dict) # formsemestre_id : { code : nb_etud }
isolated_nodes = [] # [ node_name_de_formsemestre_id, ... ] isolated_nodes = [] # [ node_name_de_formsemestre_id, ... ]
connected_nodes = set() # { node_name_de_formsemestre_id } connected_nodes = set() # { node_name_de_formsemestre_id }
diploma_nodes = [] diploma_nodes = []

View File

@ -30,7 +30,7 @@
""" """
import base64 import base64
import bisect import bisect
import copy import collections
import datetime import datetime
from enum import IntEnum from enum import IntEnum
import io import io
@ -270,32 +270,11 @@ def get_mention(moy):
return "" return ""
class DictDefault(dict): # obsolete, use collections.defaultdict def group_by_key(d: dict, key) -> dict:
"""A dictionnary with default value for all keys grouped = collections.defaultdict(lambda: [])
Each time a non existent key is requested, it is added to the dict.
(used in python 2.4, can't use new __missing__ method)
"""
defaultvalue = 0
def __init__(self, defaultvalue=0, kv_dict={}):
dict.__init__(self)
self.defaultvalue = defaultvalue
self.update(kv_dict)
def __getitem__(self, k):
if k in self:
return self.get(k)
value = copy.copy(self.defaultvalue)
self[k] = value
return value
def group_by_key(d, key):
gr = DictDefault(defaultvalue=[])
for e in d: for e in d:
gr[e[key]].append(e) grouped[e[key]].append(e)
return gr return grouped
# ----- Global lock for critical sections (except notes_tables caches) # ----- Global lock for critical sections (except notes_tables caches)