From 9987a26d9e3a77be04c5e7853a49a8b07cda3c0c Mon Sep 17 00:00:00 2001
From: Emmanuel Viennet <emmanuel.viennet@gmail.com>
Date: Sun, 31 Dec 2023 23:04:06 +0100
Subject: [PATCH] Version 9.6.73 + copyright 2024

---
 app/api/assiduites.py                        |   2 +-
 app/api/billets_absences.py                  |   2 +-
 app/api/departements.py                      |   2 +-
 app/api/etudiants.py                         |   2 +-
 app/api/evaluations.py                       |   2 +-
 app/api/formations.py                        |   2 +-
 app/api/formsemestres.py                     |   2 +-
 app/api/jury.py                              |   2 +-
 app/api/logos.py                             |   2 +-
 app/api/moduleimpl.py                        |   2 +-
 app/api/partitions.py                        |   2 +-
 app/api/semset.py                            |   2 +-
 app/api/tools.py                             |   2 +-
 app/api/users.py                             |   2 +-
 app/but/apc_edit_ue.py                       |   8 +-
 app/but/bulletin_but.py                      |   2 +-
 app/but/bulletin_but_court.py                |   2 +-
 app/but/bulletin_but_court_pdf.py            |   2 +-
 app/but/bulletin_but_pdf.py                  |   4 +-
 app/but/bulletin_but_xml_compat.py           |   2 +-
 app/but/cursus_but.py                        |   2 +-
 app/but/forms/jury_but_forms.py              |   2 +-
 app/but/forms/refcomp_forms.py               |   2 +-
 app/but/import_refcomp.py                    |   4 +-
 app/but/jury_but.py                          |  26 ++---
 app/but/jury_but_pv.py                       |   4 +-
 app/but/jury_but_results.py                  |   2 +-
 app/but/jury_but_validation_auto.py          |   2 +-
 app/but/jury_but_view.py                     |  16 +--
 app/but/jury_edit_manual.py                  |   2 +-
 app/but/rcue.py                              |   2 +-
 app/but/validations_view.py                  |   2 +-
 app/comp/aux_stats.py                        |   6 +-
 app/comp/bonus_spo.py                        |   2 +-
 app/comp/df_cache.py                         |   2 +-
 app/comp/jury.py                             |  12 +--
 app/comp/moy_mat.py                          |   2 +-
 app/comp/moy_mod.py                          |   2 +-
 app/comp/moy_sem.py                          |   4 +-
 app/comp/moy_ue.py                           |   2 +-
 app/comp/res_but.py                          |   2 +-
 app/comp/res_cache.py                        |   2 +-
 app/comp/res_classic.py                      |   2 +-
 app/comp/res_common.py                       |   2 +-
 app/comp/res_compat.py                       |   2 +-
 app/comp/res_sem.py                          |   2 +-
 app/email.py                                 |   2 +-
 app/entreprises/app_relations_entreprises.py |   2 +-
 app/entreprises/forms.py                     |   2 +-
 app/forms/assiduite/ajout_assiduite_etud.py  |   2 +-
 app/forms/formsemestre/change_formation.py   |   3 +-
 app/forms/main/config_apo.py                 |   2 +-
 app/forms/main/config_assiduites.py          |   2 +-
 app/forms/main/config_cas.py                 |   2 +-
 app/forms/main/config_logos.py               |   2 +-
 app/forms/main/config_main.py                |   2 +-
 app/forms/main/create_dept.py                |   2 +-
 app/forms/main/role_create.py                |   2 +-
 app/models/but_refcomp.py                    |   2 +-
 app/models/formsemestre.py                   |   2 +-
 app/models/groups.py                         |   2 +-
 app/pe/pe_avislatex.py                       |   8 +-
 app/pe/pe_jurype.py                          |  29 ++---
 app/pe/pe_semestretag.py                     |   2 +-
 app/pe/pe_settag.py                          |   2 +-
 app/pe/pe_tagtable.py                        |   2 +-
 app/pe/pe_tools.py                           |   3 +-
 app/pe/pe_view.py                            |   2 +-
 app/scodoc/__init__.py                       |   2 +-
 app/scodoc/codes_cursus.py                   |   2 +-
 app/scodoc/gen_tables.py                     |   2 +-
 app/scodoc/html_sco_header.py                |   2 +-
 app/scodoc/html_sidebar.py                   |   2 +-
 app/scodoc/htmlutils.py                      |   2 +-
 app/scodoc/notes_users.py                    |   2 +-
 app/scodoc/safehtml.py                       |   3 +-
 app/scodoc/sco_abs.py                        |  16 +--
 app/scodoc/sco_abs_billets.py                |   2 +-
 app/scodoc/sco_abs_notification.py           |   2 +-
 app/scodoc/sco_apogee_compare.py             |  14 +--
 app/scodoc/sco_apogee_csv.py                 |   8 +-
 app/scodoc/sco_apogee_reader.py              |   6 +-
 app/scodoc/sco_archives.py                   |   2 +-
 app/scodoc/sco_archives_etud.py              |  10 +-
 app/scodoc/sco_archives_formsemestre.py      |   2 +-
 app/scodoc/sco_bac.py                        |   2 +-
 app/scodoc/sco_bulletins.py                  |   2 +-
 app/scodoc/sco_bulletins_example.py          |   2 +-
 app/scodoc/sco_bulletins_generator.py        |   2 +-
 app/scodoc/sco_bulletins_json.py             |   2 +-
 app/scodoc/sco_bulletins_legacy.py           |   2 +-
 app/scodoc/sco_bulletins_pdf.py              |   2 +-
 app/scodoc/sco_bulletins_signature.py        |   6 +-
 app/scodoc/sco_bulletins_standard.py         |   2 +-
 app/scodoc/sco_bulletins_ucac.py             |   4 +-
 app/scodoc/sco_bulletins_xml.py              |   2 +-
 app/scodoc/sco_cache.py                      |   2 +-
 app/scodoc/sco_cal.py                        |   2 +-
 app/scodoc/sco_compute_moy.py                |   2 +-
 app/scodoc/sco_config_actions.py             |   2 +-
 app/scodoc/sco_cost_formation.py             |   2 +-
 app/scodoc/sco_cursus.py                     |   3 +-
 app/scodoc/sco_cursus_dut.py                 |   2 +-
 app/scodoc/sco_debouche.py                   |   4 +-
 app/scodoc/sco_dept.py                       |   2 +-
 app/scodoc/sco_dump_db.py                    |   2 +-
 app/scodoc/sco_edit_apc.py                   |   2 +-
 app/scodoc/sco_edit_formation.py             |   2 +-
 app/scodoc/sco_edit_matiere.py               |   6 +-
 app/scodoc/sco_edit_module.py                |   2 +-
 app/scodoc/sco_edit_ue.py                    |   2 +-
 app/scodoc/sco_edt_cal.py                    |   2 +-
 app/scodoc/sco_etape_apogee.py               |  22 ++--
 app/scodoc/sco_etape_apogee_view.py          |  24 ++---
 app/scodoc/sco_etape_bilan.py                | 108 +++++++++----------
 app/scodoc/sco_etud.py                       |   2 +-
 app/scodoc/sco_evaluation_check_abs.py       |   2 +-
 app/scodoc/sco_evaluation_db.py              |   2 +-
 app/scodoc/sco_evaluation_edit.py            |   2 +-
 app/scodoc/sco_evaluation_recap.py           |   2 +-
 app/scodoc/sco_evaluations.py                |   2 +-
 app/scodoc/sco_excel.py                      |   2 +-
 app/scodoc/sco_exceptions.py                 |   2 +-
 app/scodoc/sco_export_results.py             |   6 +-
 app/scodoc/sco_find_etud.py                  |   2 +-
 app/scodoc/sco_formation_recap.py            |   2 +-
 app/scodoc/sco_formation_versions.py         |   8 +-
 app/scodoc/sco_formations.py                 |   2 +-
 app/scodoc/sco_formsemestre.py               |   2 +-
 app/scodoc/sco_formsemestre_custommenu.py    |   2 +-
 app/scodoc/sco_formsemestre_edit.py          |   2 +-
 app/scodoc/sco_formsemestre_exterieurs.py    |  12 +--
 app/scodoc/sco_formsemestre_inscriptions.py  |   2 +-
 app/scodoc/sco_formsemestre_status.py        |   2 +-
 app/scodoc/sco_formsemestre_validation.py    |   2 +-
 app/scodoc/sco_formulas.py                   |   2 +-
 app/scodoc/sco_groups.py                     |   2 +-
 app/scodoc/sco_groups_edit.py                |   2 +-
 app/scodoc/sco_groups_exports.py             |   2 +-
 app/scodoc/sco_groups_view.py                |   2 +-
 app/scodoc/sco_import_etuds.py               |   2 +-
 app/scodoc/sco_import_users.py               |   2 +-
 app/scodoc/sco_inscr_passage.py              |   4 +-
 app/scodoc/sco_liste_notes.py                |   2 +-
 app/scodoc/sco_logos.py                      |   2 +-
 app/scodoc/sco_lycee.py                      |   6 +-
 app/scodoc/sco_modalites.py                  |   4 +-
 app/scodoc/sco_moduleimpl.py                 |  14 +--
 app/scodoc/sco_moduleimpl_inscriptions.py    |   8 +-
 app/scodoc/sco_moduleimpl_status.py          |   2 +-
 app/scodoc/sco_page_etud.py                  |   2 +-
 app/scodoc/sco_pdf.py                        |   2 +-
 app/scodoc/sco_photos.py                     |   6 +-
 app/scodoc/sco_placement.py                  |   2 +-
 app/scodoc/sco_portal_apogee.py              |   2 +-
 app/scodoc/sco_poursuite_dut.py              |   2 +-
 app/scodoc/sco_preferences.py                |   2 +-
 app/scodoc/sco_prepajury.py                  |   2 +-
 app/scodoc/sco_pv_dict.py                    |   2 +-
 app/scodoc/sco_pv_forms.py                   |   2 +-
 app/scodoc/sco_pv_lettres_inviduelles.py     |   2 +-
 app/scodoc/sco_pv_pdf.py                     |   2 +-
 app/scodoc/sco_pv_templates.py               |   2 +-
 app/scodoc/sco_recapcomplet.py               |   2 +-
 app/scodoc/sco_report.py                     |   4 +-
 app/scodoc/sco_report_but.py                 |   2 +-
 app/scodoc/sco_saisie_notes.py               |   2 +-
 app/scodoc/sco_semset.py                     |   6 +-
 app/scodoc/sco_synchro_etuds.py              |   2 +-
 app/scodoc/sco_tag_module.py                 |   8 +-
 app/scodoc/sco_trombino.py                   |   2 +-
 app/scodoc/sco_trombino_doc.py               |   2 +-
 app/scodoc/sco_trombino_tours.py             |   2 +-
 app/scodoc/sco_ue_external.py                |   8 +-
 app/scodoc/sco_undo_notes.py                 |  10 +-
 app/scodoc/sco_up_to_date.py                 |   6 +-
 app/scodoc/sco_users.py                      |   2 +-
 app/scodoc/sco_utils.py                      |   2 +-
 app/scodoc/sco_vdi.py                        |   2 +-
 app/scodoc/sco_xml.py                        |   4 +-
 app/scodoc/scolog.py                         |   2 +-
 app/tables/__init__.py                       |   2 +-
 app/tables/jury_recap.py                     |   2 +-
 app/tables/list_etuds.py                     |   2 +-
 app/tables/recap.py                          |   4 +-
 app/tables/table_builder.py                  |   2 +-
 app/tables/visu_assiduites.py                |   2 +-
 app/views/absences.py                        |   6 +-
 app/views/assiduites.py                      |   2 +-
 app/views/but_formation.py                   |   2 +-
 app/views/notes.py                           |   2 +-
 app/views/notes_formsemestre.py              |   2 +-
 app/views/pn_modules.py                      |   4 +-
 app/views/scodoc.py                          |   2 +-
 app/views/scolar.py                          |   2 +-
 app/views/users.py                           |   2 +-
 misc/csv2rules.py                            |   4 +-
 misc/geolocalize_lycees.py                   |   4 +-
 sco_version.py                               |   2 +-
 tests/unit/test_apogee_csv.py                |   2 +-
 tests/unit/test_apogee_export.py             |   2 +-
 tests/unit/test_but_jury.py                  |   2 +-
 tests/unit/yaml_setup.py                     |   2 +-
 tests/unit/yaml_setup_but.py                 |   2 +-
 tools/anonymize_db.py                        |   6 +-
 205 files changed, 411 insertions(+), 404 deletions(-)

diff --git a/app/api/assiduites.py b/app/api/assiduites.py
index eaebe1adb..d75b796c3 100644
--- a/app/api/assiduites.py
+++ b/app/api/assiduites.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 """ScoDoc 9 API : Assiduités
diff --git a/app/api/billets_absences.py b/app/api/billets_absences.py
index 98c89dfb0..160b00b73 100644
--- a/app/api/billets_absences.py
+++ b/app/api/billets_absences.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/departements.py b/app/api/departements.py
index 7214032d1..04cb8e75e 100644
--- a/app/api/departements.py
+++ b/app/api/departements.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/etudiants.py b/app/api/etudiants.py
index b709218e0..a508ee3b5 100755
--- a/app/api/etudiants.py
+++ b/app/api/etudiants.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/evaluations.py b/app/api/evaluations.py
index 60a03e9be..76b9be7c1 100644
--- a/app/api/evaluations.py
+++ b/app/api/evaluations.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/formations.py b/app/api/formations.py
index 8a5afe5bf..7ff02a07f 100644
--- a/app/api/formations.py
+++ b/app/api/formations.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/formsemestres.py b/app/api/formsemestres.py
index eca8786ca..6fc38aea0 100644
--- a/app/api/formsemestres.py
+++ b/app/api/formsemestres.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/jury.py b/app/api/jury.py
index f6d140d90..e71531eb2 100644
--- a/app/api/jury.py
+++ b/app/api/jury.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/logos.py b/app/api/logos.py
index db3a28cd8..08b59e370 100644
--- a/app/api/logos.py
+++ b/app/api/logos.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/api/moduleimpl.py b/app/api/moduleimpl.py
index 556f3d077..a4843fdf7 100644
--- a/app/api/moduleimpl.py
+++ b/app/api/moduleimpl.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/partitions.py b/app/api/partitions.py
index 268e64c92..50660fb66 100644
--- a/app/api/partitions.py
+++ b/app/api/partitions.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/semset.py b/app/api/semset.py
index 9869e6f8d..981c5a095 100644
--- a/app/api/semset.py
+++ b/app/api/semset.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/api/tools.py b/app/api/tools.py
index 10464e631..7ed1a44e6 100644
--- a/app/api/tools.py
+++ b/app/api/tools.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 """ScoDoc 9 API : outils
diff --git a/app/api/users.py b/app/api/users.py
index 3dffd2773..0a9f73978 100644
--- a/app/api/users.py
+++ b/app/api/users.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/apc_edit_ue.py b/app/but/apc_edit_ue.py
index b2fcec0d5..0ae48a218 100644
--- a/app/but/apc_edit_ue.py
+++ b/app/but/apc_edit_ue.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -23,7 +23,7 @@ def form_ue_choix_parcours(ue: UniteEns) -> str:
     if ref_comp is None:
         return f"""<div class="ue_advanced">
         <div class="warning">Pas de référentiel de compétence associé à cette formation !</div>
-        <div><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation', 
+        <div><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation',
                          scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)
             }">associer un référentiel de compétence</a>
         </div>
@@ -48,7 +48,7 @@ def form_ue_choix_parcours(ue: UniteEns) -> str:
             f" ({ue.get_ects(parcour):.3g} ects)" if ects_differents else ""
         )
         H.append(
-            f"""<label><input type="checkbox" name="{parcour.id}" value="{parcour.id}" 
+            f"""<label><input type="checkbox" name="{parcour.id}" value="{parcour.id}"
             {'checked' if parcour.id in ue_pids else ""}
             onclick="set_ue_parcour(this);"
             data-setter="{url_for("apiweb.set_ue_parcours",
@@ -62,7 +62,7 @@ def form_ue_choix_parcours(ue: UniteEns) -> str:
         <ul>
             <li>
                 <a class="stdlink" href="{
-                    url_for("notes.ue_parcours_ects", 
+                    url_for("notes.ue_parcours_ects",
                         scodoc_dept=g.scodoc_dept, ue_id=ue.id)
                 }">définir des ECTS différents dans chaque parcours</a>
             </li>
diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py
index e25074ad1..c8cf061d5 100644
--- a/app/but/bulletin_but.py
+++ b/app/but/bulletin_but.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/bulletin_but_court.py b/app/but/bulletin_but_court.py
index 9010ae350..ea52d0f23 100644
--- a/app/but/bulletin_but_court.py
+++ b/app/but/bulletin_but_court.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/bulletin_but_court_pdf.py b/app/but/bulletin_but_court_pdf.py
index 7e9e7e81d..bef62ae4b 100644
--- a/app/but/bulletin_but_court_pdf.py
+++ b/app/but/bulletin_but_court_pdf.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/bulletin_but_pdf.py b/app/but/bulletin_but_pdf.py
index dd3ec6870..f56b86c0f 100644
--- a/app/but/bulletin_but_pdf.py
+++ b/app/but/bulletin_but_pdf.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -9,7 +9,7 @@
 La génération du bulletin PDF suit le chemin suivant:
 
 - vue formsemestre_bulletinetud -> sco_bulletins.formsemestre_bulletinetud
-    
+
     bul_dict = bulletin_but.BulletinBUT(formsemestre).bulletin_etud_complet(etud)
 
 - sco_bulletins_generator.make_formsemestre_bulletin_etud()
diff --git a/app/but/bulletin_but_xml_compat.py b/app/but/bulletin_but_xml_compat.py
index 4ab940f7a..0b8c7b76e 100644
--- a/app/but/bulletin_but_xml_compat.py
+++ b/app/but/bulletin_but_xml_compat.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/but/cursus_but.py b/app/but/cursus_but.py
index d1e3f119d..9858d5177 100644
--- a/app/but/cursus_but.py
+++ b/app/but/cursus_but.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/forms/jury_but_forms.py b/app/but/forms/jury_but_forms.py
index 67bd955af..69eeaa480 100644
--- a/app/but/forms/jury_but_forms.py
+++ b/app/but/forms/jury_but_forms.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/forms/refcomp_forms.py b/app/but/forms/refcomp_forms.py
index b1ad3e71b..52b9cfc17 100644
--- a/app/but/forms/refcomp_forms.py
+++ b/app/but/forms/refcomp_forms.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/import_refcomp.py b/app/but/import_refcomp.py
index 666deb547..b203c4139 100644
--- a/app/but/import_refcomp.py
+++ b/app/but/import_refcomp.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 from xml.etree import ElementTree
@@ -33,7 +33,7 @@ def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
         scodoc_orig_filename=orig_filename, dept_id=dept_id
     ).count():
         raise ScoValueError(
-            f"""Un référentiel a déjà été chargé d'un fichier de même nom. 
+            f"""Un référentiel a déjà été chargé d'un fichier de même nom.
             ({orig_filename})
             Supprimez-le ou changez le nom du fichier."""
         )
diff --git a/app/but/jury_but.py b/app/but/jury_but.py
index bc3b7285c..41c081191 100644
--- a/app/but/jury_but.py
+++ b/app/but/jury_but.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -13,22 +13,22 @@ Utilisation:
       cherche les RCUEs de l'année (BUT1, 2, 3)
         pour un redoublant, le RCUE peut considérer un formsemestre d'une année antérieure.
 
-    on instancie des DecisionsProposees pour les 
+    on instancie des DecisionsProposees pour les
         différents éléments (UEs, RCUEs, Année, Diplôme)
-        Cela donne 
+        Cela donne
             - les codes possibles (dans .codes)
             - le code actuel si une décision existe déjà (dans code_valide)
             - pour les UEs, le rcue s'il y en a un)
-    
+
     2) Validation pour l'utilisateur (form)) => enregistrement code
             - on vérifie que le code soumis est bien dans les codes possibles
             - on enregistre la décision (dans ScolarFormSemestreValidation pour les UE,
                 ApcValidationRCUE pour les RCUE, et ApcValidationAnnee pour les années)
-            - Si RCUE validé, on déclenche d'éventuelles validations: 
-            ("La validation des deux UE du niveau d'une compétence emporte la validation 
+            - Si RCUE validé, on déclenche d'éventuelles validations:
+            ("La validation des deux UE du niveau d'une compétence emporte la validation
             de l'ensemble des UE du niveau inférieur de cette même compétence.")
-        
-Les jurys de semestre BUT impairs entrainent systématiquement la génération d'une 
+
+Les jurys de semestre BUT impairs entrainent systématiquement la génération d'une
 autorisation d'inscription dans le semestre pair suivant: `ScolarAutorisationInscription`.
 Les jurys de semestres pairs non (S2, S4, S6): il y a une décision sur l'année (ETP)
     - autorisation en S_2n+1 (S3 ou S5) si: ADM, ADJ, PASD, PAS1CN
@@ -39,8 +39,8 @@ Le formulaire permet de choisir des codes d'UE, RCUE et Année (ETP).
 Mais normalement, les codes d'UE sont à choisir: les RCUE et l'année s'en déduisent.
 Si l'utilisateur coche "décision manuelle", il peut alors choisir les codes RCUE et années.
 
-La soumission du formulaire: 
-    - etud, formation 
+La soumission du formulaire:
+    - etud, formation
     - UEs: [(formsemestre, ue, code), ...]
     - RCUE: [(formsemestre, ue, code), ...] le formsemestre est celui d'indice pair du niveau
         (S2, S4 ou S6), il sera regoupé avec celui impair de la même année ou de la suivante.
@@ -117,7 +117,7 @@ class NoRCUEError(ScoValueError):
             {warning_impair}
             {warning_pair}
             <div><b>UE {ue.acronyme}</b>: niveau {html.escape(str(ue.niveau_competence))}</div>
-            <div><b>UEs impaires:</b> {html.escape(', '.join(str(u.niveau_competence or "pas de niveau") 
+            <div><b>UEs impaires:</b> {html.escape(', '.join(str(u.niveau_competence or "pas de niveau")
                 for u in deca.ues_impair))}
             </div>
             """
@@ -273,8 +273,8 @@ class DecisionsProposeesAnnee(DecisionsProposees):
         = niveaux du tronc commun + niveau du parcours de l'étudiant.
         """
         self.rcue_by_niveau = self._compute_rcues_annee()
-        """RCUEs de l'année 
-        (peuvent être construits avec des UEs validées antérieurement: redoublants 
+        """RCUEs de l'année
+        (peuvent être construits avec des UEs validées antérieurement: redoublants
         avec UEs capitalisées, validation "antérieures")
         """
         # ---- Décision année et autorisation
diff --git a/app/but/jury_but_pv.py b/app/but/jury_but_pv.py
index 0b8dfd064..9b970a61d 100644
--- a/app/but/jury_but_pv.py
+++ b/app/but/jury_but_pv.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -69,7 +69,7 @@ def pvjury_page_but(formsemestre_id: int, fmt="html"):
         html_title=f"""<div style="margin-bottom: 8px;"><span
             style="font-size: 120%; font-weight: bold;">{title}</span>
         <span style="padding-left: 20px;">
-        <a href="{url_for("notes.pvjury_page_but", 
+        <a href="{url_for("notes.pvjury_page_but",
         scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, fmt="xlsx")}"
          class="stdlink">version excel</a></span></div>
 
diff --git a/app/but/jury_but_results.py b/app/but/jury_but_results.py
index 089b2e772..2f52e22be 100644
--- a/app/but/jury_but_results.py
+++ b/app/but/jury_but_results.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/jury_but_validation_auto.py b/app/but/jury_but_validation_auto.py
index a061b42f1..4cfffa581 100644
--- a/app/but/jury_but_validation_auto.py
+++ b/app/but/jury_but_validation_auto.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/jury_but_view.py b/app/but/jury_but_view.py
index 3ae00b2fa..544d13f2b 100644
--- a/app/but/jury_but_view.py
+++ b/app/but/jury_but_view.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -76,9 +76,9 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
         f"""
     <div class="titre_niveaux">
         <b>Niveaux de compétences et unités d'enseignement du BUT{deca.annee_but}</b>
-        <a style="margin-left: 32px;" class="stdlink" target="_blank" rel="noopener noreferrer" 
+        <a style="margin-left: 32px;" class="stdlink" target="_blank" rel="noopener noreferrer"
             href={
-                url_for("notes.validation_rcues", scodoc_dept=g.scodoc_dept, 
+                url_for("notes.validation_rcues", scodoc_dept=g.scodoc_dept,
                     etudid=deca.etud.id,
                     formsemestre_id=formsemestre_2.id if formsemestre_2 else formsemestre_1.id
             )
@@ -172,7 +172,7 @@ def _gen_but_select(
         ]
     )
     return f"""<select required name="{name}"
-        class="but_code {klass}" 
+        class="but_code {klass}"
         data-orig_code="{code_valide or (codes[0] if codes else '')}"
         data-orig_recorded="{code_valide or ''}"
         onchange="change_menu_code(this);"
@@ -201,7 +201,7 @@ def _gen_but_niveau_ue(
             <div>UE en cours
             {   "sans notes" if np.isnan(dec_ue.moy_ue)
                 else
-                ("avec moyenne <b>" + scu.fmt_note(dec_ue.moy_ue) + "</b>") 
+                ("avec moyenne <b>" + scu.fmt_note(dec_ue.moy_ue) + "</b>")
             }
             </div>
         </div>
@@ -262,14 +262,14 @@ def _gen_but_niveau_ue(
         {scoplement}
     </div>
     <div class="but_code">{
-        _gen_but_select("code_ue_"+str(ue.id), 
+        _gen_but_select("code_ue_"+str(ue.id),
             dec_ue.codes,
             dec_ue.code_valide,
             disabled=disabled,
             klass=f"code_ue ue_rcue_{niveau_id}" if not disabled else ""
         )
     }</div>
-    
+
     </div>"""
 
 
@@ -423,7 +423,7 @@ def jury_but_semestriel(
     # GET
     if formsemestre.semestre_id % 2 == 0:
         warning = f"""<div class="warning">
-        Cet étudiant de S{formsemestre.semestre_id} ne peut pas passer 
+        Cet étudiant de S{formsemestre.semestre_id} ne peut pas passer
         en jury BUT annuel car il lui manque le semestre précédent.
         </div>"""
     else:
diff --git a/app/but/jury_edit_manual.py b/app/but/jury_edit_manual.py
index d144c125c..29a81cedf 100644
--- a/app/but/jury_edit_manual.py
+++ b/app/but/jury_edit_manual.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/rcue.py b/app/but/rcue.py
index 5a5fce3ea..2fce54ffc 100644
--- a/app/but/rcue.py
+++ b/app/but/rcue.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/but/validations_view.py b/app/but/validations_view.py
index ef7dd8825..83c843015 100644
--- a/app/but/validations_view.py
+++ b/app/but/validations_view.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/aux_stats.py b/app/comp/aux_stats.py
index b0d47924e..36b2efdf8 100644
--- a/app/comp/aux_stats.py
+++ b/app/comp/aux_stats.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -30,7 +30,9 @@ class StatsMoyenne:
                 self.max = np.nanmax(vals)
                 self.size = len(vals)
                 self.nb_vals = self.size - np.count_nonzero(np.isnan(vals))
-        except TypeError:  # que des NaN dans un array d'objets, ou ce genre de choses exotiques...
+        except (
+            TypeError
+        ):  # que des NaN dans un array d'objets, ou ce genre de choses exotiques...
             self.moy = self.min = self.max = self.size = self.nb_vals = 0
 
     def to_dict(self):
diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py
index b5b4e966b..96505d167 100644
--- a/app/comp/bonus_spo.py
+++ b/app/comp/bonus_spo.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/df_cache.py b/app/comp/df_cache.py
index 1dea77c24..fb4c6cade 100644
--- a/app/comp/df_cache.py
+++ b/app/comp/df_cache.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/comp/jury.py b/app/comp/jury.py
index ee2c13738..1a4c87687 100644
--- a/app/comp/jury.py
+++ b/app/comp/jury.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -38,7 +38,7 @@ class ValidationsSemestre(ResultatsCache):
         super().__init__(formsemestre, sco_cache.ValidationsSemestreCache)
 
         self.decisions_jury = {}
-        """Décisions prises dans ce semestre: 
+        """Décisions prises dans ce semestre:
         { etudid : { 'code' : None|ATT|..., 'assidu' : 0|1 }}"""
         self.decisions_jury_ues = {}
         """Décisions sur des UEs dans ce semestre:
@@ -145,11 +145,11 @@ def formsemestre_get_ue_capitalisees(formsemestre: FormSemestre) -> pd.DataFrame
     query = sa.text(
         """
     SELECT DISTINCT SFV.*, ue.ue_code
-    FROM 
-    notes_ue ue, 
+    FROM
+    notes_ue ue,
     notes_formations nf,
-    notes_formations nf2, 
-    scolar_formsemestre_validation SFV, 
+    notes_formations nf2,
+    scolar_formsemestre_validation SFV,
     notes_formsemestre sem,
     notes_formsemestre_inscription ins
 
diff --git a/app/comp/moy_mat.py b/app/comp/moy_mat.py
index 09518857f..e95e4c961 100644
--- a/app/comp/moy_mat.py
+++ b/app/comp/moy_mat.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/moy_mod.py b/app/comp/moy_mod.py
index 7ca6c25ea..ad7c45940 100644
--- a/app/comp/moy_mod.py
+++ b/app/comp/moy_mod.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py
index 15313550a..3701f3dd0 100644
--- a/app/comp/moy_sem.py
+++ b/app/comp/moy_sem.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -89,7 +89,7 @@ def compute_sem_moys_apc_using_ects(
             flash(
                 Markup(
                     f"""Calcul moyenne générale impossible: ECTS des UE manquants !<br>
-                (formation: <a href="{url_for("notes.ue_table", 
+                (formation: <a href="{url_for("notes.ue_table",
                 scodoc_dept=g.scodoc_dept, formation_id=formation_id)}">{formation.get_titre_version()}</a>)"""
                 )
             )
diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py
index ea9124eea..6f8004188 100644
--- a/app/comp/moy_ue.py
+++ b/app/comp/moy_ue.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/comp/res_but.py b/app/comp/res_but.py
index 1d7b3ad7f..880f1b8ed 100644
--- a/app/comp/res_but.py
+++ b/app/comp/res_but.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/res_cache.py b/app/comp/res_cache.py
index 941caad2b..9374598b7 100644
--- a/app/comp/res_cache.py
+++ b/app/comp/res_cache.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py
index 50976668d..89ff95e73 100644
--- a/app/comp/res_classic.py
+++ b/app/comp/res_classic.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/res_common.py b/app/comp/res_common.py
index 175e38df8..c6985ff56 100644
--- a/app/comp/res_common.py
+++ b/app/comp/res_common.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/res_compat.py b/app/comp/res_compat.py
index 7d23bea44..a9b605aa4 100644
--- a/app/comp/res_compat.py
+++ b/app/comp/res_compat.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/comp/res_sem.py b/app/comp/res_sem.py
index 212f97102..8c28d7e44 100644
--- a/app/comp/res_sem.py
+++ b/app/comp/res_sem.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/email.py b/app/email.py
index a983ef2df..cecaa68b9 100644
--- a/app/email.py
+++ b/app/email.py
@@ -1,7 +1,7 @@
 # -*- coding: UTF-8 -*
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/entreprises/app_relations_entreprises.py b/app/entreprises/app_relations_entreprises.py
index b8bd683dd..e02a0c935 100644
--- a/app/entreprises/app_relations_entreprises.py
+++ b/app/entreprises/app_relations_entreprises.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py
index c39ac7504..804e232b7 100644
--- a/app/entreprises/forms.py
+++ b/app/entreprises/forms.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/assiduite/ajout_assiduite_etud.py b/app/forms/assiduite/ajout_assiduite_etud.py
index dae8419b0..44b7f9c7e 100644
--- a/app/forms/assiduite/ajout_assiduite_etud.py
+++ b/app/forms/assiduite/ajout_assiduite_etud.py
@@ -4,7 +4,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/formsemestre/change_formation.py b/app/forms/formsemestre/change_formation.py
index 9161c93a5..c66e96778 100644
--- a/app/forms/formsemestre/change_formation.py
+++ b/app/forms/formsemestre/change_formation.py
@@ -4,7 +4,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -43,6 +43,7 @@ def gen_formsemestre_change_formation_form(
     formations: list[Formation],
 ) -> FormSemestreChangeFormationForm:
     "Create our dynamical form"
+
     # see https://wtforms.readthedocs.io/en/2.3.x/specific_problems/#dynamic-form-composition
     class F(FormSemestreChangeFormationForm):
         pass
diff --git a/app/forms/main/config_apo.py b/app/forms/main/config_apo.py
index 5db90405a..adac92c0e 100644
--- a/app/forms/main/config_apo.py
+++ b/app/forms/main/config_apo.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/main/config_assiduites.py b/app/forms/main/config_assiduites.py
index 129b2d47e..056543045 100644
--- a/app/forms/main/config_assiduites.py
+++ b/app/forms/main/config_assiduites.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/main/config_cas.py b/app/forms/main/config_cas.py
index 3a31b47fe..a85a9b1a6 100644
--- a/app/forms/main/config_cas.py
+++ b/app/forms/main/config_cas.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/main/config_logos.py b/app/forms/main/config_logos.py
index d01cc5cc4..fcea427cc 100644
--- a/app/forms/main/config_logos.py
+++ b/app/forms/main/config_logos.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/main/config_main.py b/app/forms/main/config_main.py
index df8ec7df6..68b161ebb 100644
--- a/app/forms/main/config_main.py
+++ b/app/forms/main/config_main.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/main/create_dept.py b/app/forms/main/create_dept.py
index 1ab7f6678..059af39ca 100644
--- a/app/forms/main/create_dept.py
+++ b/app/forms/main/create_dept.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/forms/main/role_create.py b/app/forms/main/role_create.py
index c3a2b150e..aee79c0c3 100644
--- a/app/forms/main/role_create.py
+++ b/app/forms/main/role_create.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/models/but_refcomp.py b/app/models/but_refcomp.py
index a47bac1bf..aa36c08d0 100644
--- a/app/models/but_refcomp.py
+++ b/app/models/but_refcomp.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 """ScoDoc 9 models : Référentiel Compétence BUT 2021
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 3a9e00155..994e201d2 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -1,7 +1,7 @@
 # -*- coding: UTF-8 -*
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/models/groups.py b/app/models/groups.py
index d4905cda4..6c112058f 100644
--- a/app/models/groups.py
+++ b/app/models/groups.py
@@ -1,7 +1,7 @@
 # -*- coding: UTF-8 -*
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/pe/pe_avislatex.py b/app/pe/pe_avislatex.py
index d68f9509b..3c498f47d 100644
--- a/app/pe/pe_avislatex.py
+++ b/app/pe/pe_avislatex.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -51,6 +51,7 @@ DONNEE_MANQUANTE = (
     ""  # Caractère de remplacement des données manquantes dans un avis PE
 )
 
+
 # ----------------------------------------------------------------------------------------
 def get_code_latex_from_modele(fichier):
     """Lit le code latex à partir d'un modèle. Renvoie une chaine unicode.
@@ -329,14 +330,13 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
 
     lignes = []
     valeurs = {"note": [], "rang": []}
-    for (indice_aggregat, (aggregat, intitule, _)) in enumerate(entete):
+    for indice_aggregat, (aggregat, intitule, _) in enumerate(entete):
         # print("> " + aggregat)
         # listeTags = jury.get_allTagForAggregat(aggregat)  # les tags de l'aggrégat
         listeTags = [
             tag for tag in donnees_etudiant[aggregat][groupe].keys() if tag != "dut"
         ]  #
         for tag in listeTags:
-
             if tag not in lignes:
                 lignes.append(tag)
                 valeurs["note"].append(
@@ -365,7 +365,7 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
     )
     code_latex += "\\hline"
     code_latex += "\\hline \n"
-    for (i, ligne_val) in enumerate(valeurs["note"]):
+    for i, ligne_val in enumerate(valeurs["note"]):
         titre = lignes[i]  # règle le pb d'encodage
         code_latex += "\\textbf{" + titre + "} & " + " & ".join(ligne_val) + "\\\\ \n"
         code_latex += (
diff --git a/app/pe/pe_jurype.py b/app/pe/pe_jurype.py
index a18626d6a..01687f7c9 100644
--- a/app/pe/pe_jurype.py
+++ b/app/pe/pe_jurype.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -60,6 +60,7 @@ from app.pe import pe_tools
 from app.pe import pe_semestretag
 from app.pe import pe_settag
 
+
 # ----------------------------------------------------------------------------------------
 def comp_nom_semestre_dans_parcours(sem):
     """Le nom a afficher pour titrer un semestre
@@ -293,7 +294,7 @@ class JuryPE(object):
         if pe_tools.PE_DEBUG:
             pe_tools.pe_print("3) Analyse des parcours individuels des étudiants")
 
-        for (no_etud, etudid) in enumerate(listEtudId):
+        for no_etud, etudid in enumerate(listEtudId):
             self.add_etudiants(etudid)
             if pe_tools.PE_DEBUG:
                 if (no_etud + 1) % 10 == 0:
@@ -319,7 +320,6 @@ class JuryPE(object):
 
         etudiants = []
         for sem in semsListe:  # pour chacun des semestres de la liste
-
             nt = self.get_cache_notes_d_un_semestre(sem["formsemestre_id"])
             etudiantsDuSemestre = (
                 nt.get_etudids()
@@ -411,7 +411,7 @@ class JuryPE(object):
                     "aggregat"
                 ]  # Recherche du formsemestre_id de son Si valide (ou a défaut en cours)
             ]
-            for (i, nom_sem) in enumerate(JuryPE.PARCOURS["4S"]["aggregat"]):
+            for i, nom_sem in enumerate(JuryPE.PARCOURS["4S"]["aggregat"]):
                 fid = sesFormsemestre_idValidants[i]
                 self.PARCOURSINFO_DICT[etudid][nom_sem] = fid  # ['formsemestre_id']
                 if fid != None and pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
@@ -544,7 +544,8 @@ class JuryPE(object):
     # ------------------------------------------------------------------------------------------------------------------
     def get_Fid_d_un_Si_valide_d_un_etudiant(self, etudid, nom_semestre):
         """Récupère le formsemestre_id valide d'un étudiant fourni son etudid à un semestre DUT de n° semestre_id
-        donné. Si le semestre est en cours (pas encore de jury), renvoie le formsemestre_id actuel."""
+        donné. Si le semestre est en cours (pas encore de jury), renvoie le formsemestre_id actuel.
+        """
         semestre_id = JuryPE.PARCOURS["4S"]["aggregat"].index(nom_semestre) + 1
         sesSi = self.get_semestresDUT_d_un_etudiant(
             etudid, semestre_id
@@ -553,7 +554,7 @@ class JuryPE(object):
         if len(sesSi) > 0:  # S'il a obtenu au moins une note
             # mT = sesMoyennes[0]
             leFid = sesSi[0]["formsemestre_id"]
-            for (i, sem) in enumerate(
+            for i, sem in enumerate(
                 sesSi
             ):  # Parcours des éventuels semestres précédents
                 nt = self.get_cache_notes_d_un_semestre(sem["formsemestre_id"])
@@ -581,7 +582,7 @@ class JuryPE(object):
         lesFids = self.get_formsemestreids_du_jury(
             self.get_etudids_du_jury(), liste_semestres=["S1", "S2", "S3", "S4"]
         )
-        for (i, fid) in enumerate(lesFids):
+        for i, fid in enumerate(lesFids):
             if pe_tools.PE_DEBUG:
                 pe_tools.pe_print(
                     "%d) Semestre taggué %s (avec classement dans groupe)"
@@ -713,7 +714,8 @@ class JuryPE(object):
 
     def get_settags_in_jury(self):
         """Calcule les moyennes sur la totalité du parcours (S1 jusqu'à S3 ou S4)
-        en classant les étudiants au sein du semestre final du parcours (même S3, même S4, ...)"""
+        en classant les étudiants au sein du semestre final du parcours (même S3, même S4, ...)
+        """
 
         # Par groupe :
         # combinaisons = { 'S1' : ['S1'], 'S2' : ['S2'], 'S3' : ['S3'], 'S4' : ['S4'], \
@@ -722,7 +724,7 @@ class JuryPE(object):
 
         # ---> sur 2 parcours DUT (cas S3 fini, cas S4 fini)
         combinaisons = ["1A", "2A", "3S", "4S"]
-        for (i, nom) in enumerate(combinaisons):
+        for i, nom in enumerate(combinaisons):
             parcours = JuryPE.PARCOURS[nom][
                 "aggregat"
             ]  # La liste des noms de semestres (S1, S2, ...) impliqués dans l'aggrégat
@@ -781,8 +783,7 @@ class JuryPE(object):
 
         lesEtudids = self.get_etudids_du_jury()
 
-        for (i, nom) in enumerate(JuryPE.PARCOURS.keys()):
-
+        for i, nom in enumerate(JuryPE.PARCOURS.keys()):
             settag = pe_settag.SetTagInterClasse(nom, diplome=self.diplome)
             nbreEtudInscrits = settag.set_Etudiants(
                 lesEtudids, self.PARCOURSINFO_DICT, self.ETUDINFO_DICT
@@ -896,7 +897,6 @@ class JuryPE(object):
     # Méthodes d'affichage pour debug
     # **************************************************************************************************************** #
     def str_etudiants_in_jury(self, delim=";"):
-
         # En tete:
         entete = ["Id", "Nom", "Abandon", "Diplome"]
         for nom_sem in ["S1", "S2", "S3", "S4", "1A", "2A", "3S", "4S"]:
@@ -904,7 +904,6 @@ class JuryPE(object):
         chaine = delim.join(entete) + "\n"
 
         for etudid in self.PARCOURSINFO_DICT:
-
             donnees = self.PARCOURSINFO_DICT[etudid]
             # pe_tools.pe_print(etudid, donnees)
             # les infos générales
@@ -940,7 +939,8 @@ class JuryPE(object):
 
     def get_allTagForAggregat(self, nom_aggregat):
         """Extrait du dictionnaire syntheseJury la liste des tags d'un semestre ou
-        d'un aggrégat donné par son nom (S1, S2, S3 ou S4, 1A, ...). Renvoie [] si aucun tag."""
+        d'un aggrégat donné par son nom (S1, S2, S3 ou S4, 1A, ...). Renvoie [] si aucun tag.
+        """
         taglist = set()
         for etudid in self.get_etudids_du_jury():
             taglist = taglist.union(
@@ -1203,6 +1203,7 @@ class JuryPE(object):
 # ----------------------------------------------------------------------------------------
 # Fonctions
 
+
 # ----------------------------------------------------------------------------------------
 def get_annee_diplome_semestre(sem) -> int:
     """Pour un semestre donne, décrit par le biais du dictionnaire sem usuel :
diff --git a/app/pe/pe_semestretag.py b/app/pe/pe_semestretag.py
index 9e2d9b455..8384551c4 100644
--- a/app/pe/pe_semestretag.py
+++ b/app/pe/pe_semestretag.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/pe/pe_settag.py b/app/pe/pe_settag.py
index 94e80cd9c..f8c35bd42 100644
--- a/app/pe/pe_settag.py
+++ b/app/pe/pe_settag.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/pe/pe_tagtable.py b/app/pe/pe_tagtable.py
index e14ca6ade..49bf22cc8 100644
--- a/app/pe/pe_tagtable.py
+++ b/app/pe/pe_tagtable.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/pe/pe_tools.py b/app/pe/pe_tools.py
index 932a2a007..ead3a2d18 100644
--- a/app/pe/pe_tools.py
+++ b/app/pe/pe_tools.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -74,6 +74,7 @@ PE_LOCAL_FOOTER_TMPL = REP_LOCAL_AVIS + "local/modeles/un_footer.tex"
 
 # ----------------------------------------------------------------------------------------
 
+
 # ----------------------------------------------------------------------------------------
 def print_semestres_description(sems, avec_affichage_debug=False):
     """Dediee a l'affichage d'un semestre pour debug du module"""
diff --git a/app/pe/pe_view.py b/app/pe/pe_view.py
index 8c2a40b76..7a49e7210 100644
--- a/app/pe/pe_view.py
+++ b/app/pe/pe_view.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/__init__.py b/app/scodoc/__init__.py
index 1b9a59255..1edc8d5ff 100644
--- a/app/scodoc/__init__.py
+++ b/app/scodoc/__init__.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/codes_cursus.py b/app/scodoc/codes_cursus.py
index b11c7b6b6..ea6d09ca0 100644
--- a/app/scodoc/codes_cursus.py
+++ b/app/scodoc/codes_cursus.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/gen_tables.py b/app/scodoc/gen_tables.py
index 8fcda8fb9..499c16eb9 100644
--- a/app/scodoc/gen_tables.py
+++ b/app/scodoc/gen_tables.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/html_sco_header.py b/app/scodoc/html_sco_header.py
index 1b9e45194..886f0cf43 100644
--- a/app/scodoc/html_sco_header.py
+++ b/app/scodoc/html_sco_header.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/html_sidebar.py b/app/scodoc/html_sidebar.py
index 3c35157c3..9806b1159 100755
--- a/app/scodoc/html_sidebar.py
+++ b/app/scodoc/html_sidebar.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/htmlutils.py b/app/scodoc/htmlutils.py
index 51a0b19bf..41e452d4c 100644
--- a/app/scodoc/htmlutils.py
+++ b/app/scodoc/htmlutils.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/notes_users.py b/app/scodoc/notes_users.py
index 33d25a681..b1ead8949 100644
--- a/app/scodoc/notes_users.py
+++ b/app/scodoc/notes_users.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/safehtml.py b/app/scodoc/safehtml.py
index 5c897cd25..d74bf40ff 100644
--- a/app/scodoc/safehtml.py
+++ b/app/scodoc/safehtml.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@ from html.parser import HTMLParser
    (Python 3 only)
 """
 
+
 # permet de conserver les liens
 def html_to_safe_html(text, convert_br=True):  # was HTML2SafeHTML
     # text = html_to_safe_html(text, valid_tags=("b", "a", "i", "br", "p"))
diff --git a/app/scodoc/sco_abs.py b/app/scodoc/sco_abs.py
index 8ef9de03a..2f55f3c64 100755
--- a/app/scodoc/sco_abs.py
+++ b/app/scodoc/sco_abs.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -429,8 +429,8 @@ def list_abs_date(etudid, beg_date=None, end_date=None):
         ""
         if beg_date is None
         else """
-    AND A.jour >= %(beg_date)s 
-    AND A.jour <= %(end_date)s 
+    AND A.jour >= %(beg_date)s
+    AND A.jour <= %(end_date)s
         """
     )
     cursor.execute(
@@ -516,7 +516,7 @@ def list_abs_jour(date, am=True, pm=True, is_abs=True, is_just=None) -> list[dic
     """
     cnx = ndb.GetDBConnexion()
     cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
-    req = """SELECT DISTINCT etudid, jour, matin FROM ABSENCES A 
+    req = """SELECT DISTINCT etudid, jour, matin FROM ABSENCES A
 WHERE A.jour = %(date)s
 """
     if is_abs is not None:
@@ -545,12 +545,12 @@ def list_abs_non_just_jour(date, am=True, pm=True) -> list[dict]:
     if not pm:
         reqa += " AND matin "
     req = (
-        """SELECT  etudid, jour, matin FROM ABSENCES A 
-WHERE A.estabs 
+        """SELECT  etudid, jour, matin FROM ABSENCES A
+WHERE A.estabs
 AND A.jour = %(date)s
 """
         + reqa
-        + """EXCEPT SELECT etudid, jour, matin FROM ABSENCES B 
+        + """EXCEPT SELECT etudid, jour, matin FROM ABSENCES B
 WHERE B.estjust AND B.jour = %(date)s"""
         + reqa
     )
@@ -630,7 +630,7 @@ AND A.JOUR >= %(datedebut)s"""
         req += """AND A.JOUR <= %(datefin)s"""
     if only_no_abs:
         req += """
-EXCEPT SELECT ETUDID, JOUR, MATIN FROM ABSENCES B 
+EXCEPT SELECT ETUDID, JOUR, MATIN FROM ABSENCES B
 WHERE B.estabs
 AND B.ETUDID = %(etudid)s
     """
diff --git a/app/scodoc/sco_abs_billets.py b/app/scodoc/sco_abs_billets.py
index 82f8b094c..18fe777fe 100644
--- a/app/scodoc/sco_abs_billets.py
+++ b/app/scodoc/sco_abs_billets.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_abs_notification.py b/app/scodoc/sco_abs_notification.py
index 6d2923236..b97f44185 100644
--- a/app/scodoc/sco_abs_notification.py
+++ b/app/scodoc/sco_abs_notification.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_apogee_compare.py b/app/scodoc/sco_apogee_compare.py
index 3b82862db..d67dde9f0 100644
--- a/app/scodoc/sco_apogee_compare.py
+++ b/app/scodoc/sco_apogee_compare.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -73,11 +73,11 @@ def apo_compare_csv_form():
         _HELP_TXT,
         """
         <div class="apo_compare_csv_form_but">
-        Fichier Apogée A: 
+        Fichier Apogée A:
         <input type="file" size="30" name="file_a"/>
         </div>
         <div class="apo_compare_csv_form_but">
-        Fichier Apogée B: 
+        Fichier Apogée B:
         <input type="file" size="30" name="file_b"/>
         </div>
         <input type="checkbox" name="autodetect" checked/>autodétecter encodage</input>
@@ -101,7 +101,7 @@ def apo_compare_csv(file_a, file_b, autodetect=True):
             raise ScoValueError(
                 """
             Erreur: l'encodage de l'un des fichiers est mal détecté.
-            Essayez sans auto-détection, ou vérifiez le codage et le contenu 
+            Essayez sans auto-détection, ou vérifiez le codage et le contenu
             des fichiers.
             """,
                 dest_url=dest_url,
@@ -258,9 +258,9 @@ def _apo_compare_csv(apo_a: ApoData, apo_b: ApoData):
             L.append(T.html())
         else:
             L.append(
-                f"""<p class="p_ok">aucune différence de résultats 
-            sur les {nb_etuds_communs} étudiants communs 
-            (<em>les éléments Apogée n'apparaissant pas dans les deux 
+                f"""<p class="p_ok">aucune différence de résultats
+            sur les {nb_etuds_communs} étudiants communs
+            (<em>les éléments Apogée n'apparaissant pas dans les deux
             fichiers sont omis</em>)
             </p>
             """
diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py
index 61af26bdd..965222f0b 100644
--- a/app/scodoc/sco_apogee_csv.py
+++ b/app/scodoc/sco_apogee_csv.py
@@ -2,7 +2,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -29,8 +29,8 @@ Ce code a été au départ inspiré par les travaux de Damien Mascré, scodoc2ap
 A utiliser en fin de semestre, après les jury.
 On communique avec Apogée via des fichiers CSV.
 
-XXX A vérifier: AJAC car 1 sem. validé et pas de NAR 
- 
+XXX A vérifier: AJAC car 1 sem. validé et pas de NAR
+
 """
 
 import datetime
@@ -762,7 +762,7 @@ class ApoData:
 
                     raise ScoValueError(
                         f"""Incohérence détectée !
-                        
+
                         Les semestres de la période n'ont pas tous le même indice.
 
                         Période: {self.periode}. Indice courant: {self.cur_semestre_id}
diff --git a/app/scodoc/sco_apogee_reader.py b/app/scodoc/sco_apogee_reader.py
index 2a56d85d9..44ab7fa65 100644
--- a/app/scodoc/sco_apogee_reader.py
+++ b/app/scodoc/sco_apogee_reader.py
@@ -2,7 +2,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -57,7 +57,7 @@ Le fichier CSV, champs séparés par des tabulations, a la structure suivante:
  10601232	AARIF	MALIKA	 22/09/1986	18	20	ADM	18	20	ADM	18	20	ADM	18	20	ADM	18	20	ADM	18	20	18	20	ADM	18	20	ADM	18	20	ADM	18	20	ADM
  </pre>
 
- 
+
  On récupère nos éléments pédagogiques dans la section XX-APO-COLONNES-XX et
  notre liste d'étudiants dans la section XX-APO_VALEURS-XX. Les champs de la
  section XX-APO_VALEURS-XX sont décrits par les lignes successives de la
@@ -290,7 +290,7 @@ class ApoCSVReadWrite:
             fields = line.split(APO_SEP)
             if len(fields) < 4:
                 raise ScoFormatError(
-                    """Ligne étudiant invalide 
+                    """Ligne étudiant invalide
                     (doit commencer par 'NIP NOM PRENOM dd/mm/yyyy')""",
                     filename=self.get_filename(),
                 )
diff --git a/app/scodoc/sco_archives.py b/app/scodoc/sco_archives.py
index 5fb9aa564..4f3eb7636 100644
--- a/app/scodoc/sco_archives.py
+++ b/app/scodoc/sco_archives.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_archives_etud.py b/app/scodoc/sco_archives_etud.py
index e3275a8cc..1dca9f028 100644
--- a/app/scodoc/sco_archives_etud.py
+++ b/app/scodoc/sco_archives_etud.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -147,10 +147,10 @@ def etud_upload_file_form(etudid):
         html_sco_header.sco_header(
             page_title="Chargement d'un document associé à %(nomprenom)s" % etud,
         ),
-        """<h2>Chargement d'un document associé à %(nomprenom)s</h2>                     
+        """<h2>Chargement d'un document associé à %(nomprenom)s</h2>
          """
         % etud,
-        """<p>Le fichier ne doit pas dépasser %sMo.</p>             
+        """<p>Le fichier ne doit pas dépasser %sMo.</p>
          """
         % (scu.CONFIG.ETUD_MAX_FILE_SIZE // (1024 * 1024)),
     ]
@@ -287,8 +287,8 @@ def etudarchive_import_files_form(group_id):
             page_title="Import de fichiers associés aux étudiants"
         ),
         """<h2 class="formsemestre">Téléchargement de fichier associés aux étudiants</h2>
-        <p>Les fichiers associés (dossiers d'admission, certificats, ...), de 
-        types quelconques (pdf, doc, images) sont accessibles aux utilisateurs via 
+        <p>Les fichiers associés (dossiers d'admission, certificats, ...), de
+        types quelconques (pdf, doc, images) sont accessibles aux utilisateurs via
         la fiche individuelle de l'étudiant.
         </p>
         <p class="warning">Ne pas confondre avec les photos des étudiants, qui se
diff --git a/app/scodoc/sco_archives_formsemestre.py b/app/scodoc/sco_archives_formsemestre.py
index 0915b95cf..24197dd43 100644
--- a/app/scodoc/sco_archives_formsemestre.py
+++ b/app/scodoc/sco_archives_formsemestre.py
@@ -2,7 +2,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bac.py b/app/scodoc/sco_bac.py
index 7933f3514..c7411e241 100644
--- a/app/scodoc/sco_bac.py
+++ b/app/scodoc/sco_bac.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py
index 9ac41e6d7..4cba4c69d 100644
--- a/app/scodoc/sco_bulletins.py
+++ b/app/scodoc/sco_bulletins.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_example.py b/app/scodoc/sco_bulletins_example.py
index 663fc8d0d..a7e61568f 100644
--- a/app/scodoc/sco_bulletins_example.py
+++ b/app/scodoc/sco_bulletins_example.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py
index 4d76712d7..bda2567e9 100644
--- a/app/scodoc/sco_bulletins_generator.py
+++ b/app/scodoc/sco_bulletins_generator.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py
index 7676ac162..3bce083a9 100644
--- a/app/scodoc/sco_bulletins_json.py
+++ b/app/scodoc/sco_bulletins_json.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_legacy.py b/app/scodoc/sco_bulletins_legacy.py
index 14ffb6cd7..05c462f6c 100644
--- a/app/scodoc/sco_bulletins_legacy.py
+++ b/app/scodoc/sco_bulletins_legacy.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py
index cf0d1348c..f61ba8ac5 100644
--- a/app/scodoc/sco_bulletins_pdf.py
+++ b/app/scodoc/sco_bulletins_pdf.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_signature.py b/app/scodoc/sco_bulletins_signature.py
index f3a711b56..0b30f8d24 100644
--- a/app/scodoc/sco_bulletins_signature.py
+++ b/app/scodoc/sco_bulletins_signature.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -38,9 +38,9 @@ envois par mail).
 La signature est controlée par:
 - la présence d'un fichier .../ScoDoc/static/signatures/<DeptId>/<formsemestre_id>/bul_sig_{left|right}
    ou, à défaut, .../ScoDoc/signatures/<DeptId>/bul_sig_{left|right}
-- les préférences booléennes bul_sig_left et bul_sig_right 
+- les préférences booléennes bul_sig_left et bul_sig_right
    (ne pas confondre avec bul_show_sig_left...)
-- les préférences bul_sig_left_image_height et bul_sig_right_image_height 
+- les préférences bul_sig_left_image_height et bul_sig_right_image_height
     (hauteur de l'image, float, en mm)
 
 API:
diff --git a/app/scodoc/sco_bulletins_standard.py b/app/scodoc/sco_bulletins_standard.py
index d249f7fe6..a35a021e2 100644
--- a/app/scodoc/sco_bulletins_standard.py
+++ b/app/scodoc/sco_bulletins_standard.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_bulletins_ucac.py b/app/scodoc/sco_bulletins_ucac.py
index c5a592438..6ec66ccee 100644
--- a/app/scodoc/sco_bulletins_ucac.py
+++ b/app/scodoc/sco_bulletins_ucac.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
 #
 ##############################################################################
 
-"""Generation bulletins de notes 
+"""Generation bulletins de notes
 
 Format table "UCAC"
 On redéfini la table centrale du bulletin de note et hérite de tout le reste du bulletin standard.
diff --git a/app/scodoc/sco_bulletins_xml.py b/app/scodoc/sco_bulletins_xml.py
index 58305f145..25f2cfa64 100644
--- a/app/scodoc/sco_bulletins_xml.py
+++ b/app/scodoc/sco_bulletins_xml.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py
index c80049b1d..4c9960dfd 100644
--- a/app/scodoc/sco_cache.py
+++ b/app/scodoc/sco_cache.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_cal.py b/app/scodoc/sco_cal.py
index 25179c016..3ca918ffe 100644
--- a/app/scodoc/sco_cal.py
+++ b/app/scodoc/sco_cal.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_compute_moy.py b/app/scodoc/sco_compute_moy.py
index e2642f5e9..5f2959df0 100644
--- a/app/scodoc/sco_compute_moy.py
+++ b/app/scodoc/sco_compute_moy.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_config_actions.py b/app/scodoc/sco_config_actions.py
index 612027811..d6f540906 100644
--- a/app/scodoc/sco_config_actions.py
+++ b/app/scodoc/sco_config_actions.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_cost_formation.py b/app/scodoc/sco_cost_formation.py
index f266b0638..5c167e6bc 100644
--- a/app/scodoc/sco_cost_formation.py
+++ b/app/scodoc/sco_cost_formation.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_cursus.py b/app/scodoc/sco_cursus.py
index 53def6f9a..1bd9983f6 100644
--- a/app/scodoc/sco_cursus.py
+++ b/app/scodoc/sco_cursus.py
@@ -4,7 +4,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@ from app.comp import res_sem
 from app.models import FormSemestre
 import app.scodoc.notesdb as ndb
 
+
 # SituationEtudParcours -> get_situation_etud_cursus
 def get_situation_etud_cursus(
     etud: dict, formsemestre_id: int
diff --git a/app/scodoc/sco_cursus_dut.py b/app/scodoc/sco_cursus_dut.py
index f19fa00f3..b9e26e322 100644
--- a/app/scodoc/sco_cursus_dut.py
+++ b/app/scodoc/sco_cursus_dut.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_debouche.py b/app/scodoc/sco_debouche.py
index c08a6e999..cc08e8d98 100644
--- a/app/scodoc/sco_debouche.py
+++ b/app/scodoc/sco_debouche.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -212,7 +212,7 @@ def report_debouche_ask_date(msg: str) -> str:
     return f"""{html_sco_header.sco_header()}
     <h2>Table des débouchés des étudiants</h2>
     <form method="GET">
-    {msg} 
+    {msg}
     <input type="text" name="start_year" value="" size=10/>
     </form>
     {html_sco_header.sco_footer()}
diff --git a/app/scodoc/sco_dept.py b/app/scodoc/sco_dept.py
index b81ea09f5..3e050a817 100644
--- a/app/scodoc/sco_dept.py
+++ b/app/scodoc/sco_dept.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_dump_db.py b/app/scodoc/sco_dump_db.py
index 4474f3827..a74fab8d3 100644
--- a/app/scodoc/sco_dump_db.py
+++ b/app/scodoc/sco_dump_db.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_edit_apc.py b/app/scodoc/sco_edit_apc.py
index 60961c3e7..3bd945952 100644
--- a/app/scodoc/sco_edit_apc.py
+++ b/app/scodoc/sco_edit_apc.py
@@ -2,7 +2,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_edit_formation.py b/app/scodoc/sco_edit_formation.py
index 0857656df..5b1f4ec42 100644
--- a/app/scodoc/sco_edit_formation.py
+++ b/app/scodoc/sco_edit_formation.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_edit_matiere.py b/app/scodoc/sco_edit_matiere.py
index 614113fdf..277da08e6 100644
--- a/app/scodoc/sco_edit_matiere.py
+++ b/app/scodoc/sco_edit_matiere.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -109,7 +109,7 @@ def matiere_create(ue_id=None):
 d'une formation donnée. Les matières servent surtout pour la
 présentation (bulletins, etc) mais <em>n'ont pas de rôle dans le calcul
 des notes.</em>
-</p> 
+</p>
 
 <p class="help">Si votre formation n'utilise pas la notion de
 "matières", créez une matière par UE, et donnez lui le même nom que l'UE
@@ -281,7 +281,7 @@ def matiere_edit(matiere_id=None):
 d'une formation donnée. Les matières servent surtout pour la
 présentation (bulletins, etc) mais <em>n'ont pas de rôle dans le calcul
 des notes.</em>
-</p> 
+</p>
 
 <p class="help">Si votre formation n'utilise pas la notion de
 "matières", créez une matière par UE, et donnez lui le même nom que l'UE
diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py
index 4f5b9235e..b7d6fab4e 100644
--- a/app/scodoc/sco_edit_module.py
+++ b/app/scodoc/sco_edit_module.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py
index 232507ead..06975ba36 100644
--- a/app/scodoc/sco_edit_ue.py
+++ b/app/scodoc/sco_edit_ue.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_edt_cal.py b/app/scodoc/sco_edt_cal.py
index bc7dc8d3a..c21ca8620 100644
--- a/app/scodoc/sco_edt_cal.py
+++ b/app/scodoc/sco_edt_cal.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_etape_apogee.py b/app/scodoc/sco_etape_apogee.py
index ce0f5457a..a4fcdb02f 100644
--- a/app/scodoc/sco_etape_apogee.py
+++ b/app/scodoc/sco_etape_apogee.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
 #
 ##############################################################################
 
-"""ScoDoc : stockage et vérifications des "maquettes" Apogée 
+"""ScoDoc : stockage et vérifications des "maquettes" Apogée
    (fichiers CSV pour l'export vers Apogée)
    associées aux années scolaires
 
@@ -33,23 +33,23 @@
 
    Stockage: utilise sco_archive.py
     exemple:
-   /opt/scodoc-data/archives/apo_csv/<dept_id>/2016-1/2016-07-03-16-12-19/V3ASR!111.csv 
+   /opt/scodoc-data/archives/apo_csv/<dept_id>/2016-1/2016-07-03-16-12-19/V3ASR!111.csv
    pour une maquette de l'étape V3ASR version VDI 111.
 
    La version VDI sera ignorée sauf si elle est indiquée dans l'étape du semestre.
-   apo_csv_get() 
-   
+   apo_csv_get()
+
    API:
-   # apo_csv_store(csv_data, annee_scolaire, sem_id)        
+   # apo_csv_store(csv_data, annee_scolaire, sem_id)
       store maq file (archive)
-      
+
    apo_csv_get(etape_apo, annee_scolaire, sem_id, vdi_apo=None)
       get maq data (read stored file and returns string)
       if vdi_apo, get maq for this etape/vdi, else returns the first matching etape.
 
    apo_csv_delete(etape_apo, annee_scolaire, sem_id)
 
-   apo_csv_list_stored_etapes(annee_scolaire=None, sem_id=None, etapes=None) 
+   apo_csv_list_stored_etapes(annee_scolaire=None, sem_id=None, etapes=None)
        returns: liste des codes etapes et version vdi stockés (pour l'annee_scolaire et le sem_id indiqués)
 
    apo_csv_semset_check(semset)
@@ -60,7 +60,7 @@
       - etudiants dans un CSV mais pas dans sem ScoDoc
       - etudiants dans plusieurs CSV (argh!)
       detecte aussi si on a plusieurs années scolaires
-      
+
       returns: etuds_ok (in ScoDoc and CSVs)
                etuds_no_apo
                unknown_apo : liste de { 'NIP', 'nom', 'prenom' }
@@ -69,7 +69,7 @@
 
    apo_csv_check_etape(semset, set_nips, etape_apo)
       check une etape
-      
+
 """
 
 import re
@@ -385,7 +385,7 @@ formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
 nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
 #
 s = SemSet('NSS29902')
-apo_data = sco_apogee_csv.ApoData(open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2015-2/2016-07-10-11-26-15/V1RT.csv').read(), periode=1) 
+apo_data = sco_apogee_csv.ApoData(open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2015-2/2016-07-10-11-26-15/V1RT.csv').read(), periode=1)
 
 # cas Tiziri K. (inscrite en S1, démission en fin de S1, pas inscrite en S2)
 # => pas de décision, ce qui est voulu (?)
diff --git a/app/scodoc/sco_etape_apogee_view.py b/app/scodoc/sco_etape_apogee_view.py
index 8f11532b8..6247d9869 100644
--- a/app/scodoc/sco_etape_apogee_view.py
+++ b/app/scodoc/sco_etape_apogee_view.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -126,7 +126,7 @@ def apo_semset_maq_status(
     # Upload fichier:
     H.append(
         """<form id="apo_csv_add" action="view_apo_csv_store" method="post" enctype="multipart/form-data">
-        Charger votre fichier maquette Apogée: 
+        Charger votre fichier maquette Apogée:
         <input type="file" size="30" name="csvfile"/>
         <input type="hidden" name="semset_id" value="%s"/>
         <input type="submit" value="Ajouter ce fichier"/>
@@ -146,7 +146,7 @@ def apo_semset_maq_status(
         Ou récupérer maquette Apogée pour une étape:
         <script type="text/javascript">
         function change_etape(e) {
-           $('#apo_csv_download_submit_btn').attr('disabled', (e.value == ""));           
+           $('#apo_csv_download_submit_btn').attr('disabled', (e.value == ""));
         }
         </script>
         <select name="etape_apo" onchange="change_etape(this);">
@@ -355,8 +355,8 @@ def apo_semset_maq_status(
             <span class="apo_elems fontred">{
                 ", ".join(sorted(missing))
             }</span>
-            <div class="help">Ces éléments de la maquette Apogée ne sont pas déclarés dans 
-            ScoDoc et ne seront donc pas remplis.</div><div> Vous pouvez les déclarer 
+            <div class="help">Ces éléments de la maquette Apogée ne sont pas déclarés dans
+            ScoDoc et ne seront donc pas remplis.</div><div> Vous pouvez les déclarer
             dans les programmes pédagogiques: """
         )
         H.append(
@@ -377,10 +377,10 @@ def apo_semset_maq_status(
     H.append(
         f"""
     <p><a class="stdlink" href="semset_page">Retour aux ensembles de semestres</a></p>
-    
+
     <div class="pas_help">
     <h3>Explications</h3>
-    <p>Cette page permet de stocker les fichiers Apogée nécessaires pour 
+    <p>Cette page permet de stocker les fichiers Apogée nécessaires pour
     l'export des résultats après les jurys, puis de remplir et exporter ces fichiers.
     </p>
     <p>
@@ -417,14 +417,14 @@ def apo_semset_maq_status(
  apoL_a01_code	apoL_a02_nom	apoL_a03_prenom	apoL_a04_naissance	apoL_c0001	apoL_c0002	apoL_c0003	apoL_c0004	apoL_c0005	apoL_c0006 (...)
  11681234	DUPONT	TOTO	 23/09/1986	18	20	ADM	18	20	ADM	(...)
     </pre>
-    <p>Après avoir obtenu les fichier, stockez-les dans ScoDoc 
-    (bouton "Ajouter fichier" en haut de cette page. Après vérification, il va 
-    apparaitre dans une table. Vous pouvez supprimer ce fichier, ou en ajouter 
+    <p>Après avoir obtenu les fichier, stockez-les dans ScoDoc
+    (bouton "Ajouter fichier" en haut de cette page. Après vérification, il va
+    apparaitre dans une table. Vous pouvez supprimer ce fichier, ou en ajouter
     d'autres si votre semestre correspond à plusieurs étapes Apogée.
     </p>
-    <p>ScoDoc vérifie que tous les étudiants du semestre sont mentionnés dans 
+    <p>ScoDoc vérifie que tous les étudiants du semestre sont mentionnés dans
     un fichier Apogée et que les étapes correspondent.</p>
-    <p>Lorsque c'est le cas, et que les décisions de jury sont saisies, 
+    <p>Lorsque c'est le cas, et que les décisions de jury sont saisies,
     un bouton "Export vers Apogée" apparait et vous pouvez exporter les résultats.
     <p>
     <p>Vous obtiendrez alors un fichier ZIP comprenant tous les fichiers nécessaires.
diff --git a/app/scodoc/sco_etape_bilan.py b/app/scodoc/sco_etape_bilan.py
index f3b0b954a..575d2596a 100644
--- a/app/scodoc/sco_etape_bilan.py
+++ b/app/scodoc/sco_etape_bilan.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -38,16 +38,16 @@ une section permettant de faire le point sur les cas particuliers.
 
 Cette section est composée de deux parties:
 
- * Une partie effectif où figurent le nombre d'étudiants selon une répartition par  
- semestre (en ligne) et par code étape (en colonne). On ajoute également des 
+ * Une partie effectif où figurent le nombre d'étudiants selon une répartition par
+ semestre (en ligne) et par code étape (en colonne). On ajoute également des
  colonnes/lignes correspondant à des anomalies (étudiant sans code étape, sans
  semestre, avec deux semestres, sans NIP, etc.).
- 
- * Une seconde partie présente la liste des étudiants. Il est possible qu'un 
+
+ * Une seconde partie présente la liste des étudiants. Il est possible qu'un
   même nom figure deux fois dans la liste (si on a pas pu faire la correspondance
   entre une inscription Apogée et un étudiant d'un semestre, par exemple).
- 
- L'activation d'un des nombres du tableau 'effectifs' restreint l'affichage de 
+
+ L'activation d'un des nombres du tableau 'effectifs' restreint l'affichage de
  la liste aux étudiants qui contribuent à ce nombre.
 
 ## Réalisation
@@ -176,52 +176,52 @@ class DataEtudiant(object):
 
 def _help() -> str:
     return """
-    <div id="export_help" class="pas_help"> <span>Explications sur les tableaux des effectifs et liste des 
-    étudiants</span> 
-        <div> <p>Le tableau des effectifs présente le nombre d'étudiants selon deux critères:</p> 
-        <ul> 
-        <li>En colonne le statut de l'étudiant par rapport à Apogée: 
-            <ul> 
-                <li><span class="libelle">Hors Apogée</span> 
-                    <span class="anomalie">(anomalie A</span>): Le NIP de l'étudiant n'est pas connu d'apogée ou 
-                l'étudiant n'a pas de NIP</li> 
-                <li><span class="libelle">Pas d'étape</span> <span class="anomalie">(anomalie B</span>): Le NIP de 
-                    l'étudiant ne correspond à aucune des étapes connues pour cet ensemble de semestre. Il est 
-                    possible qu'il soit inscrit ailleurs (dans une autre ensemble de semestres, un autre département, 
-                    une autre composante de l'université) ou en mobilité internationale.</li> 
-                <li><span class="libelle">Plusieurs étapes</span> <span class="anomalie">(anomalie C)</span>: 
-                    Les étudiants inscrits dans plusieurs étapes apogée de l'ensemble de semestres</li> 
-                <li>Un des codes étapes connus (la liste des codes étapes connus est l'union des codes étapes 
-                    déclarés pour chaque semestre particpant</li> 
-                <li><span class="libelle">Total semestre</span>: cumul des effectifs de la ligne</li> 
-            </ul> 
-            </li> 
-        <li>En ligne le statut de l'étudiant par rapport à ScoDoc: 
-            <ul> 
-                <li>Inscription dans un des semestres de l'ensemble</li> 
-                <li><span class="libelle">Hors semestre</span> <span class="anomalie">(anomalie D)</span>: 
-                    L'étudiant, bien qu'enregistré par apogée dans un des codes étapes connus, ne figure dans aucun 
-                    des semestres de l'ensemble. On y trouve par exemple les étudiants régulièrement inscrits 
-                    mais non présents à la rentrée (donc non enregistrés dans ScoDoc) <p>Note: On ne considère 
-                    ici que les semestres de l'ensemble (l'inscription de l'étudiant dans un semestre étranger à 
-                    l'ensemble actuel n'est pas vérifiée).</p> </li> 
-                <li><span class="libelle">Plusieurs semestres</span> <span class="anomalie">(anomalie E)</span>: 
-                    L'étudiant est enregistré dans plusieurs semestres de l'ensemble.</li> 
-                <li><span class="libelle">Total</span>: cumul des effectifs de la colonne</li> 
-            </ul> 
-            </li> 
-        <li>(<span class="anomalie">anomalie U</span>) On présente également les cas où un même NIP est affecté 
-            à deux dossiers différents (Un dossier d'apogée et un dossier de ScoDoc). Un tel cas compte pour 
-            deux unités dans le tableau des effcetifs et engendre 2 lignes distinctes dans la liste des étudiants</li> 
-        </ul> 
-        </div> 
+    <div id="export_help" class="pas_help"> <span>Explications sur les tableaux des effectifs et liste des
+    étudiants</span>
+        <div> <p>Le tableau des effectifs présente le nombre d'étudiants selon deux critères:</p>
+        <ul>
+        <li>En colonne le statut de l'étudiant par rapport à Apogée:
+            <ul>
+                <li><span class="libelle">Hors Apogée</span>
+                    <span class="anomalie">(anomalie A</span>): Le NIP de l'étudiant n'est pas connu d'apogée ou
+                l'étudiant n'a pas de NIP</li>
+                <li><span class="libelle">Pas d'étape</span> <span class="anomalie">(anomalie B</span>): Le NIP de
+                    l'étudiant ne correspond à aucune des étapes connues pour cet ensemble de semestre. Il est
+                    possible qu'il soit inscrit ailleurs (dans une autre ensemble de semestres, un autre département,
+                    une autre composante de l'université) ou en mobilité internationale.</li>
+                <li><span class="libelle">Plusieurs étapes</span> <span class="anomalie">(anomalie C)</span>:
+                    Les étudiants inscrits dans plusieurs étapes apogée de l'ensemble de semestres</li>
+                <li>Un des codes étapes connus (la liste des codes étapes connus est l'union des codes étapes
+                    déclarés pour chaque semestre particpant</li>
+                <li><span class="libelle">Total semestre</span>: cumul des effectifs de la ligne</li>
+            </ul>
+            </li>
+        <li>En ligne le statut de l'étudiant par rapport à ScoDoc:
+            <ul>
+                <li>Inscription dans un des semestres de l'ensemble</li>
+                <li><span class="libelle">Hors semestre</span> <span class="anomalie">(anomalie D)</span>:
+                    L'étudiant, bien qu'enregistré par apogée dans un des codes étapes connus, ne figure dans aucun
+                    des semestres de l'ensemble. On y trouve par exemple les étudiants régulièrement inscrits
+                    mais non présents à la rentrée (donc non enregistrés dans ScoDoc) <p>Note: On ne considère
+                    ici que les semestres de l'ensemble (l'inscription de l'étudiant dans un semestre étranger à
+                    l'ensemble actuel n'est pas vérifiée).</p> </li>
+                <li><span class="libelle">Plusieurs semestres</span> <span class="anomalie">(anomalie E)</span>:
+                    L'étudiant est enregistré dans plusieurs semestres de l'ensemble.</li>
+                <li><span class="libelle">Total</span>: cumul des effectifs de la colonne</li>
+            </ul>
+            </li>
+        <li>(<span class="anomalie">anomalie U</span>) On présente également les cas où un même NIP est affecté
+            à deux dossiers différents (Un dossier d'apogée et un dossier de ScoDoc). Un tel cas compte pour
+            deux unités dans le tableau des effcetifs et engendre 2 lignes distinctes dans la liste des étudiants</li>
+        </ul>
+        </div>
     </div> """
 
 
 def entete_liste_etudiant() -> str:
     return """
             <ul>
-                <li id="sans_filtre">Pas de filtrage: Cliquez sur un des nombres du tableau ci-dessus pour 
+                <li id="sans_filtre">Pas de filtrage: Cliquez sur un des nombres du tableau ci-dessus pour
                     n'afficher que les étudiants correspondants</li>
                 <li id="filtre_row" style="display:none"></li>
                 <li id="filtre_col" style="display:none"></li>
@@ -540,31 +540,31 @@ class EtapeBilan:
         #      filtre_row: explicitation du filtre ligne éventuelle
         #      filtre_col: explicitation du filtre colonne évnetuelle
         if ind_row == ROW_CUMUL and ind_col == COL_CUMUL:
-            javascript = f"""doFiltrage({self.all_rows_str}, {self.all_cols_str}, 
+            javascript = f"""doFiltrage({self.all_rows_str}, {self.all_cols_str},
                 '*', '*',
-                '{comptage}', 
+                '{comptage}',
                 '', ''
                 );"""
 
         elif ind_row == ROW_CUMUL:
             javascript = f"""doFiltrage({self.all_rows_str}, {self.all_cols_str},
                 '*', '.{ind_col}',
-                '{comptage}', '', 
+                '{comptage}', '',
                 '{json.dumps(self.titres[ind_col].replace("<br>", " / "))[1:-1]}'
                 );"""
 
         elif ind_col == COL_CUMUL:
             javascript = f"""doFiltrage({self.all_rows_str}, {self.all_cols_str},
                 '.{ind_row}', '*',
-                ' ({count} étudiants)', 
+                ' ({count} étudiants)',
                 '{json.dumps(self.titres[ind_row])[1:-1]}', ''
                 );"""
 
         else:
-            javascript = f"""doFiltrage({self.all_rows_str}, {self.all_cols_str}, 
+            javascript = f"""doFiltrage({self.all_rows_str}, {self.all_cols_str},
                 '.{ind_row}', '.{ind_col}',
-                '{comptage}', 
-                '{json.dumps(self.titres[ind_row])[1:-1]}', 
+                '{comptage}',
+                '{json.dumps(self.titres[ind_row])[1:-1]}',
                 '{json.dumps(self.titres[ind_col].replace("<br>", " / "))[1:-1]}'
                 );"""
 
diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py
index ea7de19c4..e7041021c 100644
--- a/app/scodoc/sco_etud.py
+++ b/app/scodoc/sco_etud.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_evaluation_check_abs.py b/app/scodoc/sco_evaluation_check_abs.py
index fe6a5ec5b..bd6b8ded4 100644
--- a/app/scodoc/sco_evaluation_check_abs.py
+++ b/app/scodoc/sco_evaluation_check_abs.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_evaluation_db.py b/app/scodoc/sco_evaluation_db.py
index 2d58b5773..e0668eb85 100644
--- a/app/scodoc/sco_evaluation_db.py
+++ b/app/scodoc/sco_evaluation_db.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_evaluation_edit.py b/app/scodoc/sco_evaluation_edit.py
index ed63817cd..9e0c487f4 100644
--- a/app/scodoc/sco_evaluation_edit.py
+++ b/app/scodoc/sco_evaluation_edit.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_evaluation_recap.py b/app/scodoc/sco_evaluation_recap.py
index a5896ceb5..25042ecc2 100644
--- a/app/scodoc/sco_evaluation_recap.py
+++ b/app/scodoc/sco_evaluation_recap.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/scodoc/sco_evaluations.py b/app/scodoc/sco_evaluations.py
index 8ae20755f..22aa43ebc 100644
--- a/app/scodoc/sco_evaluations.py
+++ b/app/scodoc/sco_evaluations.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_excel.py b/app/scodoc/sco_excel.py
index a336fa1a9..0d4095b6f 100644
--- a/app/scodoc/sco_excel.py
+++ b/app/scodoc/sco_excel.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_exceptions.py b/app/scodoc/sco_exceptions.py
index 4fdc53c93..776dd98d6 100644
--- a/app/scodoc/sco_exceptions.py
+++ b/app/scodoc/sco_exceptions.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_export_results.py b/app/scodoc/sco_export_results.py
index 9a4cee643..d9a89b2b9 100644
--- a/app/scodoc/sco_export_results.py
+++ b/app/scodoc/sco_export_results.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -210,7 +210,7 @@ def get_set_formsemestre_id_dates(start_date, end_date) -> set:
     s = ndb.SimpleDictFetch(
         """SELECT id
         FROM notes_formsemestre
-        WHERE date_debut >= %(start_date)s 
+        WHERE date_debut >= %(start_date)s
         AND date_fin <= %(end_date)s
         AND dept_id = %(dept_id)s
         """,
@@ -335,7 +335,7 @@ _DATE_FORM = """
 
 # ------- debug
 """
-# /opt/scodoc/bin/zopectl debug 
+# /opt/scodoc/bin/zopectl debug
 from debug import *
 from app.scodoc.sco_export_results import *
 _ = go_dept(app, 'RT').Notes
diff --git a/app/scodoc/sco_find_etud.py b/app/scodoc/sco_find_etud.py
index eade74930..579992da1 100644
--- a/app/scodoc/sco_find_etud.py
+++ b/app/scodoc/sco_find_etud.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formation_recap.py b/app/scodoc/sco_formation_recap.py
index 957037c35..fbd72b54c 100644
--- a/app/scodoc/sco_formation_recap.py
+++ b/app/scodoc/sco_formation_recap.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formation_versions.py b/app/scodoc/sco_formation_versions.py
index 8ffcb39c1..8c74ad25e 100644
--- a/app/scodoc/sco_formation_versions.py
+++ b/app/scodoc/sco_formation_versions.py
@@ -4,7 +4,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -110,9 +110,9 @@ def formsemestre_associate_new_version(
             + f"""<p><b>Formation: </b><a class="stdlink" href="{
                 url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation.id)
                 }">{formation.titre} version {formation.version}</a></p>
-            
+
                 <p class="help">Le programme pédagogique ("formation") va être dupliqué
-                pour que vous puissiez le modifier sans affecter les semestres déjà terminés. 
+                pour que vous puissiez le modifier sans affecter les semestres déjà terminés.
                 </p>
                 <p class="help">Veillez à ne pas abuser de cette possibilité, car créer
                 trop de versions de formations va vous compliquer la gestion
@@ -122,7 +122,7 @@ def formsemestre_associate_new_version(
                 <div class="othersemlist">
                     <p>Si vous voulez associer des semestres à la nouvelle
                     version, cochez-les maintenant <br>
-                    (<b>attention&nbsp;: vous ne pourrez pas le faire plus tard car on ne peut pas 
+                    (<b>attention&nbsp;: vous ne pourrez pas le faire plus tard car on ne peut pas
                     changer la formation d'un semestre !</b>):
                     </p>
                     { "".join(H) }
diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py
index e17b4945a..1939d7f1f 100644
--- a/app/scodoc/sco_formations.py
+++ b/app/scodoc/sco_formations.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py
index d01c7af82..6659109d1 100644
--- a/app/scodoc/sco_formsemestre.py
+++ b/app/scodoc/sco_formsemestre.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formsemestre_custommenu.py b/app/scodoc/sco_formsemestre_custommenu.py
index 86c5bb391..485fdcd14 100644
--- a/app/scodoc/sco_formsemestre_custommenu.py
+++ b/app/scodoc/sco_formsemestre_custommenu.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py
index f34ba88b0..b199aa924 100644
--- a/app/scodoc/sco_formsemestre_edit.py
+++ b/app/scodoc/sco_formsemestre_edit.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formsemestre_exterieurs.py b/app/scodoc/sco_formsemestre_exterieurs.py
index de32912f3..22b600af2 100644
--- a/app/scodoc/sco_formsemestre_exterieurs.py
+++ b/app/scodoc/sco_formsemestre_exterieurs.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@
 
 """Saisie et gestion des semestres extérieurs à ScoDoc dans un parcours.
 
-On va créer/gérer des semestres de la même formation que le semestre ScoDoc 
+On va créer/gérer des semestres de la même formation que le semestre ScoDoc
 où est inscrit l'étudiant, leur attribuer la modalité 'EXT'.
 Ces semestres n'auront qu'un seul inscrit !
 """
@@ -302,12 +302,12 @@ def _make_page(etud: Identite, formsemestre: FormSemestre, tf, message="") -> li
         ),
         tf_error_message(message),
         f"""<p><b>{etud.nomprenom}</b> est inscrit{etud.e} à ce semestre extérieur.</p>
-        <p>Voici ses UE enregistrées avec leur notes 
+        <p>Voici ses UE enregistrées avec leur notes
         { "et coefficients" if not formsemestre.formation.is_apc()
         else " (en BUT, les coefficients sont égaux aux ECTS)"}.
         </p>
         """,
-        f"""<p>La moyenne de ce semestre serait: 
+        f"""<p>La moyenne de ce semestre serait:
         <span class="ext_sem_moy"><span class="ext_sem_moy_val">{moy_gen}</span> / 20</span>
         </p>
         """,
@@ -364,7 +364,7 @@ def _ue_form_description(
         select_name = f"valid_{ue.id}"
         menu_code_ue = f"""<select class="ueext_valid_select" name="{select_name}">"""
         cur_code_value = values.get("valid_{ue.id}", False)
-        for (code, explanation) in _UE_VALID_CODES.items():
+        for code, explanation in _UE_VALID_CODES.items():
             if cur_code_value is False:  # pas dans le form, cherche en base
                 validation = ScolarFormSemestreValidation.query.filter_by(
                     ue_id=ue.id, etudid=etud.id, formsemestre_id=formsemestre.id
@@ -404,7 +404,7 @@ def _ue_form_description(
         """
             + (
                 f"""<td class="tf-field tf_field_coef">
-            <input type="text" size="4" name="coef_{ue.id}" 
+            <input type="text" size="4" name="coef_{ue.id}"
             class="{coef_input_class}"
             value="{cur_coef_value}" {coef_disabled}></input>
         </td>"""
diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py
index 887a0625e..b1d73150f 100644
--- a/app/scodoc/sco_formsemestre_inscriptions.py
+++ b/app/scodoc/sco_formsemestre_inscriptions.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py
index 7254fc275..2b89c1f72 100755
--- a/app/scodoc/sco_formsemestre_status.py
+++ b/app/scodoc/sco_formsemestre_status.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py
index 26d9e6c16..d11b334c1 100644
--- a/app/scodoc/sco_formsemestre_validation.py
+++ b/app/scodoc/sco_formsemestre_validation.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_formulas.py b/app/scodoc/sco_formulas.py
index 9a3273a5b..ad61573b1 100644
--- a/app/scodoc/sco_formulas.py
+++ b/app/scodoc/sco_formulas.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py
index 2e05297d7..3e47e1e68 100644
--- a/app/scodoc/sco_groups.py
+++ b/app/scodoc/sco_groups.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_groups_edit.py b/app/scodoc/sco_groups_edit.py
index bb0429eff..a14498ce6 100644
--- a/app/scodoc/sco_groups_edit.py
+++ b/app/scodoc/sco_groups_edit.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_groups_exports.py b/app/scodoc/sco_groups_exports.py
index 232f4cc3c..b8571fb4a 100644
--- a/app/scodoc/sco_groups_exports.py
+++ b/app/scodoc/sco_groups_exports.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py
index 04da7fb1f..aacbae646 100644
--- a/app/scodoc/sco_groups_view.py
+++ b/app/scodoc/sco_groups_view.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_import_etuds.py b/app/scodoc/sco_import_etuds.py
index 4cd7cca58..7107217b3 100644
--- a/app/scodoc/sco_import_etuds.py
+++ b/app/scodoc/sco_import_etuds.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_import_users.py b/app/scodoc/sco_import_users.py
index 1f06f0284..8f0ac7700 100644
--- a/app/scodoc/sco_import_users.py
+++ b/app/scodoc/sco_import_users.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py
index 5a44ddbd7..8a9ef08f8 100644
--- a/app/scodoc/sco_inscr_passage.py
+++ b/app/scodoc/sco_inscr_passage.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -597,7 +597,7 @@ def etuds_select_boxes(
          elems[i].checked=true;
       } else {
          elems[i].checked=false;
-      }      
+      }
     }
     }
     </script>
diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py
index 467808b33..3bf7c0b6a 100644
--- a/app/scodoc/sco_liste_notes.py
+++ b/app/scodoc/sco_liste_notes.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py
index 8f48f7443..e10e6de77 100644
--- a/app/scodoc/sco_logos.py
+++ b/app/scodoc/sco_logos.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_lycee.py b/app/scodoc/sco_lycee.py
index 12af85280..606fabf2a 100644
--- a/app/scodoc/sco_lycee.py
+++ b/app/scodoc/sco_lycee.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -98,7 +98,7 @@ def scodoc_table_etuds_lycees(fmt="html"):
         """<h2 class="formsemestre">Lycées d'origine des %d étudiants (%d semestres)</h2>"""
         % (len(etuds), len(semdepts)),
         t,
-        """<div id="lyc_map_canvas"></div>          
+        """<div id="lyc_map_canvas"></div>
           """,
         js_coords_lycees(etuds_by_lycee),
         html_sco_header.sco_footer(),
@@ -205,7 +205,7 @@ def formsemestre_etuds_lycees(
         """<h2 class="formsemestre">Lycées d'origine des étudiants</h2>""",
         "\n".join(F),
         t,
-        """<div id="lyc_map_canvas"></div>          
+        """<div id="lyc_map_canvas"></div>
           """,
         js_coords_lycees(etuds_by_lycee),
         html_sco_header.sco_footer(),
diff --git a/app/scodoc/sco_modalites.py b/app/scodoc/sco_modalites.py
index 1f79201a3..805d0d48b 100644
--- a/app/scodoc/sco_modalites.py
+++ b/app/scodoc/sco_modalites.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@
 
 La "modalite" est utilisee pour organiser les listes de semestres sur la page d'accueil.
 
-Elle n'est pas utilisée pour les parcours, ni pour rien d'autre 
+Elle n'est pas utilisée pour les parcours, ni pour rien d'autre
 (c'est donc un attribut "cosmétique").
 
 """
diff --git a/app/scodoc/sco_moduleimpl.py b/app/scodoc/sco_moduleimpl.py
index d677a7b0e..197180f1b 100644
--- a/app/scodoc/sco_moduleimpl.py
+++ b/app/scodoc/sco_moduleimpl.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -232,12 +232,12 @@ def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None):
 
 def moduleimpl_listeetuds(moduleimpl_id):  # XXX OBSOLETE
     "retourne liste des etudids inscrits a ce module"
-    req = """SELECT DISTINCT Im.etudid 
-    FROM notes_moduleimpl_inscription Im, 
-    notes_formsemestre_inscription Isem, 
-    notes_moduleimpl M 
-    WHERE Isem.etudid = Im.etudid 
-    and Im.moduleimpl_id = M.id 
+    req = """SELECT DISTINCT Im.etudid
+    FROM notes_moduleimpl_inscription Im,
+    notes_formsemestre_inscription Isem,
+    notes_moduleimpl M
+    WHERE Isem.etudid = Im.etudid
+    and Im.moduleimpl_id = M.id
     and M.id = %(moduleimpl_id)s
     """
     cnx = ndb.GetDBConnexion()
diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py
index 11d8529ac..34b3d3bd6 100644
--- a/app/scodoc/sco_moduleimpl_inscriptions.py
+++ b/app/scodoc/sco_moduleimpl_inscriptions.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -144,7 +144,7 @@ def moduleimpl_inscriptions_edit(moduleimpl_id, etuds=[], submitted=False):
        var cells = elems[i].parentNode.parentNode.getElementsByTagName("td")[partitionIdx].childNodes;
        if (cells.length && cells[0].nodeValue == groupName) {
           elems[i].checked=check;
-       }      
+       }
      }
     }
     }
@@ -475,7 +475,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
                     if can_change:
                         H.append(
                             f"""<div><a class="stdlink" href="{
-                                url_for("notes.etud_inscrit_ue", 
+                                url_for("notes.etud_inscrit_ue",
                                     scodoc_dept=g.scodoc_dept, etudid=etud["etudid"],
                                     formsemestre_id=formsemestre_id, ue_id=ue["ue_id"])
                             }">inscrire à {"" if is_apc else "tous les modules de"} cette UE</a></div>
@@ -799,7 +799,7 @@ def do_etud_inscrit_ue(etudid, formsemestre_id, ue_id):
     cnx = ndb.GetDBConnexion()
     cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
     cursor.execute(
-        """SELECT mi.id 
+        """SELECT mi.id
       FROM notes_moduleimpl mi, notes_modules mod, notes_formsemestre sem
       WHERE sem.id = %(formsemestre_id)s
       AND mi.formsemestre_id = sem.id
diff --git a/app/scodoc/sco_moduleimpl_status.py b/app/scodoc/sco_moduleimpl_status.py
index 67119d5d1..d3f83c287 100644
--- a/app/scodoc/sco_moduleimpl_status.py
+++ b/app/scodoc/sco_moduleimpl_status.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py
index 010273d49..2a23059fe 100644
--- a/app/scodoc/sco_page_etud.py
+++ b/app/scodoc/sco_page_etud.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_pdf.py b/app/scodoc/sco_pdf.py
index b21f62670..02d6af7ae 100755
--- a/app/scodoc/sco_pdf.py
+++ b/app/scodoc/sco_pdf.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_photos.py b/app/scodoc/sco_photos.py
index 3a37124aa..5c4bfbdcf 100755
--- a/app/scodoc/sco_photos.py
+++ b/app/scodoc/sco_photos.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
 """(Nouvelle) (Nouvelle) gestion des photos d'etudiants
 
 Les images sont stockées dans .../var/scodoc/photos
-L'attribut "photo_filename" de la table identite donne le nom du fichier image, 
+L'attribut "photo_filename" de la table identite donne le nom du fichier image,
 sans extension (e.g. "F44/RT_EID31545").
 Toutes les images sont converties en jpg, et stockées dans photo_filename.jpg en taille originale.
 Elles sont aussi réduites en 90 pixels de hauteur, et stockées dans photo_filename.h90.jpg
@@ -37,7 +37,7 @@ Les images sont servies par ScoDoc, via la méthode getphotofile?etudid=xxx
 
 
 ## Historique:
- - jusqu'à novembre 2009, les images étaient stockées dans Zope (ZODB). 
+ - jusqu'à novembre 2009, les images étaient stockées dans Zope (ZODB).
  - jusqu'à v1908, stockées dans .../static/photos (et donc accessibles sans authentification).
  - support for legacy ZODB removed in v1909.
 
diff --git a/app/scodoc/sco_placement.py b/app/scodoc/sco_placement.py
index daaa2f186..db5080981 100644
--- a/app/scodoc/sco_placement.py
+++ b/app/scodoc/sco_placement.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_portal_apogee.py b/app/scodoc/sco_portal_apogee.py
index ae58aa737..bfec3eb52 100644
--- a/app/scodoc/sco_portal_apogee.py
+++ b/app/scodoc/sco_portal_apogee.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_poursuite_dut.py b/app/scodoc/sco_poursuite_dut.py
index 428f60aec..cfb4a2ed9 100644
--- a/app/scodoc/sco_poursuite_dut.py
+++ b/app/scodoc/sco_poursuite_dut.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py
index 08ffa7007..ed126bce7 100644
--- a/app/scodoc/sco_preferences.py
+++ b/app/scodoc/sco_preferences.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_prepajury.py b/app/scodoc/sco_prepajury.py
index ba74b0aa9..4806a0681 100644
--- a/app/scodoc/sco_prepajury.py
+++ b/app/scodoc/sco_prepajury.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_pv_dict.py b/app/scodoc/sco_pv_dict.py
index e4e58ca12..9944417af 100644
--- a/app/scodoc/sco_pv_dict.py
+++ b/app/scodoc/sco_pv_dict.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_pv_forms.py b/app/scodoc/sco_pv_forms.py
index 97d94c5c1..54722be17 100644
--- a/app/scodoc/sco_pv_forms.py
+++ b/app/scodoc/sco_pv_forms.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_pv_lettres_inviduelles.py b/app/scodoc/sco_pv_lettres_inviduelles.py
index 747a0da75..e5bf055c3 100644
--- a/app/scodoc/sco_pv_lettres_inviduelles.py
+++ b/app/scodoc/sco_pv_lettres_inviduelles.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_pv_pdf.py b/app/scodoc/sco_pv_pdf.py
index 797582bd4..bc398128c 100644
--- a/app/scodoc/sco_pv_pdf.py
+++ b/app/scodoc/sco_pv_pdf.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_pv_templates.py b/app/scodoc/sco_pv_templates.py
index da1c963a7..cc22ac402 100644
--- a/app/scodoc/sco_pv_templates.py
+++ b/app/scodoc/sco_pv_templates.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py
index 7ddcbcc9c..d17f37c79 100644
--- a/app/scodoc/sco_recapcomplet.py
+++ b/app/scodoc/sco_recapcomplet.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_report.py b/app/scodoc/sco_report.py
index 4f80b26b8..d532ea2c9 100644
--- a/app/scodoc/sco_report.py
+++ b/app/scodoc/sco_report.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -408,7 +408,7 @@ def formsemestre_report_counts(
         "\n".join(F),
         """<p class="help">Le tableau affiche le nombre d'étudiants de ce semestre dans chacun
           des cas choisis: à l'aide des deux menus, vous pouvez choisir les catégories utilisées
-          pour les lignes et les colonnes. Le <tt>codedecision</tt> est le code de la décision 
+          pour les lignes et les colonnes. Le <tt>codedecision</tt> est le code de la décision
           du jury.
           </p>""",
         html_sco_header.sco_footer(),
diff --git a/app/scodoc/sco_report_but.py b/app/scodoc/sco_report_but.py
index f44cdde6c..5692c3232 100644
--- a/app/scodoc/sco_report_but.py
+++ b/app/scodoc/sco_report_but.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_saisie_notes.py b/app/scodoc/sco_saisie_notes.py
index 642411e19..1cf207d54 100644
--- a/app/scodoc/sco_saisie_notes.py
+++ b/app/scodoc/sco_saisie_notes.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_semset.py b/app/scodoc/sco_semset.py
index 34f940fc4..fba228fe3 100644
--- a/app/scodoc/sco_semset.py
+++ b/app/scodoc/sco_semset.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
 """Gestion des ensembles de semestres:
 
 class SemSet:  un ensemble de semestres d'un département, à exporter ves Apogée. En principe de la meme annee scolaire.
- 
+
  SemSet.annees_scolaires() : les annees scolaires. e.g. [ 2015, 2016 ], ou le plus souvent, une seule: [2016]
  SemSet.list_etapes(): listes des étapes apogee et vdi des semestres (instances de ApoEtapeVDI)
 
@@ -196,7 +196,7 @@ class SemSet(dict):
     def remove(self, formsemestre_id):
         ndb.SimpleQuery(
             """DELETE FROM notes_semset_formsemestre
-            WHERE semset_id=%(semset_id)s 
+            WHERE semset_id=%(semset_id)s
             AND formsemestre_id=%(formsemestre_id)s
             """,
             {"formsemestre_id": formsemestre_id, "semset_id": self.semset_id},
diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py
index da4813f3f..9982dfba1 100644
--- a/app/scodoc/sco_synchro_etuds.py
+++ b/app/scodoc/sco_synchro_etuds.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_tag_module.py b/app/scodoc/sco_tag_module.py
index 809facac0..cf535e3b1 100644
--- a/app/scodoc/sco_tag_module.py
+++ b/app/scodoc/sco_tag_module.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -126,8 +126,8 @@ class ScoTag(object):
         if not r:
             # log("tag %s with %s" % (object_id, self.title))
             cnx = ndb.GetDBConnexion()
-            query = f"""INSERT INTO {self.assoc_table} 
-                (tag_id, {self.obj_colname}) 
+            query = f"""INSERT INTO {self.assoc_table}
+                (tag_id, {self.obj_colname})
                 VALUES"""
             ndb.SimpleQuery(
                 query + " (%(tag_id)s, %(object_id)s)",
@@ -187,7 +187,7 @@ class ModuleTag(ScoTag):
             args["formation_code"] = formation_code
 
             r = ndb.SimpleDictFetch(
-                """SELECT mt.module_id 
+                """SELECT mt.module_id
                 FROM notes_modules_tags mt, notes_modules m, notes_formations f
                 WHERE mt.tag_id = %(tag_id)s
                 AND m.id = mt.module_id
diff --git a/app/scodoc/sco_trombino.py b/app/scodoc/sco_trombino.py
index d5fbdebb1..c197cefd9 100644
--- a/app/scodoc/sco_trombino.py
+++ b/app/scodoc/sco_trombino.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_trombino_doc.py b/app/scodoc/sco_trombino_doc.py
index 7cdbad974..91b573e5a 100644
--- a/app/scodoc/sco_trombino_doc.py
+++ b/app/scodoc/sco_trombino_doc.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/scodoc/sco_trombino_tours.py b/app/scodoc/sco_trombino_tours.py
index a70965363..ddec23492 100644
--- a/app/scodoc/sco_trombino_tours.py
+++ b/app/scodoc/sco_trombino_tours.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_ue_external.py b/app/scodoc/sco_ue_external.py
index 69f6103dc..593d0568b 100644
--- a/app/scodoc/sco_ue_external.py
+++ b/app/scodoc/sco_ue_external.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -208,7 +208,7 @@ def get_external_moduleimpl_id(formsemestre_id: int, ue_id: int) -> int:
         return r[0]["moduleimpl_id"]
     else:
         raise ScoValueError(
-            f"""Aucun module externe ne correspond 
+            f"""Aucun module externe ne correspond
         (formsemestre_id={formsemestre_id}, ue_id={ue_id})"""
         )
 
@@ -241,10 +241,10 @@ def external_ue_create_form(formsemestre_id: int, etudid: int):
             "Ajout d'une UE externe pour %(nomprenom)s" % etud,
             javascripts=["js/sco_ue_external.js"],
         ),
-        """<p class="help">Cette page permet d'indiquer que l'étudiant a suivi une UE 
+        """<p class="help">Cette page permet d'indiquer que l'étudiant a suivi une UE
     dans un autre établissement et qu'elle doit être intégrée dans le semestre courant.<br>
     La note (/20) obtenue par l'étudiant doit toujours être spécifiée.</br>
-    On peut choisir une UE externe existante (dans le menu), ou bien en créer une, qui sera 
+    On peut choisir une UE externe existante (dans le menu), ou bien en créer une, qui sera
     alors ajoutée à la formation.
     </p>
     """,
diff --git a/app/scodoc/sco_undo_notes.py b/app/scodoc/sco_undo_notes.py
index dd1895048..b04ba870c 100644
--- a/app/scodoc/sco_undo_notes.py
+++ b/app/scodoc/sco_undo_notes.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ note = {evaluation_id, etudid, value, date, uid, comment}
 
 Pour une évaluation:
  - notes actuelles: table notes_notes
- - historique: table notes_notes_log 
+ - historique: table notes_notes_log
 
 saisie de notes == saisir ou supprimer une ou plusieurs notes (mêmes date et uid)
 ! tolérance sur les dates (200ms ?)
@@ -179,7 +179,7 @@ def formsemestre_list_saisies_notes(formsemestre_id, fmt="html"):
     """
     formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
     rows = ndb.SimpleDictFetch(
-        """SELECT i.nom, i.prenom, code_nip, n.*, mod.titre, e.description, e.date_debut, 
+        """SELECT i.nom, i.prenom, code_nip, n.*, mod.titre, e.description, e.date_debut,
                     u.user_name, e.id as evaluation_id
         FROM notes_notes n, notes_evaluation e, notes_moduleimpl mi,
         notes_modules mod, identite i, "user" u
@@ -257,7 +257,7 @@ def get_note_history(evaluation_id, etudid, fmt=""):
     cursor.execute(
         """
     SELECT * FROM notes_notes
-    WHERE evaluation_id=%(evaluation_id)s AND etudid=%(etudid)s 
+    WHERE evaluation_id=%(evaluation_id)s AND etudid=%(etudid)s
     """,
         {"evaluation_id": evaluation_id, "etudid": etudid},
     )
@@ -267,7 +267,7 @@ def get_note_history(evaluation_id, etudid, fmt=""):
     cursor.execute(
         """
     SELECT * FROM notes_notes_log
-    WHERE evaluation_id=%(evaluation_id)s AND etudid=%(etudid)s 
+    WHERE evaluation_id=%(evaluation_id)s AND etudid=%(etudid)s
     ORDER BY date DESC""",
         {"evaluation_id": evaluation_id, "etudid": etudid},
     )
diff --git a/app/scodoc/sco_up_to_date.py b/app/scodoc/sco_up_to_date.py
index 464a5ba09..4e93a293b 100644
--- a/app/scodoc/sco_up_to_date.py
+++ b/app/scodoc/sco_up_to_date.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -54,7 +54,7 @@ def is_up_to_date() -> str:
         current_app.logger.debug("is_up_to_date: %s", diag)
         return f"""<div>Attention: installation de {SCONAME} non fonctionnelle.</div>
         <div>Détails: pas de connexion à {scu.SCO_WEBSITE}.
-        Vérifier paramètrages réseau, 
+        Vérifier paramètrages réseau,
         <a href="https://scodoc.org/GuideInstallDebian11/#informations-sur-les-flux-reseau">voir la documentation</a>.
         </div>
         """
@@ -62,7 +62,7 @@ def is_up_to_date() -> str:
         current_app.logger.debug("is_up_to_date: %s", diag)
         return f"""<div>Attention: installation de {SCONAME} non fonctionnelle.</div>
         <div>Détails: erreur inconnue lors de la connexion à {scu.SCO_WEBSITE}.
-        Vérifier paramètrages réseau, 
+        Vérifier paramètrages réseau,
         <a href="https://scodoc.org/GuideInstallDebian11/#informations-sur-les-flux-reseau">voir la documentation</a>.
         </div>
         """
diff --git a/app/scodoc/sco_users.py b/app/scodoc/sco_users.py
index 76f3f3a87..c896c2af7 100644
--- a/app/scodoc/sco_users.py
+++ b/app/scodoc/sco_users.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index 277f188c6..7f23f8465 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_vdi.py b/app/scodoc/sco_vdi.py
index 47d77c21d..9b8e50fe7 100644
--- a/app/scodoc/sco_vdi.py
+++ b/app/scodoc/sco_vdi.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/scodoc/sco_xml.py b/app/scodoc/sco_xml.py
index 8634b8a4f..852951560 100644
--- a/app/scodoc/sco_xml.py
+++ b/app/scodoc/sco_xml.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -116,7 +116,7 @@ def _dictlist2xml(dictlist, root=None, tagname=None, quote=False):
                 elem.set(k, d_scalar[k])
             d_list = dict([(k, v) for (k, v) in d.items() if isinstance(v, list)])
             if d_list:
-                for (k, v) in d_list.items():
+                for k, v in d_list.items():
                     _dictlist2xml(v, tagname=k, root=elem, quote=quote)
     return root
 
diff --git a/app/scodoc/scolog.py b/app/scodoc/scolog.py
index a3b07f05f..f972d3b4b 100644
--- a/app/scodoc/scolog.py
+++ b/app/scodoc/scolog.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/tables/__init__.py b/app/tables/__init__.py
index 59fca9d76..ad6ee4e5c 100644
--- a/app/tables/__init__.py
+++ b/app/tables/__init__.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/tables/jury_recap.py b/app/tables/jury_recap.py
index aca249139..abe11e740 100644
--- a/app/tables/jury_recap.py
+++ b/app/tables/jury_recap.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/tables/list_etuds.py b/app/tables/list_etuds.py
index bd3c5ff9d..463295d93 100644
--- a/app/tables/list_etuds.py
+++ b/app/tables/list_etuds.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/tables/recap.py b/app/tables/recap.py
index df9247bcf..ff8c1eb76 100644
--- a/app/tables/recap.py
+++ b/app/tables/recap.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
@@ -523,7 +523,7 @@ class TableRecap(tb.Table):
             if self.is_empty()
             else super().html(
                 extra_classes=[
-                    "table_recap", 
+                    "table_recap",
                     "apc" if self.res.formsemestre.formation.is_apc() else "classic",
                     "jury" if self.mode_jury else "",
                     "with_evaluations" if self.include_evaluations else "",
diff --git a/app/tables/table_builder.py b/app/tables/table_builder.py
index aea76c0d5..d47847044 100644
--- a/app/tables/table_builder.py
+++ b/app/tables/table_builder.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/tables/visu_assiduites.py b/app/tables/visu_assiduites.py
index 304ab405e..0b7ee3fc5 100644
--- a/app/tables/visu_assiduites.py
+++ b/app/tables/visu_assiduites.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/app/views/absences.py b/app/views/absences.py
index fe9cc8f79..408605bc6 100644
--- a/app/views/absences.py
+++ b/app/views/absences.py
@@ -3,7 +3,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -393,9 +393,9 @@ def process_billet_absence_form(billet_id: int):
                 <em>Vérifiez le justificatif avant d'enregistrer.</em></p>"""
             )
         F = f"""<p><a class="stdlink" href="{
-                url_for("absences.delete_billets_absence", 
+                url_for("absences.delete_billets_absence",
                     scodoc_dept=g.scodoc_dept, billet_id=billet_id)
-            }">Supprimer ce billet</a> 
+            }">Supprimer ce billet</a>
             (utiliser en cas d'erreur, par ex. billet en double)
             </p>
             <p><a class="stdlink" href="{
diff --git a/app/views/assiduites.py b/app/views/assiduites.py
index 0f8e8a3c2..44ca2ba8a 100644
--- a/app/views/assiduites.py
+++ b/app/views/assiduites.py
@@ -3,7 +3,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/views/but_formation.py b/app/views/but_formation.py
index 7af20d2a7..e4bd83670 100644
--- a/app/views/but_formation.py
+++ b/app/views/but_formation.py
@@ -2,7 +2,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/views/notes.py b/app/views/notes.py
index 7f21b2bd6..08086b444 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/views/notes_formsemestre.py b/app/views/notes_formsemestre.py
index 1373f63fb..b683d0a22 100644
--- a/app/views/notes_formsemestre.py
+++ b/app/views/notes_formsemestre.py
@@ -4,7 +4,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/views/pn_modules.py b/app/views/pn_modules.py
index fdf6542ec..5ec9d2081 100644
--- a/app/views/pn_modules.py
+++ b/app/views/pn_modules.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -214,7 +214,7 @@ def edit_modules_ue_coefs():
         {lockicon}
         </h2>
         """,
-        """<span class="warning">Formation verrouilée car un ou plusieurs 
+        """<span class="warning">Formation verrouilée car un ou plusieurs
         semestres verrouillés l'utilisent.
         </span>"""
         if locked
diff --git a/app/views/scodoc.py b/app/views/scodoc.py
index bd2a642ef..8a8b5319c 100644
--- a/app/views/scodoc.py
+++ b/app/views/scodoc.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/views/scolar.py b/app/views/scolar.py
index 78c693052..7be21ee04 100644
--- a/app/views/scolar.py
+++ b/app/views/scolar.py
@@ -3,7 +3,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/app/views/users.py b/app/views/users.py
index 0b4d6bed4..03785d759 100644
--- a/app/views/users.py
+++ b/app/views/users.py
@@ -5,7 +5,7 @@
 #
 # ScoDoc
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/misc/csv2rules.py b/misc/csv2rules.py
index 6db81965f..d60fd998d 100755
--- a/misc/csv2rules.py
+++ b/misc/csv2rules.py
@@ -6,7 +6,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@ HEAD = """# -*- coding: utf-8 -*-
 # Generated by csv2rules.py    *** DO NOT EDIT ***
 #
 # Command: %s %s
-# 
+#
 from codes_cursus import (
     DUTRule,
     ADC,
diff --git a/misc/geolocalize_lycees.py b/misc/geolocalize_lycees.py
index ab16cd2db..5e4f9d6b3 100644
--- a/misc/geolocalize_lycees.py
+++ b/misc/geolocalize_lycees.py
@@ -5,7 +5,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -57,7 +57,7 @@ for line in inf:
             place, (lat, lng) = g.geocode(address + ' France', exactly_one=False)[0]
         except:
             place, (lat, lng) = 'NOT FOUND', (0.,0.)
-    print "%s: %.5f, %.5f" % (address, lat, lng)  
+    print "%s: %.5f, %.5f" % (address, lat, lng)
     out.write( line.strip() + ';%s;%s\n' % (lat,lng) )
     time.sleep(0.11) # Google API Rate limit of 10 requests per second.
 
diff --git a/sco_version.py b/sco_version.py
index 88104d881..d7fb73ab8 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -1,7 +1,7 @@
 # -*- mode: python -*-
 # -*- coding: utf-8 -*-
 
-SCOVERSION = "9.6.72"
+SCOVERSION = "9.6.73"
 
 SCONAME = "ScoDoc"
 
diff --git a/tests/unit/test_apogee_csv.py b/tests/unit/test_apogee_csv.py
index ae8b22d55..eb4b31bb8 100644
--- a/tests/unit/test_apogee_csv.py
+++ b/tests/unit/test_apogee_csv.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/tests/unit/test_apogee_export.py b/tests/unit/test_apogee_export.py
index 4b84f0a86..90e66ce1c 100644
--- a/tests/unit/test_apogee_export.py
+++ b/tests/unit/test_apogee_export.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/tests/unit/test_but_jury.py b/tests/unit/test_but_jury.py
index 0eb2458af..ca61d2c60 100644
--- a/tests/unit/test_but_jury.py
+++ b/tests/unit/test_but_jury.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/tests/unit/yaml_setup.py b/tests/unit/yaml_setup.py
index 6140537ce..142a3c6ec 100644
--- a/tests/unit/yaml_setup.py
+++ b/tests/unit/yaml_setup.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/tests/unit/yaml_setup_but.py b/tests/unit/yaml_setup_but.py
index 0198fcf65..a0bbff8ea 100644
--- a/tests/unit/yaml_setup_but.py
+++ b/tests/unit/yaml_setup_but.py
@@ -1,6 +1,6 @@
 ##############################################################################
 # ScoDoc
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 # See LICENSE
 ##############################################################################
 
diff --git a/tools/anonymize_db.py b/tools/anonymize_db.py
index cc7a5a042..e537d43f0 100755
--- a/tools/anonymize_db.py
+++ b/tools/anonymize_db.py
@@ -6,7 +6,7 @@
 #
 # Gestion scolarite IUT
 #
-# Copyright (c) 1999 - 2023 Emmanuel Viennet.  All rights reserved.
+# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -70,8 +70,8 @@ ANONYMIZED_FIELDS = {
     "identite.nom": anonymize_name,
     "identite.prenom": anonymize_name,
     "identite.nom_usuel": anonymize_null,
-    "identite.civilite_etat_civil" : anonymize_null,
-    "identite.prenom_etat_civil" : anonymize_null,
+    "identite.civilite_etat_civil": anonymize_null,
+    "identite.prenom_etat_civil": anonymize_null,
     "identite.date_naissance": anonymize_date,
     "identite.lieu_naissance": anonymize_question_str,
     "identite.dept_naissance": anonymize_question_str,
-- 
GitLab