diff --git a/README.md b/README.md
index a757f17e48f75a2523513fdf8573c1372017e6c9..e28a92aacf109bfab23852c55b243be53ad078de 100644
--- a/README.md
+++ b/README.md
@@ -130,12 +130,12 @@ base de données (tous les départements, et les utilisateurs) avant de commence
 
 On utilise SQLAlchemy avec Alembic et Flask-Migrate.
 
-    flask db migrate -m "ScoDoc 9.0.x: ..." # ajuster le message !
+    flask db migrate -m "message explicatif....."
     flask db upgrade
 
-Ne pas oublier de commiter les migrations (`git add migrations` ...).
+Ne pas oublier de d'ajouter le script de migration à git (`git add migrations/...`).
 
-Mémo pour développeurs: séquence re-création d'une base (vérifiez votre `.env`
+**Mémo**: séquence re-création d'une base (vérifiez votre `.env`
 ou variables d'environnement pour interroger la bonne base !).
 
     dropdb SCODOC_DEV
diff --git a/app/api/sco_api.py b/app/api/sco_api.py
index 46be85a7a20fbc99245d9d93995a491ad2f46537..e2619a0b0d5e242fc6f7d5349b5af44adda6d6be 100644
--- a/app/api/sco_api.py
+++ b/app/api/sco_api.py
@@ -29,7 +29,7 @@
 """
 # PAS ENCORE IMPLEMENTEE, juste un essai
 # Pour P. Bouron, il faudrait en priorité l'équivalent de
-# Scolarite/Notes/do_moduleimpl_withmodule_list
+# Scolarite/Notes/moduleimpl_withmodule_list (alias scodoc7 do_moduleimpl_withmodule_list)
 # Scolarite/Notes/evaluation_create
 # Scolarite/Notes/evaluation_delete
 # Scolarite/Notes/formation_list
diff --git a/app/scodoc/notes_table.py b/app/scodoc/notes_table.py
index a06c2ccd5d9b95ff50a643a1b5f35add110428f7..5e8f2f1901d6c93817e31da885e18d77df5c21e1 100644
--- a/app/scodoc/notes_table.py
+++ b/app/scodoc/notes_table.py
@@ -102,7 +102,7 @@ def get_sem_ues_modimpls(formsemestre_id, modimpls=None):
     (utilisé quand on ne peut pas construire nt et faire nt.get_ues())
     """
     if modimpls is None:
-        modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+        modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
     uedict = {}
     for modimpl in modimpls:
         mod = sco_edit_module.do_module_list(args={"module_id": modimpl["module_id"]})[
@@ -212,7 +212,7 @@ class NotesTable(object):
             valid_evals,
             mods_att,
             self.expr_diagnostics,
-        ) = sco_compute_moy.do_formsemestre_moyennes(self, formsemestre_id)
+        ) = sco_compute_moy.compute_modimpls_moyennes(self, formsemestre_id)
         self._mods_att = mods_att  # liste des modules avec des notes en attente
         self._matmoys = {}  # moyennes par matieres
         self._valid_evals = {}  # { evaluation_id : eval }
@@ -221,7 +221,7 @@ class NotesTable(object):
         uedict = {}  # public member: { ue_id : ue }
         self.uedict = uedict
         for modimpl in self._modimpls:
-            mod = modimpl["module"]  # has been added here by do_formsemestre_moyennes
+            mod = modimpl["module"]  # has been added here by compute_modimpls_moyennes
             if not mod["ue_id"] in uedict:
                 ue = sco_edit_ue.do_ue_list(args={"ue_id": mod["ue_id"]})[0]
                 uedict[ue["ue_id"]] = ue
diff --git a/app/scodoc/sco_abs.py b/app/scodoc/sco_abs.py
index 5eb7f7f4de1a09262a36bd8782fb077a6d1b4a8c..7d5e7976ea234733dfa2e8d62a3c4c3c495cb014 100644
--- a/app/scodoc/sco_abs.py
+++ b/app/scodoc/sco_abs.py
@@ -474,7 +474,7 @@ def _get_abs_description(a, cursor=None):
             desc = a["description"]
         if a["moduleimpl_id"] and a["moduleimpl_id"] != "NULL":
             # Trouver le nom du module
-            Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
+            Mlist = sco_moduleimpl.moduleimpl_withmodule_list(
                 moduleimpl_id=a["moduleimpl_id"]
             )
             if Mlist:
diff --git a/app/scodoc/sco_abs_views.py b/app/scodoc/sco_abs_views.py
index d4632bbc185afdd26a31d9b91cec099d73ec4d55..50984e04ebe13c103d08b83993af7c25b874424a 100644
--- a/app/scodoc/sco_abs_views.py
+++ b/app/scodoc/sco_abs_views.py
@@ -115,7 +115,7 @@ def doSignaleAbsence(
         J = "NON "
     M = ""
     if moduleimpl_id and moduleimpl_id != "NULL":
-        mod = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+        mod = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
         formsemestre_id = mod["formsemestre_id"]
         nt = sco_cache.NotesTableCache.get(formsemestre_id)
         ues = nt.get_ues(etudid=etudid)
@@ -939,7 +939,7 @@ def _tables_abs_etud(
             return ""
         ex = []
         for ev in a["evals"]:
-            mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
+            mod = sco_moduleimpl.moduleimpl_withmodule_list(
                 moduleimpl_id=ev["moduleimpl_id"]
             )[0]
             if format == "html":
@@ -957,7 +957,7 @@ def _tables_abs_etud(
     def descr_abs(a):
         ex = []
         for ev in a.get("absent", []):
-            mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
+            mod = sco_moduleimpl.moduleimpl_withmodule_list(
                 moduleimpl_id=ev["moduleimpl_id"]
             )[0]
             if format == "html":
diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py
index 043104ed4737302472d11938796a3c0931e2acdb..53a26d7781edb1426a4370f08d436984b8198c7e 100644
--- a/app/scodoc/sco_cache.py
+++ b/app/scodoc/sco_cache.py
@@ -292,7 +292,7 @@ def invalidate_formsemestre(  # was inval_cache(formsemestre_id=None, pdfonly=Fa
 
 
 class DefferedSemCacheManager:
-    """Experimental: pour effectuer des opérations indépendantes dans la
+    """Contexte pour effectuer des opérations indépendantes dans la
     même requete qui invalident le cache. Par exemple, quand on inscrit
     des étudiants un par un à un semestre, chaque inscription va invalider
     le cache, et la suivante va le reconstruire... pour l'invalider juste après.
diff --git a/app/scodoc/sco_compute_moy.py b/app/scodoc/sco_compute_moy.py
index 94d1f1f36d7797d6224d18e8bda0ff56736d1e82..86ce3bd1be42a2fc4fde7e1fa6118ecd51e97c86 100644
--- a/app/scodoc/sco_compute_moy.py
+++ b/app/scodoc/sco_compute_moy.py
@@ -79,7 +79,7 @@ def formsemestre_expressions_use_abscounts(formsemestre_id):
         if expr and expr[0] != "#" and ab in expr:
             return True
     # 2- moyennes de modules
-    for mod in sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id):
+    for mod in sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id):
         if moduleimpl_has_expression(mod) and ab in mod["computation_expr"]:
             return True
     return False
@@ -199,7 +199,7 @@ def do_moduleimpl_moyennes(nt, mod):
     moduleimpl_id = mod["moduleimpl_id"]
     is_malus = mod["module"]["module_type"] == scu.MODULE_MALUS
     sem = sco_formsemestre.get_formsemestre(mod["formsemestre_id"])
-    etudids = sco_moduleimpl.do_moduleimpl_listeetuds(
+    etudids = sco_moduleimpl.moduleimpl_listeetuds(
         moduleimpl_id
     )  # tous, y compris demissions
     # Inscrits au semestre (pour traiter les demissions):
@@ -365,7 +365,7 @@ def do_moduleimpl_moyennes(nt, mod):
     return R, valid_evals, attente, diag_info
 
 
-def do_formsemestre_moyennes(nt, formsemestre_id):
+def compute_modimpls_moyennes(nt, formsemestre_id):
     """retourne dict { moduleimpl_id : { etudid, note_moyenne_dans_ce_module } },
     la liste des moduleimpls, la liste des evaluations valides,
     liste des moduleimpls  avec notes en attente.
@@ -375,7 +375,7 @@ def do_formsemestre_moyennes(nt, formsemestre_id):
     #    args={"formsemestre_id": formsemestre_id}
     # )
     # etudids = [x["etudid"] for x in inscr]
-    modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+    modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
     # recupere les moyennes des etudiants de tous les modules
     D = {}
     valid_evals = []
diff --git a/app/scodoc/sco_cost_formation.py b/app/scodoc/sco_cost_formation.py
index 1c28ed4f187455f32862ade0b02e410b69721f11..d53d38619a36adaf0414ed8c42244bafa0ed375b 100644
--- a/app/scodoc/sco_cost_formation.py
+++ b/app/scodoc/sco_cost_formation.py
@@ -59,9 +59,7 @@ def formsemestre_table_estim_cost(
     """
     sem = sco_formsemestre.get_formsemestre(formsemestre_id)
     sco_formsemestre_status.fill_formsemestre(sem)
-    Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        formsemestre_id=formsemestre_id
-    )
+    Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     T = []
     for M in Mlist:
         Mod = M["module"]
diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py
index 6ec8bce3ee18f9d062f9d07fc0923f0ff2dffcc1..1aeb20df661fa51a5d490b16276c024763bacc59 100644
--- a/app/scodoc/sco_edit_module.py
+++ b/app/scodoc/sco_edit_module.py
@@ -257,7 +257,7 @@ def do_module_delete(oid):
         raise ScoLockedFormError()
 
     # S'il y a des moduleimpls, on ne peut pas detruire le module !
-    mods = sco_moduleimpl.do_moduleimpl_list(module_id=oid)
+    mods = sco_moduleimpl.moduleimpl_list(module_id=oid)
     if mods:
         err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
         <p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de 
@@ -580,7 +580,7 @@ def module_is_locked(module_id):
 
 def module_count_moduleimpls(module_id):
     "Number of moduleimpls using this module"
-    mods = sco_moduleimpl.do_moduleimpl_list(module_id=module_id)
+    mods = sco_moduleimpl.moduleimpl_list(module_id=module_id)
     return len(mods)
 
 
diff --git a/app/scodoc/sco_evaluations.py b/app/scodoc/sco_evaluations.py
index e2faf71b9488e9d0faaa2edeeff11bc3f39eb559..cf6be3f13a0128e650ff4c92677d2be3f7708b6c 100644
--- a/app/scodoc/sco_evaluations.py
+++ b/app/scodoc/sco_evaluations.py
@@ -179,7 +179,7 @@ def do_evaluation_list(args, sortkey=None):
 
 def do_evaluation_list_in_formsemestre(formsemestre_id):
     "list evaluations in this formsemestre"
-    mods = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+    mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
     evals = []
     for mod in mods:
         evals += do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
@@ -213,7 +213,7 @@ def _check_evaluation_args(args):
     jour = args.get("jour", None)
     args["jour"] = jour
     if jour:
-        M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+        M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
         sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
         d, m, y = [int(x) for x in sem["date_debut"].split("/")]
         date_debut = datetime.date(y, m, d)
@@ -301,7 +301,7 @@ def do_evaluation_create(
     r = _evaluationEditor.create(cnx, args)
 
     # news
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     mod["moduleimpl_id"] = M["moduleimpl_id"]
     mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
@@ -332,7 +332,7 @@ def do_evaluation_edit(args):
     cnx = ndb.GetDBConnexion()
     _evaluationEditor.edit(cnx, args)
     # inval cache pour ce semestre
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
 
 
@@ -357,7 +357,7 @@ def do_evaluation_delete(evaluation_id):
 
     _evaluationEditor.delete(cnx, evaluation_id)
     # inval cache pour ce semestre
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
     # news
     mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
@@ -373,9 +373,6 @@ def do_evaluation_delete(evaluation_id):
     )
 
 
-_DEE_TOT = 0
-
-
 def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=False):
     """donne infos sur l'etat du evaluation
     { nb_inscrits, nb_notes, nb_abs, nb_neutre, nb_att,
@@ -412,7 +409,7 @@ def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=
         last_modif = None
     # ---- Liste des groupes complets et incomplets
     E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     is_malus = Mod["module_type"] == scu.MODULE_MALUS  # True si module de malus
     formsemestre_id = M["formsemestre_id"]
@@ -735,7 +732,7 @@ def formsemestre_evaluations_cal(formsemestre_id):
         if not e["jour"]:
             continue
         day = e["jour"].strftime("%Y-%m-%d")
-        mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
+        mod = sco_moduleimpl.moduleimpl_withmodule_list(
             moduleimpl_id=e["moduleimpl_id"]
         )[0]
         txt = mod["module"]["code"] or mod["module"]["abbrev"] or "eval"
@@ -812,7 +809,7 @@ def evaluation_date_first_completion(evaluation_id):
     # (pour avoir l'etat et le groupe) et aussi les inscriptions
     # au module (pour gerer les modules optionnels correctement)
     # E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
-    # M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    # M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     # formsemestre_id = M["formsemestre_id"]
     # insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits( formsemestre_id)
     # insmod = sco_moduleimpl.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
@@ -854,7 +851,7 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
     evals = nt.get_sem_evaluation_etat_list()
     T = []
     for e in evals:
-        M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
+        M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
         Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
         if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
             Mod["module_type"] == scu.MODULE_MALUS
@@ -1035,7 +1032,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
 
     E = do_evaluation_list({"evaluation_id": evaluation_id})[0]
     moduleimpl_id = E["moduleimpl_id"]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     formsemestre_id = M["formsemestre_id"]
     u = sco_users.user_info(M["responsable_id"])
@@ -1115,7 +1112,7 @@ def evaluation_create_form(
         the_eval = do_evaluation_list({"evaluation_id": evaluation_id})[0]
         moduleimpl_id = the_eval["moduleimpl_id"]
     #
-    M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
     is_malus = M["module"]["module_type"] == scu.MODULE_MALUS  # True si module de malus
     formsemestre_id = M["formsemestre_id"]
     min_note_max = scu.NOTES_PRECISION  # le plus petit bareme possible
diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py
index fb6c6a54b11cd454698bf117f2da99feef6ce6bb..bcfdddb70e37ac755483252969654c607142220d 100644
--- a/app/scodoc/sco_formsemestre_edit.py
+++ b/app/scodoc/sco_formsemestre_edit.py
@@ -171,7 +171,7 @@ def do_formsemestre_createwithmodules(edit=False):
         initvalues = sem
         semestre_id = initvalues["semestre_id"]
         # add associated modules to tf-checked:
-        ams = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+        ams = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
         sem_module_ids = set([x["module_id"] for x in ams])
         initvalues["tf-checked"] = ["MI" + str(x["module_id"]) for x in ams]
         for x in ams:
@@ -751,7 +751,7 @@ def do_formsemestre_createwithmodules(edit=False):
             # (retire le "MI" du début du nom de champs)
             checkedmods = [int(x[2:]) for x in tf[2]["tf-checked"]]
             sco_formsemestre.do_formsemestre_edit(tf[2])
-            ams = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+            ams = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
             existingmods = [x["module_id"] for x in ams]
             mods_tocreate = [x for x in checkedmods if not x in existingmods]
             # modules a existants a modifier
@@ -801,7 +801,7 @@ def do_formsemestre_createwithmodules(edit=False):
             ok, diag = formsemestre_delete_moduleimpls(formsemestre_id, mods_todelete)
             msg += diag
             for module_id in mods_toedit:
-                moduleimpl_id = sco_moduleimpl.do_moduleimpl_list(
+                moduleimpl_id = sco_moduleimpl.moduleimpl_list(
                     formsemestre_id=formsemestre_id, module_id=module_id
                 )[0]["moduleimpl_id"]
                 modargs = {
@@ -846,7 +846,7 @@ def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
     msg = []
     for module_id in module_ids_to_del:
         # get id
-        moduleimpl_id = sco_moduleimpl.do_moduleimpl_list(
+        moduleimpl_id = sco_moduleimpl.moduleimpl_list(
             formsemestre_id=formsemestre_id, module_id=module_id
         )[0]["moduleimpl_id"]
         mod = sco_edit_module.do_module_list({"module_id": module_id})[0]
@@ -1015,7 +1015,7 @@ def do_formsemestre_clone(
     formsemestre_id = sco_formsemestre.do_formsemestre_create(args)
     log("created formsemestre %s" % formsemestre_id)
     # 2- create moduleimpls
-    mods_orig = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=orig_formsemestre_id)
+    mods_orig = sco_moduleimpl.moduleimpl_list(formsemestre_id=orig_formsemestre_id)
     for mod_orig in mods_orig:
         args = mod_orig.copy()
         args["formsemestre_id"] = formsemestre_id
@@ -1191,7 +1191,7 @@ def _reassociate_moduleimpls(cnx, formsemestre_id, ues_old2new, modules_old2new)
     et met à jour les décisions de jury (validations d'UE).
     """
     # re-associate moduleimpls to new modules:
-    modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+    modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
     for mod in modimpls:
         mod["module_id"] = modules_old2new[mod["module_id"]]
         sco_moduleimpl.do_moduleimpl_edit(mod, formsemestre_id=formsemestre_id)
@@ -1308,7 +1308,7 @@ def do_formsemestre_delete(formsemestre_id):
     sco_cache.EvaluationCache.invalidate_sem(formsemestre_id)
 
     # --- Destruction des modules de ce semestre
-    mods = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+    mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
     for mod in mods:
         # evaluations
         evals = sco_evaluations.do_evaluation_list(
diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py
index c6bd3fab0f4c2f4acfea7d38fb4bdd9b348134a6..bbfb81b953438f7cb6cce02c893dcc63bab59857 100644
--- a/app/scodoc/sco_formsemestre_inscriptions.py
+++ b/app/scodoc/sco_formsemestre_inscriptions.py
@@ -237,7 +237,7 @@ def do_formsemestre_inscription_with_modules(
             gdone[group_id] = 1
 
     # inscription a tous les modules de ce semestre
-    modimpls = sco_moduleimpl.do_moduleimpl_withmodule_list(
+    modimpls = sco_moduleimpl.moduleimpl_withmodule_list(
         formsemestre_id=formsemestre_id
     )
     for mod in modimpls:
@@ -448,7 +448,7 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
     ]
 
     # Cherche les moduleimpls et les inscriptions
-    mods = sco_moduleimpl.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
+    mods = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     inscr = sco_moduleimpl.do_moduleimpl_inscription_list(etudid=etudid)
     # Formulaire
     modimpls_by_ue_ids = scu.DictDefault(defaultvalue=[])  # ue_id : [ moduleimpl_id ]
@@ -680,7 +680,7 @@ def do_moduleimpl_incription_options(
     # inscriptions
     for moduleimpl_id in a_inscrire:
         # verifie que ce module existe bien
-        mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
+        mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
         if len(mods) != 1:
             raise ScoValueError(
                 "inscription: invalid moduleimpl_id: %s" % moduleimpl_id
@@ -693,7 +693,7 @@ def do_moduleimpl_incription_options(
     # desinscriptions
     for moduleimpl_id in a_desinscrire:
         # verifie que ce module existe bien
-        mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
+        mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
         if len(mods) != 1:
             raise ScoValueError(
                 "desinscription: invalid moduleimpl_id: %s" % moduleimpl_id
diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py
index 5aa948e43214aa8f410b7ab21f0fc5afa08fca85..d2b8609c49f1f186cf9c663a4b1f857c731da7e5 100644
--- a/app/scodoc/sco_formsemestre_status.py
+++ b/app/scodoc/sco_formsemestre_status.py
@@ -453,7 +453,7 @@ def retreive_formsemestre_from_request() -> int:
     if "formsemestre_id" in args:
         formsemestre_id = args["formsemestre_id"]
     elif "moduleimpl_id" in args and args["moduleimpl_id"]:
-        modimpl = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=args["moduleimpl_id"])
+        modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=args["moduleimpl_id"])
         if not modimpl:
             return None  # suppressed ?
         modimpl = modimpl[0]
@@ -463,7 +463,7 @@ def retreive_formsemestre_from_request() -> int:
         if not E:
             return None  # evaluation suppressed ?
         E = E[0]
-        modimpl = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+        modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
         formsemestre_id = modimpl["formsemestre_id"]
     elif "group_id" in args:
         group = sco_groups.get_group(args["group_id"])
@@ -593,9 +593,7 @@ def formsemestre_description_table(formsemestre_id, with_evals=False):
     use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
     F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
     parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
-    Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        formsemestre_id=formsemestre_id
-    )
+    Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
 
     R = []
     sum_coef = 0
@@ -885,7 +883,7 @@ def html_expr_diagnostic(diagnostics):
     last_id, last_msg = None, None
     for diag in diagnostics:
         if "moduleimpl_id" in diag:
-            mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
+            mod = sco_moduleimpl.moduleimpl_withmodule_list(
                 moduleimpl_id=diag["moduleimpl_id"]
             )[0]
             H.append(
@@ -982,9 +980,7 @@ def formsemestre_status(formsemestre_id=None):
     # porté du DTML
     cnx = ndb.GetDBConnexion()
     sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
-    Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        formsemestre_id=formsemestre_id
-    )
+    Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     # inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
     #    args={"formsemestre_id": formsemestre_id}
     # )
diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py
index dd1de1f33a760943b780638bb6bc520123ae0a22..668bbbebd9d6199a07fd6a426a5b4ad109293ddb 100644
--- a/app/scodoc/sco_groups.py
+++ b/app/scodoc/sco_groups.py
@@ -47,7 +47,7 @@ from flask import url_for, make_response
 
 import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
-from app import log
+from app import log, cache
 from app.scodoc.scolog import logdb
 from app.scodoc import html_sco_header
 from app.scodoc import sco_codes_parcours
@@ -438,6 +438,7 @@ def etud_add_group_infos(etud, sem, sep=" "):
     return etud
 
 
+@cache.memoize(timeout=50)  # seconds
 def get_etud_groups_in_partition(partition_id):
     """Returns { etudid : group }, with all students in this partition"""
     infos = ndb.SimpleDictFetch(
@@ -1391,6 +1392,7 @@ def do_evaluation_listeetuds_groups(
     Si include_dems, compte aussi les etudiants démissionnaires
     (sinon, par défaut, seulement les 'I')
     """
+    # nb: pour notes_table / do_evaluation_etat, getallstudents est vrai et include_dems faux
     fromtables = [
         "notes_moduleimpl_inscription Im",
         "notes_formsemestre_inscription Isem",
@@ -1402,7 +1404,7 @@ def do_evaluation_listeetuds_groups(
         if not groups:
             return []  # no groups, so no students
         rg = ["gm.group_id = '%(group_id)s'" % g for g in groups]
-        rq = """and Isem.etudid = gm.etudid 
+        rq = """and Isem.etudid = gm.etudid
         and gd.partition_id = p.id 
         and p.formsemestre_id = Isem.formsemestre_id
         """
@@ -1415,7 +1417,7 @@ def do_evaluation_listeetuds_groups(
     req = (
         "SELECT distinct Im.etudid FROM "
         + ", ".join(fromtables)
-        + """ WHERE Isem.etudid = Im.etudid 
+        + """ WHERE Isem.etudid = Im.etudid
         and Im.moduleimpl_id = M.id 
         and Isem.formsemestre_id = M.formsemestre_id 
         and E.moduleimpl_id = M.id 
@@ -1426,10 +1428,9 @@ def do_evaluation_listeetuds_groups(
         req += " and Isem.etat='I'"
     req += r
     cnx = ndb.GetDBConnexion()
-    cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
+    cursor = cnx.cursor()
     cursor.execute(req, {"evaluation_id": evaluation_id})
-    res = cursor.fetchall()
-    return [x[0] for x in res]
+    return [x[0] for x in cursor]
 
 
 def do_evaluation_listegroupes(evaluation_id, include_default=False):
@@ -1443,7 +1444,7 @@ def do_evaluation_listegroupes(evaluation_id, include_default=False):
     else:
         c = " AND p.partition_name is not NULL"
     cnx = ndb.GetDBConnexion()
-    cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
+    cursor = cnx.cursor()
     cursor.execute(
         """SELECT DISTINCT gd.id AS group_id
         FROM group_descr gd, group_membership gm, partition p, 
@@ -1457,8 +1458,7 @@ def do_evaluation_listegroupes(evaluation_id, include_default=False):
         + c,
         {"evaluation_id": evaluation_id},
     )
-    res = cursor.fetchall()
-    group_ids = [x[0] for x in res]
+    group_ids = [x[0] for x in cursor]
     return listgroups(group_ids)
 
 
diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py
index 914447299f0213ce85107ffdb80b05a62e0d978a..4fd4e7d6298597c2bea844eb9487f5cfecaa6a9a 100644
--- a/app/scodoc/sco_groups_view.py
+++ b/app/scodoc/sco_groups_view.py
@@ -304,7 +304,7 @@ class DisplayedGroupsInfos(object):
         else:
             group_ids = [int(g) for g in group_ids]
         if not formsemestre_id and moduleimpl_id:
-            mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
+            mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
             if len(mods) != 1:
                 raise ValueError("invalid moduleimpl_id")
             formsemestre_id = mods[0]["formsemestre_id"]
diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py
index a9ea6ce8461b913dd2c0c41166b11d4d46770dc8..04f94fff8e4013e199d87bef7ff8894a106270d1 100644
--- a/app/scodoc/sco_liste_notes.py
+++ b/app/scodoc/sco_liste_notes.py
@@ -228,7 +228,7 @@ def _make_table_notes(
         return "<p>Aucune évaluation !</p>"
     E = evals[0]
     moduleimpl_id = E["moduleimpl_id"]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
     # (debug) check that all evals are in same module:
@@ -872,9 +872,7 @@ def formsemestre_check_absences_html(formsemestre_id):
           </p>""",
     ]
     # Modules, dans l'ordre
-    Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        formsemestre_id=formsemestre_id
-    )
+    Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     for M in Mlist:
         evals = sco_evaluations.do_evaluation_list(
             {"moduleimpl_id": M["moduleimpl_id"]}
diff --git a/app/scodoc/sco_moduleimpl.py b/app/scodoc/sco_moduleimpl.py
index b1d0ea474a8a092357504d09f572e2a8a0dba43d..87a11bf7cb76b7b17168e9f2d078f44a7c6b505f 100644
--- a/app/scodoc/sco_moduleimpl.py
+++ b/app/scodoc/sco_moduleimpl.py
@@ -100,7 +100,7 @@ def do_moduleimpl_delete(oid, formsemestre_id=None):
     )  # > moduleimpl_delete
 
 
-def do_moduleimpl_list(moduleimpl_id=None, formsemestre_id=None, module_id=None):
+def moduleimpl_list(moduleimpl_id=None, formsemestre_id=None, module_id=None):
     "list moduleimpls"
     args = locals()
     cnx = ndb.GetDBConnexion()
@@ -122,10 +122,11 @@ def do_moduleimpl_edit(args, formsemestre_id=None, cnx=None):
     )  # > modif moduleimpl
 
 
-def do_moduleimpl_withmodule_list(
+def moduleimpl_withmodule_list(
     moduleimpl_id=None, formsemestre_id=None, module_id=None
 ):
-    """Liste les moduleimpls et ajoute dans chacun le module correspondant
+    """Liste les moduleimpls et ajoute dans chacun
+    l'UE, la matière et le module auxquels ils appartiennent.
     Tri la liste par semestre/UE/numero_matiere/numero_module.
 
     Attention: Cette fonction fait partie de l'API ScoDoc 7 et est publiée.
@@ -134,22 +135,33 @@ def do_moduleimpl_withmodule_list(
     from app.scodoc import sco_edit_matiere
     from app.scodoc import sco_edit_module
 
-    args = locals()
-    modimpls = do_moduleimpl_list(
+    modimpls = moduleimpl_list(
         **{
             "moduleimpl_id": moduleimpl_id,
             "formsemestre_id": formsemestre_id,
             "module_id": module_id,
         }
     )
-    for mo in modimpls:
-        mo["module"] = sco_edit_module.do_module_list(
-            args={"module_id": mo["module_id"]}
-        )[0]
-        mo["ue"] = sco_edit_ue.do_ue_list(args={"ue_id": mo["module"]["ue_id"]})[0]
-        mo["matiere"] = sco_edit_matiere.do_matiere_list(
-            args={"matiere_id": mo["module"]["matiere_id"]}
-        )[0]
+    ues = {}
+    matieres = {}
+    modules = {}
+    for mi in modimpls:
+        module_id = mi["module_id"]
+        if not mi["module_id"] in modules:
+            modules[module_id] = sco_edit_module.do_module_list(
+                args={"module_id": module_id}
+            )[0]
+        mi["module"] = modules[module_id]
+        ue_id = mi["module"]["ue_id"]
+        if not ue_id in ues:
+            ues[ue_id] = sco_edit_ue.do_ue_list(args={"ue_id": ue_id})[0]
+        mi["ue"] = ues[ue_id]
+        matiere_id = mi["module"]["matiere_id"]
+        if not matiere_id in matieres:
+            matieres[matiere_id] = sco_edit_matiere.do_matiere_list(
+                args={"matiere_id": matiere_id}
+            )[0]
+        mi["matiere"] = matieres[matiere_id]
 
     # tri par semestre/UE/numero_matiere/numero_module
     modimpls.sort(
@@ -173,7 +185,7 @@ def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None):
     return _moduleimpl_inscriptionEditor.list(cnx, args)
 
 
-def do_moduleimpl_listeetuds(moduleimpl_id):
+def moduleimpl_listeetuds(moduleimpl_id):
     "retourne liste des etudids inscrits a ce module"
     req = """SELECT DISTINCT Im.etudid 
     FROM notes_moduleimpl_inscription Im, 
@@ -306,7 +318,7 @@ def can_change_module_resp(moduleimpl_id):
     """Check if current user can modify module resp. (raise exception if not).
     = Admin, et dir des etud. (si option l'y autorise)
     """
-    M = do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
+    M = moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
     # -- check lock
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
     if not sem["etat"]:
@@ -322,7 +334,7 @@ def can_change_module_resp(moduleimpl_id):
 
 def can_change_ens(moduleimpl_id, raise_exc=True):
     "check if current user can modify ens list (raise exception if not)"
-    M = do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
+    M = moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
     # -- check lock
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
     if not sem["etat"]:
diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py
index 93d420d0e071e5822122fa545aa5c8c987438675..1517e626863260521cf8e94f724a0791bb50b000 100644
--- a/app/scodoc/sco_moduleimpl_inscriptions.py
+++ b/app/scodoc/sco_moduleimpl_inscriptions.py
@@ -63,7 +63,7 @@ def moduleimpl_inscriptions_edit(moduleimpl_id, etuds=[], submitted=False):
 
      * Si pas les droits: idem en readonly
     """
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     formsemestre_id = M["formsemestre_id"]
     mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     sem = sco_formsemestre.get_formsemestre(formsemestre_id)
@@ -263,9 +263,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
     can_change = authuser.has_permission(Permission.ScoEtudInscrit) and sem["etat"]
 
     # Liste des modules
-    Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        formsemestre_id=formsemestre_id
-    )
+    Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     # Decrit les inscriptions aux modules:
     commons = []  # modules communs a tous les etuds du semestre
     options = []  # modules ou seuls quelques etudiants sont inscrits
diff --git a/app/scodoc/sco_moduleimpl_status.py b/app/scodoc/sco_moduleimpl_status.py
index c358b25c046d82b39693fe23e83e150ee42f2004..a54a0e431e25b2b4ece4def27180be9d89b5799a 100644
--- a/app/scodoc/sco_moduleimpl_status.py
+++ b/app/scodoc/sco_moduleimpl_status.py
@@ -58,7 +58,7 @@ from app.scodoc import sco_users
 def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
     "Menu avec actions sur une evaluation"
     E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-    modimpl = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
 
     group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
 
@@ -156,7 +156,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
 
 def moduleimpl_status(moduleimpl_id=None, partition_id=None):
     """Tableau de bord module (liste des evaluations etc)"""
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     formsemestre_id = M["formsemestre_id"]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     sem = sco_formsemestre.get_formsemestre(formsemestre_id)
diff --git a/app/scodoc/sco_news.py b/app/scodoc/sco_news.py
index f2c19cf4cdd9942da8394a187dca688337674f50..e063a81dc79f7caafd7cdf4d00b4f607b23cf494 100644
--- a/app/scodoc/sco_news.py
+++ b/app/scodoc/sco_news.py
@@ -174,7 +174,7 @@ def _get_formsemestre_infos_from_news(n):
     elif n["type"] == NEWS_NOTE:
         moduleimpl_id = n["object"]
         if n["object"]:
-            mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
+            mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
             if not mods:
                 return {}  # module does not exists anymore
         return {}  # pas d'indication du module
diff --git a/app/scodoc/sco_permissions_check.py b/app/scodoc/sco_permissions_check.py
index 0bf77b3907ea8e0754f0e7bbbcd7cbcf4ff2d24f..5c166dbe3ad1462c1827a0e027afef57f1a38ad5 100644
--- a/app/scodoc/sco_permissions_check.py
+++ b/app/scodoc/sco_permissions_check.py
@@ -26,7 +26,7 @@ def can_edit_notes(authuser, moduleimpl_id, allow_ens=True):
     from app.scodoc import sco_formsemestre
     from app.scodoc import sco_parcours_dut
 
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
     if not sem["etat"]:
         return False  # semestre verrouillé
@@ -64,7 +64,7 @@ def can_edit_evaluation(moduleimpl_id=None):
     # acces pour resp. moduleimpl et resp. form semestre (dir etud)
     if moduleimpl_id is None:
         raise ValueError("no moduleimpl specified")  # bug
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
 
     if (
@@ -200,4 +200,4 @@ def can_handle_passwd(user, allow_admindepts=False):
     if (current_user.dept == user.dept) or allow_admindepts:
         return True
     else:
-        return False
\ No newline at end of file
+        return False
diff --git a/app/scodoc/sco_placement.py b/app/scodoc/sco_placement.py
index c2ef9d937dd3614bed49230abc35214102040c3e..e09df0e88b0b82b5e7c1ce09798743631414e439 100644
--- a/app/scodoc/sco_placement.py
+++ b/app/scodoc/sco_placement.py
@@ -244,7 +244,7 @@ class PlacementRunner:
         # gr_title = sco_groups.listgroups_abbrev(d['groups'])
         self.current_user = current_user
         self.moduleimpl_id = self.eval_data["moduleimpl_id"]
-        self.moduleimpl_data = sco_moduleimpl.do_moduleimpl_list(
+        self.moduleimpl_data = sco_moduleimpl.moduleimpl_list(
             moduleimpl_id=self.moduleimpl_id
         )[0]
         self.module_data = sco_edit_module.do_module_list(
diff --git a/app/scodoc/sco_saisie_notes.py b/app/scodoc/sco_saisie_notes.py
index 90dec730780d50dcbbf73d1a80d9865db6a56b6a..6c6638cd127682cfb48fcaa8bcdfdf1e1d392040 100644
--- a/app/scodoc/sco_saisie_notes.py
+++ b/app/scodoc/sco_saisie_notes.py
@@ -177,9 +177,7 @@ def do_evaluation_upload_xls():
     evaluation_id = int(vals["evaluation_id"])
     comment = vals["comment"]
     E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-    M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[
-        0
-    ]
+    M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
     # Check access
     # (admin, respformation, and responsable_id)
     if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
@@ -253,7 +251,7 @@ def do_evaluation_upload_xls():
             )
             # news
             E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-            M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+            M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
             mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
             mod["moduleimpl_id"] = M["moduleimpl_id"]
             mod["url"] = url_for(
@@ -292,9 +290,7 @@ def do_evaluation_upload_xls():
 def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
     """Initialisation des notes manquantes"""
     E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-    M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[
-        0
-    ]
+    M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
     # Check access
     # (admin, respformation, and responsable_id)
     if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
@@ -340,7 +336,7 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
     comment = "Initialisation notes manquantes"
     nb_changed, _, _ = _notes_add(current_user, evaluation_id, L, comment)
     # news
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     mod["moduleimpl_id"] = M["moduleimpl_id"]
     mod["url"] = url_for(
@@ -429,7 +425,7 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
         % E["moduleimpl_id"]
     ]
     # news
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     mod["moduleimpl_id"] = M["moduleimpl_id"]
     mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
@@ -476,7 +472,7 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
     nb_changed = 0
     nb_suppress = 0
     E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     existing_decisions = (
         []
     )  # etudids pour lesquels il y a une decision de jury et que la note change
@@ -598,7 +594,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=()):
     if not evals:
         raise ScoValueError("invalid evaluation_id")
     E = evals[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     formsemestre_id = M["formsemestre_id"]
     if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
         return (
@@ -769,7 +765,7 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]):
     if not evals:
         raise ScoValueError("invalid evaluation_id")
     E = evals[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     formsemestre_id = M["formsemestre_id"]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
@@ -868,9 +864,7 @@ def saisie_notes(evaluation_id, group_ids=[]):
     if not evals:
         raise ScoValueError("invalid evaluation_id")
     E = evals[0]
-    M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[
-        0
-    ]
+    M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
     formsemestre_id = M["formsemestre_id"]
     # Check access
     # (admin, respformation, and responsable_id)
@@ -1230,7 +1224,7 @@ def save_note(etudid=None, evaluation_id=None, value=None, comment=""):
         % (evaluation_id, etudid, authuser, value)
     )
     E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     Mod["url"] = url_for(
         "notes.moduleimpl_status",
diff --git a/app/scodoc/sco_undo_notes.py b/app/scodoc/sco_undo_notes.py
index add8757240f8b671795ba689427220713ec1d718..1f410c7048086085d1570591b4622dff85fa20bf 100644
--- a/app/scodoc/sco_undo_notes.py
+++ b/app/scodoc/sco_undo_notes.py
@@ -149,7 +149,7 @@ def list_operations(evaluation_id):
 def evaluation_list_operations(evaluation_id):
     """Page listing operations on evaluation"""
     E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
 
     Ops = list_operations(evaluation_id)
 
diff --git a/app/views/notes.py b/app/views/notes.py
index ad2d82f05e65d75c6ea0aa38c16c8822d6157df8..ece1029ee589da4352fb35b68d18a7c6fc41c251 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -1059,11 +1059,11 @@ def edit_moduleimpl_expr(moduleimpl_id):
 @scodoc7func
 def view_module_abs(moduleimpl_id, format="html"):
     """Visualisation des absences a un module"""
-    M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
+    M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
     sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
     debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
     fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
-    list_insc = sco_moduleimpl.do_moduleimpl_listeetuds(moduleimpl_id)
+    list_insc = sco_moduleimpl.moduleimpl_listeetuds(moduleimpl_id)
 
     T = []
     for etudid in list_insc:
@@ -1213,7 +1213,7 @@ def formsemestre_enseignants_list(formsemestre_id, format="html"):
     """
     sem = sco_formsemestre.get_formsemestre(formsemestre_id)
     # resp. de modules:
-    mods = sco_moduleimpl.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
+    mods = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     sem_ens = {}
     for mod in mods:
         if not mod["responsable_id"] in sem_ens:
@@ -1527,7 +1527,7 @@ def evaluation_delete(evaluation_id):
     if not El:
         raise ValueError("Evalution inexistante ! (%s)" % evaluation_id)
     E = El[0]
-    M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
+    M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
     Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
     tit = "Suppression de l'évaluation %(description)s (%(jour)s)" % E
     etat = sco_evaluations.do_evaluation_etat(evaluation_id)
@@ -2424,7 +2424,7 @@ def check_sem_integrity(formsemestre_id, fix=False):
     """
     sem = sco_formsemestre.get_formsemestre(formsemestre_id)
 
-    modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
+    modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
     bad_ue = []
     bad_sem = []
     formations_set = set()  # les formations mentionnées dans les UE et modules
@@ -2534,9 +2534,7 @@ def check_formsemestre_integrity(formsemestre_id):
     # de formations
     diag = []
 
-    Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        formsemestre_id=formsemestre_id
-    )
+    Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
     for mod in Mlist:
         if mod["module"]["ue_id"] != mod["matiere"]["ue_id"]:
             diag.append(
@@ -2593,14 +2591,14 @@ def check_integrity_all():
 # --------------------------------------------------------------------
 #     Support for legacy ScoDoc 7 API
 # --------------------------------------------------------------------
-@bp.route("/do_moduleimpl_list")
+@bp.route("/moduleimpl_list")
 @scodoc
 @permission_required(Permission.ScoView)
 @scodoc7func
-def do_moduleimpl_list(
+def moduleimpl_list(
     moduleimpl_id=None, formsemestre_id=None, module_id=None, format="json"
 ):
-    data = sco_moduleimpl.do_moduleimpl_list(
+    data = sco_moduleimpl.moduleimpl_list(
         moduleimpl_id=moduleimpl_id,
         formsemestre_id=formsemestre_id,
         module_id=module_id,
@@ -2608,15 +2606,16 @@ def do_moduleimpl_list(
     return scu.sendResult(data, format=format)
 
 
-@bp.route("/do_moduleimpl_withmodule_list")
+@bp.route("/do_moduleimpl_withmodule_list")  # ancien nom
+@bp.route("/moduleimpl_withmodule_list")
 @scodoc
 @permission_required(Permission.ScoView)
 @scodoc7func
-def do_moduleimpl_withmodule_list(
+def moduleimpl_withmodule_list(
     moduleimpl_id=None, formsemestre_id=None, module_id=None
 ):
     """API ScoDoc 7"""
-    data = sco_moduleimpl.do_moduleimpl_withmodule_list(
+    data = sco_moduleimpl.moduleimpl_withmodule_list(
         moduleimpl_id=moduleimpl_id,
         formsemestre_id=formsemestre_id,
         module_id=module_id,
diff --git a/bench.py b/bench.py
new file mode 100644
index 0000000000000000000000000000000000000000..79fe77d85e8cfcdb49c6cf62347a660c2858c287
--- /dev/null
+++ b/bench.py
@@ -0,0 +1,13 @@
+"""Script pour faciliter le lancement de benchmarks
+"""
+
+from tests.bench.notes_table import bench_notes_table
+
+BENCH_DEPT = "RT"
+BENCH_FORMSEMESTRE_IDS = (
+    149,  # RT S1 2020-21
+    145,  # RT S2 2021
+    119,  # RT S1 2029
+)
+
+bench_notes_table(BENCH_DEPT, BENCH_FORMSEMESTRE_IDS)
diff --git a/misc/example-api-1.py b/misc/example-api-1.py
index e79b329a338820a3dc5d788412946448be5b1f4c..37a06c56f991e26a991463943198da5cce489b3f 100644
--- a/misc/example-api-1.py
+++ b/misc/example-api-1.py
@@ -78,7 +78,7 @@ pp(sem)
 # semdescr = GET(s, f"Notes/formsemestre_description?formsemestre_id={sem['formsemestre_id']}&with_evals=0&format=json" )
 
 # ---- Liste les modules et prend le premier
-mods = GET(s, f"/Notes/do_moduleimpl_list?formsemestre_id={sem['formsemestre_id']}")
+mods = GET(s, f"/Notes/moduleimpl_list?formsemestre_id={sem['formsemestre_id']}")
 print(f"{len(mods)} modules dans le semestre {sem['titre']}")
 
 mod = mods[0]
diff --git a/tests/bench/notes_table.py b/tests/bench/notes_table.py
new file mode 100644
index 0000000000000000000000000000000000000000..0803be6eb001e8fa366bce846aca0cf5602c0cd9
--- /dev/null
+++ b/tests/bench/notes_table.py
@@ -0,0 +1,50 @@
+# Simple benchmark
+# mesure temps execution NotesTable
+
+import time
+
+from flask import g
+from flask_login import login_user
+
+from config import RunningConfig as BenchConfig
+import app
+from app import db, create_app
+from app import clear_scodoc_cache
+from app.auth.models import get_super_admin
+from app.scodoc import notesdb as ndb
+from app.scodoc import notes_table
+
+
+def setup_generator(dept: str):
+    # Setup
+    apptest = create_app(BenchConfig)
+    # Run tests:
+    with apptest.test_client() as client:
+        with apptest.app_context():
+            with apptest.test_request_context():
+                # Clear application cache:
+                print("clearing cache...")
+                clear_scodoc_cache()
+                # initialize scodoc "g":
+                g.stored_get_formsemestre = {}
+                # Loge l'utilisateur super-admin
+                admin_user = get_super_admin()
+                login_user(admin_user)
+                app.set_sco_dept(dept)  # set db connection
+                yield client
+                ndb.close_db_connection()
+                # Teardown:
+                db.session.commit()
+                db.session.remove()
+
+
+def bench_notes_table(dept: str, formsemestre_ids: list[int]) -> float:
+    for client in setup_generator(dept):
+        tot_time = 0.0
+        for formsemestre_id in formsemestre_ids:
+            print(f"building sem {formsemestre_id}...")
+            t0 = time.time()
+            nt = notes_table.NotesTable(formsemestre_id)
+            tot_time += time.time() - t0
+        print(f"Total time: {tot_time}")
+    return tot_time
diff --git a/tests/unit/sco_fake_gen.py b/tests/unit/sco_fake_gen.py
index 0ad1453b81ff05c4a4286033e688c863dc454a85..1daf142b9cc5aa04565fa1fef976588959fedeb4 100644
--- a/tests/unit/sco_fake_gen.py
+++ b/tests/unit/sco_fake_gen.py
@@ -251,7 +251,7 @@ class ScoFake(object):
         if not responsable_id:
             responsable_id = self.default_user.id
         oid = sco_moduleimpl.do_moduleimpl_create(locals())
-        oids = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=oid)  # API inconsistency
+        oids = sco_moduleimpl.moduleimpl_list(moduleimpl_id=oid)  # API inconsistency
         if not oids:
             raise ScoValueError("moduleimpl not created !")
         return oids[0]
diff --git a/tests/unit/test_formations.py b/tests/unit/test_formations.py
index 8859b3ca8485271edeeb0e2e984548ae9390fbd9..36cb6736749ade3aed866d508de8500eb91ff1cb 100644
--- a/tests/unit/test_formations.py
+++ b/tests/unit/test_formations.py
@@ -30,7 +30,7 @@
 # - formation_list
 # - formation_export
 # - formsemestre_list
-# - do_moduleimpl_list
+# - moduleimpl_list
 # - do_module_impl_with_module_list
 # - do_formsemestre_delete
 # - do_module_list
@@ -231,28 +231,24 @@ def test_formations(test_client):
 
     # --- Liste des modules
 
-    lim_sem1 = sco_moduleimpl.do_moduleimpl_list(
-        formsemestre_id=sem1["formsemestre_id"]
-    )
+    lim_sem1 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem1["formsemestre_id"])
 
     assert len(lim_sem1) == 2
     assert mod["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
     assert mod2["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
 
-    lim_modid = sco_moduleimpl.do_moduleimpl_list(module_id=mod["module_id"])
+    lim_modid = sco_moduleimpl.moduleimpl_list(module_id=mod["module_id"])
 
     assert len(lim_modid) == 1
 
-    lim_modimpl_id = sco_moduleimpl.do_moduleimpl_list(
-        moduleimpl_id=mi["moduleimpl_id"]
-    )
+    lim_modimpl_id = sco_moduleimpl.moduleimpl_list(moduleimpl_id=mi["moduleimpl_id"])
     # print(lim_modimpl_id)
 
-    # ---- Test de do_moduleimpl_withmodule_list
+    # ---- Test de moduleimpl_withmodule_list
 
     assert lim_modid == lim_modimpl_id  # doit etre le meme resultat
 
-    liimp_sem1 = sco_moduleimpl.do_moduleimpl_withmodule_list(
+    liimp_sem1 = sco_moduleimpl.moduleimpl_withmodule_list(
         formsemestre_id=sem1["formsemestre_id"]
     )
 
@@ -262,16 +258,14 @@ def test_formations(test_client):
         liimp_sem1[0]["module_id"],
         liimp_sem1[1]["module_id"],
     )
-    liimp_sem2 = sco_moduleimpl.do_moduleimpl_withmodule_list(
+    liimp_sem2 = sco_moduleimpl.moduleimpl_withmodule_list(
         formsemestre_id=sem2["formsemestre_id"]
     )
     assert modt["module_id"] == liimp_sem2[0]["module_id"]
-    liimp_modid = sco_moduleimpl.do_moduleimpl_withmodule_list(
-        module_id=mod["module_id"]
-    )
+    liimp_modid = sco_moduleimpl.moduleimpl_withmodule_list(module_id=mod["module_id"])
     assert len(liimp_modid) == 1
 
-    liimp_modimplid = sco_moduleimpl.do_moduleimpl_withmodule_list(
+    liimp_modimplid = sco_moduleimpl.moduleimpl_withmodule_list(
         moduleimpl_id=mi["moduleimpl_id"]
     )
 
@@ -305,9 +299,7 @@ def test_formations(test_client):
 
     assert len(li_module2) == 3  # verification de la suppression du module
 
-    lim_sem2 = sco_moduleimpl.do_moduleimpl_list(
-        formsemestre_id=sem2["formsemestre_id"]
-    )
+    lim_sem2 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem2["formsemestre_id"])
 
     assert len(lim_sem2) == 0  # deuxieme vérification si le module s'est bien sup