sco_placement: feuilles placement étudiants évaluation: modernisation code.

This commit is contained in:
Emmanuel Viennet 2024-10-20 11:02:08 +02:00
parent f8db40ffc0
commit fdc01a5c3b
4 changed files with 63 additions and 80 deletions

View File

@ -26,7 +26,8 @@ class MultiSelect:
HTML : group_ids="val1"&group_ids="val2"... HTML : group_ids="val1"&group_ids="val2"...
JS : ["val1","val2", ...] JS : ["val1","val2", ...]
**kwargs: Arguments supplémentaires (appliqué au multiselect en HTML <multi-select key="value" ...>) **kwargs: Arguments supplémentaires (appliqués au multiselect en
HTML <multi-select key="value" ...>)
""" """
def __init__( def __init__(
@ -61,7 +62,8 @@ class MultiSelect:
for value in values: for value in values:
selected = "selected" if value.get("selected", False) else "" selected = "selected" if value.get("selected", False) else ""
single = "single" if value.get("single", False) else "" single = "single" if value.get("single", False) else ""
opt = f"<option value='{value.get('value')}' {selected} {single} >{value.get('label')}</option>" opt = f"""<option value='{value.get('value')}' {selected} {single} >{
value.get('label')}</option>"""
optgroup += opt optgroup += opt
optgroup += "</optgroup>" optgroup += "</optgroup>"
opts.append(optgroup) opts.append(optgroup)

View File

@ -48,23 +48,16 @@ from wtforms import (
HiddenField, HiddenField,
SelectMultipleField, SelectMultipleField,
) )
from app.models import Evaluation, Module, ModuleImpl from app.models import Evaluation, Identite, ModuleImpl
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
from app.scodoc import sco_excel from app.scodoc import sco_excel
from app.scodoc.sco_excel import ScoExcelBook, COLORS from app.scodoc.sco_excel import ScoExcelBook, COLORS
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc.gen_tables import GenTable from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_etud
import sco_version import sco_version
_ = lambda x: x # sans babel
_l = _
COORD = "Coordonnées" COORD = "Coordonnées"
SEQ = "Continue" SEQ = "Continue"
@ -83,11 +76,9 @@ def _get_group_info(evaluation_id):
if partition not in groups_tree: if partition not in groups_tree:
groups_tree[partition] = {} groups_tree[partition] = {}
groups_tree[partition][group_name] = group_id groups_tree[partition][group_name] = group_id
if partition != TOUS: has_groups = partition != TOUS
has_groups = True
else: nb_groups = sum(len(pg) for pg in groups_tree.values())
has_groups = False
nb_groups = sum([len(groups_tree[p]) for p in groups_tree])
return groups_tree, has_groups, nb_groups return groups_tree, has_groups, nb_groups
@ -102,9 +93,9 @@ class PlacementForm(FlaskForm):
wtforms.validators.DataRequired("indiquez le format du fichier attendu"), wtforms.validators.DataRequired("indiquez le format du fichier attendu"),
], ],
) )
surveillants = StringField("Surveillants", validators=[]) surveillants = StringField("Surveillants", validators=[], description="texte libre")
batiment = StringField("Batiment") batiment = StringField("Bâtiment", description="texte libre")
salle = StringField("Salle") salle = StringField("Salle", description="texte libre")
nb_rangs = SelectField( nb_rangs = SelectField(
"nb de places en largeur", "nb de places en largeur",
coerce=int, coerce=int,
@ -139,19 +130,21 @@ class PlacementForm(FlaskForm):
evaluation_id evaluation_id
) )
choices = [] choices = []
for partition in self.groups_tree: for partition, groupes in self.groups_tree.items():
for groupe in self.groups_tree[partition]: for groupe in groupes:
if ( if (
groupe == TOUS groupe == TOUS
): # Affichage et valeur spécifique pour le groupe TOUS ): # Affichage et valeur spécifique pour le groupe TOUS
self.tous_id = str(self.groups_tree[partition][groupe]) self.tous_id = str(groupes[groupe])
choices.append((TOUS, TOUS)) choices.append((TOUS, TOUS))
else: else:
groupe_id = str(self.groups_tree[partition][groupe]) groupe_id = str(self.groups_tree[partition][groupe])
choices.append((groupe_id, "%s (%s)" % (str(groupe), partition))) choices.append((groupe_id, f"{str(groupe)} ({partition})"))
self.groups.choices = choices self.groups.choices = choices
# self.groups.default = [TOUS] # Ne fonctionnne pas... (ni dans la déclaration de PlaceForm.groups) # self.groups.default = [TOUS] # Ne fonctionnne pas...
# la réponse [] est de toute façon transposée en [ self.tous_id ] lors du traitement (cas du groupe unique) # (ni dans la déclaration de PlaceForm.groups)
# la réponse [] est de toute façon transposée en [ self.tous_id ]
# lors du traitement (cas du groupe unique)
class _DistributeurContinu: class _DistributeurContinu:
@ -227,48 +220,34 @@ class PlacementRunner:
self.file_format = form["file_format"].data self.file_format = form["file_format"].data
if len(form["groups"].data) == 0: if len(form["groups"].data) == 0:
self.groups_ids = [form.tous_id] self.groups_ids = [form.tous_id]
else: # On remplace le mot-clé TOUS le l'identiant de ce groupe else: # On remplace le mot-clé TOUS par l'identifiant de ce groupe
self.groups_ids = [ self.groups_ids = [
gid if gid != TOUS else form.tous_id for gid in form["groups"].data gid if gid != TOUS else form.tous_id for gid in form["groups"].data
] ]
self.evaluation = Evaluation.get_evaluation(self.evaluation_id) evl = Evaluation.get_evaluation(self.evaluation_id)
self.evaluation = evl
self.groups = sco_groups.listgroups(self.groups_ids) self.groups = sco_groups.listgroups(self.groups_ids)
self.gr_title_filename = sco_groups.listgroups_filename(self.groups) self.gr_title_filename = sco_groups.listgroups_filename(self.groups)
# gr_title = sco_groups.listgroups_abbrev(d['groups'])
self.current_user = current_user self.current_user = current_user
self.moduleimpl_id = self.evaluation.moduleimpl_id self.moduleimpl_id = evl.moduleimpl_id
self.moduleimpl: ModuleImpl = ModuleImpl.query.get_or_404(self.moduleimpl_id) self.moduleimpl: ModuleImpl = evl.moduleimpl
# TODO: à revoir pour utiliser modèle ModuleImpl self.moduleimpl_data = self.moduleimpl.to_dict()
self.moduleimpl_data = sco_moduleimpl.moduleimpl_list( mod = evl.moduleimpl.module
moduleimpl_id=self.moduleimpl_id self.module_data = mod.to_dict()
)[0] self.evalname = f"""{mod.code or "?"}-{
self.module_data = Module.get_module( evl.date_debut.strftime("%Y-%m-%d_%Hh%M") if evl.date_debut else ""}"""
self.moduleimpl_data["module_id"] if evl.description:
).to_dict()
self.sem = sco_formsemestre.get_formsemestre(
self.moduleimpl_data["formsemestre_id"]
)
self.evalname = "%s-%s" % (
self.module_data["code"] or "?",
(
self.evaluation.date_debut.strftime("%Y-%m-%d_%Hh%M")
if self.evaluation.date_debut
else ""
),
)
if self.evaluation.description:
self.evaltitre = self.evaluation.description self.evaltitre = self.evaluation.description
else: else:
self.evaltitre = f"""évaluation{ self.evaltitre = f"""évaluation{
self.evaluation.date_debut.strftime(' du %d/%m/%Y à %Hh%M') evl.date_debut.strftime(' du ' + scu.DATEATIME_FMT)
if self.evaluation.date_debut else ''}""" if evl.date_debut else ''}"""
self.desceval = [ # une liste de chaines: description de l'evaluation self.desceval = [ # une liste de chaines: description de l'evaluation
self.sem["titreannee"], evl.moduleimpl.formsemestre.titre_annee(),
"Module : %s - %s" f"""Module : {mod.code or "?"} - {evl.moduleimpl.module.abbrev or ""}""",
% (self.module_data["code"] or "?", self.module_data["abbrev"] or ""), f"Surveillants : {self.surveillants}",
"Surveillants : %s" % self.surveillants, f"Bâtiment : {self.batiment} - Salle : {self.salle}",
"Batiment : %(batiment)s - Salle : %(salle)s" % self.__dict__, f"Évaluation : {self.evaltitre} (coef. {evl.coefficient:g})",
"Controle : %s (coef. %g)" % (self.evaltitre, self.evaluation.coefficient),
] ]
self.styles = None self.styles = None
self.plan = None self.plan = None
@ -295,26 +274,26 @@ class PlacementRunner:
self.listetud = self._build_listetud() self.listetud = self._build_listetud()
self.plan = self._affectation_places() self.plan = self._affectation_places()
def _build_listetud(self): def _build_listetud(self) -> list[tuple[str, str, int]]:
get_all_students = None in [ # tous les etudiants ?
g["group_name"] for g in self.groups get_all_students = None in [g["group_name"] for g in self.groups]
] # tous les etudiants
etudid_etats = sco_groups.do_evaluation_listeetuds_groups( etudid_etats = sco_groups.do_evaluation_listeetuds_groups(
self.evaluation_id, self.evaluation_id,
self.groups, self.groups,
getallstudents=get_all_students, getallstudents=get_all_students,
include_demdef=True, include_demdef=True,
) )
listetud = [] # liste de couples (nom,prenom) listetud = [] # liste de tuples (nom, prenom, etudid)
for etudid, etat in etudid_etats: for etudid, etat in etudid_etats:
# infos identite etudiant (xxx sous-optimal: 1/select par etudiant) if etat != scu.DEMISSION:
ident = sco_etud.etudident_list(ndb.GetDBConnexion(), {"etudid": etudid})[0] # infos identite etudiant
if etat != "D": etud = Identite.get_etud(etudid)
nom = ident["nom"].upper() nom = etud.nom.upper()
prenom = ident["prenom"].lower().capitalize() prenom = etud.prenom.lower().capitalize()
etudid = ident["etudid"] listetud.append((nom, prenom, etud.id))
listetud.append((nom, prenom, etudid))
random.shuffle(listetud) random.shuffle(listetud)
return listetud return listetud
def _affectation_places(self): def _affectation_places(self):
@ -328,7 +307,7 @@ class PlacementRunner:
return plan return plan
def _production_xls(self): def _production_xls(self):
filename = "placement_%s_%s" % (self.evalname, self.gr_title_filename) filename = f"placement_{self.evalname}_{self.gr_title_filename}"
xls = self._excel_feuille_placement() xls = self._excel_feuille_placement()
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE) return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE)
@ -338,10 +317,10 @@ class PlacementRunner:
if self.evaluation.date_debut else '-' if self.evaluation.date_debut else '-'
} - Horaire : {self.evaluation.heure_debut()} à {self.evaluation.heure_fin() } - Horaire : {self.evaluation.heure_debut()} à {self.evaluation.heure_fin()
}""" }"""
filename = "placement_%(evalname)s_%(gr_title_filename)s" % self.__dict__ filename = f"placement_{self.evalname}_{self.gr_title_filename}"
titles = { titles = {
"nom": "Nom", "nom": "Nom",
"prenom": "Prenom", "prenom": "Prénom",
"colonne": "Colonne", "colonne": "Colonne",
"ligne": "Ligne", "ligne": "Ligne",
"place": "Place", "place": "Place",
@ -369,9 +348,7 @@ class PlacementRunner:
columns_ids=columns_ids, columns_ids=columns_ids,
rows=rows, rows=rows,
filename=filename, filename=filename,
origin="Généré par %s le " % sco_version.SCONAME origin=f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}",
+ scu.timedate_human_repr()
+ "",
pdf_title=pdf_title, pdf_title=pdf_title,
# pdf_shorttitle = '', # pdf_shorttitle = '',
preferences=sco_preferences.SemPreferences( preferences=sco_preferences.SemPreferences(
@ -476,9 +453,9 @@ class PlacementRunner:
} }
def _titres(self, worksheet): def _titres(self, worksheet):
datetime = time.strftime("%d/%m/%Y a %Hh%M") date_time = time.strftime(scu.DATEATIME_FMT)
worksheet.append_single_cell_row( worksheet.append_single_cell_row(
"Feuille placement etudiants éditée le %s" % datetime, self.styles["titres"] f"Feuille placement etudiants éditée le {date_time}", self.styles["titres"]
) )
for line, desceval in enumerate(self.desceval): for line, desceval in enumerate(self.desceval):
if line in [1, 4, 7]: if line in [1, 4, 7]:
@ -497,7 +474,7 @@ class PlacementRunner:
# entetes colonnes - feuille0 # entetes colonnes - feuille0
cells = [ws0.make_cell()] cells = [ws0.make_cell()]
for col in range(self.nb_rangs): for col in range(self.nb_rangs):
cells.append(ws0.make_cell("colonne %s" % (col + 1), self.styles["2b"])) cells.append(ws0.make_cell(f"colonne {col + 1}", self.styles["2b"]))
ws0.append_row(cells) ws0.append_row(cells)
# etudiants - feuille0 # etudiants - feuille0
@ -517,7 +494,7 @@ class PlacementRunner:
if self.etiquetage == COORD: if self.etiquetage == COORD:
cell_c = ws0.make_cell("", self.styles["1bb"]) cell_c = ws0.make_cell("", self.styles["1bb"])
else: else:
cell_c = ws0.make_cell("place %s" % place, self.styles["1bb"]) cell_c = ws0.make_cell(f"place {place}", self.styles["1bb"])
place = place + 1 place = place + 1
cells_c.append(cell_c) cells_c.append(cell_c)
ws0.set_row_dimension_height(row, space / 25) ws0.set_row_dimension_height(row, space / 25)

View File

@ -13,6 +13,7 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
<span class="help">{{field.description}}</span>
</td> </td>
</tr> </tr>
{% endmacro %} {% endmacro %}
@ -60,6 +61,8 @@
<input id="gr_cancel" type=submit value="Annuler"> <input id="gr_cancel" type=submit value="Annuler">
</script> </script>
</form> </form>
<div class="help">
<h3>Explications</h3> <h3>Explications</h3>
<ul> <ul>
<li>préciser les surveillants et la localisation (bâtiment et salle) et indiquer la largeur de la salle (nombre <li>préciser les surveillants et la localisation (bâtiment et salle) et indiquer la largeur de la salle (nombre
@ -85,5 +88,6 @@
</ul> </ul>
</li> </li>
</ul> </ul>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -3,7 +3,7 @@
"Infos sur version ScoDoc" "Infos sur version ScoDoc"
SCOVERSION = "9.7.31" SCOVERSION = "9.7.32"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"