""" Test calcul moyennes pour les poursuites d'études """ import numpy as np import pytest import app.pe.moys.pe_moy from tests.unit import setup from app import db import pandas as pd import app.pe.moys.pe_moy as pe_moy import app.pe.moys.pe_rcstag as pe_rcstag import app.pe.moys.pe_tabletags as pe_tabletags import app.pe.moys.pe_moytag as pe_moytag def egalite_df(df1, df2): return ((df1 == df2) | (np.isnan(df1) & np.isnan(df2))).all() # ****************************** # app.pe.moys.pe_moy # ****************************** class Test_pe_moy: infos = { "aggregat": "S1", "tag": "maths", "intitule": "UE1.1", "cohorte": "groupe", } def test_init(self): """Test de pe_moy.Moyenne.__init__""" notes = pd.Series({1: 10.0, 2: 14.0, 3: np.nan, 4: 0.0}) moy = pe_moy.Moyenne(notes, Test_pe_moy.infos) assert moy.etudids == [1, 2, 3, 4], "Etudids incorrect" assert moy.inscrits_ids == [1, 2, 4], "Inscriptions incorrectes" # Les notes notes_attendues = pd.Series([10.0, 14.0, np.nan, 0.0], index=[1, 2, 3, 4]) assert "note" in moy.df.columns, "Colonne manquante" assert egalite_df(moy.df["note"], notes_attendues), "Notes incorrecte" # Les étuds nb_etuds = pd.Series([4] * 4, index=[1, 2, 3, 4]) assert "nb_etuds" in moy.df.columns, "Colonne manquante" assert egalite_df(moy.df["nb_etuds"], nb_etuds) # Les inscrits nb_inscrits = pd.Series([3, 3, np.nan, 3], index=[1, 2, 3, 4]) assert "nb_inscrits" in moy.df.columns, "Colonne manquante" assert egalite_df(moy.df["nb_inscrits"], nb_inscrits) # Les classements classement = pd.Series([2.0, 1.0, np.nan, 3.0], index=[1, 2, 3, 4]) assert "classement" in moy.df, "Colonne manquante" assert egalite_df(moy.df["classement"], classement), "Classements incorrects" # Les rangs rang = pd.Series(["2/3", "1/3", "nan", "3/3"], index=[1, 2, 3, 4]) assert "rang" in moy.df, "Colonne manquante" assert moy.df["rang"].isnull().sum() == 0, "Des Nan dans les rangs interdits" assert (moy.df["rang"] == rang).any(), "Rangs incorrects" # Les mins assert "min" in moy.df, "Colonne manquante" mina = pd.Series([0.0, 0.0, np.nan, 0.0], index=[1, 2, 3, 4]) assert egalite_df(moy.df["min"], mina), "Min incorrect" # Les max assert "max" in moy.df, "Colonne manquante" maxa = pd.Series([14.0, 14.0, np.nan, 14.0], index=[1, 2, 3, 4]) assert egalite_df(moy.df["max"], maxa), "Max incorrect" # Les moy assert "moy" in moy.df, "Colonne manquante" moya = pd.Series([8.0, 8.0, np.nan, 8.0], index=[1, 2, 3, 4]) assert egalite_df(moy.df["moy"], moya), "Moy incorrect" def test_init_ex_aequo(self): """Test de pe_moy.Moyenne.__init__ pour des ex-aequo""" notes = pd.Series({1: 10.0, 2: 14.0, 3: 10.0, 4: 0.0}) moy = pe_moy.Moyenne(notes, Test_pe_moy.infos) # Les rangs rang = pd.Series(["2 ex/4", "1/4", "2 ex/4", "3/4"], index=[1, 2, 3, 4]) assert moy.df["rang"].isnull().sum() == 0, "Des Nan dans les rangs interdits" assert (moy.df["rang"] == rang).any(), "Rangs incorrects" @pytest.mark.parametrize( "notes, resultat", [ pytest.param( pd.Series({1: 10.0, 2: 14.0, 3: np.nan, 4: 0.0}), True, id="avec_notes" ), pytest.param(pd.Series({1: np.nan, 2: np.nan}), False, id="sans_note"), pytest.param(pd.Series({1: 0.0, 2: np.nan}), True, id="avec 0"), ], ) def test_has_notes(self, notes, resultat): moy = pe_moy.Moyenne(notes, Test_pe_moy.infos) assert ( moy.has_notes() == resultat ), "Le test sur la présence de notes est incorrect" @pytest.mark.parametrize( "aggregat, tag, champ, cohorte, critere, attendu", [ pytest.param( "S1", "Math", "UE", "Gr", "note", "S1|Math|UE|Gr|note", id="tous_args" ), pytest.param( None, "Math", "UE", "Gr", "note", "Math|UE|Gr|note", id="aggregat manquant", ), pytest.param( None, "Math", "UE", None, "note", "Math|UE|note", id="aggregat et cohorte manquant", ), ], ) def test_colonnes_df(self, aggregat, tag, champ, cohorte, critere, attendu): descr = app.pe.moys.pe_moy.get_colonne_df( aggregat, tag, champ, cohorte, critere ) assert descr == attendu, "Nom de colonne incorrect" def to_df(self): notes = pd.Series({1: 10.0, 2: 14.0, 3: np.nan, 4: 0.0}) infos = { "aggregat": "S1", "tag": "maths", "intitule": "Général", "cohorte": "promo", } cols = [ f"S1|maths|Général|promo|{critere}" for critere in ["note", "rang", "min", "max", "moy"] ] moy = pe_moy.Moyenne(notes, infos) df = moy.to_df(with_min_max_moy=True) assert ( list(df.columns) == cols ), "Colonnes du df de synthèse pour Excel pas correctes" # ****************************** # app.pe.moys.pe_moytag # ****************************** class Test_pe_moytag: infos = {"aggregat": "S1", "cohorte": "promo"} def test_moyennes_tag__init__(self): matrice_notes = pd.DataFrame.from_dict( { 1: [12.0, 14.0, 15.0], 2: [8.0, np.nan, 12.0], 3: [0.0, 11.0, 13.0], 4: [np.nan, np.nan, np.nan], 5: [np.nan, np.nan, np.nan], 6: [0.0, 0.0, 0.0], }, orient="index", columns=["UE1.1", "UE1.2", "UE1.3"], ) matrice_coeffs = pd.DataFrame.from_dict( { 1: [1, 2, 3], 2: [2, 10, 6], 3: [1, 2, np.nan], 4: [5, 4, 3], 5: [np.nan, np.nan, np.nan], 6: [1, 1, 1], }, orient="index", columns=["UE1.1", "UE1.2", "UE1.3"], ) moy_tag = pe_moytag.MoyennesTag( "maths", None, matrice_notes, matrice_coeffs, Test_pe_moytag.infos ) attendu = pd.Series( [ (12 * 1 + 14 * 2 + 15 * 3) / (1 + 2 + 3), (8 * 2 + 12 * 6) / (2 + 6), (0 * 1 + 2 * 11) / (1 + 2), np.nan, np.nan, 0, ], index=[1, 2, 3, 4, 5, 6], ) assert egalite_df(moy_tag.notes_gen, attendu), "La moyenne n'est pas correcte" def test_to_df_sans_renommage_colonne(self): """Test le dataframe de synthèse""" infos = {"aggregat": "S1", "cohorte": "promo"} matrice_notes = pd.DataFrame.from_dict( { 2: [13.0, 13.0, 13], 1: [12.0, 14.0, 15.0], }, orient="index", columns=["UE1.1", "UE1.2", "UE1.3"], ) matrice_coeffs = pd.DataFrame.from_dict( { 2: [1, 2, 3], 1: [1, 2, 3], }, orient="index", columns=["UE1.1", "UE1.2", "UE1.3"], ) moy_tag = pe_moytag.MoyennesTag( "maths", None, matrice_notes, matrice_coeffs, infos ) synthese = moy_tag.to_df( aggregat="S1", cohorte="promo", options={"min_max_moy": True} ) colonnes_attendues = [] for ue in ["UE1.1", "UE1.2", "UE1.3", "Général"]: for champ in ["note", "rang", "min", "max", "moy"]: colonnes_attendues += [f"S1|maths|{ue}|promo|{champ}"] assert ( list(synthese.columns) == colonnes_attendues ), "Les colonnes de synthèse ne sont pas correctes" assert list(synthese.index) == [ 1, 2, ], "Les lignes ne sont pas triées par id d'étudiants" @pytest.mark.parametrize( "colonnes, ajouts, resultat", [ pytest.param(["toto", "titi"], ["tutu"], None, id="pas de modif"), pytest.param(["toto", "titi"], ["titi"], ["titi (1)"], id="ajout de (1)"), pytest.param( ["toto", "toto (1)"], ["toto"], ["toto (2)"], id="ajout de (2)" ), pytest.param( ["toto (1)", "titi (3)"], ["toto", "titi"], ["toto (4)", "titi (4)"], id="ajout multiple", ), ], ) def test_renomme_colonnes(self, colonnes, ajouts, resultat): res = pe_moytag.ajout_numero_a_colonnes(colonnes, ajouts) assert res == resultat, "L'ajout d'un numéro au colonne est incorrect" # ****************************** # app.pe.moys.pe_rcstag # ****************************** @pytest.mark.parametrize( "notes_S1, notes_S2, coeffs_S1, coeffs_S2, " "coeffs_rcues_S1, coeffs_rcues_S2, inscr_S1, inscr_S2," "moyenne, coeffs_aggreges", [ pytest.param( [17.0, 15.0, 12.0], [16.0, 14.0, 13.0], # notes [1.0, 2.0, 3.0], [4.0, 5.0, 6.0], # coeffs moy gen [2.0, 4.0, 6.0], [8.0, 10.0, 12.0], # coeffs recus [1.0, 1.0, 1.0], [1.0, 1.0, 1.0], # inscr [ (17.0 * 2.0 + 16.0 * 8.0) / (2.0 + 8.0), (15.0 * 4.0 + 14.0 * 10.0) / (4.0 + 10.0), (12.0 * 6.0 + 13.0 * 12.0) / (6.0 + 12.0), ], [1.0 + 4.0, 2.0 + 5.0, 3.0 + 6.0], id="etudiant_parfait", ), pytest.param( [17.0, 15.0, 12.0], [16.0, 14.0, 13.0], # notes [1.0, 2.0, 3.0], [4.0, 5.0, 6.0], # coeffs moy gen [2.0, 4.0, 6.0], [8.0, 10.0, 12.0], # coeffs recus [np.nan, 1.0, np.nan], [1.0, np.nan, np.nan], # inscr [ (16.0 * 8.0) / (8.0), (15.0 * 4.0) / (4.0), np.nan, ], [4.0, 2.0, np.nan], id="etudiant_non_inscrit", ), pytest.param( [0.0, 15.0, 0.0], [0.0, 0.0, 0.0], # notes [1.0, 2.0, 3.0], [4.0, 5.0, 6.0], # coeffs moy gen [2.0, 4.0, 6.0], [8.0, 10.0, 12.0], # coeffs recus [np.nan, 1.0, 1.0], [1.0, np.nan, 1.0], # inscr [0.0, 15.0, 0.0], [4.0, 2.0, 3.0 + 6.0], id="etudiant_avec_0", ), ], ) def test_compute_moyennes_par_RCS( notes_S1, notes_S2, coeffs_S1, coeffs_S2, coeffs_rcues_S1, coeffs_rcues_S2, inscr_S1, inscr_S2, moyenne, coeffs_aggreges, ): """Test de pe_rcstag.compute_moyennes_par_RCS""" notes_cube = np.stack([np.array([notes_S1]), np.array([notes_S2])], axis=-1) # Vérifie les dimensions dim1, dim2, dim3 = notes_cube.shape assert dim1 == 1, "La dim 0 doit être le nombre d'étudiants" assert dim2 == 3, "La dim 1 doit être le nombre d'UEs/Compétences" assert dim3 == 2, "La dim 2 doit être le nombre de semestres" coeffs_cube = np.stack([np.array([coeffs_S1]), np.array([coeffs_S2])], axis=-1) coeffs_rcue_cube = np.stack( [np.array([coeffs_rcues_S1]), np.array([coeffs_rcues_S2])], axis=-1 ) inscr_cube = np.stack([np.array([inscr_S1]), np.array([inscr_S2])], axis=-1) moys, coeffs = pe_rcstag.compute_moyennes_par_RCS( notes_cube, coeffs_cube, coeffs_rcue_cube, inscr_cube ) moy_resultat = np.array([moyenne]) assert ( (moys == moy_resultat) | (np.isnan(moys) & np.isnan(moy_resultat)) ).all(), "Moyenne erronée" coeffs_resultat = np.array([coeffs_aggreges]) assert ( (coeffs == coeffs_resultat) | (np.isnan(coeffs) & np.isnan(coeffs_resultat)) ).all(), "Coeffs (pour moyenne générale sur toutes les UE) erronés"