diff --git a/app/api/jury.py b/app/api/jury.py index 7cf067cc3..b58147c7f 100644 --- a/app/api/jury.py +++ b/app/api/jury.py @@ -15,6 +15,7 @@ import app from app import db, log from app.api import api_bp as bp, api_web_bp from app.decorators import scodoc, permission_required +from app.scodoc.sco_exceptions import ScoException from app.scodoc.sco_utils import json_error from app.but import jury_but_recap from app.models import FormSemestre, FormSemestreInscription, Identite @@ -30,6 +31,9 @@ def decisions_jury(formsemestre_id: int): """Décisions du jury des étudiants du formsemestre.""" # APC, pair: formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id) - app.set_sco_dept(formsemestre.departement.acronym) - rows = jury_but_recap.get_jury_but_results(formsemestre) - return jsonify(rows) + if formsemestre.formation.is_apc(): + app.set_sco_dept(formsemestre.departement.acronym) + rows = jury_but_recap.get_jury_but_results(formsemestre) + return jsonify(rows) + else: + raise ScoException("non implemente") diff --git a/app/but/jury_but.py b/app/but/jury_but.py index 2091c16af..c4236910c 100644 --- a/app/but/jury_but.py +++ b/app/but/jury_but.py @@ -63,13 +63,13 @@ from operator import attrgetter import re from typing import Union +import numpy as np from flask import g, url_for from app import db from app import log from app.comp.res_but import ResultatsSemestreBUT -from app.comp import inscr_mod, res_sem -from app.models import formsemestre +from app.comp import res_sem from app.models.but_refcomp import ( ApcAnneeParcours, @@ -917,7 +917,7 @@ class DecisionsProposeesUE(DecisionsProposees): self.codes = [ sco_codes.DEM if inscription_etat == scu.DEMISSION else sco_codes.DEF ] - self.moy_ue = "-" + self.moy_ue = np.NaN return # Moyenne de l'UE ? diff --git a/app/but/jury_but_recap.py b/app/but/jury_but_recap.py index 038335ac2..90ee14be4 100644 --- a/app/but/jury_but_recap.py +++ b/app/but/jury_but_recap.py @@ -448,6 +448,9 @@ def get_jury_but_table( def get_jury_but_results(formsemestre: FormSemestre) -> list[dict]: """Liste des résultats jury BUT sous forme de dict, pour API""" + if formsemestre.formation.referentiel_competence is None: + # pas de ref. comp., donc pas de decisions de jury (ne lance pas d'exception) + return [] dpv = sco_pvjury.dict_pvjury(formsemestre.id) rows = [] for etudid in formsemestre.etuds_inscriptions: diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index 5f432387c..b6f47d663 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -221,10 +221,7 @@ def compute_ue_moys_apc( modimpl_mask: np.array, ) -> pd.DataFrame: """Calcul de la moyenne d'UE en mode APC (BUT). - La moyenne d'UE est un nombre (note/20), ou NI ou NA ou ERR - NI non inscrit à (au moins un) module de cette UE - NA pas de notes disponibles - ERR erreur dans une formule utilisateurs (pas gérées ici). + La moyenne d'UE est un nombre (note/20), ou NaN si pas de notes disponibles sem_cube: notes moyennes aux modules ndarray (etuds x modimpls x UEs) diff --git a/tests/api/exemple-api-basic.py b/tests/api/exemple-api-basic.py index 2bc5f9ec1..022065a59 100644 --- a/tests/api/exemple-api-basic.py +++ b/tests/api/exemple-api-basic.py @@ -28,6 +28,7 @@ avec la config du client API: """ from pprint import pprint as pp +import sys import urllib3 from setup_test_api import ( API_PASSWORD, @@ -128,7 +129,42 @@ pp(partitions) POST_JSON(f"/group/5559/delete", headers=HEADERS) POST_JSON(f"/group/5327/edit", data={"group_name": "TDXXX"}, headers=HEADERS) -# --------- XXX à passer en dans les tests unitaires +# --------- Toutes les bulletins, un à un, et les décisions de jury d'un semestre +formsemestre_id = 911 +etuds = GET(f"/formsemestre/{formsemestre_id}/etudiants", headers=admin_h) +etudid = 16450 +bul = GET( + f"/etudiant/etudid/{etudid}/formsemestre/{formsemestre_id}/bulletin", + headers=HEADERS, +) +for etud in etuds: + bul = GET( + f"/etudiant/etudid/{etud['id']}/formsemestre/{formsemestre_id}/bulletin", + headers=HEADERS, + ) + sys.stdout.write(".") + sys.stdout.flush() + +print("") +decisions = GET(f"/formsemestre/{formsemestre_id}/decisions_jury", headers=HEADERS) + +# Decisions de jury des _tous_ les formsemestre, un à un, en partant de l'id le plus élevé +formsemestres = GET("/formsemestres/query", headers=HEADERS) +formsemestres.sort(key=lambda s: s["id"], reverse=1) +print(f"###### Testing {len(formsemestres)} formsemestres...") +for formsemestre in formsemestres: + print(formsemestre["session_id"]) + try: + decisions = GET( + f"/formsemestre/{formsemestre['id']}/decisions_jury", headers=HEADERS + ) + except APIError as exc: + if exc.payload.get("message") != "non implemente": + raise + decisions = [] + print(f"{len(decisions)} decisions") + +# --------- A été passé dans les tests unitaires: # 0- Prend un étudiant au hasard dans le semestre etud = GET(f"/formsemestre/{formsemestre_id}/etudiants", headers=HEADERS)[10] diff --git a/tests/api/setup_test_api.py b/tests/api/setup_test_api.py index b71467ca2..fb7517ce8 100644 --- a/tests/api/setup_test_api.py +++ b/tests/api/setup_test_api.py @@ -38,7 +38,9 @@ print(f"API URL={API_URL}") class APIError(Exception): - pass + def __init__(self, message: str = "", payload=None): + self.message = message + self.payload = payload or {} def get_auth_headers(user, password) -> dict: @@ -70,7 +72,7 @@ def GET(path: str, headers: dict = None, errmsg=None, dept=None): url = API_URL + path r = requests.get(url, headers=headers or {}, verify=CHECK_CERTIFICATE) if r.status_code != 200: - raise APIError(errmsg or f"""erreur status={r.status_code} !\n{r.text}""") + raise APIError(errmsg or f"""erreur status={r.status_code} !""", r.json()) return r.json() # decode la reponse JSON @@ -83,5 +85,5 @@ def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None): verify=CHECK_CERTIFICATE, ) if r.status_code != 200: - raise APIError(errmsg or f"erreur status={r.status_code} !\n{r.text}") + raise APIError(errmsg or f"erreur status={r.status_code} !", r.json()) return r.json() # decode la reponse JSON