FIX: calcul notes moyennes avec rattrapages ou session 2 + test unitaire

This commit is contained in:
Emmanuel Viennet 2022-11-13 14:22:47 +01:00 committed by iziram
parent f6d8de5a20
commit a2ea7d7a02
2 changed files with 97 additions and 12 deletions

View File

@ -35,14 +35,15 @@ moyenne générale d'une UE.
""" """
import dataclasses import dataclasses
from dataclasses import dataclass from dataclasses import dataclass
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from app import db from app import db
from app.models import ModuleImpl, Evaluation, EvaluationUEPoids from app.models import Evaluation, EvaluationUEPoids, ModuleImpl
from app.scodoc import sco_cache
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc.sco_codes_parcours import UE_SPORT from app.scodoc.sco_codes_parcours import UE_SPORT
from app.scodoc import sco_cache
from app.scodoc.sco_exceptions import ScoBugCatcher from app.scodoc.sco_exceptions import ScoBugCatcher
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
@ -217,12 +218,19 @@ class ModuleImplResults:
] ]
def get_evaluations_coefs(self, moduleimpl: ModuleImpl) -> np.array: def get_evaluations_coefs(self, moduleimpl: ModuleImpl) -> np.array:
"""Coefficients des évaluations, met à zéro ceux des évals incomplètes. """Coefficients des évaluations.
Les coefs des évals incomplètes et non "normales" (session 2, rattrapage)
sont zéro.
Résultat: 2d-array of floats, shape (nb_evals, 1) Résultat: 2d-array of floats, shape (nb_evals, 1)
""" """
return ( return (
np.array( np.array(
[e.coefficient for e in moduleimpl.evaluations], [
e.coefficient
if e.evaluation_type == scu.EVALUATION_NORMALE
else 0.0
for e in moduleimpl.evaluations
],
dtype=float, dtype=float,
) )
* self.evaluations_completes * self.evaluations_completes
@ -236,8 +244,8 @@ class ModuleImplResults:
] ]
def get_eval_notes_sur_20(self, moduleimpl: ModuleImpl) -> np.array: def get_eval_notes_sur_20(self, moduleimpl: ModuleImpl) -> np.array:
"""Les notes des évaluations, """Les notes de toutes les évaluations du module, complètes ou non.
remplace les ATT, EXC, ABS, NaN par zéro et mets les notes sur 20. Remplace les ATT, EXC, ABS, NaN par zéro et mets les notes sur 20.
Résultat: 2d array of floats, shape nb_etuds x nb_evaluations Résultat: 2d array of floats, shape nb_etuds x nb_evaluations
""" """
return np.where( return np.where(
@ -368,7 +376,7 @@ class ModuleImplResultsAPC(ModuleImplResults):
etuds_moy_module = np.where( etuds_moy_module = np.where(
etuds_use_rattrapage, notes_rat_ues, etuds_moy_module etuds_use_rattrapage, notes_rat_ues, etuds_moy_module
) )
# Serie indiquant que l'étudiant utilise une note de rattarage sur l'une des UE: # Serie indiquant que l'étudiant utilise une note de rattrapage sur l'une des UE:
self.etuds_use_rattrapage = pd.Series( self.etuds_use_rattrapage = pd.Series(
etuds_use_rattrapage.any(axis=1), index=self.evals_notes.index etuds_use_rattrapage.any(axis=1), index=self.evals_notes.index
) )

View File

@ -1,15 +1,22 @@
"""Test calculs rattrapages """Test calculs rattrapages
""" """
from config import TestConfig
from tests.unit import sco_fake_gen
from flask import g from flask import g
import app import app
from app.scodoc import sco_bulletins from app.but.bulletin_but import *
from app.scodoc import sco_formsemestre from app.comp import res_sem
from app.comp.res_but import ResultatsSemestreBUT
from app.models import ModuleImpl
from app.scodoc import (
sco_bulletins,
sco_evaluation_db,
sco_formsemestre,
sco_saisie_notes,
)
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from config import TestConfig
from tests.unit import sco_fake_gen
DEPT = TestConfig.DEPT_TEST DEPT = TestConfig.DEPT_TEST
@ -70,6 +77,19 @@ def test_notes_rattrapage(test_client):
etud = etuds[0] etud = etuds[0]
_, _, _ = G.create_note(evaluation=e, etud=etud, note=12.0) _, _, _ = G.create_note(evaluation=e, etud=etud, note=12.0)
_, _, _ = G.create_note(evaluation=e_rat, etud=etud, note=11.0) _, _, _ = G.create_note(evaluation=e_rat, etud=etud, note=11.0)
# --- Vérifications internes structures ScoDoc
formsemestre = FormSemestre.query.get(formsemestre_id)
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
mod_res = res.modimpls_results[moduleimpl_id]
moduleimpl = ModuleImpl.query.get(moduleimpl_id)
# retrouve l'éval. de rattrapage:
eval_rat = mod_res.get_evaluation_rattrapage(moduleimpl)
assert eval_rat.id == e_rat["id"]
# Les deux évaluations sont considérées comme complètes:
assert len(mod_res.get_evaluations_completes(moduleimpl)) == 2
# --- Vérification sur bulletin
b = sco_bulletins.formsemestre_bulletinetud_dict( b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"] sem["formsemestre_id"], etud["etudid"]
) )
@ -99,3 +119,60 @@ def test_notes_rattrapage(test_client):
sem["formsemestre_id"], etud["etudid"] sem["formsemestre_id"], etud["etudid"]
) )
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(10.0) assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(10.0)
# Supprime toutes les notes de l'évaluation de rattrapage:
sco_saisie_notes.evaluation_suppress_alln(e_rat["id"], dialog_confirmed=True)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Vérifie structure du bulletin:
assert b["etudid"] == etud["etudid"]
assert len(b["ues"][0]["modules"][0]["evaluations"]) == 1 # reste une eval normale
assert len(b["ues"][0]["modules"]) == 1
# Note moyenne: reviens à 10/20
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(10.0)
# Supprime l'évaluation de rattrapage:
sco_evaluation_db.do_evaluation_delete(e_rat["id"])
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
assert len(b["ues"][0]["modules"][0]["evaluations"]) == 1 # reste une eval normale
# Création évaluation session 2:
e_session2 = G.create_evaluation(
moduleimpl_id=moduleimpl_id,
jour="02/01/2020",
description="evaluation session 2",
coefficient=1.0,
evaluation_type=scu.EVALUATION_SESSION2,
)
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
mod_res = res.modimpls_results[moduleimpl_id]
# retrouve l'éval. de session 2:
eval_session2 = mod_res.get_evaluation_session2(moduleimpl)
assert eval_session2.id == e_session2["id"]
# Les deux évaluations sont considérées comme complètes:
assert len(mod_res.get_evaluations_completes(moduleimpl)) == 2
# Saisie note session 2:
_, _, _ = G.create_note(evaluation=e_session2, etud=etud, note=5.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Note moyenne: utilise session 2 même si inférieure
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(5.0)
_, _, _ = G.create_note(evaluation=e_session2, etud=etud, note=20.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Note moyenne: utilise session 2 même si inférieure
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(20.0)
_, _, _ = G.create_note(evaluation=e_session2, etud=etud, note=None)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Note moyenne: revient à note normale
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(10.0)