ScoDoc/tests/unit/sco_fake_gen.py

461 lines
14 KiB
Python
Raw Normal View History

2020-12-26 00:11:55 +01:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
"""Creation environnement pour test.
A utiliser avec debug.py (côté serveur).
La classe ScoFake offre un ensemble de raccourcis permettant d'écrire
facilement des tests ou de reproduire des bugs.
2020-12-26 00:11:55 +01:00
"""
2023-08-25 17:58:57 +02:00
import datetime
2020-12-27 13:45:24 +01:00
from functools import wraps
2021-08-10 09:10:36 +02:00
import random
2020-12-26 00:11:55 +01:00
import sys
import string
2021-08-10 09:10:36 +02:00
import typing
2023-02-20 21:04:29 +01:00
from app import db, log
2021-08-10 09:10:36 +02:00
from app.auth.models import User
2023-08-22 17:02:00 +02:00
from app.models import (
Departement,
Evaluation,
Formation,
FormationModalite,
Identite,
2023-08-22 17:02:00 +02:00
Matiere,
ModuleImpl,
)
from app.scodoc import codes_cursus
2021-06-24 10:59:03 +02:00
from app.scodoc import sco_edit_matiere
from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_formsemestre_validation
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_saisie_notes
from app.scodoc import sco_synchro_etuds
from app.scodoc import sco_utils as scu
from app.scodoc.sco_exceptions import ScoValueError
from config import Config, TestConfig
2021-06-24 10:59:03 +02:00
2020-12-26 00:11:55 +01:00
random.seed(12345) # tests reproductibles
2021-06-24 10:59:03 +02:00
NOMS_DIR = Config.SCODOC_DIR + "/tools/fakeportal/nomsprenoms"
NOMS = [
x.strip()
for x in open(NOMS_DIR + "/noms.txt", encoding=scu.SCO_ENCODING).readlines()
]
PRENOMS_H = [
x.strip()
for x in open(NOMS_DIR + "/prenoms-h.txt", encoding=scu.SCO_ENCODING).readlines()
]
PRENOMS_F = [
x.strip()
for x in open(NOMS_DIR + "/prenoms-f.txt", encoding=scu.SCO_ENCODING).readlines()
]
PRENOMS_X = [
x.strip()
for x in open(NOMS_DIR + "/prenoms-x.txt", encoding=scu.SCO_ENCODING).readlines()
]
2021-06-24 10:59:03 +02:00
2020-12-26 00:11:55 +01:00
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return "".join(random.choice(chars) for _ in range(size))
2020-12-27 13:45:24 +01:00
def logging_meth(func):
@wraps(func)
def wrapper_logging_meth(self, *args, **kwargs):
r = func(self, *args, **kwargs)
# self.log("%s(%s) -> \n%s" % (func.__name__, kwargs, pprint.pformat(r)))
2020-12-27 13:45:24 +01:00
return r
return wrapper_logging_meth
2021-07-09 23:31:16 +02:00
class ScoFake(object):
2021-08-07 16:34:03 +02:00
"""Helper for ScoDoc tests"""
def __init__(self, verbose=True, dept=None):
2020-12-26 00:11:55 +01:00
self.verbose = verbose
2021-08-10 09:10:36 +02:00
self.default_user = User.query.filter_by(user_name="bach").first()
if not self.default_user:
raise ScoValueError('User test "bach" not found !')
self.dept = (
dept or Departement.query.filter_by(acronym=TestConfig.DEPT_TEST).first()
)
assert self.dept
2020-12-26 00:11:55 +01:00
def log(self, msg):
if self.verbose:
print("ScoFake: " + str(msg), file=sys.stderr)
sys.stderr.flush()
log("ScoFake: " + str(msg))
def civilitenomprenom(self):
2020-12-26 00:11:55 +01:00
"""un nom et un prenom au hasard,
toujours en majuscules.
"""
civilite = random.choice(("M", "M", "M", "F", "F", "F", "X"))
if civilite == "F":
2020-12-26 00:11:55 +01:00
prenom = random.choice(PRENOMS_F)
elif civilite == "M":
2020-12-26 00:11:55 +01:00
prenom = random.choice(PRENOMS_H)
elif civilite == "X":
prenom = random.choice(PRENOMS_X)
else:
raise ValueError("invalid civilite value")
return civilite, random.choice(NOMS).upper(), prenom.upper()
2020-12-26 00:11:55 +01:00
2020-12-27 13:45:24 +01:00
@logging_meth
2020-12-26 00:11:55 +01:00
def create_etud(
self,
2020-12-26 00:11:55 +01:00
cnx=None,
code_nip=None,
2020-12-26 00:11:55 +01:00
nom="",
prenom="",
code_ine=None,
civilite="",
2020-12-26 00:11:55 +01:00
etape="TST1",
email="test@localhost",
emailperso="perso@localhost",
date_naissance="01/01/2001",
lieu_naissance="Paris",
dept_naissance="75",
domicile="1, rue du test",
codepostaldomicile="75123",
villedomicile="TestCity",
paysdomicile="France",
telephone="0102030405",
typeadresse="domicile",
boursier=None,
description="etudiant test",
) -> dict:
2020-12-26 00:11:55 +01:00
"""Crée un étudiant"""
if code_nip == "":
code_nip = str(random.randint(10000, 99999))
if not civilite or not nom or not prenom:
r_civilite, r_nom, r_prenom = self.civilitenomprenom()
if not civilite:
civilite = r_civilite
2020-12-26 00:11:55 +01:00
if not nom:
nom = r_nom
if not prenom:
prenom = r_prenom
dept_id = self.dept.id # pylint: disable=possibly-unused-variable
inscription = "2020" # pylint: disable=possibly-unused-variable
args = locals()
etud = Identite.create_from_dict(args)
db.session.commit()
sco_synchro_etuds.do_import_etud_admission(etud, args)
return etud.to_dict_scodoc7()
2020-12-26 00:11:55 +01:00
2020-12-27 13:45:24 +01:00
@logging_meth
2020-12-26 00:11:55 +01:00
def create_formation(
self,
acronyme="test",
titre="Formation test",
titre_officiel="Le titre officiel de la formation test",
type_parcours: int = codes_cursus.CursusDUT.TYPE_CURSUS,
2020-12-26 00:11:55 +01:00
formation_code=None,
code_specialite=None,
2022-01-15 21:36:06 +01:00
) -> int:
2020-12-26 00:11:55 +01:00
"""Crée une formation"""
2021-01-28 23:02:18 +01:00
if not acronyme:
2020-12-26 00:11:55 +01:00
acronyme = "TEST" + str(random.randint(100000, 999999))
2023-02-20 21:04:29 +01:00
formation = Formation(
acronyme=scu.strip_str(acronyme),
titre=scu.strip_str(titre),
titre_officiel=scu.strip_str(titre_officiel),
type_parcours=type_parcours,
2023-02-20 21:04:29 +01:00
formation_code=scu.strip_str(formation_code),
code_specialite=scu.strip_str(code_specialite),
dept_id=self.dept.id,
2023-02-20 21:04:29 +01:00
)
db.session.add(formation)
db.session.commit()
return formation.id
2020-12-26 00:11:55 +01:00
2020-12-27 13:45:24 +01:00
@logging_meth
def create_ue(
self,
formation_id=None,
acronyme=None,
numero=0,
2020-12-27 13:45:24 +01:00
titre="",
type=None,
ue_code=None,
ects=None,
is_external=None,
code_apogee=None,
coefficient=None,
2021-11-17 10:28:51 +01:00
semestre_idx=None,
2022-01-15 21:36:06 +01:00
) -> int:
"""Crée une UE.
return: ue_id
"""
2020-12-27 13:45:24 +01:00
if numero is None:
2021-08-20 01:09:55 +02:00
numero = sco_edit_ue.next_ue_numero(formation_id, 0)
oid = sco_edit_ue.do_ue_create(locals())
2021-10-17 23:19:26 +02:00
oids = sco_edit_ue.ue_list(args={"ue_id": oid})
2020-12-27 13:45:24 +01:00
if not oids:
raise ScoValueError("ue not created !")
2022-01-15 21:36:06 +01:00
return oid
2020-12-27 13:45:24 +01:00
@logging_meth
def create_matiere(self, ue_id=None, titre=None, numero=0) -> int:
2021-08-20 01:09:55 +02:00
oid = sco_edit_matiere.do_matiere_create(locals())
2021-10-17 23:19:26 +02:00
oids = sco_edit_matiere.matiere_list(args={"matiere_id": oid})
2020-12-27 13:45:24 +01:00
if not oids:
raise ScoValueError("matiere not created !")
2022-01-15 21:36:06 +01:00
return oid
2020-12-26 00:11:55 +01:00
2020-12-27 13:45:24 +01:00
@logging_meth
def create_module(
self,
titre=None,
code=None,
heures_cours=None,
heures_td=None,
heures_tp=None,
coefficient=None,
matiere_id=None,
semestre_id=1,
numero=0,
2020-12-27 13:45:24 +01:00
abbrev=None,
ects=None,
code_apogee=None,
2022-04-21 22:54:06 +02:00
module_type=scu.ModuleType.STANDARD,
2022-01-15 21:36:06 +01:00
) -> int:
matiere = db.session.get(Matiere, matiere_id)
ue_id = matiere.ue.id
formation_id = matiere.ue.formation.id
2021-08-20 01:09:55 +02:00
oid = sco_edit_module.do_module_create(locals())
2021-10-16 19:20:36 +02:00
oids = sco_edit_module.module_list(args={"module_id": oid})
2020-12-27 13:45:24 +01:00
if not oids:
raise ScoValueError(f"module not created ! (oid={oid})")
2022-01-15 21:36:06 +01:00
return oid
2020-12-26 00:11:55 +01:00
2020-12-27 13:45:24 +01:00
@logging_meth
def create_formsemestre(
self,
formation_id=None,
semestre_id=None,
titre="",
2020-12-27 13:45:24 +01:00
date_debut=None,
date_fin=None,
etat=None,
gestion_compensation=None,
bul_hide_xml=None,
block_moyennes=None,
block_moyenne_generale=None,
2020-12-27 13:45:24 +01:00
gestion_semestrielle=None,
bul_bgcolor=None,
modalite=FormationModalite.DEFAULT_MODALITE,
2020-12-27 13:45:24 +01:00
resp_can_edit=None,
resp_can_change_ens=None,
ens_can_edit_eval=None,
elt_sem_apo=None,
elt_annee_apo=None,
etapes=None,
2021-08-10 09:10:36 +02:00
responsables=None, # sequence of resp. ids
2022-01-15 21:36:06 +01:00
) -> int:
2021-08-10 09:10:36 +02:00
if responsables is None:
responsables = (self.default_user.id,)
titre = titre or "sans titre"
oid = sco_formsemestre.do_formsemestre_create(locals())
2020-12-27 13:45:24 +01:00
oids = sco_formsemestre.do_formsemestre_list(
2021-08-19 10:28:35 +02:00
args={"formsemestre_id": oid}
2020-12-27 13:45:24 +01:00
) # API inconsistency
if not oids:
raise ScoValueError("formsemestre not created !")
2022-01-15 21:36:06 +01:00
return oid
2020-12-27 13:45:24 +01:00
@logging_meth
def create_moduleimpl(
self,
2021-08-10 09:10:36 +02:00
module_id: int = None,
formsemestre_id: int = None,
responsable_id: typing.Optional[int] = None,
2022-01-15 21:36:06 +01:00
) -> int:
2021-08-10 09:10:36 +02:00
if not responsable_id:
responsable_id = self.default_user.id
2021-08-20 01:09:55 +02:00
oid = sco_moduleimpl.do_moduleimpl_create(locals())
oids = sco_moduleimpl.moduleimpl_list(moduleimpl_id=oid) # API inconsistency
2020-12-27 13:45:24 +01:00
if not oids:
raise ScoValueError("moduleimpl not created !")
2022-01-15 21:36:06 +01:00
return oid
2020-12-27 13:45:24 +01:00
@logging_meth
2022-01-15 21:36:06 +01:00
def inscrit_etudiant(self, formsemestre_id: int, etud: dict):
2020-12-26 00:11:55 +01:00
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
2022-01-15 21:36:06 +01:00
formsemestre_id,
2020-12-26 00:11:55 +01:00
etud["etudid"],
etat="I",
2020-12-27 13:45:24 +01:00
etape=etud.get("etape", None),
2020-12-26 00:11:55 +01:00
method="test_inscrit_etudiant",
)
2020-12-27 13:45:24 +01:00
@logging_meth
def create_evaluation(
self,
moduleimpl_id=None,
2023-08-25 17:58:57 +02:00
date_debut: datetime.datetime = None,
date_fin: datetime.datetime = None,
2020-12-27 13:45:24 +01:00
description=None,
note_max=20,
coefficient=None,
visibulletin=None,
publish_incomplete=None,
evaluation_type=None,
numero=None,
2023-08-25 17:58:57 +02:00
) -> dict:
2020-12-27 13:45:24 +01:00
args = locals()
del args["self"]
2023-08-22 17:02:00 +02:00
moduleimpl: ModuleImpl = db.session.get(ModuleImpl, moduleimpl_id)
assert moduleimpl
evaluation: Evaluation = Evaluation.create(moduleimpl=moduleimpl, **args)
db.session.add(evaluation)
db.session.commit()
2023-08-25 17:58:57 +02:00
eval_dict = evaluation.to_dict()
eval_dict["id"] = evaluation.id
return eval_dict
2020-12-27 13:45:24 +01:00
@logging_meth
def create_note(
self,
evaluation_id: int = None,
etudid: int = None,
2020-12-27 13:45:24 +01:00
note=None,
comment: str = None,
user: User = None, # User instance
2020-12-27 13:45:24 +01:00
):
2021-08-10 12:57:38 +02:00
if user is None:
user = self.default_user
return sco_saisie_notes.notes_add(
2021-08-10 12:57:38 +02:00
user,
evaluation_id,
[(etudid, note)],
2020-12-27 13:45:24 +01:00
comment=comment,
)
2021-01-28 23:02:18 +01:00
def setup_formation(
self,
nb_semestre=1,
nb_ue_per_semestre=2,
nb_module_per_ue=2,
acronyme=None,
titre=None,
):
"""Création d'une formation, avec UE, modules et évaluations.
Formation avec `nb_semestre` comportant chacun `nb_ue_per_semestre` UE
et dans chaque UE `nb_module_per_ue` modules (on a une seule matière par UE).
Returns:
2022-01-15 21:36:06 +01:00
formation_id, liste d'ue (dicts), liste de modules.
"""
2022-01-15 21:36:06 +01:00
formation_id = self.create_formation(acronyme=acronyme, titre=titre)
ue_ids = []
mod_ids = []
for semestre_id in range(1, nb_semestre + 1):
for n in range(1, nb_ue_per_semestre + 1):
2022-01-15 21:36:06 +01:00
ue_id = self.create_ue(
formation_id=formation_id,
acronyme="TSU%s%s" % (semestre_id, n),
titre="ue test %s%s" % (semestre_id, n),
)
2022-01-15 21:36:06 +01:00
ue_ids.append(ue_id)
matiere_id = self.create_matiere(ue_id=ue_id, titre="matière test")
for _ in range(nb_module_per_ue):
mod = self.create_module(
2022-01-15 21:36:06 +01:00
matiere_id=matiere_id,
semestre_id=semestre_id,
2022-01-15 21:36:06 +01:00
code="TSM%s" % len(mod_ids),
coefficient=1.0,
titre="module test",
)
2022-01-15 21:36:06 +01:00
mod_ids.append(mod)
return formation_id, ue_ids, mod_ids
def setup_formsemestre(
self,
f,
mod_list,
semestre_id=1,
date_debut="01/01/2020",
date_fin="30/06/2020",
nb_evaluations_per_module=1,
2021-01-28 23:02:18 +01:00
titre=None,
2021-08-10 12:57:38 +02:00
responsables=None, # list of users ids
2021-01-28 23:02:18 +01:00
modalite=None,
):
"""Création semestre, avec modules et évaluations."""
2022-01-15 21:36:06 +01:00
formsemestre_id = self.create_formsemestre(
formation_id=f["formation_id"],
semestre_id=semestre_id,
date_debut=date_debut,
date_fin=date_fin,
2021-01-28 23:02:18 +01:00
titre=titre,
responsables=responsables,
modalite=modalite,
)
eval_list = []
for mod in mod_list:
if mod["semestre_id"] == semestre_id:
2022-01-15 21:36:06 +01:00
moduleimpl_id = self.create_moduleimpl(
module_id=mod["module_id"],
2022-01-15 21:36:06 +01:00
formsemestre_id=formsemestre_id,
responsable_id="bach",
)
for e_idx in range(1, nb_evaluations_per_module + 1):
e = self.create_evaluation(
2022-01-15 21:36:06 +01:00
moduleimpl_id=moduleimpl_id,
date_debut=datetime.datetime.strptime(date_debut, scu.DATE_FMT),
description="evaluation test %s" % e_idx,
coefficient=1.0,
)
eval_list.append(e)
2022-01-15 21:36:06 +01:00
return formsemestre_id, eval_list
def set_etud_notes_evals(
self, eval_list: list[dict], etuds: list[dict], notes=None
):
"""Met des notes aux étudiants indiqués des evals indiquées.
Args:
notes: liste des notes (float).
Si non spécifié, utilise la liste NOTES_T
"""
2023-10-19 23:47:04 +02:00
from tests.unit.setup import NOTES_T
if notes is None:
notes = NOTES_T
for e in eval_list:
for idx, etud in enumerate(etuds):
self.create_note(
2023-08-25 17:58:57 +02:00
evaluation_id=e["evaluation_id"],
2022-12-06 13:06:50 +01:00
etudid=etud["etudid"],
note=notes[idx % len(notes)],
)
def set_code_jury(
self,
2022-01-15 21:36:06 +01:00
formsemestre_id,
etud,
code_etat=codes_cursus.ADM,
devenir=codes_cursus.NEXT,
assidu=True,
):
"""Affecte décision de jury"""
sco_formsemestre_validation.formsemestre_validation_etud_manu(
2022-01-15 21:36:06 +01:00
formsemestre_id=formsemestre_id,
etudid=etud["etudid"],
code_etat=code_etat,
devenir=devenir,
assidu=assidu,
)