diff --git a/app/comp/res_common.py b/app/comp/res_common.py
index c4bc908ff43a9bc1083bb4fa6f9623789eadfa75..954f35235470fdae951e4f928d0f67457c006bb2 100644
--- a/app/comp/res_common.py
+++ b/app/comp/res_common.py
@@ -209,7 +209,7 @@ class ResultatsSemestre(ResultatsCache):
                 "last_modif" : datetime.datetime | None, # saisie de note la plus récente
                 "nb_notes" : int, # nb notes d'étudiants inscrits
             },
-            "evaluatiuon_id" : int,
+            "evaluation_id" : int,
             "jour" : datetime.datetime, # e.date_debut or datetime.datetime(1900, 1, 1)
             "publish_incomplete" : bool,
         }
@@ -435,6 +435,21 @@ class ResultatsSemestre(ResultatsCache):
     def get_etud_ue_status(self, etudid: int, ue_id: int) -> dict:
         """L'état de l'UE pour cet étudiant.
         Result: dict, ou None si l'UE n'est pas dans ce semestre.
+        {
+            "is_capitalized": # vrai si la version capitalisée est celle prise en compte (meilleure)
+            "was_capitalized":# si elle a été capitalisée (meilleure ou pas)
+            "is_external": # si UE externe
+            "coef_ue": 0.0,
+            "cur_moy_ue": 0.0, # moyenne de l'UE courante
+            "moy": 0.0, # moyenne prise en compte
+            "event_date": # date de la capiltalisation éventuelle (ou None)
+            "ue": ue_dict, # l'UE, comme un dict
+            "formsemestre_id": None,
+            "capitalized_ue_id": None, # l'id de l'UE capitalisée, ou None
+            "ects_pot": 0.0, # deprecated (les ECTS liés à cette UE)
+            "ects": 0.0, # les ECTS acquis grace à cette UE
+            "ects_ue": # les ECTS liés à cette UE
+        }
         """
         ue: UniteEns = db.session.get(UniteEns, ue_id)
         ue_dict = ue.to_dict()
@@ -512,11 +527,13 @@ class ResultatsSemestre(ResultatsCache):
             "is_external": ue_cap["is_external"] if is_capitalized else ue.is_external,
             "coef_ue": coef_ue,
             "ects_pot": ue.ects or 0.0,
-            "ects": self.validations.decisions_jury_ues.get(etudid, {})
-            .get(ue.id, {})
-            .get("ects", 0.0)
-            if self.validations.decisions_jury_ues
-            else 0.0,
+            "ects": (
+                self.validations.decisions_jury_ues.get(etudid, {})
+                .get(ue.id, {})
+                .get("ects", 0.0)
+                if self.validations.decisions_jury_ues
+                else 0.0
+            ),
             "ects_ue": ue.ects,
             "cur_moy_ue": cur_moy_ue,
             "moy": moy_ue,
diff --git a/app/models/etudiants.py b/app/models/etudiants.py
index bd70e03c180a181c0178e62075630fd1d79e276f..ef470f3e6adc8e47a6c990145139062715008282 100644
--- a/app/models/etudiants.py
+++ b/app/models/etudiants.py
@@ -125,7 +125,7 @@ class Identite(models.ScoDocModel):
     )
 
     # Champs "protégés" par ViewEtudData (RGPD)
-    protected_attrs = {"boursier"}
+    protected_attrs = {"boursier", "nationalite"}
 
     def __repr__(self):
         return (
diff --git a/app/scodoc/sco_evaluations.py b/app/scodoc/sco_evaluations.py
index 20ae235675b5a3391ef99aa5a4e31318e020632e..610cb255a9e97f0c39810a690d8a5a1a0d416b27 100644
--- a/app/scodoc/sco_evaluations.py
+++ b/app/scodoc/sco_evaluations.py
@@ -44,7 +44,6 @@ from app.models import Evaluation, FormSemestre, ModuleImpl
 
 import app.scodoc.sco_utils as scu
 from app.scodoc.sco_utils import ModuleType
-import app.scodoc.notesdb as ndb
 from app.scodoc.gen_tables import GenTable
 from app.scodoc import html_sco_header
 from app.scodoc import sco_cal
@@ -114,9 +113,9 @@ def do_evaluation_etat(
         nb_neutre,
         nb_att,
         moy, median, mini, maxi : # notes, en chaine, sur 20
-        last_modif: datetime,
+        last_modif: datetime, *
         gr_complets, gr_incomplets,
-        evalcomplete
+        evalcomplete *
     }
     evalcomplete est vrai si l'eval est complete (tous les inscrits
     à ce module ont des notes)
@@ -519,9 +518,9 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, fmt="html"):
             {
                 "date_first_complete": date_first_complete,
                 "delai_correction": delai_correction,
-                "jour": e.date_debut.strftime("%d/%m/%Y")
-                if e.date_debut
-                else "sans date",
+                "jour": (
+                    e.date_debut.strftime("%d/%m/%Y") if e.date_debut else "sans date"
+                ),
                 "_jour_target": url_for(
                     "notes.evaluation_listenotes",
                     scodoc_dept=g.scodoc_dept,
diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py
index a404c7fa3df037c525802e9e94af18ef607e557f..0d1d1dfb7ccbaa463247ad250f1d9f42bdb9746e 100644
--- a/app/scodoc/sco_groups_view.py
+++ b/app/scodoc/sco_groups_view.py
@@ -514,10 +514,11 @@ def groups_table(
         "paiementinscription_str": "Paiement",
         "etudarchive": "Fichiers",
         "annotations_str": "Annotations",
-        "bourse_str": "Boursier",
+        "bourse_str": "Boursier",  # requière ViewEtudData
         "etape": "Etape",
         "semestre_groupe": "Semestre-Groupe",  # pour Moodle
         "annee": "annee_admission",
+        "nationalite": "nationalite",  # requière ViewEtudData
     }
 
     # ajoute colonnes pour groupes
@@ -559,53 +560,61 @@ def groups_table(
     moodle_sem_name = groups_infos.formsemestre["session_id"]
     moodle_groupenames = set()
     # ajoute liens
-    for etud in groups_infos.members:
-        if etud["email"]:
-            etud["_email_target"] = "mailto:" + etud["email"]
+    for etud_info in groups_infos.members:
+        if etud_info["email"]:
+            etud_info["_email_target"] = "mailto:" + etud_info["email"]
         else:
-            etud["_email_target"] = ""
-        if etud["emailperso"]:
-            etud["_emailperso_target"] = "mailto:" + etud["emailperso"]
+            etud_info["_email_target"] = ""
+        if etud_info["emailperso"]:
+            etud_info["_emailperso_target"] = "mailto:" + etud_info["emailperso"]
         else:
-            etud["_emailperso_target"] = ""
+            etud_info["_emailperso_target"] = ""
         fiche_url = url_for(
-            "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"]
+            "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud_info["etudid"]
         )
-        etud["_nom_disp_target"] = fiche_url
-        etud["_nom_disp_order"] = etud_sort_key(etud)
-        etud["_prenom_target"] = fiche_url
-
-        etud["_nom_disp_td_attrs"] = 'id="%s" class="etudinfo"' % (etud["etudid"])
-        etud["bourse_str"] = "oui" if etud["boursier"] else "non"
-        if etud["etat"] == "D":
-            etud["_css_row_class"] = "etuddem"
+        etud_info["_nom_disp_target"] = fiche_url
+        etud_info["_nom_disp_order"] = etud_sort_key(etud_info)
+        etud_info["_prenom_target"] = fiche_url
+
+        etud_info["_nom_disp_td_attrs"] = 'id="%s" class="etudinfo"' % (
+            etud_info["etudid"]
+        )
+        etud_info["bourse_str"] = "oui" if etud_info["boursier"] else "non"
+        if etud_info["etat"] == "D":
+            etud_info["_css_row_class"] = "etuddem"
         # et groupes:
-        for partition_id in etud["partitions"]:
-            etud[partition_id] = etud["partitions"][partition_id]["group_name"]
+        for partition_id in etud_info["partitions"]:
+            etud_info[partition_id] = etud_info["partitions"][partition_id][
+                "group_name"
+            ]
         # Ajoute colonne pour moodle: semestre_groupe, de la forme
         #     RT-DUT-FI-S3-2021-PARTITION-GROUPE
         moodle_groupename = []
         if groups_infos.selected_partitions:
             # il y a des groupes selectionnes, utilise leurs partitions
             for partition_id in groups_infos.selected_partitions:
-                if partition_id in etud["partitions"]:
+                if partition_id in etud_info["partitions"]:
                     moodle_groupename.append(
                         partitions_name[partition_id]
                         + "-"
-                        + etud["partitions"][partition_id]["group_name"]
+                        + etud_info["partitions"][partition_id]["group_name"]
                     )
         else:
             # pas de groupes sélectionnés: prend le premier s'il y en a un
             moodle_groupename = ["tous"]
-            if etud["partitions"]:
-                for p in etud["partitions"].items():  # partitions is an OrderedDict
+            if etud_info["partitions"]:
+                for p in etud_info[
+                    "partitions"
+                ].items():  # partitions is an OrderedDict
                     moodle_groupename = [
                         partitions_name[p[0]] + "-" + p[1]["group_name"]
                     ]
                     break
 
         moodle_groupenames |= set(moodle_groupename)
-        etud["semestre_groupe"] = moodle_sem_name + "-" + "+".join(moodle_groupename)
+        etud_info["semestre_groupe"] = (
+            moodle_sem_name + "-" + "+".join(moodle_groupename)
+        )
 
     if groups_infos.nbdem > 1:
         s = "s"
@@ -714,9 +723,11 @@ def groups_table(
                     });
                     </script>
                     """,
-                    """<span class="warning_unauthorized">accès aux données personnelles interdit</span>"""
-                    if not can_view_etud_data
-                    else "",
+                    (
+                        """<span class="warning_unauthorized">accès aux données personnelles interdit</span>"""
+                        if not can_view_etud_data
+                        else ""
+                    ),
                 ]
             )
         H.append("</div></form>")
@@ -768,13 +779,7 @@ def groups_table(
 
         return "".join(H)
 
-    elif (
-        fmt == "pdf"
-        or fmt == "xml"
-        or fmt == "json"
-        or fmt == "xls"
-        or fmt == "moodlecsv"
-    ):
+    elif fmt in {"pdf", "xml", "json", "xls", "moodlecsv"}:
         if fmt == "moodlecsv":
             fmt = "csv"
         return tab.make_page(fmt=fmt)
@@ -789,7 +794,7 @@ def groups_table(
             with_paiement=with_paiement,
             server_name=request.url_root,
         )
-        filename = "liste_%s" % groups_infos.groups_filename
+        filename = f"liste_{groups_infos.groups_filename}"
         return scu.send_file(xls, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
     elif fmt == "allxls":
         if not can_view_etud_data:
@@ -823,6 +828,7 @@ def groups_table(
             "fax",
             "date_naissance",
             "lieu_naissance",
+            "nationalite",
             "bac",
             "specialite",
             "annee_bac",
@@ -845,16 +851,16 @@ def groups_table(
         # remplis infos lycee si on a que le code lycée
         # et ajoute infos inscription
         for m in groups_infos.members:
-            etud = sco_etud.get_etud_info(m["etudid"], filled=True)[0]
-            m.update(etud)
-            sco_etud.etud_add_lycee_infos(etud)
+            etud_info = sco_etud.get_etud_info(m["etudid"], filled=True)[0]
+            m.update(etud_info)
+            sco_etud.etud_add_lycee_infos(etud_info)
             # et ajoute le parcours
             Se = sco_cursus.get_situation_etud_cursus(
-                etud, groups_infos.formsemestre_id
+                etud_info, groups_infos.formsemestre_id
             )
             m["parcours"] = Se.get_cursus_descr()
             m["code_cursus"], _ = sco_report.get_code_cursus_etud(
-                etud["etudid"], sems=etud["sems"]
+                etud_info["etudid"], sems=etud_info["sems"]
             )
         rows = [[m.get(k, "") for k in keys] for m in groups_infos.members]
         title = "etudiants_%s" % groups_infos.groups_filename
@@ -905,9 +911,11 @@ def tab_absences_html(groups_infos, etat=None):
             % groups_infos.groups_query_args,
             """<li><a class="stdlink" href="trombino?%s&fmt=pdflist">Liste d'appel avec photos</a></li>"""
             % groups_infos.groups_query_args,
-            f"""<li><a class="stdlink" href="groups_export_annotations?{groups_infos.groups_query_args}">Liste des annotations</a></li>"""
-            if authuser.has_permission(Permission.ViewEtudData)
-            else """<li class="unauthorized" title="non autorisé">Liste des annotations</li>""",
+            (
+                f"""<li><a class="stdlink" href="groups_export_annotations?{groups_infos.groups_query_args}">Liste des annotations</a></li>"""
+                if authuser.has_permission(Permission.ViewEtudData)
+                else """<li class="unauthorized" title="non autorisé">Liste des annotations</li>"""
+            ),
             "</ul>",
         ]
     )
diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py
index c4b683ebc5a432de62836036e5f0617356fb77e9..20467db7db4070b9942dc7511fa59a97736ee7da 100644
--- a/app/scodoc/sco_moduleimpl_inscriptions.py
+++ b/app/scodoc/sco_moduleimpl_inscriptions.py
@@ -617,7 +617,7 @@ def _list_but_ue_inscriptions(res: NotesTableCompat, read_only: bool = True) ->
     <p>L'inscription ou désinscription aux UEs du BUT n'affecte pas les inscriptions aux modules
     mais permet de "dispenser" un étudiant de suivre certaines UEs de son parcours.
     </p>
-    <p>Il peut s'agit d'étudiants redoublants ayant déjà acquis l'UE, ou d'une UE
+    <p>Il peut s'agir d'étudiants redoublants ayant déjà acquis l'UE, ou d'une UE
     présente dans le semestre mais pas dans le parcours de l'étudiant, ou bien d'autres
     cas particuliers.
     </p>