From 8f02f16442d94dfaeee13ea03a0220af68ceacf1 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 13 Feb 2021 17:28:55 +0100 Subject: [PATCH] Handling of neutral genders. Closes #65 --- ImportScolars.py | 10 +-- ZScolar.py | 18 ++-- config/postupgrade-db.py | 15 ++++ html_sidebar.py | 2 +- misc/createtables.sql | 2 +- misc/format_import_etudiants.txt | 2 +- notes_table.py | 12 +-- pe_avislatex.py | 12 +-- pe_jurype.py | 8 +- pe_tools.py | 2 +- sco_bulletins_json.py | 4 +- sco_bulletins_xml.py | 3 +- sco_debouche.py | 6 +- sco_excel.py | 2 +- sco_export_results.py | 6 +- sco_find_etud.py | 6 +- sco_groups.py | 25 +++--- sco_groups_view.py | 5 +- sco_inscr_passage.py | 2 +- sco_lycee.py | 4 +- sco_poursuite_dut.py | 4 +- sco_prepajury.py | 4 +- sco_pvjury.py | 1 - sco_recapcomplet.py | 3 +- sco_report.py | 136 ++++++++++++++++++++----------- sco_synchro_etuds.py | 28 +++---- sco_trombino.py | 16 +--- sco_utils.py | 4 +- scolars.py | 76 ++++++++++------- scotests/demo/demo_reset_noms.py | 12 +-- scotests/demo/gen_nomprenoms.py | 15 ++-- scotests/demo/prenoms-x.txt | 10 +++ scotests/sco_fake_gen.py | 25 +++--- 33 files changed, 281 insertions(+), 199 deletions(-) create mode 100644 scotests/demo/prenoms-x.txt diff --git a/ImportScolars.py b/ImportScolars.py index 8e06e93c5c..c264e9d4cf 100644 --- a/ImportScolars.py +++ b/ImportScolars.py @@ -368,16 +368,16 @@ def scolars_import_excel_file( # xxx Ad-hoc checks (should be in format description) if scu.strlower(titleslist[i]) == "sexe": try: - val = scolars.normalize_sexe(val) + val = scolars.input_civilite(val) except: raise ScoValueError( - "valeur invalide pour 'SEXE' (doit etre 'M' ou 'MME' ou 'H' ou 'F', pas '%s') ligne %d, colonne %s" + "valeur invalide pour 'SEXE' (doit etre 'M', 'F', ou 'MME', 'H', 'X' ou vide, mais pas '%s') ligne %d, colonne %s" % (val, linenum, titleslist[i]) ) # Excel date conversion: if scu.strlower(titleslist[i]) == "date_naissance": if val: - if re.match("^[0-9]*\.?[0-9]*$", str(val)): + if re.match(r"^[0-9]*\.?[0-9]*$", str(val)): val = sco_excel.xldate_as_datetime(float(val)) # INE if ( @@ -515,11 +515,11 @@ def _import_one_student( # Admissions args["etudid"] = etudid args["annee"] = annee_courante - adm_id = scolars.admission_create(cnx, args) + _ = scolars.admission_create(cnx, args) # Adresse args["typeadresse"] = "domicile" args["description"] = "(infos admission)" - adresse_id = scolars.adresse_create(cnx, args) + _ = scolars.adresse_create(cnx, args) # Inscription au semestre args["etat"] = "I" # etat insc. semestre if formsemestre_id: diff --git a/ZScolar.py b/ZScolar.py index f61d6a4328..6cc176cce6 100644 --- a/ZScolar.py +++ b/ZScolar.py @@ -99,7 +99,7 @@ import sco_formations from scolars import ( format_nom, format_prenom, - format_sexe, + format_civilite, format_lycee, format_lycee_from_code, ) @@ -916,7 +916,8 @@ REQUEST.URL0=%s
"nom": "?", "nom_usuel": "", "prenom": "?", - "sexe": "?", + "civilite": "?", + "sexe": "?", # for backward compat "email": "?", "emailperso": "", "error": "code etudiant inconnu", @@ -935,7 +936,6 @@ REQUEST.URL0=%s
"nom", "nom_usuel", "prenom", - "sexe", "nomprenom", "email", "emailperso", @@ -956,6 +956,10 @@ REQUEST.URL0=%s
"date_naissance_iso", ): d[a] = scu.quote_xml_attr(etud[a]) + d["civilite"] = scu.quote_xml_attr( + etud["civilite_str"] + ) # exception: ne sort pas la civilite brute + d["sexe"] = d["civilite"] # backward compat pour anciens clients d["photo_url"] = scu.quote_xml_attr(sco_photos.etud_photo_url(self, etud)) sem = etud["cursem"] @@ -1750,12 +1754,12 @@ REQUEST.URL0=%s
}, ), ( - "sexe", + "civilite", { "input_type": "menu", - "labels": ["H", "F"], - "allowed_values": ["MR", "MME"], - "title": "Genre", + "labels": ["Homme", "Femme", "Autre/neutre"], + "allowed_values": ["M", "F", "X"], + "title": "Civilité", }, ), ( diff --git a/config/postupgrade-db.py b/config/postupgrade-db.py index 29f2c2ca60..e423984cdd 100755 --- a/config/postupgrade-db.py +++ b/config/postupgrade-db.py @@ -1070,6 +1070,21 @@ for dept in get_depts(): "etape", ["alter table notes_formsemestre_inscription add column etape text"], ) + # Migre identite.sexe vers identite.civilite: normalise valeurs: M, F, X + check_field( + cnx, + "identite", + "civilite", + [ + "UPDATE identite set sexe='M' where upper(sexe) = 'M' or upper(sexe) = 'M.' or upper(sexe) = 'MR' or upper(sexe) = 'H'", + "UPDATE identite set sexe='F' where upper(sexe) = 'F' or upper(sexe) = 'MME' or upper(sexe) = 'MLLE' or upper(sexe) = 'MELLE' or upper(sexe) = 'MLLE.' or upper(sexe) = 'F'", + "UPDATE identite set sexe='X' where sexe is NULL", + "ALTER TABLE identite RENAME COLUMN sexe TO civilite", + "ALTER TABLE identite ALTER COLUMN civilite SET NOT NULL", + "ALTER TABLE identite ADD CONSTRAINT civchk CHECK (civilite IN ('M', 'F', 'X'))", + ], + ) + # Add here actions to performs after upgrades: cnx.commit() cnx.close() diff --git a/html_sidebar.py b/html_sidebar.py index 7c50d5c3b7..e9e022fcb9 100644 --- a/html_sidebar.py +++ b/html_sidebar.py @@ -103,7 +103,7 @@ def sidebar(context, REQUEST=None): # compte les absences du semestre en cours H.append( """

- %(sexe)s %(nom_disp)s + %(civilite_str)s %(nom_disp)s

Absences""" % params diff --git a/misc/createtables.sql b/misc/createtables.sql index bb809dfe9c..bc937d0d27 100644 --- a/misc/createtables.sql +++ b/misc/createtables.sql @@ -49,7 +49,7 @@ CREATE TABLE identite ( etudid text DEFAULT notes_newid_etud('EID'::text) UNIQUE NOT NULL, nom text, prenom text, - sexe text, + civilite text NOT NULL CHECK (civilite IN ('M', 'F', 'X')), date_naissance date, -- new: date en texte lieu_naissance text, dept_naissance text, diff --git a/misc/format_import_etudiants.txt b/misc/format_import_etudiants.txt index 365a713684..658c6d2cac 100644 --- a/misc/format_import_etudiants.txt +++ b/misc/format_import_etudiants.txt @@ -8,7 +8,7 @@ Code_INE; text; identite; 1; code INE;INE nom; text; identite; 0; nom de l'etudiant; nom_usuel; text; identite; 1; nom usuel (si different); prenom; text; identite; 0; prenom de l'etudiant -sexe (H ou F); text; identite; 0; sexe ('H' ou 'F');sexe;genre +civilite; text; identite; 1; sexe ('M', 'F', 'X');sexe;genre date_naissance;text;identite; 1; date de naissance (jj/mm/aaaa) lieu_naissance;text;identite; 1; lieu de naissance nationalite; text; identite; 1; nationalite diff --git a/notes_table.py b/notes_table.py index 1ba2810be3..38de3147ed 100644 --- a/notes_table.py +++ b/notes_table.py @@ -372,7 +372,9 @@ class NotesTable: def get_sexnom(self, etudid): "M. DUPONT" etud = self.identdict[etudid] - return etud["sexe"] + " " + scu.strupper(etud["nom_usuel"] or etud["nom"]) + return ( + etud["civilite_str"] + " " + scu.strupper(etud["nom_usuel"] or etud["nom"]) + ) def get_nom_short(self, etudid): "formatte nom d'un etud (pour table recap)" @@ -391,13 +393,7 @@ class NotesTable: def get_nom_long(self, etudid): "formatte nom d'un etud: M. Pierre DUPONT" etud = self.identdict[etudid] - return " ".join( - [ - scolars.format_sexe(etud["sexe"]), - scolars.format_prenom(etud["prenom"]), - scolars.format_nom(etud["nom_usuel"] or etud["nom"]), - ] - ) + return scolars.format_nomprenom(etud) def get_displayed_etud_code(self, etudid): 'code à afficher sur les listings "anonymes"' diff --git a/pe_avislatex.py b/pe_avislatex.py index fdb2644c1f..a882a43e46 100644 --- a/pe_avislatex.py +++ b/pe_avislatex.py @@ -213,7 +213,7 @@ def get_code_latex_avis_etudiant( elif tag_latex == u"bilanParTag": valeur = get_bilanParTag(donnees_etudiant) - # Les tags "simples": par ex. nom, prenom, sexe, ... + # Les tags "simples": par ex. nom, prenom, civilite, ... else: if tag_latex in donnees_etudiant: valeur = donnees_etudiant[tag_latex].decode(scu.SCO_ENCODING) @@ -410,7 +410,7 @@ def get_avis_poursuite_par_etudiant( if pe_tools.PE_DEBUG: pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + etudid) - sexe = jury.syntheseJury[etudid]["sexe"].decode(scu.SCO_ENCODING) + civilite_str = jury.syntheseJury[etudid]["civilite_str"].decode(scu.SCO_ENCODING) nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-").decode(scu.SCO_ENCODING) prenom = ( jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(scu.SCO_ENCODING) @@ -429,7 +429,9 @@ def get_avis_poursuite_par_etudiant( # Entete (commentaire) - contenu_latex = u"%% ---- Etudiant: " + sexe + " " + nom + " " + prenom + u"\n" + contenu_latex = ( + u"%% ---- Etudiant: " + civilite_str + " " + nom + " " + prenom + u"\n" + ) # les annnotations annotationPE = get_annotation_PE( @@ -502,7 +504,7 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe): [syntheseJury[etudid]["nbSemestres"] for etudid in etudids] ) # le nombre de semestre le + grand - infos = ["sexe", "nom", "prenom", "age", "nbSemestres"] + infos = ["civilite", "nom", "prenom", "age", "nbSemestres"] entete = ["etudid"] entete.extend(infos) entete.extend(["P%d" % i for i in range(1, maxParcours + 1)]) # ajout du parcours @@ -518,7 +520,7 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe): # Les info générales: row = { "etudid": etudid, - "sexe": e["sexe"], + "civilite": e["civilite"], "nom": e["nom"], "prenom": e["prenom"], "age": e["age"], diff --git a/pe_jurype.py b/pe_jurype.py index fe43e7d1b2..0b0fad771a 100644 --- a/pe_jurype.py +++ b/pe_jurype.py @@ -85,7 +85,7 @@ class JuryPE: - context : le contexte Zope - juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives + celles des semestres valides à prendre en compte permettant le calcul des moyennes ... - {'etudid : { 'nom', 'prenom', 'sexe', 'diplome', '', }} + {'etudid : { 'nom', 'prenom', 'civilite', 'diplome', '', }} Rq: il contient à la fois les étudiants qui vont être diplomés à la date prévue et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif @@ -812,7 +812,7 @@ class JuryPE: self.syntheseJury[etudid] = { "nom": etudinfo["nom"], "prenom": etudinfo["prenom"], - "sexe": etudinfo["sexe"], + "civilite": etudinfo["civilite"], "age": str(pe_tools.calcul_age(etudinfo["date_naissance"])), "lycee": etudinfo["nomlycee"] + ( @@ -985,7 +985,7 @@ class JuryPE: [self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids] ) - infos = ["sexe", "nom", "prenom", "age", "nbSemestres"] + infos = ["civilite", "nom", "prenom", "age", "nbSemestres"] entete = ["etudid"] entete.extend(infos) entete.extend(["P%d" % i for i in range(1, maxParcours + 1)]) @@ -1036,7 +1036,7 @@ class JuryPE: # Les info générales: row = { "etudid": etudid, - "sexe": e["sexe"], + "civilite": e["civilite"], "nom": e["nom"], "prenom": e["prenom"], "age": e["age"], diff --git a/pe_tools.py b/pe_tools.py index ecaebaaeb8..5dad00994c 100644 --- a/pe_tools.py +++ b/pe_tools.py @@ -217,7 +217,7 @@ JURY_SYNTHESE_POUR_DEBUG = { "EID1810": { "nom": "ROUX", "entree": "2016", - "sexe": "M.", + "civilite_str": "M.", "promo": 2016, "S2": { "groupe": { diff --git a/sco_bulletins_json.py b/sco_bulletins_json.py index 9a86c5832a..d21c958673 100644 --- a/sco_bulletins_json.py +++ b/sco_bulletins_json.py @@ -124,14 +124,14 @@ def formsemestre_bulletinetud_published_dict( code_ine=etudinfo["code_ine"], nom=scu.quote_xml_attr(etudinfo["nom"]), prenom=scu.quote_xml_attr(etudinfo["prenom"]), - sexe=scu.quote_xml_attr(etudinfo["sexe"]), + civilite=scu.quote_xml_attr(etudinfo["civilite_str"]), photo_url=scu.quote_xml_attr( sco_photos.etud_photo_url(context, etudinfo, fast=True) ), email=scu.quote_xml_attr(etudinfo["email"]), emailperso=scu.quote_xml_attr(etudinfo["emailperso"]), ) - + d["etudiant"]["sexe"] = d["etudiant"]["civilite"] # backward compat for our clients # Disponible pour publication ? if not published: return d # stop ! diff --git a/sco_bulletins_xml.py b/sco_bulletins_xml.py index 95d9454cba..8d9aaecb14 100644 --- a/sco_bulletins_xml.py +++ b/sco_bulletins_xml.py @@ -107,7 +107,8 @@ def make_xml_formsemestre_bulletinetud( code_ine=etudinfo["code_ine"], nom=scu.quote_xml_attr(etudinfo["nom"]), prenom=scu.quote_xml_attr(etudinfo["prenom"]), - sexe=scu.quote_xml_attr(etudinfo["sexe"]), + civilite=scu.quote_xml_attr(etudinfo["civilite_str"]), + sexe=scu.quote_xml_attr(etudinfo["civilite_str"]), # compat photo_url=scu.quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)), email=scu.quote_xml_attr(etudinfo["email"]), emailperso=scu.quote_xml_attr(etudinfo["emailperso"]), diff --git a/sco_debouche.py b/sco_debouche.py index ad3c653053..8641d68dc0 100644 --- a/sco_debouche.py +++ b/sco_debouche.py @@ -115,7 +115,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True): ) row = { "etudid": etudid, - "sexe": etud["sexe"], + "civilite": etud["civilite"], "nom": etud["nom"], "prenom": etud["prenom"], "_nom_target": "ficheEtud?etudid=" + etud["etudid"], @@ -154,7 +154,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True): L.sort(key=lambda x: x["sem_ident"]) titles = { - "sexe": "", + "civilite": "", "nom": "Nom", "prenom": "Prénom", "semestre": "Dernier semestre", @@ -170,7 +170,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True): "semestre", "semestre_id", "periode", - "sexe", + "civilite", "nom", "prenom", "moy", diff --git a/sco_excel.py b/sco_excel.py index 1e81aa43c2..d4a2b20baa 100644 --- a/sco_excel.py +++ b/sco_excel.py @@ -616,7 +616,7 @@ def Excel_feuille_listeappel( li += 1 ws0.write(li, 0, n, style1b) nomprenom = ( - t["sexe"] + t["civilite_str"] + " " + t["nom"] + " " diff --git a/sco_export_results.py b/sco_export_results.py index 223d3eb21c..992c802ae3 100644 --- a/sco_export_results.py +++ b/sco_export_results.py @@ -122,7 +122,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos): "code_nip": "NIP", "nom": "Nom", "prenom": "Prénom", - "sexe": "Civ.", + "civilite_str": "Civ.", "nom_usuel": "Nom usuel", "bac": "Bac", "parcours": "Parcours", @@ -133,7 +133,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos): "periode", "sid", "code_nip", - "sexe", + "civilite_str", "nom", # 'nom_usuel', # inutile ? "prenom", @@ -171,7 +171,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos): "nom": etud["nom"], "nom_usuel": etud["nom_usuel"], "prenom": etud["prenom"], - "sexe": etud["sexe"], + "civilite_str": etud["civilite_str"], "_nom_target": "%s/ficheEtud?etudid=%s" % (context.ScoURL(), etudid), "_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid, "bac": bac.abbrev(), diff --git a/sco_find_etud.py b/sco_find_etud.py index 25d76dc083..0af146e217 100644 --- a/sco_find_etud.py +++ b/sco_find_etud.py @@ -384,7 +384,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"): Seuls les départements accessibles par l'utilisateur sont cherchés. Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc: - code_nip, nom, prenom, sexe, dept, formsemestre_id, date_debut_sem, date_fin_sem + code_nip, nom, prenom, civilite_str, dept, formsemestre_id, date_debut_sem, date_fin_sem """ result, _ = search_etud_in_accessible_depts( context, code_nip=code_nip, REQUEST=REQUEST @@ -401,7 +401,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"): "dept": DeptId, "etudid": e["etudid"], "code_nip": e["code_nip"], - "sexe": e["sexe"], + "civilite_str": e["civilite_str"], "nom": e["nom"], "prenom": e["prenom"], "formsemestre_id": sem["formsemestre_id"], @@ -414,7 +414,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"): "dept", "etudid", "code_nip", - "sexe", + "civilite_str", "nom", "prenom", "formsemestre_id", diff --git a/sco_groups.py b/sco_groups.py index c4746f6087..aa79d05fdd 100644 --- a/sco_groups.py +++ b/sco_groups.py @@ -473,7 +473,8 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG doc._push() doc.etud( etudid=e["etudid"], - sexe=scolars.format_sexe(etud["sexe"]), + civilite=etud["civilite_str"], + sexe=etud["civilite_str"], # compat nom=scolars.format_nom(etud["nom"]), prenom=scolars.format_prenom(etud["prenom"]), origin=comp_origin(etud, sem), @@ -497,7 +498,7 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG doc._push() doc.etud( etudid=etud["etudid"], - sexe=scolars.format_sexe(etud["sexe"]), + sexe=etud["civilite_str"], nom=scolars.format_nom(etud["nom"]), prenom=scolars.format_prenom(etud["prenom"]), origin=comp_origin(etud, sem), @@ -1255,26 +1256,26 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None): context.Notes, formsemestre_id ) # > identdict identdict = nt.identdict - # build: { sexe : liste etudids trie par niveau croissant } - sexes = sets.Set([x["sexe"] for x in identdict.values()]) + # build: { civilite : liste etudids trie par niveau croissant } + civilites = sets.Set([x["civilite"] for x in identdict.values()]) listes = {} - for sexe in sexes: - listes[sexe] = [ + for civilite in civilites: + listes[civilite] = [ (get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"]) for x in identdict.values() - if x["sexe"] == sexe + if x["civilite"] == civilite ] - listes[sexe].sort() - log("listes[%s] = %s" % (sexe, listes[sexe])) + listes[civilite].sort() + log("listes[%s] = %s" % (civilite, listes[civilite])) # affect aux groupes: n = len(identdict) igroup = 0 nbgroups = len(group_ids) while n > 0: - for sexe in sexes: - if len(listes[sexe]): + for civilite in civilites: + if len(listes[civilite]): n -= 1 - etudid = listes[sexe].pop()[1] + etudid = listes[civilite].pop()[1] group_id = group_ids[igroup] igroup = (igroup + 1) % nbgroups change_etud_group_in_partition( diff --git a/sco_groups_view.py b/sco_groups_view.py index f3cafcbbe1..627a7c489c 100644 --- a/sco_groups_view.py +++ b/sco_groups_view.py @@ -464,8 +464,9 @@ def groups_table( % (with_paiement, with_archives, with_annotations) ) # - columns_ids = ["nom_disp", "prenom"] # colonnes a inclure + columns_ids = ["civilite_str", "nom_disp", "prenom"] # colonnes a inclure titles = { + "civilite_str": "Civ.", "nom_disp": "Nom", "prenom": "Prénom", "email": "Mail", @@ -733,7 +734,7 @@ def groups_table( "etudid", "code_nip", "etat", - "sexe", + "civilite_str", "nom", "nom_usuel", "prenom", diff --git a/sco_inscr_passage.py b/sco_inscr_passage.py index f746238e5a..e5bdd1c4f4 100644 --- a/sco_inscr_passage.py +++ b/sco_inscr_passage.py @@ -611,7 +611,7 @@ def etuds_select_boxes( def etuds_select_box_xls(context, src_cat): "export a box to excel" etuds = src_cat["etuds"] - columns_ids = ["etudid", "sexe", "nom", "prenom", "etape"] + columns_ids = ["etudid", "civilite_str", "nom", "prenom", "etape"] titles = {x: x for x in columns_ids} # Ajoute colonne paiement inscription diff --git a/sco_lycee.py b/sco_lycee.py index 8d25650e13..0b3fbf9335 100644 --- a/sco_lycee.py +++ b/sco_lycee.py @@ -128,7 +128,7 @@ def _table_etuds_lycees( else: L = etuds columns_ids = ( - "sexe", + "civilite_str", "nom", "prenom", "codelycee", @@ -148,7 +148,7 @@ def _table_etuds_lycees( rows=L, titles={ "nbetuds": "Nb d'étudiants", - "sexe": "", + "civilite_str": "", "nom": "Nom", "prenom": "Prénom", "etudid": "etudid", diff --git a/sco_poursuite_dut.py b/sco_poursuite_dut.py index 97c3a14a1b..a2fdc2fe9a 100644 --- a/sco_poursuite_dut.py +++ b/sco_poursuite_dut.py @@ -44,7 +44,7 @@ import VERSION def etud_get_poursuite_info(context, sem, etud): """{ 'nom' : ..., 'semlist' : [ { 'semestre_id': , 'moy' : ... }, {}, ...] }""" I = {} - I.update(etud) # copie nom, prenom, sexe, ... + I.update(etud) # copie nom, prenom, civilite, ... # Now add each semester, starting from the first one semlist = [] @@ -174,7 +174,7 @@ def formsemestre_poursuite_report( infos.append(info) # column_ids = ( - ("sexe", "nom", "prenom", "annee", "date_naissance") + ("civilite_str", "nom", "prenom", "annee", "date_naissance") + tuple(ids) + ("debouche",) ) diff --git a/sco_prepajury.py b/sco_prepajury.py index 4845defc40..82e60819b3 100644 --- a/sco_prepajury.py +++ b/sco_prepajury.py @@ -37,7 +37,7 @@ import sco_excel import sco_formsemestre import sco_parcours_dut import sco_codes_parcours -from scolars import format_nom, format_prenom, format_sexe, format_lycee +from scolars import format_nom, format_prenom, format_civilite, format_lycee from sco_abs import getAbsSemEtud import VERSION @@ -229,7 +229,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST): l.append(etud["code_ine"]) l += [ etudid, - format_sexe(etud["sexe"]), + etud["civilite_str"], format_nom(etud["nom"]), format_prenom(etud["prenom"]), etud["date_naissance"], diff --git a/sco_pvjury.py b/sco_pvjury.py index 148ad1fb94..f62a345f5d 100644 --- a/sco_pvjury.py +++ b/sco_pvjury.py @@ -844,7 +844,6 @@ def formsemestre_lettres_individuelles( else: # submit sf = tf[2]["signature"] - # pdb.set_trace() signature = sf.read() # image of signature try: PDFLOCK.acquire() diff --git a/sco_recapcomplet.py b/sco_recapcomplet.py index 63a8c8d780..8727f74b30 100644 --- a/sco_recapcomplet.py +++ b/sco_recapcomplet.py @@ -270,7 +270,7 @@ def make_formsemestre_recapcomplet( )[0] nt = context._getNotesCache().get_NotesTable( context, formsemestre_id - ) # > get_modimpls, get_ues, get_table_moyennes_triees, get_etud_decision_sem, get_etud_etat, get_etud_rang, get_nom_short, get_mod_stats, nt.moy_moy, get_nom_long, get_etud_decision_sem, + ) # > get_modimpls, get_ues, get_table_moyennes_triees, get_etud_decision_sem, get_etud_etat, get_etud_rang, get_nom_short, get_mod_stats, nt.moy_moy, get_etud_decision_sem, modimpls = nt.get_modimpls() ues = nt.get_ues() # incluant le(s) UE de sport # @@ -628,7 +628,6 @@ def make_formsemestre_recapcomplet( "formsemestre_id": formsemestre_id, "etudid": etudid, "name": l[1], - "nomprenom": nt.get_nom_long(etudid), } if ir % 2 == 0: cells = '' % etudid diff --git a/sco_report.py b/sco_report.py index ed795c534a..246c4f62f9 100644 --- a/sco_report.py +++ b/sco_report.py @@ -293,7 +293,7 @@ def formsemestre_report_counts( "codedecision", "devenir", "etat", - "sexe", + "civilite", "qualite", "villelycee", "statut", @@ -365,7 +365,7 @@ def table_suivi_cohorte( bac="", # selection sur type de bac bacspecialite="", annee_bac="", - sexe="", + civilite=None, statut="", only_primo=False, ): @@ -404,7 +404,7 @@ def table_suivi_cohorte( bacs = set() bacspecialites = set() annee_bacs = set() - sexes = set() + civilites = set() statuts = set() for etudid in etudids: etud = context.getEtudInfo(etudid=etudid, filled=True)[0] @@ -414,7 +414,7 @@ def table_suivi_cohorte( (not bac or (bac == etud["bac"])) and (not bacspecialite or (bacspecialite == bacspe)) and (not annee_bac or (annee_bac == str(etud["annee_bac"]))) - and (not sexe or (sexe == etud["sexe"])) + and (not civilite or (civilite == etud["civilite"])) and (not statut or (statut == etud["statut"])) and (not only_primo or context.isPrimoEtud(etud, sem)) ): @@ -426,7 +426,7 @@ def table_suivi_cohorte( bacs.add(etud["bac"]) bacspecialites.add(bacspe) annee_bacs.add(etud["annee_bac"]) - sexes.add(etud["sexe"]) + civilites.add(etud["civilite"]) if etud["statut"]: # ne montre pas les statuts non renseignés statuts.add(etud["statut"]) sems = S.values() @@ -617,8 +617,8 @@ def table_suivi_cohorte( dbac += " (spécialité %s)" % bacspecialite if annee_bac: dbac += " (année bac %s)" % annee_bac - if sexe: - dbac += " genre: %s" % sexe + if civilite: + dbac += " civilité: %s" % civilite if statut: dbac += " statut: %s" % statut tab = GenTable( @@ -652,7 +652,15 @@ def table_suivi_cohorte( expl.append(", ".join(ls) + "") expl.append("") logt("Z: table_suivi_cohorte done") - return tab, "\n".join(expl), bacs, bacspecialites, annee_bacs, sexes, statuts + return ( + tab, + "\n".join(expl), + bacs, + bacspecialites, + annee_bacs, + civilites, + statuts, + ) def formsemestre_suivi_cohorte( @@ -663,27 +671,35 @@ def formsemestre_suivi_cohorte( bac="", bacspecialite="", annee_bac="", - sexe="", + civilite=None, statut="", only_primo=False, REQUEST=None, ): """Affiche suivi cohortes par numero de semestre""" percent = int(percent) - tab, expl, bacs, bacspecialites, annee_bacs, sexes, statuts = table_suivi_cohorte( + ( + tab, + expl, + bacs, + bacspecialites, + annee_bacs, + civilites, + statuts, + ) = table_suivi_cohorte( context, formsemestre_id, percent=percent, bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, only_primo=only_primo, ) tab.base_url = ( - "%s?formsemestre_id=%s&percent=%s&bac=%s&bacspecialite=%s&sexe=%s" - % (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, sexe) + "%s?formsemestre_id=%s&percent=%s&bac=%s&bacspecialite=%s&civilite=%s" + % (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, civilite) ) if only_primo: tab.base_url += "&only_primo=on" @@ -693,8 +709,8 @@ def formsemestre_suivi_cohorte( base_url = REQUEST.URL0 burl = ( - "%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&sexe=%s&statut=%s" - % (base_url, formsemestre_id, bac, bacspecialite, sexe, statut) + "%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&civilite=%s&statut=%s" + % (base_url, formsemestre_id, bac, bacspecialite, civilite, statut) ) if percent: pplink = ( @@ -724,12 +740,12 @@ def formsemestre_suivi_cohorte( bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, bacs=bacs, bacspecialites=bacspecialites, annee_bacs=annee_bacs, - sexes=sexes, + civilites=civilites, statuts=statuts, percent=percent, ), @@ -749,12 +765,12 @@ def _gen_form_selectetuds( bac=None, bacspecialite=None, annee_bac=None, - sexe=None, + civilite=None, statut=None, bacs=None, bacspecialites=None, annee_bacs=None, - sexes=None, + civilites=None, statuts=None, ): """HTML form pour choix criteres selection etudiants""" @@ -764,8 +780,8 @@ def _gen_form_selectetuds( bacspecialites.sort() annee_bacs = list(annee_bacs) annee_bacs.sort() - sexes = list(sexes) - sexes.sort() + civilites = list(civilites) + civilites.sort() statuts = list(statuts) statuts.sort() # @@ -824,13 +840,13 @@ def _gen_form_selectetuds( F.append("") # F.append( - """  Genre: """ % selected ) - for b in sexes: - if sexe == b: + for b in civilites: + if civilite == b: selected = 'selected="selected"' else: selected = "" @@ -984,7 +1000,7 @@ def tsp_etud_list( bac="", # selection sur type de bac bacspecialite="", annee_bac="", - sexe="", + civilite="", statut="", ): """Liste des etuds a considerer dans table suivi parcours @@ -1000,7 +1016,7 @@ def tsp_etud_list( bacs = set() bacspecialites = set() annee_bacs = set() - sexes = set() + civilites = set() statuts = set() for etudid in etudids: etud = context.getEtudInfo(etudid=etudid, filled=True)[0] @@ -1010,7 +1026,7 @@ def tsp_etud_list( (not bac or (bac == etud["bac"])) and (not bacspecialite or (bacspecialite == bacspe)) and (not annee_bac or (annee_bac == str(etud["annee_bac"]))) - and (not sexe or (sexe == etud["sexe"])) + and (not civilite or (civilite == etud["civilite"])) and (not statut or (statut == etud["statut"])) and (not only_primo or context.isPrimoEtud(etud, sem)) ): @@ -1019,11 +1035,11 @@ def tsp_etud_list( bacs.add(etud["bac"]) bacspecialites.add(bacspe) annee_bacs.add(etud["annee_bac"]) - sexes.add(etud["sexe"]) + civilites.add(etud["civilite"]) if etud["statut"]: # ne montre pas les statuts non renseignés statuts.add(etud["statut"]) # log('tsp_etud_list: %s etuds' % len(etuds)) - return etuds, bacs, bacspecialites, annee_bacs, sexes, statuts + return etuds, bacs, bacspecialites, annee_bacs, civilites, statuts def tsp_grouped_list(context, codes_etuds): @@ -1049,7 +1065,7 @@ def table_suivi_parcours( ): """Tableau recapitulant tous les parcours""" sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) - etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list( + etuds, bacs, bacspecialites, annee_bacs, civilites, statuts = tsp_etud_list( context, formsemestre_id, only_primo=only_primo ) codes_etuds = scu.DictDefault(defaultvalue=[]) @@ -1065,7 +1081,7 @@ def table_suivi_parcours( titles = { "parcours": "Code parcours", "nb": "Nombre d'étudiants", - "sexe": "", + "civilite": "", "nom": "Nom", "prenom": "Prénom", "etudid": "etudid", @@ -1082,7 +1098,7 @@ def table_suivi_parcours( L = etuds columns_ids = ( "etudid", - "sexe", + "civilite", "nom", "prenom", "bac", @@ -1209,25 +1225,25 @@ def graph_parcours( bac="", # selection sur type de bac bacspecialite="", annee_bac="", - sexe="", + civilite="", statut="", ): """""" if not scu.WITH_PYDOT: raise ScoValueError("pydot module is not installed") - etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list( + etuds, bacs, bacspecialites, annee_bacs, civilites, statuts = tsp_etud_list( context, formsemestre_id, only_primo=only_primo, bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, ) # log('graph_parcours: %s etuds (only_primo=%s)' % (len(etuds), only_primo)) if not etuds: - return "", etuds, bacs, bacspecialites, annee_bacs, sexes, statuts + return "", etuds, bacs, bacspecialites, annee_bacs, civilites, statuts edges = scu.DictDefault( defaultvalue=set() ) # {(formsemestre_id_origin, formsemestre_id_dest) : etud_set} @@ -1417,7 +1433,7 @@ def graph_parcours( # cf http://groups.google.com/group/pydot/browse_thread/thread/b3704c53e331e2ec data = data.replace("font-family:Arial", "font-family:Helvetica") - return data, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts + return data, etuds, bacs, bacspecialites, annee_bacs, civilites, statuts def formsemestre_graph_parcours( @@ -1428,7 +1444,7 @@ def formsemestre_graph_parcours( bac="", # selection sur type de bac bacspecialite="", annee_bac="", - sexe="", + civilite="", statut="", allkeys=False, # unused REQUEST=None, @@ -1437,7 +1453,15 @@ def formsemestre_graph_parcours( # log("formsemestre_graph_parcours") sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) if format == "pdf": - doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours( + ( + doc, + etuds, + bacs, + bacspecialites, + annee_bacs, + civilites, + statuts, + ) = graph_parcours( context, formsemestre_id, format="pdf", @@ -1445,14 +1469,22 @@ def formsemestre_graph_parcours( bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, ) filename = scu.make_filename("flux " + sem["titreannee"]) return scu.sendPDFFile(REQUEST, doc, filename + ".pdf") elif format == "png": # - doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours( + ( + doc, + etuds, + bacs, + bacspecialites, + annee_bacs, + civilites, + statuts, + ) = graph_parcours( context, formsemestre_id, format="png", @@ -1460,7 +1492,7 @@ def formsemestre_graph_parcours( bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, ) filename = scu.make_filename("flux " + sem["titreannee"]) @@ -1475,17 +1507,25 @@ def formsemestre_graph_parcours( else: op = "" url = urllib.quote( - "formsemestre_graph_parcours?formsemestre_id=%s&%sbac=%s&bacspecialite=%s&sexe=%s&statut=%s&format=" - % (formsemestre_id, op, bac, bacspecialite, sexe, statut) + "formsemestre_graph_parcours?formsemestre_id=%s&%sbac=%s&bacspecialite=%s&civilite=%s&statut=%s&format=" + % (formsemestre_id, op, bac, bacspecialite, civilite, statut) ) - doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours( + ( + doc, + etuds, + bacs, + bacspecialites, + annee_bacs, + civilites, + statuts, + ) = graph_parcours( context, formsemestre_id, only_primo=only_primo, bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, ) @@ -1505,12 +1545,12 @@ def formsemestre_graph_parcours( bac=bac, bacspecialite=bacspecialite, annee_bac=annee_bac, - sexe=sexe, + civilite=civilite, statut=statut, bacs=bacs, bacspecialites=bacspecialites, annee_bacs=annee_bacs, - sexes=sexes, + civilites=civilites, statuts=statuts, percent=0, ), diff --git a/sco_synchro_etuds.py b/sco_synchro_etuds.py index 14fe953a3e..ec70f80fed 100644 --- a/sco_synchro_etuds.py +++ b/sco_synchro_etuds.py @@ -408,7 +408,7 @@ def list_synch(context, sem, anneeapogee=None): etud = etudsapo_ident[key] etud["etudid"] = "" - etud["sexe"] = etud.get( + etud["civilite"] = etud.get( "sexe", etud.get("gender", "") ) # la cle 'sexe' est prioritaire sur 'gender' etud["inscrit"] = is_inscrit # checkbox state @@ -545,16 +545,14 @@ def formsemestre_synchro_etuds_help(context, sem): ) -def gender2sex(gender): - """Le portail code en 'M', 'F', et ScoDoc en 'MR', 'MME' - Les F sont ici codées en MME - """ - if gender == "M": - return "MR" - elif gender == "F": - return "MME" - log('gender2sex: invalid value "%s", defaulting to "M"' % gender) - return "MR" +def gender2civilite(gender): + """Le portail code en 'M', 'F', et ScoDoc en 'M', 'F', 'X'""" + if gender == "M" or gender == "F" or gender == "X": + return gender + elif not gender: + return "X" + log('gender2civilite: invalid value "%s", defaulting to "X"' % gender) + return "X" # "X" en général n'est pas affiché, donc bon choix si invalide def get_opt_str(etud, k): @@ -598,7 +596,7 @@ def do_import_etuds_from_portal(context, sem, a_importer, etudsapo_ident, REQUES "prenom": etud["prenom"].strip(), # Les champs suivants sont facultatifs (pas toujours renvoyés par le portail) "code_ine": etud.get("ine", "").strip(), - "sexe": gender2sex(etud["gender"].strip()), + "civilite": gender2civilite(etud["gender"].strip()), "etape": etud.get("etape", None), "email": etud.get("mail", "").strip(), "emailperso": etud.get("mailperso", "").strip(), @@ -738,9 +736,9 @@ def do_import_etud_admission( if x: args[sco_field] = x # Champs spécifiques: - sexe = gender2sex(etud["gender"].strip()) - if sexe: - args["sexe"] = sexe + civilite = gender2civilite(etud["gender"].strip()) + if civilite: + args["civilite"] = civilite scolars.identite_edit_nocheck(cnx, args) diff --git a/sco_trombino.py b/sco_trombino.py index b529ea7735..ce3ca1b12e 100644 --- a/sco_trombino.py +++ b/sco_trombino.py @@ -337,13 +337,7 @@ def _trombino_pdf(context, groups_infos, REQUEST): [img], [ Paragraph( - SU( - scolars.format_sexe(t["sexe"]) - + " " - + scolars.format_prenom(t["prenom"]) - + " " - + scolars.format_nom(t["nom"]) - ), + SU(scolars.format_nomprenom(t)), StyleSheet["Normal"], ) ], @@ -422,13 +416,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST): t = groups_infos.members[i] img = _get_etud_platypus_image(context, t, image_width=PHOTOWIDTH) txt = Paragraph( - SU( - scolars.format_sexe(t["sexe"]) - + " " - + scolars.format_prenom(t["prenom"]) - + " " - + scolars.format_nom(t["nom"]) - ), + SU(scolars.format_nomprenom(t)), StyleSheet["Normal"], ) if currow: diff --git a/sco_utils.py b/sco_utils.py index 88c2a29a61..60b26cbcb8 100644 --- a/sco_utils.py +++ b/sco_utils.py @@ -704,7 +704,7 @@ if WITH_PYDOT: junk_graph = pydot.Dot("junk") junk_graph.add_node(pydot.Node("a")) n = junk_graph.get_node("a") - if type(n) == type([]): + if type(n) == type([]): # "modern" pydot def pydot_get_node(g, name): r = g.get_node(name) @@ -713,7 +713,7 @@ if WITH_PYDOT: else: return r[0] - else: + else: # very old pydot def pydot_get_node(g, name): return g.get_node(name) diff --git a/scolars.py b/scolars.py index 7a17a772e3..4fb479def9 100644 --- a/scolars.py +++ b/scolars.py @@ -101,7 +101,7 @@ def format_etud_ident(etud): else: etud["nom_usuel"] = "" etud["prenom"] = format_prenom(etud["prenom"]) - etud["sexe"] = format_sexe(etud["sexe"]) + etud["civilite_str"] = format_civilite(etud["civilite"]) # Nom à afficher: if etud["nom_usuel"]: etud["nom_disp"] = etud["nom_usuel"] @@ -111,10 +111,12 @@ def format_etud_ident(etud): etud["nom_disp"] = etud["nom"] etud["nomprenom"] = format_nomprenom(etud) # M. Pierre DUPONT - if etud["sexe"] == "M.": + if etud["civilite"] == "M": etud["ne"] = "" - else: + elif etud["civilite"] == "F": etud["ne"] = "e" + else: # 'X' + etud["ne"] = "(e)" # Mail à utiliser pour les envois vers l'étudiant: # choix qui pourrait être controé par une preference # ici priorité au mail institutionnel: @@ -128,14 +130,20 @@ def force_uppercase(s): def format_nomprenom(etud): - "formatte sexe/nom/prenom pour affichages" - return " ".join( - [format_sexe(etud["sexe"]), format_prenom(etud["prenom"]), etud["nom_disp"]] - ) + """Formatte civilité/nom/prenom pour affichages: "M. Pierre Dupont" """ + l = [] + for x in [ + format_civilite(etud["civilite"]), + format_prenom(etud["prenom"]), + etud.get("nom_disp", "") or etud.get("nom_usuel", "") or etud["nom"], + ]: + if x: + l.append(x) + return " ".join(l) def format_prenom(s): - "formatte prenom etudiant pour affichage" + "Formatte prenom etudiant pour affichage" if not s: return "" frags = s.split() @@ -162,22 +170,33 @@ def format_nom(s, uppercase=True): return format_prenom(s) -def format_sexe(sexe): - sexe = scu.strlower(sexe) - if sexe == "mr" or sexe == "m." or sexe == "m": - return "M." - else: - return "Mme" +def input_civilite(s): + """Converts external representation of civilite to internal: + 'M', 'F', or 'X' (and nothing else). + Raises valueError if conversion fails. + """ + s = scu.strupper(s).strip() + if s in ("M", "M.", "MR", "H"): + return "M" + elif s in ("F", "MLLE", "MLLE.", "MELLE", "MME"): + return "F" + elif s == "X" or not s: + return "X" + raise ValueError("valeur invalide pour la civilité: %s" % s) -def normalize_sexe(sexe): - "returns 'MR' ou 'MME'" - sexe = scu.strupper(sexe).strip() - if sexe in ("M.", "M", "MR", "H"): - return "MR" - elif sexe in ("MLLE", "MLLE.", "MELLE", "MME", "F"): - return "MME" - raise ValueError("valeur invalide pour le sexe: %s" % sexe) +def format_civilite(civilite): + """returns 'M.' ou 'Mme' ou '' (pour le genre neutre, + personne ne souhaitant pas d'affichage) + """ + try: + return { + "M": "M.", + "F": "Mme", + "X": "", + }[civilite] + except KeyError: + raise ValueError("valeur invalide pour la civilité: %s" % civilite) def format_lycee(nomlycee): @@ -241,7 +260,7 @@ _identiteEditor = EditableTable( "nom", "nom_usuel", "prenom", - "sexe", + "civilite", # 'M", "F", or "X" "date_naissance", "lieu_naissance", "dept_naissance", @@ -257,10 +276,10 @@ _identiteEditor = EditableTable( input_formators={ "nom": force_uppercase, "prenom": force_uppercase, - "sexe": force_uppercase, + "civilite": input_civilite, "date_naissance": DateDMYtoISO, }, - output_formators={"date_naissance": DateISOtoDMY, "sexe": normalize_sexe}, + output_formators={"date_naissance": DateISOtoDMY}, convert_null_outputs_to_empty=True, allow_set_id=True, # car on specifie le code Apogee a la creation ) @@ -269,13 +288,14 @@ identite_delete = _identiteEditor.delete def identite_list(cnx, *a, **kw): - "list, add 'annee_naissance'" + """List, adding on the fly 'annee_naissance' and 'civilite_str' (M., Mme, "").""" objs = _identiteEditor.list(cnx, *a, **kw) for o in objs: if o["date_naissance"]: o["annee_naissance"] = int(o["date_naissance"].split("/")[2]) else: o["annee_naissance"] = o["date_naissance"] + o["civilite_str"] = format_civilite(o["civilite"]) return objs @@ -372,7 +392,6 @@ def identite_edit(cnx, args, context=None, REQUEST=None): if notify_to: # etat AVANT edition pour envoyer diffs before = identite_list(cnx, {"etudid": args["etudid"]})[0] - before["sexe"] = format_sexe(before["sexe"]) identite_edit_nocheck(cnx, args) @@ -380,7 +399,6 @@ def identite_edit(cnx, args, context=None, REQUEST=None): if notify_to: etud = context.getEtudInfo(etudid=args["etudid"], filled=True)[0] after = identite_list(cnx, {"etudid": args["etudid"]})[0] - after["sexe"] = format_sexe(after["sexe"]) notify_etud_change( context, notify_to, @@ -412,7 +430,7 @@ def notify_etud_change(context, email_addr, etud, before, after, subject): """ txt = [ "Code NIP:" + etud["code_nip"], - "Genre: " + etud["sexe"], + "Civilité: " + etud["civilite_str"], "Nom: " + etud["nom"], "Prénom: " + etud["prenom"], "Etudid: " + etud["etudid"], diff --git a/scotests/demo/demo_reset_noms.py b/scotests/demo/demo_reset_noms.py index 5d569362bd..d1f00cf35c 100755 --- a/scotests/demo/demo_reset_noms.py +++ b/scotests/demo/demo_reset_noms.py @@ -3,12 +3,12 @@ """Outils pour environnements de démo. -Change aléatoirement les identites (nip, sexe, nom, prenom) des étudiants d'un semestre. +Change aléatoirement les identites (nip, civilite, nom, prenom) des étudiants d'un semestre. Le NIP est choisi aléatoirement (nombre entier à 8 chiffres). Les noms et prénoms sont issus des fichiers noms.txt, prenoms-h.txt, prenoms-f.txt (ce sont simlement les plus fréquemment rencontrés en France). -Le sexe est choisi aléatoirement 50-50. +La civilité est choisie aléatoirement 50-50 Homme/Femme. """ import sys @@ -54,17 +54,17 @@ cursor.execute( wcursor = cnx.cursor() n = 0 for (etudid,) in cursor: - sexe = random.choice(("M.", "MME")) - nom, prenom = nomprenom(sexe) + civilite = random.choice(("M", "F")) # pas de neutre, on pourrait ajouter 'X' + nom, prenom = nomprenom(civilite) print(f"{etudid}: {nom}\t{prenom}") args = { "nom": nom, "prenom": prenom, - "sexe": sexe, + "civilite": civilite, "etudid": etudid, "code_nip": random.randrange(10000000, 99999999), } - req = "update identite set nom=%(nom)s, prenom=%(prenom)s, sexe=%(sexe)s where etudid=%(etudid)s" + req = "update identite set nom=%(nom)s, prenom=%(prenom)s, civilite=%(civilite)s where etudid=%(etudid)s" # print( req % args) wcursor.execute(req, args) n += 1 diff --git a/scotests/demo/gen_nomprenoms.py b/scotests/demo/gen_nomprenoms.py index ec36fd7503..6ab8518861 100644 --- a/scotests/demo/gen_nomprenoms.py +++ b/scotests/demo/gen_nomprenoms.py @@ -10,14 +10,19 @@ cur_dir = Path(os.path.abspath(__file__)).parent NOMS = [x.strip() for x in open(cur_dir / "noms.txt").readlines()] PRENOMS_H = [x.strip() for x in open(cur_dir / "prenoms-h.txt").readlines()] PRENOMS_F = [x.strip() for x in open(cur_dir / "prenoms-f.txt").readlines()] +PRENOMS_X = [x.strip() for x in open(cur_dir / "prenoms-x.txt").readlines()] -def nomprenom(sexe): - """un nom et un prenom au hasard, - toujours en majuscules. +def nomprenom(civilite): + """Un nom et un prenom au hasard, + toujours en majuscules. Pour tests et démos. """ - if "e" in sexe.lower() or "f" in sexe.lower(): + if civilite == "F": prenom = random.choice(PRENOMS_F) - else: + elif civilite == "M": prenom = random.choice(PRENOMS_H) + elif civilite == "X": + prenom = random.choice(PRENOMS_X) + else: + raise ValueError("civilite must be M, F or X") return random.choice(NOMS).upper(), prenom.upper() diff --git a/scotests/demo/prenoms-x.txt b/scotests/demo/prenoms-x.txt new file mode 100644 index 0000000000..68ce1abf65 --- /dev/null +++ b/scotests/demo/prenoms-x.txt @@ -0,0 +1,10 @@ +Camille +Sacha +Eden +Maxime +Morgan +Charlie +Alix +Claude +Ufuk +Lou diff --git a/scotests/sco_fake_gen.py b/scotests/sco_fake_gen.py index 2a066de0fe..5bf59fe5e3 100644 --- a/scotests/sco_fake_gen.py +++ b/scotests/sco_fake_gen.py @@ -38,6 +38,7 @@ DEMODIR = sco_utils.SCO_SRCDIR + "/scotests/demo/" NOMS = [x.strip() for x in open(DEMODIR + "/noms.txt").readlines()] PRENOMS_H = [x.strip() for x in open(DEMODIR + "/prenoms-h.txt").readlines()] PRENOMS_F = [x.strip() for x in open(DEMODIR + "/prenoms-f.txt").readlines()] +PRENOMS_X = [x.strip() for x in open(DEMODIR + "/prenoms-x.txt").readlines()] # nb: en python2, les chaines ci-dessus sont en utf8 @@ -66,16 +67,20 @@ class ScoFake: sys.stderr.flush() log("ScoFake: " + str(msg)) - def sexenomprenom(self): + def civilitenomprenom(self): """un nom et un prenom au hasard, toujours en majuscules. """ - sexe = random.choice(("M", "F")) - if "e" in sexe.lower() or "f" in sexe.lower(): + civilite = random.choice(("M", "M", "M", "F", "F", "F", "X")) + if civilite == "F": prenom = random.choice(PRENOMS_F) - else: + elif civilite == "M": prenom = random.choice(PRENOMS_H) - return sexe, random.choice(NOMS).upper(), prenom.upper() + elif civilite == "X": + prenom = random.choice(PRENOMS_X) + else: + raise ValueError("invalid civilite value") + return civilite, random.choice(NOMS).upper(), prenom.upper() @logging_meth def create_etud( @@ -85,7 +90,7 @@ class ScoFake: nom="", prenom="", code_ine="", - sexe="", + civilite="", etape="TST1", email="test@localhost", emailperso="perso@localhost", @@ -106,10 +111,10 @@ class ScoFake: cnx = self.context.GetDBConnexion() if code_nip == "": code_nip = str(random.randint(10000, 99999)) - if not sexe or not nom or not prenom: - r_sexe, r_nom, r_prenom = self.sexenomprenom() - if not sexe: - sexe = r_sexe + if not civilite or not nom or not prenom: + r_civilite, r_nom, r_prenom = self.civilitenomprenom() + if not civilite: + civilite = r_civilite if not nom: nom = r_nom if not prenom: