Handling of neutral genders.

Closes #65
This commit is contained in:
Emmanuel Viennet 2021-02-13 17:28:55 +01:00
parent 8d7ec2faea
commit 8f02f16442
33 changed files with 281 additions and 199 deletions

View File

@ -368,16 +368,16 @@ def scolars_import_excel_file(
# xxx Ad-hoc checks (should be in format description) # xxx Ad-hoc checks (should be in format description)
if scu.strlower(titleslist[i]) == "sexe": if scu.strlower(titleslist[i]) == "sexe":
try: try:
val = scolars.normalize_sexe(val) val = scolars.input_civilite(val)
except: except:
raise ScoValueError( 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]) % (val, linenum, titleslist[i])
) )
# Excel date conversion: # Excel date conversion:
if scu.strlower(titleslist[i]) == "date_naissance": if scu.strlower(titleslist[i]) == "date_naissance":
if val: 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)) val = sco_excel.xldate_as_datetime(float(val))
# INE # INE
if ( if (
@ -515,11 +515,11 @@ def _import_one_student(
# Admissions # Admissions
args["etudid"] = etudid args["etudid"] = etudid
args["annee"] = annee_courante args["annee"] = annee_courante
adm_id = scolars.admission_create(cnx, args) _ = scolars.admission_create(cnx, args)
# Adresse # Adresse
args["typeadresse"] = "domicile" args["typeadresse"] = "domicile"
args["description"] = "(infos admission)" args["description"] = "(infos admission)"
adresse_id = scolars.adresse_create(cnx, args) _ = scolars.adresse_create(cnx, args)
# Inscription au semestre # Inscription au semestre
args["etat"] = "I" # etat insc. semestre args["etat"] = "I" # etat insc. semestre
if formsemestre_id: if formsemestre_id:

View File

@ -99,7 +99,7 @@ import sco_formations
from scolars import ( from scolars import (
format_nom, format_nom,
format_prenom, format_prenom,
format_sexe, format_civilite,
format_lycee, format_lycee,
format_lycee_from_code, format_lycee_from_code,
) )
@ -916,7 +916,8 @@ REQUEST.URL0=%s<br/>
"nom": "?", "nom": "?",
"nom_usuel": "", "nom_usuel": "",
"prenom": "?", "prenom": "?",
"sexe": "?", "civilite": "?",
"sexe": "?", # for backward compat
"email": "?", "email": "?",
"emailperso": "", "emailperso": "",
"error": "code etudiant inconnu", "error": "code etudiant inconnu",
@ -935,7 +936,6 @@ REQUEST.URL0=%s<br/>
"nom", "nom",
"nom_usuel", "nom_usuel",
"prenom", "prenom",
"sexe",
"nomprenom", "nomprenom",
"email", "email",
"emailperso", "emailperso",
@ -956,6 +956,10 @@ REQUEST.URL0=%s<br/>
"date_naissance_iso", "date_naissance_iso",
): ):
d[a] = scu.quote_xml_attr(etud[a]) 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)) d["photo_url"] = scu.quote_xml_attr(sco_photos.etud_photo_url(self, etud))
sem = etud["cursem"] sem = etud["cursem"]
@ -1750,12 +1754,12 @@ REQUEST.URL0=%s<br/>
}, },
), ),
( (
"sexe", "civilite",
{ {
"input_type": "menu", "input_type": "menu",
"labels": ["H", "F"], "labels": ["Homme", "Femme", "Autre/neutre"],
"allowed_values": ["MR", "MME"], "allowed_values": ["M", "F", "X"],
"title": "Genre", "title": "Civilité",
}, },
), ),
( (

View File

@ -1070,6 +1070,21 @@ for dept in get_depts():
"etape", "etape",
["alter table notes_formsemestre_inscription add column etape text"], ["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: # Add here actions to performs after upgrades:
cnx.commit() cnx.commit()
cnx.close() cnx.close()

View File

@ -103,7 +103,7 @@ def sidebar(context, REQUEST=None):
# compte les absences du semestre en cours # compte les absences du semestre en cours
H.append( H.append(
"""<h2 id="insidebar-etud"><a href="%(ScoURL)s/ficheEtud?etudid=%(etudid)s" class="sidebar"> """<h2 id="insidebar-etud"><a href="%(ScoURL)s/ficheEtud?etudid=%(etudid)s" class="sidebar">
<font color="#FF0000">%(sexe)s %(nom_disp)s</font></a> <font color="#FF0000">%(civilite_str)s %(nom_disp)s</font></a>
</h2> </h2>
<b>Absences</b>""" <b>Absences</b>"""
% params % params

View File

@ -49,7 +49,7 @@ CREATE TABLE identite (
etudid text DEFAULT notes_newid_etud('EID'::text) UNIQUE NOT NULL, etudid text DEFAULT notes_newid_etud('EID'::text) UNIQUE NOT NULL,
nom text, nom text,
prenom text, prenom text,
sexe text, civilite text NOT NULL CHECK (civilite IN ('M', 'F', 'X')),
date_naissance date, -- new: date en texte date_naissance date, -- new: date en texte
lieu_naissance text, lieu_naissance text,
dept_naissance text, dept_naissance text,

View File

@ -8,7 +8,7 @@ Code_INE; text; identite; 1; code INE;INE
nom; text; identite; 0; nom de l'etudiant; nom; text; identite; 0; nom de l'etudiant;
nom_usuel; text; identite; 1; nom usuel (si different); nom_usuel; text; identite; 1; nom usuel (si different);
prenom; text; identite; 0; prenom de l'etudiant 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) date_naissance;text;identite; 1; date de naissance (jj/mm/aaaa)
lieu_naissance;text;identite; 1; lieu de naissance lieu_naissance;text;identite; 1; lieu de naissance
nationalite; text; identite; 1; nationalite nationalite; text; identite; 1; nationalite

View File

@ -372,7 +372,9 @@ class NotesTable:
def get_sexnom(self, etudid): def get_sexnom(self, etudid):
"M. DUPONT" "M. DUPONT"
etud = self.identdict[etudid] 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): def get_nom_short(self, etudid):
"formatte nom d'un etud (pour table recap)" "formatte nom d'un etud (pour table recap)"
@ -391,13 +393,7 @@ class NotesTable:
def get_nom_long(self, etudid): def get_nom_long(self, etudid):
"formatte nom d'un etud: M. Pierre DUPONT" "formatte nom d'un etud: M. Pierre DUPONT"
etud = self.identdict[etudid] etud = self.identdict[etudid]
return " ".join( return scolars.format_nomprenom(etud)
[
scolars.format_sexe(etud["sexe"]),
scolars.format_prenom(etud["prenom"]),
scolars.format_nom(etud["nom_usuel"] or etud["nom"]),
]
)
def get_displayed_etud_code(self, etudid): def get_displayed_etud_code(self, etudid):
'code à afficher sur les listings "anonymes"' 'code à afficher sur les listings "anonymes"'

View File

@ -213,7 +213,7 @@ def get_code_latex_avis_etudiant(
elif tag_latex == u"bilanParTag": elif tag_latex == u"bilanParTag":
valeur = get_bilanParTag(donnees_etudiant) valeur = get_bilanParTag(donnees_etudiant)
# Les tags "simples": par ex. nom, prenom, sexe, ... # Les tags "simples": par ex. nom, prenom, civilite, ...
else: else:
if tag_latex in donnees_etudiant: if tag_latex in donnees_etudiant:
valeur = donnees_etudiant[tag_latex].decode(scu.SCO_ENCODING) valeur = donnees_etudiant[tag_latex].decode(scu.SCO_ENCODING)
@ -410,7 +410,7 @@ def get_avis_poursuite_par_etudiant(
if pe_tools.PE_DEBUG: if pe_tools.PE_DEBUG:
pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + etudid) 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) nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-").decode(scu.SCO_ENCODING)
prenom = ( prenom = (
jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(scu.SCO_ENCODING) jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(scu.SCO_ENCODING)
@ -429,7 +429,9 @@ def get_avis_poursuite_par_etudiant(
# Entete (commentaire) # Entete (commentaire)
contenu_latex = u"%% ---- Etudiant: " + sexe + " " + nom + " " + prenom + u"\n" contenu_latex = (
u"%% ---- Etudiant: " + civilite_str + " " + nom + " " + prenom + u"\n"
)
# les annnotations # les annnotations
annotationPE = get_annotation_PE( annotationPE = get_annotation_PE(
@ -502,7 +504,7 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
[syntheseJury[etudid]["nbSemestres"] for etudid in etudids] [syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
) # le nombre de semestre le + grand ) # le nombre de semestre le + grand
infos = ["sexe", "nom", "prenom", "age", "nbSemestres"] infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
entete = ["etudid"] entete = ["etudid"]
entete.extend(infos) entete.extend(infos)
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)]) # ajout du parcours 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: # Les info générales:
row = { row = {
"etudid": etudid, "etudid": etudid,
"sexe": e["sexe"], "civilite": e["civilite"],
"nom": e["nom"], "nom": e["nom"],
"prenom": e["prenom"], "prenom": e["prenom"],
"age": e["age"], "age": e["age"],

View File

@ -85,7 +85,7 @@ class JuryPE:
- context : le contexte Zope - context : le contexte Zope
- juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives + - 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 ... 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 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 et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif
@ -812,7 +812,7 @@ class JuryPE:
self.syntheseJury[etudid] = { self.syntheseJury[etudid] = {
"nom": etudinfo["nom"], "nom": etudinfo["nom"],
"prenom": etudinfo["prenom"], "prenom": etudinfo["prenom"],
"sexe": etudinfo["sexe"], "civilite": etudinfo["civilite"],
"age": str(pe_tools.calcul_age(etudinfo["date_naissance"])), "age": str(pe_tools.calcul_age(etudinfo["date_naissance"])),
"lycee": etudinfo["nomlycee"] "lycee": etudinfo["nomlycee"]
+ ( + (
@ -985,7 +985,7 @@ class JuryPE:
[self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids] [self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
) )
infos = ["sexe", "nom", "prenom", "age", "nbSemestres"] infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
entete = ["etudid"] entete = ["etudid"]
entete.extend(infos) entete.extend(infos)
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)]) entete.extend(["P%d" % i for i in range(1, maxParcours + 1)])
@ -1036,7 +1036,7 @@ class JuryPE:
# Les info générales: # Les info générales:
row = { row = {
"etudid": etudid, "etudid": etudid,
"sexe": e["sexe"], "civilite": e["civilite"],
"nom": e["nom"], "nom": e["nom"],
"prenom": e["prenom"], "prenom": e["prenom"],
"age": e["age"], "age": e["age"],

View File

@ -217,7 +217,7 @@ JURY_SYNTHESE_POUR_DEBUG = {
"EID1810": { "EID1810": {
"nom": "ROUX", "nom": "ROUX",
"entree": "2016", "entree": "2016",
"sexe": "M.", "civilite_str": "M.",
"promo": 2016, "promo": 2016,
"S2": { "S2": {
"groupe": { "groupe": {

View File

@ -124,14 +124,14 @@ def formsemestre_bulletinetud_published_dict(
code_ine=etudinfo["code_ine"], code_ine=etudinfo["code_ine"],
nom=scu.quote_xml_attr(etudinfo["nom"]), nom=scu.quote_xml_attr(etudinfo["nom"]),
prenom=scu.quote_xml_attr(etudinfo["prenom"]), 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( photo_url=scu.quote_xml_attr(
sco_photos.etud_photo_url(context, etudinfo, fast=True) sco_photos.etud_photo_url(context, etudinfo, fast=True)
), ),
email=scu.quote_xml_attr(etudinfo["email"]), email=scu.quote_xml_attr(etudinfo["email"]),
emailperso=scu.quote_xml_attr(etudinfo["emailperso"]), emailperso=scu.quote_xml_attr(etudinfo["emailperso"]),
) )
d["etudiant"]["sexe"] = d["etudiant"]["civilite"] # backward compat for our clients
# Disponible pour publication ? # Disponible pour publication ?
if not published: if not published:
return d # stop ! return d # stop !

View File

@ -107,7 +107,8 @@ def make_xml_formsemestre_bulletinetud(
code_ine=etudinfo["code_ine"], code_ine=etudinfo["code_ine"],
nom=scu.quote_xml_attr(etudinfo["nom"]), nom=scu.quote_xml_attr(etudinfo["nom"]),
prenom=scu.quote_xml_attr(etudinfo["prenom"]), 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)), photo_url=scu.quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)),
email=scu.quote_xml_attr(etudinfo["email"]), email=scu.quote_xml_attr(etudinfo["email"]),
emailperso=scu.quote_xml_attr(etudinfo["emailperso"]), emailperso=scu.quote_xml_attr(etudinfo["emailperso"]),

View File

@ -115,7 +115,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
) )
row = { row = {
"etudid": etudid, "etudid": etudid,
"sexe": etud["sexe"], "civilite": etud["civilite"],
"nom": etud["nom"], "nom": etud["nom"],
"prenom": etud["prenom"], "prenom": etud["prenom"],
"_nom_target": "ficheEtud?etudid=" + etud["etudid"], "_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"]) L.sort(key=lambda x: x["sem_ident"])
titles = { titles = {
"sexe": "", "civilite": "",
"nom": "Nom", "nom": "Nom",
"prenom": "Prénom", "prenom": "Prénom",
"semestre": "Dernier semestre", "semestre": "Dernier semestre",
@ -170,7 +170,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
"semestre", "semestre",
"semestre_id", "semestre_id",
"periode", "periode",
"sexe", "civilite",
"nom", "nom",
"prenom", "prenom",
"moy", "moy",

View File

@ -616,7 +616,7 @@ def Excel_feuille_listeappel(
li += 1 li += 1
ws0.write(li, 0, n, style1b) ws0.write(li, 0, n, style1b)
nomprenom = ( nomprenom = (
t["sexe"] t["civilite_str"]
+ " " + " "
+ t["nom"] + t["nom"]
+ " " + " "

View File

@ -122,7 +122,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
"code_nip": "NIP", "code_nip": "NIP",
"nom": "Nom", "nom": "Nom",
"prenom": "Prénom", "prenom": "Prénom",
"sexe": "Civ.", "civilite_str": "Civ.",
"nom_usuel": "Nom usuel", "nom_usuel": "Nom usuel",
"bac": "Bac", "bac": "Bac",
"parcours": "Parcours", "parcours": "Parcours",
@ -133,7 +133,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
"periode", "periode",
"sid", "sid",
"code_nip", "code_nip",
"sexe", "civilite_str",
"nom", "nom",
# 'nom_usuel', # inutile ? # 'nom_usuel', # inutile ?
"prenom", "prenom",
@ -171,7 +171,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
"nom": etud["nom"], "nom": etud["nom"],
"nom_usuel": etud["nom_usuel"], "nom_usuel": etud["nom_usuel"],
"prenom": etud["prenom"], "prenom": etud["prenom"],
"sexe": etud["sexe"], "civilite_str": etud["civilite_str"],
"_nom_target": "%s/ficheEtud?etudid=%s" % (context.ScoURL(), etudid), "_nom_target": "%s/ficheEtud?etudid=%s" % (context.ScoURL(), etudid),
"_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid, "_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid,
"bac": bac.abbrev(), "bac": bac.abbrev(),

View File

@ -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. Seuls les départements accessibles par l'utilisateur sont cherchés.
Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc: 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( result, _ = search_etud_in_accessible_depts(
context, code_nip=code_nip, REQUEST=REQUEST 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, "dept": DeptId,
"etudid": e["etudid"], "etudid": e["etudid"],
"code_nip": e["code_nip"], "code_nip": e["code_nip"],
"sexe": e["sexe"], "civilite_str": e["civilite_str"],
"nom": e["nom"], "nom": e["nom"],
"prenom": e["prenom"], "prenom": e["prenom"],
"formsemestre_id": sem["formsemestre_id"], "formsemestre_id": sem["formsemestre_id"],
@ -414,7 +414,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
"dept", "dept",
"etudid", "etudid",
"code_nip", "code_nip",
"sexe", "civilite_str",
"nom", "nom",
"prenom", "prenom",
"formsemestre_id", "formsemestre_id",

View File

@ -473,7 +473,8 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
doc._push() doc._push()
doc.etud( doc.etud(
etudid=e["etudid"], etudid=e["etudid"],
sexe=scolars.format_sexe(etud["sexe"]), civilite=etud["civilite_str"],
sexe=etud["civilite_str"], # compat
nom=scolars.format_nom(etud["nom"]), nom=scolars.format_nom(etud["nom"]),
prenom=scolars.format_prenom(etud["prenom"]), prenom=scolars.format_prenom(etud["prenom"]),
origin=comp_origin(etud, sem), origin=comp_origin(etud, sem),
@ -497,7 +498,7 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
doc._push() doc._push()
doc.etud( doc.etud(
etudid=etud["etudid"], etudid=etud["etudid"],
sexe=scolars.format_sexe(etud["sexe"]), sexe=etud["civilite_str"],
nom=scolars.format_nom(etud["nom"]), nom=scolars.format_nom(etud["nom"]),
prenom=scolars.format_prenom(etud["prenom"]), prenom=scolars.format_prenom(etud["prenom"]),
origin=comp_origin(etud, sem), origin=comp_origin(etud, sem),
@ -1255,26 +1256,26 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
context.Notes, formsemestre_id context.Notes, formsemestre_id
) # > identdict ) # > identdict
identdict = nt.identdict identdict = nt.identdict
# build: { sexe : liste etudids trie par niveau croissant } # build: { civilite : liste etudids trie par niveau croissant }
sexes = sets.Set([x["sexe"] for x in identdict.values()]) civilites = sets.Set([x["civilite"] for x in identdict.values()])
listes = {} listes = {}
for sexe in sexes: for civilite in civilites:
listes[sexe] = [ listes[civilite] = [
(get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"]) (get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"])
for x in identdict.values() for x in identdict.values()
if x["sexe"] == sexe if x["civilite"] == civilite
] ]
listes[sexe].sort() listes[civilite].sort()
log("listes[%s] = %s" % (sexe, listes[sexe])) log("listes[%s] = %s" % (civilite, listes[civilite]))
# affect aux groupes: # affect aux groupes:
n = len(identdict) n = len(identdict)
igroup = 0 igroup = 0
nbgroups = len(group_ids) nbgroups = len(group_ids)
while n > 0: while n > 0:
for sexe in sexes: for civilite in civilites:
if len(listes[sexe]): if len(listes[civilite]):
n -= 1 n -= 1
etudid = listes[sexe].pop()[1] etudid = listes[civilite].pop()[1]
group_id = group_ids[igroup] group_id = group_ids[igroup]
igroup = (igroup + 1) % nbgroups igroup = (igroup + 1) % nbgroups
change_etud_group_in_partition( change_etud_group_in_partition(

View File

@ -464,8 +464,9 @@ def groups_table(
% (with_paiement, with_archives, with_annotations) % (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 = { titles = {
"civilite_str": "Civ.",
"nom_disp": "Nom", "nom_disp": "Nom",
"prenom": "Prénom", "prenom": "Prénom",
"email": "Mail", "email": "Mail",
@ -733,7 +734,7 @@ def groups_table(
"etudid", "etudid",
"code_nip", "code_nip",
"etat", "etat",
"sexe", "civilite_str",
"nom", "nom",
"nom_usuel", "nom_usuel",
"prenom", "prenom",

View File

@ -611,7 +611,7 @@ def etuds_select_boxes(
def etuds_select_box_xls(context, src_cat): def etuds_select_box_xls(context, src_cat):
"export a box to excel" "export a box to excel"
etuds = src_cat["etuds"] 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} titles = {x: x for x in columns_ids}
# Ajoute colonne paiement inscription # Ajoute colonne paiement inscription

View File

@ -128,7 +128,7 @@ def _table_etuds_lycees(
else: else:
L = etuds L = etuds
columns_ids = ( columns_ids = (
"sexe", "civilite_str",
"nom", "nom",
"prenom", "prenom",
"codelycee", "codelycee",
@ -148,7 +148,7 @@ def _table_etuds_lycees(
rows=L, rows=L,
titles={ titles={
"nbetuds": "Nb d'étudiants", "nbetuds": "Nb d'étudiants",
"sexe": "", "civilite_str": "",
"nom": "Nom", "nom": "Nom",
"prenom": "Prénom", "prenom": "Prénom",
"etudid": "etudid", "etudid": "etudid",

View File

@ -44,7 +44,7 @@ import VERSION
def etud_get_poursuite_info(context, sem, etud): def etud_get_poursuite_info(context, sem, etud):
"""{ 'nom' : ..., 'semlist' : [ { 'semestre_id': , 'moy' : ... }, {}, ...] }""" """{ 'nom' : ..., 'semlist' : [ { 'semestre_id': , 'moy' : ... }, {}, ...] }"""
I = {} I = {}
I.update(etud) # copie nom, prenom, sexe, ... I.update(etud) # copie nom, prenom, civilite, ...
# Now add each semester, starting from the first one # Now add each semester, starting from the first one
semlist = [] semlist = []
@ -174,7 +174,7 @@ def formsemestre_poursuite_report(
infos.append(info) infos.append(info)
# #
column_ids = ( column_ids = (
("sexe", "nom", "prenom", "annee", "date_naissance") ("civilite_str", "nom", "prenom", "annee", "date_naissance")
+ tuple(ids) + tuple(ids)
+ ("debouche",) + ("debouche",)
) )

View File

@ -37,7 +37,7 @@ import sco_excel
import sco_formsemestre import sco_formsemestre
import sco_parcours_dut import sco_parcours_dut
import sco_codes_parcours 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 from sco_abs import getAbsSemEtud
import VERSION import VERSION
@ -229,7 +229,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
l.append(etud["code_ine"]) l.append(etud["code_ine"])
l += [ l += [
etudid, etudid,
format_sexe(etud["sexe"]), etud["civilite_str"],
format_nom(etud["nom"]), format_nom(etud["nom"]),
format_prenom(etud["prenom"]), format_prenom(etud["prenom"]),
etud["date_naissance"], etud["date_naissance"],

View File

@ -844,7 +844,6 @@ def formsemestre_lettres_individuelles(
else: else:
# submit # submit
sf = tf[2]["signature"] sf = tf[2]["signature"]
# pdb.set_trace()
signature = sf.read() # image of signature signature = sf.read() # image of signature
try: try:
PDFLOCK.acquire() PDFLOCK.acquire()

View File

@ -270,7 +270,7 @@ def make_formsemestre_recapcomplet(
)[0] )[0]
nt = context._getNotesCache().get_NotesTable( nt = context._getNotesCache().get_NotesTable(
context, formsemestre_id 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() modimpls = nt.get_modimpls()
ues = nt.get_ues() # incluant le(s) UE de sport ues = nt.get_ues() # incluant le(s) UE de sport
# #
@ -628,7 +628,6 @@ def make_formsemestre_recapcomplet(
"formsemestre_id": formsemestre_id, "formsemestre_id": formsemestre_id,
"etudid": etudid, "etudid": etudid,
"name": l[1], "name": l[1],
"nomprenom": nt.get_nom_long(etudid),
} }
if ir % 2 == 0: if ir % 2 == 0:
cells = '<tr class="recap_row_even" id="etudid%s">' % etudid cells = '<tr class="recap_row_even" id="etudid%s">' % etudid

View File

@ -293,7 +293,7 @@ def formsemestre_report_counts(
"codedecision", "codedecision",
"devenir", "devenir",
"etat", "etat",
"sexe", "civilite",
"qualite", "qualite",
"villelycee", "villelycee",
"statut", "statut",
@ -365,7 +365,7 @@ def table_suivi_cohorte(
bac="", # selection sur type de bac bac="", # selection sur type de bac
bacspecialite="", bacspecialite="",
annee_bac="", annee_bac="",
sexe="", civilite=None,
statut="", statut="",
only_primo=False, only_primo=False,
): ):
@ -404,7 +404,7 @@ def table_suivi_cohorte(
bacs = set() bacs = set()
bacspecialites = set() bacspecialites = set()
annee_bacs = set() annee_bacs = set()
sexes = set() civilites = set()
statuts = set() statuts = set()
for etudid in etudids: for etudid in etudids:
etud = context.getEtudInfo(etudid=etudid, filled=True)[0] etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
@ -414,7 +414,7 @@ def table_suivi_cohorte(
(not bac or (bac == etud["bac"])) (not bac or (bac == etud["bac"]))
and (not bacspecialite or (bacspecialite == bacspe)) and (not bacspecialite or (bacspecialite == bacspe))
and (not annee_bac or (annee_bac == str(etud["annee_bac"]))) 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 statut or (statut == etud["statut"]))
and (not only_primo or context.isPrimoEtud(etud, sem)) and (not only_primo or context.isPrimoEtud(etud, sem))
): ):
@ -426,7 +426,7 @@ def table_suivi_cohorte(
bacs.add(etud["bac"]) bacs.add(etud["bac"])
bacspecialites.add(bacspe) bacspecialites.add(bacspe)
annee_bacs.add(etud["annee_bac"]) 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 if etud["statut"]: # ne montre pas les statuts non renseignés
statuts.add(etud["statut"]) statuts.add(etud["statut"])
sems = S.values() sems = S.values()
@ -617,8 +617,8 @@ def table_suivi_cohorte(
dbac += " (spécialité %s)" % bacspecialite dbac += " (spécialité %s)" % bacspecialite
if annee_bac: if annee_bac:
dbac += " (année bac %s)" % annee_bac dbac += " (année bac %s)" % annee_bac
if sexe: if civilite:
dbac += " genre: %s" % sexe dbac += " civilité: %s" % civilite
if statut: if statut:
dbac += " statut: %s" % statut dbac += " statut: %s" % statut
tab = GenTable( tab = GenTable(
@ -652,7 +652,15 @@ def table_suivi_cohorte(
expl.append(", ".join(ls) + "</li>") expl.append(", ".join(ls) + "</li>")
expl.append("</ul>") expl.append("</ul>")
logt("Z: table_suivi_cohorte done") 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( def formsemestre_suivi_cohorte(
@ -663,27 +671,35 @@ def formsemestre_suivi_cohorte(
bac="", bac="",
bacspecialite="", bacspecialite="",
annee_bac="", annee_bac="",
sexe="", civilite=None,
statut="", statut="",
only_primo=False, only_primo=False,
REQUEST=None, REQUEST=None,
): ):
"""Affiche suivi cohortes par numero de semestre""" """Affiche suivi cohortes par numero de semestre"""
percent = int(percent) 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, context,
formsemestre_id, formsemestre_id,
percent=percent, percent=percent,
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
only_primo=only_primo, only_primo=only_primo,
) )
tab.base_url = ( tab.base_url = (
"%s?formsemestre_id=%s&amp;percent=%s&amp;bac=%s&amp;bacspecialite=%s&amp;sexe=%s" "%s?formsemestre_id=%s&amp;percent=%s&amp;bac=%s&amp;bacspecialite=%s&amp;civilite=%s"
% (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, sexe) % (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, civilite)
) )
if only_primo: if only_primo:
tab.base_url += "&amp;only_primo=on" tab.base_url += "&amp;only_primo=on"
@ -693,8 +709,8 @@ def formsemestre_suivi_cohorte(
base_url = REQUEST.URL0 base_url = REQUEST.URL0
burl = ( burl = (
"%s?formsemestre_id=%s&amp;bac=%s&amp;bacspecialite=%s&amp;sexe=%s&amp;statut=%s" "%s?formsemestre_id=%s&amp;bac=%s&amp;bacspecialite=%s&amp;civilite=%s&amp;statut=%s"
% (base_url, formsemestre_id, bac, bacspecialite, sexe, statut) % (base_url, formsemestre_id, bac, bacspecialite, civilite, statut)
) )
if percent: if percent:
pplink = ( pplink = (
@ -724,12 +740,12 @@ def formsemestre_suivi_cohorte(
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
bacs=bacs, bacs=bacs,
bacspecialites=bacspecialites, bacspecialites=bacspecialites,
annee_bacs=annee_bacs, annee_bacs=annee_bacs,
sexes=sexes, civilites=civilites,
statuts=statuts, statuts=statuts,
percent=percent, percent=percent,
), ),
@ -749,12 +765,12 @@ def _gen_form_selectetuds(
bac=None, bac=None,
bacspecialite=None, bacspecialite=None,
annee_bac=None, annee_bac=None,
sexe=None, civilite=None,
statut=None, statut=None,
bacs=None, bacs=None,
bacspecialites=None, bacspecialites=None,
annee_bacs=None, annee_bacs=None,
sexes=None, civilites=None,
statuts=None, statuts=None,
): ):
"""HTML form pour choix criteres selection etudiants""" """HTML form pour choix criteres selection etudiants"""
@ -764,8 +780,8 @@ def _gen_form_selectetuds(
bacspecialites.sort() bacspecialites.sort()
annee_bacs = list(annee_bacs) annee_bacs = list(annee_bacs)
annee_bacs.sort() annee_bacs.sort()
sexes = list(sexes) civilites = list(civilites)
sexes.sort() civilites.sort()
statuts = list(statuts) statuts = list(statuts)
statuts.sort() statuts.sort()
# #
@ -824,13 +840,13 @@ def _gen_form_selectetuds(
F.append("</select>") F.append("</select>")
# #
F.append( F.append(
"""&nbsp; Genre: <select name="sexe" onchange="javascript: submit(this);"> """&nbsp; Genre: <select name="civilite" onchange="javascript: submit(this);">
<option value="" %s>tous</option> <option value="" %s>tous</option>
""" """
% selected % selected
) )
for b in sexes: for b in civilites:
if sexe == b: if civilite == b:
selected = 'selected="selected"' selected = 'selected="selected"'
else: else:
selected = "" selected = ""
@ -984,7 +1000,7 @@ def tsp_etud_list(
bac="", # selection sur type de bac bac="", # selection sur type de bac
bacspecialite="", bacspecialite="",
annee_bac="", annee_bac="",
sexe="", civilite="",
statut="", statut="",
): ):
"""Liste des etuds a considerer dans table suivi parcours """Liste des etuds a considerer dans table suivi parcours
@ -1000,7 +1016,7 @@ def tsp_etud_list(
bacs = set() bacs = set()
bacspecialites = set() bacspecialites = set()
annee_bacs = set() annee_bacs = set()
sexes = set() civilites = set()
statuts = set() statuts = set()
for etudid in etudids: for etudid in etudids:
etud = context.getEtudInfo(etudid=etudid, filled=True)[0] etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
@ -1010,7 +1026,7 @@ def tsp_etud_list(
(not bac or (bac == etud["bac"])) (not bac or (bac == etud["bac"]))
and (not bacspecialite or (bacspecialite == bacspe)) and (not bacspecialite or (bacspecialite == bacspe))
and (not annee_bac or (annee_bac == str(etud["annee_bac"]))) 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 statut or (statut == etud["statut"]))
and (not only_primo or context.isPrimoEtud(etud, sem)) and (not only_primo or context.isPrimoEtud(etud, sem))
): ):
@ -1019,11 +1035,11 @@ def tsp_etud_list(
bacs.add(etud["bac"]) bacs.add(etud["bac"])
bacspecialites.add(bacspe) bacspecialites.add(bacspe)
annee_bacs.add(etud["annee_bac"]) 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 if etud["statut"]: # ne montre pas les statuts non renseignés
statuts.add(etud["statut"]) statuts.add(etud["statut"])
# log('tsp_etud_list: %s etuds' % len(etuds)) # 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): def tsp_grouped_list(context, codes_etuds):
@ -1049,7 +1065,7 @@ def table_suivi_parcours(
): ):
"""Tableau recapitulant tous les parcours""" """Tableau recapitulant tous les parcours"""
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) 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 context, formsemestre_id, only_primo=only_primo
) )
codes_etuds = scu.DictDefault(defaultvalue=[]) codes_etuds = scu.DictDefault(defaultvalue=[])
@ -1065,7 +1081,7 @@ def table_suivi_parcours(
titles = { titles = {
"parcours": "Code parcours", "parcours": "Code parcours",
"nb": "Nombre d'étudiants", "nb": "Nombre d'étudiants",
"sexe": "", "civilite": "",
"nom": "Nom", "nom": "Nom",
"prenom": "Prénom", "prenom": "Prénom",
"etudid": "etudid", "etudid": "etudid",
@ -1082,7 +1098,7 @@ def table_suivi_parcours(
L = etuds L = etuds
columns_ids = ( columns_ids = (
"etudid", "etudid",
"sexe", "civilite",
"nom", "nom",
"prenom", "prenom",
"bac", "bac",
@ -1209,25 +1225,25 @@ def graph_parcours(
bac="", # selection sur type de bac bac="", # selection sur type de bac
bacspecialite="", bacspecialite="",
annee_bac="", annee_bac="",
sexe="", civilite="",
statut="", statut="",
): ):
"""""" """"""
if not scu.WITH_PYDOT: if not scu.WITH_PYDOT:
raise ScoValueError("pydot module is not installed") 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, context,
formsemestre_id, formsemestre_id,
only_primo=only_primo, only_primo=only_primo,
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
) )
# log('graph_parcours: %s etuds (only_primo=%s)' % (len(etuds), only_primo)) # log('graph_parcours: %s etuds (only_primo=%s)' % (len(etuds), only_primo))
if not etuds: if not etuds:
return "", etuds, bacs, bacspecialites, annee_bacs, sexes, statuts return "", etuds, bacs, bacspecialites, annee_bacs, civilites, statuts
edges = scu.DictDefault( edges = scu.DictDefault(
defaultvalue=set() defaultvalue=set()
) # {(formsemestre_id_origin, formsemestre_id_dest) : etud_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 # cf http://groups.google.com/group/pydot/browse_thread/thread/b3704c53e331e2ec
data = data.replace("font-family:Arial", "font-family:Helvetica") 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( def formsemestre_graph_parcours(
@ -1428,7 +1444,7 @@ def formsemestre_graph_parcours(
bac="", # selection sur type de bac bac="", # selection sur type de bac
bacspecialite="", bacspecialite="",
annee_bac="", annee_bac="",
sexe="", civilite="",
statut="", statut="",
allkeys=False, # unused allkeys=False, # unused
REQUEST=None, REQUEST=None,
@ -1437,7 +1453,15 @@ def formsemestre_graph_parcours(
# log("formsemestre_graph_parcours") # log("formsemestre_graph_parcours")
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if format == "pdf": if format == "pdf":
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours( (
doc,
etuds,
bacs,
bacspecialites,
annee_bacs,
civilites,
statuts,
) = graph_parcours(
context, context,
formsemestre_id, formsemestre_id,
format="pdf", format="pdf",
@ -1445,14 +1469,22 @@ def formsemestre_graph_parcours(
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
) )
filename = scu.make_filename("flux " + sem["titreannee"]) filename = scu.make_filename("flux " + sem["titreannee"])
return scu.sendPDFFile(REQUEST, doc, filename + ".pdf") return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
elif format == "png": elif format == "png":
# #
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours( (
doc,
etuds,
bacs,
bacspecialites,
annee_bacs,
civilites,
statuts,
) = graph_parcours(
context, context,
formsemestre_id, formsemestre_id,
format="png", format="png",
@ -1460,7 +1492,7 @@ def formsemestre_graph_parcours(
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
) )
filename = scu.make_filename("flux " + sem["titreannee"]) filename = scu.make_filename("flux " + sem["titreannee"])
@ -1475,17 +1507,25 @@ def formsemestre_graph_parcours(
else: else:
op = "" op = ""
url = urllib.quote( url = urllib.quote(
"formsemestre_graph_parcours?formsemestre_id=%s&amp;%sbac=%s&amp;bacspecialite=%s&amp;sexe=%s&amp;statut=%s&amp;format=" "formsemestre_graph_parcours?formsemestre_id=%s&amp;%sbac=%s&amp;bacspecialite=%s&amp;civilite=%s&amp;statut=%s&amp;format="
% (formsemestre_id, op, bac, bacspecialite, sexe, statut) % (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, context,
formsemestre_id, formsemestre_id,
only_primo=only_primo, only_primo=only_primo,
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
) )
@ -1505,12 +1545,12 @@ def formsemestre_graph_parcours(
bac=bac, bac=bac,
bacspecialite=bacspecialite, bacspecialite=bacspecialite,
annee_bac=annee_bac, annee_bac=annee_bac,
sexe=sexe, civilite=civilite,
statut=statut, statut=statut,
bacs=bacs, bacs=bacs,
bacspecialites=bacspecialites, bacspecialites=bacspecialites,
annee_bacs=annee_bacs, annee_bacs=annee_bacs,
sexes=sexes, civilites=civilites,
statuts=statuts, statuts=statuts,
percent=0, percent=0,
), ),

View File

@ -408,7 +408,7 @@ def list_synch(context, sem, anneeapogee=None):
etud = etudsapo_ident[key] etud = etudsapo_ident[key]
etud["etudid"] = "" etud["etudid"] = ""
etud["sexe"] = etud.get( etud["civilite"] = etud.get(
"sexe", etud.get("gender", "") "sexe", etud.get("gender", "")
) # la cle 'sexe' est prioritaire sur 'gender' ) # la cle 'sexe' est prioritaire sur 'gender'
etud["inscrit"] = is_inscrit # checkbox state etud["inscrit"] = is_inscrit # checkbox state
@ -545,16 +545,14 @@ def formsemestre_synchro_etuds_help(context, sem):
) )
def gender2sex(gender): def gender2civilite(gender):
"""Le portail code en 'M', 'F', et ScoDoc en 'MR', 'MME' """Le portail code en 'M', 'F', et ScoDoc en 'M', 'F', 'X'"""
Les F sont ici codées en MME if gender == "M" or gender == "F" or gender == "X":
""" return gender
if gender == "M": elif not gender:
return "MR" return "X"
elif gender == "F": log('gender2civilite: invalid value "%s", defaulting to "X"' % gender)
return "MME" return "X" # "X" en général n'est pas affiché, donc bon choix si invalide
log('gender2sex: invalid value "%s", defaulting to "M"' % gender)
return "MR"
def get_opt_str(etud, k): 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(), "prenom": etud["prenom"].strip(),
# Les champs suivants sont facultatifs (pas toujours renvoyés par le portail) # Les champs suivants sont facultatifs (pas toujours renvoyés par le portail)
"code_ine": etud.get("ine", "").strip(), "code_ine": etud.get("ine", "").strip(),
"sexe": gender2sex(etud["gender"].strip()), "civilite": gender2civilite(etud["gender"].strip()),
"etape": etud.get("etape", None), "etape": etud.get("etape", None),
"email": etud.get("mail", "").strip(), "email": etud.get("mail", "").strip(),
"emailperso": etud.get("mailperso", "").strip(), "emailperso": etud.get("mailperso", "").strip(),
@ -738,9 +736,9 @@ def do_import_etud_admission(
if x: if x:
args[sco_field] = x args[sco_field] = x
# Champs spécifiques: # Champs spécifiques:
sexe = gender2sex(etud["gender"].strip()) civilite = gender2civilite(etud["gender"].strip())
if sexe: if civilite:
args["sexe"] = sexe args["civilite"] = civilite
scolars.identite_edit_nocheck(cnx, args) scolars.identite_edit_nocheck(cnx, args)

View File

@ -337,13 +337,7 @@ def _trombino_pdf(context, groups_infos, REQUEST):
[img], [img],
[ [
Paragraph( Paragraph(
SU( SU(scolars.format_nomprenom(t)),
scolars.format_sexe(t["sexe"])
+ " "
+ scolars.format_prenom(t["prenom"])
+ " "
+ scolars.format_nom(t["nom"])
),
StyleSheet["Normal"], StyleSheet["Normal"],
) )
], ],
@ -422,13 +416,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
t = groups_infos.members[i] t = groups_infos.members[i]
img = _get_etud_platypus_image(context, t, image_width=PHOTOWIDTH) img = _get_etud_platypus_image(context, t, image_width=PHOTOWIDTH)
txt = Paragraph( txt = Paragraph(
SU( SU(scolars.format_nomprenom(t)),
scolars.format_sexe(t["sexe"])
+ " "
+ scolars.format_prenom(t["prenom"])
+ " "
+ scolars.format_nom(t["nom"])
),
StyleSheet["Normal"], StyleSheet["Normal"],
) )
if currow: if currow:

View File

@ -704,7 +704,7 @@ if WITH_PYDOT:
junk_graph = pydot.Dot("junk") junk_graph = pydot.Dot("junk")
junk_graph.add_node(pydot.Node("a")) junk_graph.add_node(pydot.Node("a"))
n = junk_graph.get_node("a") n = junk_graph.get_node("a")
if type(n) == type([]): if type(n) == type([]): # "modern" pydot
def pydot_get_node(g, name): def pydot_get_node(g, name):
r = g.get_node(name) r = g.get_node(name)
@ -713,7 +713,7 @@ if WITH_PYDOT:
else: else:
return r[0] return r[0]
else: else: # very old pydot
def pydot_get_node(g, name): def pydot_get_node(g, name):
return g.get_node(name) return g.get_node(name)

View File

@ -101,7 +101,7 @@ def format_etud_ident(etud):
else: else:
etud["nom_usuel"] = "" etud["nom_usuel"] = ""
etud["prenom"] = format_prenom(etud["prenom"]) etud["prenom"] = format_prenom(etud["prenom"])
etud["sexe"] = format_sexe(etud["sexe"]) etud["civilite_str"] = format_civilite(etud["civilite"])
# Nom à afficher: # Nom à afficher:
if etud["nom_usuel"]: if etud["nom_usuel"]:
etud["nom_disp"] = etud["nom_usuel"] etud["nom_disp"] = etud["nom_usuel"]
@ -111,10 +111,12 @@ def format_etud_ident(etud):
etud["nom_disp"] = etud["nom"] etud["nom_disp"] = etud["nom"]
etud["nomprenom"] = format_nomprenom(etud) # M. Pierre DUPONT etud["nomprenom"] = format_nomprenom(etud) # M. Pierre DUPONT
if etud["sexe"] == "M.": if etud["civilite"] == "M":
etud["ne"] = "" etud["ne"] = ""
else: elif etud["civilite"] == "F":
etud["ne"] = "e" etud["ne"] = "e"
else: # 'X'
etud["ne"] = "(e)"
# Mail à utiliser pour les envois vers l'étudiant: # Mail à utiliser pour les envois vers l'étudiant:
# choix qui pourrait être controé par une preference # choix qui pourrait être controé par une preference
# ici priorité au mail institutionnel: # ici priorité au mail institutionnel:
@ -128,14 +130,20 @@ def force_uppercase(s):
def format_nomprenom(etud): def format_nomprenom(etud):
"formatte sexe/nom/prenom pour affichages" """Formatte civilité/nom/prenom pour affichages: "M. Pierre Dupont" """
return " ".join( l = []
[format_sexe(etud["sexe"]), format_prenom(etud["prenom"]), etud["nom_disp"]] 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): def format_prenom(s):
"formatte prenom etudiant pour affichage" "Formatte prenom etudiant pour affichage"
if not s: if not s:
return "" return ""
frags = s.split() frags = s.split()
@ -162,22 +170,33 @@ def format_nom(s, uppercase=True):
return format_prenom(s) return format_prenom(s)
def format_sexe(sexe): def input_civilite(s):
sexe = scu.strlower(sexe) """Converts external representation of civilite to internal:
if sexe == "mr" or sexe == "m." or sexe == "m": 'M', 'F', or 'X' (and nothing else).
return "M." Raises valueError if conversion fails.
else: """
return "Mme" 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): def format_civilite(civilite):
"returns 'MR' ou 'MME'" """returns 'M.' ou 'Mme' ou '' (pour le genre neutre,
sexe = scu.strupper(sexe).strip() personne ne souhaitant pas d'affichage)
if sexe in ("M.", "M", "MR", "H"): """
return "MR" try:
elif sexe in ("MLLE", "MLLE.", "MELLE", "MME", "F"): return {
return "MME" "M": "M.",
raise ValueError("valeur invalide pour le sexe: %s" % sexe) "F": "Mme",
"X": "",
}[civilite]
except KeyError:
raise ValueError("valeur invalide pour la civilité: %s" % civilite)
def format_lycee(nomlycee): def format_lycee(nomlycee):
@ -241,7 +260,7 @@ _identiteEditor = EditableTable(
"nom", "nom",
"nom_usuel", "nom_usuel",
"prenom", "prenom",
"sexe", "civilite", # 'M", "F", or "X"
"date_naissance", "date_naissance",
"lieu_naissance", "lieu_naissance",
"dept_naissance", "dept_naissance",
@ -257,10 +276,10 @@ _identiteEditor = EditableTable(
input_formators={ input_formators={
"nom": force_uppercase, "nom": force_uppercase,
"prenom": force_uppercase, "prenom": force_uppercase,
"sexe": force_uppercase, "civilite": input_civilite,
"date_naissance": DateDMYtoISO, "date_naissance": DateDMYtoISO,
}, },
output_formators={"date_naissance": DateISOtoDMY, "sexe": normalize_sexe}, output_formators={"date_naissance": DateISOtoDMY},
convert_null_outputs_to_empty=True, convert_null_outputs_to_empty=True,
allow_set_id=True, # car on specifie le code Apogee a la creation 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): 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) objs = _identiteEditor.list(cnx, *a, **kw)
for o in objs: for o in objs:
if o["date_naissance"]: if o["date_naissance"]:
o["annee_naissance"] = int(o["date_naissance"].split("/")[2]) o["annee_naissance"] = int(o["date_naissance"].split("/")[2])
else: else:
o["annee_naissance"] = o["date_naissance"] o["annee_naissance"] = o["date_naissance"]
o["civilite_str"] = format_civilite(o["civilite"])
return objs return objs
@ -372,7 +392,6 @@ def identite_edit(cnx, args, context=None, REQUEST=None):
if notify_to: if notify_to:
# etat AVANT edition pour envoyer diffs # etat AVANT edition pour envoyer diffs
before = identite_list(cnx, {"etudid": args["etudid"]})[0] before = identite_list(cnx, {"etudid": args["etudid"]})[0]
before["sexe"] = format_sexe(before["sexe"])
identite_edit_nocheck(cnx, args) identite_edit_nocheck(cnx, args)
@ -380,7 +399,6 @@ def identite_edit(cnx, args, context=None, REQUEST=None):
if notify_to: if notify_to:
etud = context.getEtudInfo(etudid=args["etudid"], filled=True)[0] etud = context.getEtudInfo(etudid=args["etudid"], filled=True)[0]
after = identite_list(cnx, {"etudid": args["etudid"]})[0] after = identite_list(cnx, {"etudid": args["etudid"]})[0]
after["sexe"] = format_sexe(after["sexe"])
notify_etud_change( notify_etud_change(
context, context,
notify_to, notify_to,
@ -412,7 +430,7 @@ def notify_etud_change(context, email_addr, etud, before, after, subject):
""" """
txt = [ txt = [
"Code NIP:" + etud["code_nip"], "Code NIP:" + etud["code_nip"],
"Genre: " + etud["sexe"], "Civilité: " + etud["civilite_str"],
"Nom: " + etud["nom"], "Nom: " + etud["nom"],
"Prénom: " + etud["prenom"], "Prénom: " + etud["prenom"],
"Etudid: " + etud["etudid"], "Etudid: " + etud["etudid"],

View File

@ -3,12 +3,12 @@
"""Outils pour environnements de démo. """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). 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 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). (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 import sys
@ -54,17 +54,17 @@ cursor.execute(
wcursor = cnx.cursor() wcursor = cnx.cursor()
n = 0 n = 0
for (etudid,) in cursor: for (etudid,) in cursor:
sexe = random.choice(("M.", "MME")) civilite = random.choice(("M", "F")) # pas de neutre, on pourrait ajouter 'X'
nom, prenom = nomprenom(sexe) nom, prenom = nomprenom(civilite)
print(f"{etudid}: {nom}\t{prenom}") print(f"{etudid}: {nom}\t{prenom}")
args = { args = {
"nom": nom, "nom": nom,
"prenom": prenom, "prenom": prenom,
"sexe": sexe, "civilite": civilite,
"etudid": etudid, "etudid": etudid,
"code_nip": random.randrange(10000000, 99999999), "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) # print( req % args)
wcursor.execute(req, args) wcursor.execute(req, args)
n += 1 n += 1

View File

@ -10,14 +10,19 @@ cur_dir = Path(os.path.abspath(__file__)).parent
NOMS = [x.strip() for x in open(cur_dir / "noms.txt").readlines()] 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_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_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): def nomprenom(civilite):
"""un nom et un prenom au hasard, """Un nom et un prenom au hasard,
toujours en majuscules. 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) prenom = random.choice(PRENOMS_F)
else: elif civilite == "M":
prenom = random.choice(PRENOMS_H) 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() return random.choice(NOMS).upper(), prenom.upper()

View File

@ -0,0 +1,10 @@
Camille
Sacha
Eden
Maxime
Morgan
Charlie
Alix
Claude
Ufuk
Lou

View File

@ -38,6 +38,7 @@ DEMODIR = sco_utils.SCO_SRCDIR + "/scotests/demo/"
NOMS = [x.strip() for x in open(DEMODIR + "/noms.txt").readlines()] 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_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_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 # nb: en python2, les chaines ci-dessus sont en utf8
@ -66,16 +67,20 @@ class ScoFake:
sys.stderr.flush() sys.stderr.flush()
log("ScoFake: " + str(msg)) log("ScoFake: " + str(msg))
def sexenomprenom(self): def civilitenomprenom(self):
"""un nom et un prenom au hasard, """un nom et un prenom au hasard,
toujours en majuscules. toujours en majuscules.
""" """
sexe = random.choice(("M", "F")) civilite = random.choice(("M", "M", "M", "F", "F", "F", "X"))
if "e" in sexe.lower() or "f" in sexe.lower(): if civilite == "F":
prenom = random.choice(PRENOMS_F) prenom = random.choice(PRENOMS_F)
else: elif civilite == "M":
prenom = random.choice(PRENOMS_H) 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 @logging_meth
def create_etud( def create_etud(
@ -85,7 +90,7 @@ class ScoFake:
nom="", nom="",
prenom="", prenom="",
code_ine="", code_ine="",
sexe="", civilite="",
etape="TST1", etape="TST1",
email="test@localhost", email="test@localhost",
emailperso="perso@localhost", emailperso="perso@localhost",
@ -106,10 +111,10 @@ class ScoFake:
cnx = self.context.GetDBConnexion() cnx = self.context.GetDBConnexion()
if code_nip == "": if code_nip == "":
code_nip = str(random.randint(10000, 99999)) code_nip = str(random.randint(10000, 99999))
if not sexe or not nom or not prenom: if not civilite or not nom or not prenom:
r_sexe, r_nom, r_prenom = self.sexenomprenom() r_civilite, r_nom, r_prenom = self.civilitenomprenom()
if not sexe: if not civilite:
sexe = r_sexe civilite = r_civilite
if not nom: if not nom:
nom = r_nom nom = r_nom
if not prenom: if not prenom: