DocScoDoc/scotests/sco_fake_gen.py

437 lines
14 KiB
Python

# -*- 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.
"""
from __future__ import print_function
from functools import wraps
import sys
import string
import collections
import pprint
import random
import scodoc_manager
from app.scodoc import notesdb as ndb
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_edit_formation
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_etud
from app.scodoc import sco_evaluations
from app.scodoc import sco_formations
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.debug import REQUEST
from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import ScoValueError
random.seed(12345) # tests reproductibles
DEMO_DIR = scu.SCO_SRC_DIR + "/scotests/demo/"
NOMS = [x.strip() for x in open(DEMO_DIR + "/noms.txt").readlines()]
PRENOMS_H = [x.strip() for x in open(DEMO_DIR + "/prenoms-h.txt").readlines()]
PRENOMS_F = [x.strip() for x in open(DEMO_DIR + "/prenoms-f.txt").readlines()]
PRENOMS_X = [x.strip() for x in open(DEMO_DIR + "/prenoms-x.txt").readlines()]
# nb: en python2, les chaines ci-dessus sont en utf8
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return "".join(random.choice(chars) for _ in range(size))
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)))
return r
return wrapper_logging_meth
class ScoFake:
def __init__(self, context, verbose=True):
self.context = context
self.verbose = verbose
def log(self, msg):
if self.verbose:
print("ScoFake: " + str(msg), file=sys.stderr)
sys.stderr.flush()
log("ScoFake: " + str(msg))
def civilitenomprenom(self):
"""un nom et un prenom au hasard,
toujours en majuscules.
"""
civilite = random.choice(("M", "M", "M", "F", "F", "F", "X"))
if civilite == "F":
prenom = random.choice(PRENOMS_F)
elif civilite == "M":
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()
@logging_meth
def create_etud(
self,
cnx=None,
code_nip="",
nom="",
prenom="",
code_ine="",
civilite="",
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",
):
"""Crée un étudiant"""
if not cnx:
cnx = ndb.GetDBConnexion()
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
if not nom:
nom = r_nom
if not prenom:
prenom = r_prenom
etud = sco_etud.create_etud(self.context, cnx, args=locals(), REQUEST=REQUEST)
inscription = "2020" # pylint: disable=unused-variable
sco_synchro_etuds.do_import_etud_admission(
self.context, cnx, etud["etudid"], locals()
)
return etud
@logging_meth
def create_formation(
self,
acronyme="test",
titre="Formation test",
titre_officiel="Le titre officiel de la formation test",
type_parcours=sco_codes_parcours.ParcoursDUT.TYPE_PARCOURS,
formation_code=None,
code_specialite=None,
):
"""Crée une formation"""
if not acronyme:
acronyme = "TEST" + str(random.randint(100000, 999999))
oid = sco_edit_formation.do_formation_create(
self.context, locals(), REQUEST=REQUEST
)
oids = sco_formations.formation_list(self.context, formation_id=oid)
if not oids:
raise ScoValueError("formation not created !")
return oids[0]
@logging_meth
def create_ue(
self,
formation_id=None,
acronyme=None,
numero=None,
titre="",
type=None,
ue_code=None,
ects=None,
is_external=None,
code_apogee=None,
coefficient=None,
):
"""Crée une UE"""
if numero is None:
numero = sco_edit_ue.next_ue_numero(self.context, formation_id, 0)
oid = sco_edit_ue.do_ue_create(self.context, locals(), REQUEST)
oids = sco_edit_ue.do_ue_list(self.context, args={"ue_id": oid})
if not oids:
raise ScoValueError("ue not created !")
return oids[0]
@logging_meth
def create_matiere(self, ue_id=None, titre=None, numero=None):
oid = sco_edit_matiere.do_matiere_create(self.context, locals(), REQUEST)
oids = sco_edit_matiere.do_matiere_list(self.context, args={"matiere_id": oid})
if not oids:
raise ScoValueError("matiere not created !")
return oids[0]
@logging_meth
def create_module(
self,
titre=None,
code=None,
heures_cours=None,
heures_td=None,
heures_tp=None,
coefficient=None,
ue_id=None,
formation_id=None,
matiere_id=None,
semestre_id=1,
numero=None,
abbrev=None,
ects=None,
code_apogee=None,
module_type=None,
):
oid = sco_edit_module.do_module_create(self.context, locals(), REQUEST)
oids = sco_edit_module.do_module_list(self.context, args={"module_id": oid})
if not oids:
raise ScoValueError("module not created ! (oid=%s)" % oid)
return oids[0]
@logging_meth
def create_formsemestre(
self,
formation_id=None,
semestre_id=None,
titre=None,
date_debut=None,
date_fin=None,
etat=None,
gestion_compensation=None,
bul_hide_xml=None,
gestion_semestrielle=None,
bul_bgcolor=None,
modalite=None,
resp_can_edit=None,
resp_can_change_ens=None,
ens_can_edit_eval=None,
elt_sem_apo=None,
elt_annee_apo=None,
etapes=None,
responsables=["bach"],
):
oid = sco_formsemestre.do_formsemestre_create(self.context, locals(), REQUEST)
# oids = self.context.do_formsemestre_list(args={"formsemestre_id": oid})
oids = sco_formsemestre.do_formsemestre_list(
self.context, args={"formsemestre_id": oid}
) # API inconsistency
if not oids:
raise ScoValueError("formsemestre not created !")
return oids[0]
@logging_meth
def create_moduleimpl(
self,
module_id=None,
formsemestre_id=None,
responsable_id=None,
):
oid = sco_moduleimpl.do_moduleimpl_create(self.context, locals())
oids = sco_moduleimpl.do_moduleimpl_list(
self.context, moduleimpl_id=oid
) # API inconsistency
if not oids:
raise ScoValueError("moduleimpl not created !")
return oids[0]
@logging_meth
def inscrit_etudiant(self, sem, etud):
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
self.context,
sem["formsemestre_id"],
etud["etudid"],
etat="I",
etape=etud.get("etape", None),
REQUEST=REQUEST,
method="test_inscrit_etudiant",
)
@logging_meth
def create_evaluation(
self,
moduleimpl_id=None,
jour=None,
heure_debut="8h00",
heure_fin="9h00",
description=None,
note_max=20,
coefficient=None,
visibulletin=None,
publish_incomplete=None,
evaluation_type=None,
numero=None,
REQUEST=REQUEST,
):
args = locals()
del args["self"]
oid = sco_evaluations.do_evaluation_create(self.context, **args)
oids = sco_evaluations.do_evaluation_list(
self.context, args={"evaluation_id": oid}
)
if not oids:
raise ScoValueError("evaluation not created !")
return oids[0]
@logging_meth
def create_note(
self,
evaluation=None,
etud=None,
note=None,
comment=None,
uid="bach",
):
return sco_saisie_notes._notes_add(
self.context,
uid,
evaluation["evaluation_id"],
[(etud["etudid"], note)],
comment=comment,
)
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:
formation (dict), liste d'ue (dicts), liste de modules.
"""
f = self.create_formation(acronyme=acronyme, titre=titre)
ue_list = []
mod_list = []
for semestre_id in range(1, nb_semestre + 1):
for n in range(1, nb_ue_per_semestre + 1):
ue = self.create_ue(
formation_id=f["formation_id"],
acronyme="TSU%s%s" % (semestre_id, n),
titre="ue test %s%s" % (semestre_id, n),
)
ue_list.append(ue)
mat = self.create_matiere(ue_id=ue["ue_id"], titre="matière test")
for _ in range(nb_module_per_ue):
mod = self.create_module(
matiere_id=mat["matiere_id"],
semestre_id=semestre_id,
code="TSM%s" % len(mod_list),
coefficient=1.0,
titre="module test",
ue_id=ue["ue_id"], # faiblesse de l'API
formation_id=f["formation_id"], # faiblesse de l'API
)
mod_list.append(mod)
return f, ue_list, mod_list
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,
titre=None,
responsables=["bach"],
modalite=None,
):
"""Création semestre, avec modules et évaluations."""
sem = self.create_formsemestre(
formation_id=f["formation_id"],
semestre_id=semestre_id,
date_debut=date_debut,
date_fin=date_fin,
titre=titre,
responsables=responsables,
modalite=modalite,
)
eval_list = []
for mod in mod_list:
if mod["semestre_id"] == semestre_id:
mi = self.create_moduleimpl(
module_id=mod["module_id"],
formsemestre_id=sem["formsemestre_id"],
responsable_id="bach",
)
for e_idx in range(1, nb_evaluations_per_module + 1):
e = self.create_evaluation(
moduleimpl_id=mi["moduleimpl_id"],
jour=date_debut,
description="evaluation test %s" % e_idx,
coefficient=1.0,
)
eval_list.append(e)
return sem, eval_list
def set_etud_notes_sem(
self, sem, eval_list, etuds, notes=None, random_min=0, random_max=20
):
"""Met des notes aux étudiants indiqués des evals indiquées.
Args:
sem: dict
eval_list: list of dicts
etuds: list of dicts
notes: liste des notes (float).
Si non spécifié, tire au hasard dans `[random_min, random_max]`
"""
set_random = notes is None
for e in eval_list:
if set_random:
notes = [float(random.randint(random_min, random_max)) for _ in etuds]
for etud, note in zip(etuds, notes):
self.create_note(evaluation=e, etud=etud, note=note)
def set_code_jury(
self,
sem,
etud,
code_etat=sco_codes_parcours.ADM,
devenir=sco_codes_parcours.NEXT,
assidu=True,
):
"""Affecte décision de jury"""
sco_formsemestre_validation.formsemestre_validation_etud_manu(
self.context,
formsemestre_id=sem["formsemestre_id"],
etudid=etud["etudid"],
code_etat=code_etat,
devenir=devenir,
assidu=assidu,
REQUEST=REQUEST,
)
# band aid for #sco8 dev (temporaire en attendant Users)
class Sco8Context(object):
Users = scodoc_manager.FakeUsers()