]> git.immae.eu Git - perso/Denise/oms.git/blame - gestion_donnees.py
Changelog mis à jour
[perso/Denise/oms.git] / gestion_donnees.py
CommitLineData
5679dfd0
DL
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
d03279e7 4from configuration import CONFIG,DEFAUT
a680b2f7
DL
5from gestion_erreurs import debug, warning, erreur, initialise_erreurs
6from gestion_couleurs import rgb_vers_tuple, tuple_vers_rgb
7from gestion_unites import choix_unite
5679dfd0 8import datetime
be2bf515
DL
9import json
10import unidecode
915e90bb 11import copy
5679dfd0 12
61020126
DL
13### Les données "tournent" selon :
14### python -> json -> (export/import) -> formulaire HTML -> données POST -> python etc
5679dfd0
DL
15
16############ Fonctions de conversion
17
18def convertit_jours_vers_python(chaine,liste_err):
19 """ convertit une chaine de type 1a 3m 1s 10j en jours
be2bf515 20 Renvoie un nombre de jours en float
5679dfd0
DL
21 Si un des caractères n'est ni un nombre, ni une lettre "autorisée" ni une espace,
22 on affiche un warning et on ignore ce caractère
23 """
b5ac625b 24# debug("conversion de "+chaine+" vers un nb de jours",liste_err)
5679dfd0
DL
25 chainenombre = ""
26 agejours = 0.
27 for lettre in chaine:
28 if lettre.isdigit():
29 chainenombre += lettre
30 else:
31 if lettre == 'a' or lettre == 'A':
32 # On a trouvé l'année, on ajoute tout ce qui est trouvé jusque là
d03279e7 33 agejours += int(chainenombre)*CONFIG["jours_dans_annee"]
5679dfd0
DL
34 chainenombre = ""
35 elif lettre == 'm' or lettre == 'M':
36 # On a trouvé le mois
d03279e7 37 agejours += int(chainenombre)*CONFIG["jours_dans_mois"]
5679dfd0
DL
38 chainenombre = ""
39 elif lettre == 's' or lettre == 'S':
40 # la semaine
d03279e7 41 agejours += int(chainenombre)*CONFIG["jours_dans_semaine"]
5679dfd0
DL
42 chainenombre = ""
43 elif lettre == 'j' or lettre == 'J':
44 # On a trouvé le jour
45 agejours += int(chainenombre)
46 chainenombre = ""
47 elif lettre != ' ':
48 # autre caractère : bizarre ?
2dc9eb43 49 warning("problème à la conversion de "+chaine+". Caractère invalide : "+lettre,liste_err)
5679dfd0
DL
50 # à la fin s'il reste qqch on le garde dans les jours
51 if chainenombre != "":
be2bf515 52 agejours += int(chainenombre)
5679dfd0
DL
53 if agejours<0:
54 warning("L'âge est négatif !",liste_err)
55 agejours = 0
b5ac625b 56# debug("On a convertit ! Résultat : "+str(agejours),liste_err)
be2bf515 57 return agejours
5679dfd0 58
8b5845ff 59# python -> json
5679dfd0
DL
60def convertit_age_vers_texte(nombre):
61 """ convertit un nombre de jours en un truc plus lisible en mois, années, jours
62 et renvoie une chaîne sous la forme 3a2m1j par exemple"""
d03279e7
DL
63 annees = int(nombre / CONFIG["jours_dans_annee"])
64 restant = nombre - annees*CONFIG["jours_dans_annee"]
65 mois = int(restant/CONFIG["jours_dans_mois"])
32b3d061 66 #print("mois : ",mois, ", restant : ",nombre - mois*CONFIG["jours_dans_mois"])
d03279e7 67 jours= round(nombre - mois*CONFIG["jours_dans_mois"] - annees*CONFIG["jours_dans_annee"])
5679dfd0
DL
68
69 chaine = ""
70 if annees >0:
71 chaine += str(annees)+"a"
72 if mois >0:
73 chaine += str(mois)+"m"
d4daf461 74 if jours>0 or nombre ==0: # si c'est la naissance, faut bien écrire 0j quand même
5679dfd0
DL
75 chaine += str(jours)+"j"
76 return chaine
a680b2f7 77
5679dfd0 78##########################
be2bf515 79
8b5845ff
DL
80# fonction qui calcule "auto" le maxi du graphique en fonction du max
81def calcule_max_graphique(l_jours):
82 """ calcule l'age maxi sur le graphique"""
83 if l_jours == []:
84 return CONFIG["jours_defaut_donneesvides"]
85 else:
86 jour_maxi = max(l_jours)# pas la peine d'aller très au delà du jour max
c2fe511b 87 jour_maxi = int(jour_maxi* 1.2)+3 # on rajoute un peu
8b5845ff
DL
88 return jour_maxi
89
be2bf515
DL
90
91def simplifie_nom(chaine):
92 """ simplifie le nom chaine afin d'en faire une extension
7aac9b2a 93 pour le nom du fichier. Vire les caractères spéciaux
be2bf515
DL
94 et max 15 caractères"""
95 chaine2 = ""
96 for l in chaine:
97 if l.isalpha():
98 chaine2+=l
99 chaine2 = unidecode.unidecode(chaine2)
100 return chaine2[:15]
5679dfd0 101
8b5845ff
DL
102def convertit_donnee_vers_python(chaine,typedonnee,liste_err):
103 """ convertit une chaine vers un float qui est le type donnee voulu.
104 La virgule peut être . ou , et on vire d'éventuels espaces.
ca61f310
DL
105 Taille invalide : on renvoie 0 avec un warning.
106 Si la chaine est en fait déjà au format float, on laisse tel quel"""
107 if type(chaine) == float:
108 return chaine
5679dfd0
DL
109 chaine2 = chaine.replace(",",".")
110 chaine2 = chaine2.replace(" ","")
ca61f310 111
5679dfd0
DL
112
113 try:
8b5845ff 114 donnee = float(chaine2)
5679dfd0 115 except:
8b5845ff
DL
116 warning(typedonnee+" impossible à lire : "+chaine,liste_err)
117 donnee = 0
d9eaf2e2
DL
118
119 # Pour le poids, un cas particulier
120 if typedonnee == "poids" and donnee > CONFIG["poids_maxi_conversion"]:
121 donnee = donnee/1000 # conversion en grammes
8b5845ff 122 if not( 0<=donnee<CONFIG[typedonnee+"_maxi"]):
d9eaf2e2 123 warning(typedonnee+" incohérent(e) : "+str(donnee),liste_err)
8b5845ff
DL
124 donnee = 0
125 return donnee
5679dfd0 126
5679dfd0
DL
127
128#########################
129
8b5845ff 130# web -> python
5679dfd0
DL
131def convertit_date_vers_python(chaine,liste_err):
132 """ prend une chaine comme renvoyée par un champ de formulaire date
133 aaaa-mm-jj et en fait une date python
64be08b2
DL
134 renvoie "" si ne marche pas.
135 Si jamais la date est au format avec des / ça devrait passer aussi."""
136 if "/" in chaine:
137 liste = chaine.split("/")
138 else:
139 liste = chaine.split("-")
5679dfd0
DL
140 if len(liste) != 3:
141 warning("La date : "+chaine+" est invalide !",liste_err)
142 return ""
143 else:
7aac9b2a
D
144 print(liste_err)
145
30158504 146 debug("Conversion de la date "+chaine+". Découpage : "+str(liste),liste_err)
9cb3c31c
DL
147 try:
148 date = datetime.date(int(liste[0]),int(liste[1]),int(liste[2]))
149 except:
150 date = ""
7aac9b2a 151 warning("Impossible de lire la date "+chaine+". Format accepté : aaaa-mm-jj ou aaaa/mm/jj",liste_err)
9cb3c31c 152 return date
8b5845ff
DL
153
154# python -> json
5679dfd0
DL
155def convertit_date_vers_texte(date):
156 """ convertit une date python en format texte aaaa-mm-jj"""
157 if date == "":
158 return ""
159 else:
2dc9eb43
DL
160 #return (str(date.year)+"-"+str(date.month)+"-"+str(date.day))
161 return str(date)
5679dfd0 162
9d7f1506 163def delta_date(date1,datenaissance, liste_err):
5679dfd0
DL
164 """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
165 datenaissance est supposée antérieure. Erreur sinon."""
32b3d061
D
166 if type(date1) != datetime.date or type(datenaissance) != datetime.date:
167 return -1
5679dfd0
DL
168 d = date1 - datenaissance
169 jours = d.days
170 if jours<0:
9d7f1506 171 warning("Une des dates saisies ("+str(date1)+") est inférieure à la date de naissance (la donnée est donc ignorée)", liste_err)
5679dfd0
DL
172 return -1
173 return jours
174
175
2dc9eb43 176
8b5845ff
DL
177################### On regroupe tout ce qui gère les données en une fonction
178
ca61f310 179def web_vers_python(data,liste_err, court=False):
8b5845ff 180 """ prend en argument le dictionnaire de requête et renvoie la config, et les
a63ef1b0 181 tableaux de données
ca61f310
DL
182 court : si True est précisé, on ne met que le nom dans la config (enfant
183 additionnel)"""
8b5845ff
DL
184
185 # Régler la configuration
ca61f310 186 config = gere_configuration(data,liste_err, court)
8b5845ff
DL
187
188 # récupérer les données
189 listes_jours = {}
190 listes_donnees = {}
191 for typed in CONFIG["liste_typedonnees"]:
192 listes_jours[typed],listes_donnees[typed] = gere_donnees(data,config["naissance"],typed,liste_err)
193
438ef56d
DL
194 # Si on veut extrapoler au-delà du jour maxi, on adapte
195
8b5845ff 196 # Si on a choisi la même échelle de données
ca61f310 197 if config.get("memechelle") == "oui":
8b5845ff 198 config["non_sauve"]["maxi"] = calcule_max_graphique([j for lj in listes_jours.values() for j in lj])
438ef56d
DL
199 # En cas d'extrapolation, on prend le maxi
200 if config["non_sauve"]["calculextradata_type"] !="" and config["non_sauve"]["calculextradata_age"]>config["non_sauve"]["maxi"]:
201 config["non_sauve"]["maxi"] = int(config["non_sauve"]["calculextradata_age"]) +1
8b5845ff
DL
202 config["non_sauve"]["unite"] = choix_unite(config["non_sauve"]["maxi"])
203
204 return (config,listes_jours,listes_donnees)
205
206
207
a680b2f7 208########### Fonctions qui gèretn les données web vers python
5679dfd0 209
8b5845ff
DL
210def gere_checkbox(chaine):
211 """ prend en arg une chaine, et renvoie "oui" si c'est "on" (sortie de la checkbox)
212 et chaîne vide si n'importe quoi d'autre"""
213 if chaine == "on":
214 return "oui"
215 else:
216 return ""
5679dfd0 217
ca61f310
DL
218def gere_symbole(chaine):
219 """ prend en arg une chaîne genre "o", ">" et vérifie si c'est un symbole valide.
220 Renvoie ce symbole-là ou le défaut"""
221 if chaine in CONFIG["liste_symboles"]:
222 return chaine
223 else:
224 return DEFAUT["symbole"]
225
226def gere_configuration(data,liste_err, court=False):
be2bf515 227 """ prend en argument le dictionnaire de requête (configuration imparfaite), et
5679dfd0 228 construit le dictionnaire de configuration qui va bien.
ca61f310
DL
229 Vérifie que chaque entrée est cohérente évidemment.
230 court : si mis à True, on ne met que le nom dans la configuraion,
231 ainsi que la date de naissance et le sexe"""
a680b2f7 232 # Initialisation
685a5f75 233 configuration = {"non_sauve": {}}
5679dfd0
DL
234
235 # Pour le nom, osef qu'il soit vide
236 nom = data.get("nom","")
237 # Par contre s'il est trop long on le tronque
d03279e7 238 configuration["nom"] = nom[:CONFIG["longueur_max_nom_bebe"]]
ca61f310 239
5679dfd0
DL
240 naissance = data.get("naissance","")
241 if naissance !="":
242 naissance = convertit_date_vers_python(naissance,liste_err)
243 configuration["naissance"] = naissance
244
ca61f310
DL
245 sexe = data.get("sexe","")
246 if not (sexe in ["F","M","N"]):
a63fb483 247 warning("Le sexe de l'enfant est invalide. "+sexe,liste_err)
ca61f310
DL
248 sexe = "N"
249 configuration["sexe"] = sexe
250
251 if not(court):
252
253 prematurite = data.get("prematurite","")
254 j = convertit_jours_vers_python(prematurite,liste_err)
255 configuration["prematurite"] = convertit_age_vers_texte(j)
5679dfd0 256
ca61f310
DL
257 configuration["agecorrige"] = gere_checkbox(data.get("agecorrige",""))
258
259 # Type de courbe. Au pire on met P
260 tyc = data.get("typecourbe","")
261 if not (tyc in ["P","Z"]):
262 tyc = "P"
263 configuration["typecourbe"] = tyc
264
265 # unité
266 unite = data.get("unite","")
267 if not (unite in CONFIG["liste_unites"]):
268 unite = ""
269 #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
270 configuration["unite"] = unite
271
272 # grille
273 configuration["grille"] = gere_checkbox(data.get("grille",""))
274
275 # tracer ou non les courbes vides
276 configuration["tracevide"] = gere_checkbox(data.get("tracevide",""))
277
278 # Même échelle sur tous les graphiques
279 configuration["memechelle"] = gere_checkbox(data.get("memechelle",""))
5679dfd0 280
ca61f310
DL
281
282 # maxi. 0 signifie qu'on veut pas de maxi
283 maxi = data.get("maxi","")
284 if maxi == "":
285 configuration["maxi"] = 0
286 else:
287 configuration["maxi"] = int(convertit_jours_vers_python(maxi,liste_err))
288
289 # dimensions du graphique
290 largeur = data.get("largeur","")
291 if largeur == "":
915e90bb 292 largeur = DEFAUT["largeur_graphique"]
ca61f310
DL
293 else:
294 try:
295 largeur = int(largeur)
296 except:
297 warning("La largeur "+largeur+"est invalide !",liste_err)
298 largeur = DEFAUT["largeur_graphique"]
299 if largeur > CONFIG["largeur_graphique_max"]:
300 largeur = CONFIG["largeur_graphique_max"]
301 warning("Largeur du graphique trop grande !",liste_err)
302 elif largeur < CONFIG["largeur_graphique_min"]:
303 largeur = CONFIG["largeur_graphique_min"]
304 warning("Largeur du graphique trop petite !",liste_err)
305 configuration["largeur"] = largeur
306
307 hauteur = data.get("hauteur","")
308 if hauteur == "":
915e90bb 309 hauteur = DEFAUT["hauteur_graphique"]
ca61f310
DL
310 else:
311 try:
312 hauteur = int(hauteur)
313 except:
314 warning("La hauteur "+hauteur+"est invalide !",liste_err)
315 hauteur = DEFAUT["hauteur_graphique"]
316 if hauteur > CONFIG["hauteur_graphique_max"]:
317 hauteur = CONFIG["hauteur_graphique_max"]
318 warning("Hauteur du graphique trop grande !",liste_err)
319 elif hauteur < CONFIG["hauteur_graphique_min"]:
320 hauteur = CONFIG["hauteur_graphique_min"]
321 warning("Hauteur du graphique trop petite !",liste_err)
322 configuration["hauteur"] = hauteur
323
324 # existence et position de la légende
325 configuration["legende"] = gere_checkbox(data.get("legende",""))
326
327 positionlegende = data.get("positionlegende","")
328 if not(positionlegende in ['upper left','upper right','lower left','lower right']):
329 positionlegende = "upper left"
330 configuration["positionlegende"] = positionlegende
331
332 configuration["couleurs"] = {}
333 # gérer les couleurs
334 for clecouleur in DEFAUT["couleurs"]:
38b5e10a 335 coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),DEFAUT["couleurs"].get(clecouleur, ""),liste_err)
ca61f310
DL
336 configuration["couleurs"][clecouleur] = coul
337
338 # symbole
339 configuration["symbole"] = gere_symbole( data.get("symbole", ""))
fd69b6b5 340
ca61f310 341 configuration["non_sauve"]["grilleamelio"] = gere_checkbox(data.get("grilleamelio",""))
cf0d4c8c 342
cf0d4c8c 343
ca61f310
DL
344 #### La partie extrapolation n'a pas besoin d'être sauvée
345 configuration["non_sauve"]["prolongercourbes"] = gere_checkbox(data.get("prolongercourbes",""))
fd69b6b5 346
ca61f310
DL
347 # Valeur par défaut : 1
348 debug(data.get("nbextradata", "aaargh"), liste_err)
349 nbextradata = data.get("nbextradata",1)
350 try:
351 nbextradata = int(nbextradata)
352 except:
353 warning("Le nombre de données sur lequel on extrapole est invalide : "+nbextradata, liste_err)
354 nbextradata = 1
355 configuration["non_sauve"]["nbextradata"] = nbextradata
356
32b3d061
D
357 if data.get("calculextradata_type","") in CONFIG["liste_typedonnees"]: # Si on a choisi un type de données à calculer
358
ca61f310 359 configuration["non_sauve"]["calculextradata_type"] = data.get("calculextradata_type","")
32b3d061 360 age = convertit_jours_vers_python(data.get("calculextradata_age","0j"),liste_err)
7aac9b2a 361 date = convertit_date_vers_python(data.get("calculextradata_date", ""), liste_err)
32b3d061
D
362 agecalcule = delta_date(date, configuration["naissance"], liste_err)
363 if configuration["naissance"] != "" and agecalcule != -1: # On garde plutôt la date
364 configuration["non_sauve"]["calculextradata_age"] = agecalcule
365 configuration["non_sauve"]["calculextradata_date"] = date
366 else: # On garde l'âge
367 configuration["non_sauve"]["calculextradata_age"] = age
368 if type(configuration["naissance"]) == datetime.date:
369# print(configuration["naissance"], type(configuration["naissance"]))
370 configuration["non_sauve"]["calculextradata_date"] = configuration["naissance"] + datetime.timedelta(days=round(age))
371 else:
372 configuration["non_sauve"]["calculextradata_date"] = None
ca61f310
DL
373 else:
374 configuration["non_sauve"]["calculextradata_type"] = ""
32b3d061 375 # On ne met rien dans les autres données, pas la peine
ca61f310
DL
376
377 ctyped = data.get("calculextratemps_type","")
378 if ctyped in CONFIG["liste_typedonnees"]:
379 configuration["non_sauve"]["calculextratemps_type"] = ctyped
380 configuration["non_sauve"]["calculextratemps_val"] = convertit_donnee_vers_python(data.get("calculextratemps_val",""), ctyped, liste_err)
381 else:
382 configuration["non_sauve"]["calculextratemps_type"] = ""
383
384 # Tracer les calculs sur la grille
385 configuration["non_sauve"]["calculextradata_trace"] = gere_checkbox(data.get("calculextradata_trace"))
386 configuration["non_sauve"]["calculextratemps_trace"] = gere_checkbox(data.get("calculextratemps_trace"))
3d7da80a
DL
387
388
6ac2173a
DL
389 ### Gestion des repères additionnels
390 configuration["liste_reperes"] = []
391 i=0
392 while "repere_texte_"+str(i) in data: # Tant qu'il y a des trucs définis
393 debug("Repère trouvé", liste_err)
32b3d061
D
394 jegardecerepere = False # On va passer à True uniquementsi tout va bien
395
6ac2173a 396 age=data.get("repere_age_"+str(i), "")
32b3d061 397 date=data.get("repere_date_"+str(i), "")
6ac2173a 398 trace=gere_checkbox(data.get("repere_trace_"+str(i), ""))
32b3d061
D
399 affichedate=gere_checkbox(data.get("repere_affichedate_"+str(i), ""))
400
401 if date!="" and configuration['naissance'] != "": # Si on a saisi une date (et qu'il y a la date de naissance)
402 datepython = convertit_date_vers_python(date,liste_err)
403 if datepython !="": # Si la conversion s'est bien passée
404 nbjours = delta_date(datepython, configuration['naissance'], liste_err)
405 if nbjours != -1: # Si tout va bien jusque là
406 jegardecerepere=True
407 elif age !="":
408 nbjours=convertit_jours_vers_python(age, liste_err)
409 jegardecerepere=True
410
411 if jegardecerepere:
6ac2173a 412 texte = data.get("repere_texte_"+str(i), "") # Même si le texte est vide, osef
32b3d061 413 configuration["liste_reperes"].append({"typed": "age", "donnee": nbjours, "date": date, "texte": texte, "trace": trace, "affichedate":affichedate})
6ac2173a
DL
414 i+=1
415
5679dfd0 416 return configuration
5679dfd0 417
cf0d4c8c
DL
418
419
a680b2f7 420## web vers python : données
8b5845ff
DL
421def gere_donnees(data,naissance,typedonnee,liste_err):
422 """ prend en argument le dictionnaire de requête, et la date de
423 naissance (éventuellement vide), et construit deux listes :
424 l_jours et l_data correspondantes.
425 Il faut donner en argument le type de données : voir
426 CONFIG["liste_typedonnees"]"""
427 if typedonnee not in CONFIG["liste_typedonnees"]:
428 warning("gere_donnees : le type de données : "+typedonnee+" est invalide !! Types acceptés : "+str(CONFIG["liste_typedonnees"]),liste_err)
429 return ([],[])
430
431 # On construit une liste de couples d'abord
5679dfd0
DL
432 liste_donnees = []
433
434 i = 0
8b5845ff 435 # On va chercher si y'a des données à donnee_i
a63ef1b0
DL
436 while "age_"+str(i) in data.keys():
437 if data.get(typedonnee+"_"+str(i), "") != "": # si la donne de ce type existe
8b5845ff 438 donnee = convertit_donnee_vers_python(data[typedonnee+"_"+str(i)],typedonnee,liste_err)
d4daf461
DL
439
440 ## Si une date est saisie, on la prend en priorité car c'est des entiers et les entiers c'est BIEN
441 date = data.get("date_"+str(i),"")
7aac9b2a
D
442 if date != "":
443 datep = convertit_date_vers_python(date,liste_err)
444 else:
445 datep = ""
d4daf461
DL
446
447 if naissance != "" and datep != "": # On ne peut pas calculer l'âge si on n'a pas ces deux données
448 age = delta_date(datep,naissance, liste_err)
449 if age != -1: # -1 signifie une erreur donc on ne garde pas la donnée
9d7f1506 450 liste_donnees.append((age,donnee))
d4daf461
DL
451 else: # Sinon, on regarde si on a saisi l'âge
452 age = data.get("age_"+str(i),"")
453 if age == "":
454 warning("gere_donnees : ni l'âge ni la date ne sont saisies... donnée ignorée", liste_err)
455 else:
456 age = convertit_jours_vers_python(age,liste_err)
457 liste_donnees.append((age,donnee))
5679dfd0
DL
458 i+=1
459
460 # Trier la liste
461 liste_donnees.sort(key=lambda x : x[0])
462
463 # splitter la liste
464 l_jours = [x[0] for x in liste_donnees]
8b5845ff 465 l_donnee = [x[1] for x in liste_donnees]
5679dfd0 466
8b5845ff 467 return (l_jours,l_donnee)
be2bf515 468
e4ec2d3d
DL
469# web vers python : enfants additionnels
470def gere_enfants_additionnels(data, files, liste_err):
471 """ data est le dictionnaire de requête.
472 files est le dictionnaire des fichiers (flask.request.files).
473 Renvoie les enfants additionnels sous forme de liste de dictionnaires :
474 {typed: (conf, lj, ldonnees)}
475 Dans conf y'a les infos qu'il faut pour tracer la courbe additionnelle voulue.
476 """
477
478 enfants_add = [] # Enfants additionnels
479 # Les enfants additionnels commencent à 2 (puis 3, 4, etc)
480 i=2
481 while "couleur_donnees_"+str(i) in data: # Tant qu'il y a des données de ce type
482 if 'fichier_donnees_'+str(i) in files: # Un enfant à ajouter
483 fichier = files["fichier_donnees_"+str(i)]
484 chaine = fichier.read() # On récupère la chaîne
485 if len(chaine)>=5: # Si elle a une longueur à peu près raisonnable
486 debug("Un fichier de données additionnel trouvé", liste_err)
487 formulaire_2 = fichier_json_vers_configdonnees(chaine, liste_err)
488 if formulaire_2 =={}:
489 warning("Le fichier de données additionnel est vide ou mal formaté", liste_err)
490 else:
491 debug("Form 2 : "+str(formulaire_2), liste_err)
492 # Récupérer sous forme python
493 conf2, ljours2, listes_donnees2 = web_vers_python(formulaire_2,liste_err, court=True)
494 debug("Form 2 données travaillées "+str(ljours2)+str(listes_donnees2), liste_err)
495 # Le symbole et la couleur
496 symb2 = gere_symbole(data.get("symbole_donnees_"+str(i)))
497 coul2 = rgb_vers_tuple(data.get("couleur_donnees_"+str(i),""),CONFIG["couleurs"]["cadretxt"],liste_err)
7aac9b2a
D
498 alias = data.get("alias_"+str(i), "")
499 if alias != "": # Si l'alias n'est pas vide, il remplace le prénom
500 print(conf2)
501 conf2["nom"] = alias
502
e4ec2d3d
DL
503 enfant2 = eclate_donnees_additionnelles(conf2, ljours2, listes_donnees2, symb2, coul2)
504 enfants_add.append(enfant2)
505 i+=1
506
507 return enfants_add
508
509
510
511
be2bf515 512
a680b2f7 513# python vers Json
8b5845ff 514#### export vers json
be2bf515 515
8b5845ff 516def donnees_vers_json(l_jours,l_poids,l_jourst,l_taille,config):
be2bf515 517 """ retourne le json à renvoyer"""
915e90bb 518 gros_dico = copy.deepcopy(config)
2dc9eb43 519 gros_dico["version"] = CONFIG["version"]
be2bf515 520 l_jours2 = [convertit_age_vers_texte(d) for d in l_jours]
8b5845ff 521 l_jourst2 = [convertit_age_vers_texte(d) for d in l_jourst]
be2bf515
DL
522 gros_dico["data_j"] = l_jours2
523 gros_dico["data_p"] = l_poids
8b5845ff
DL
524 gros_dico["data_jours_taille"] = l_jourst2
525 gros_dico["data_taille"] = l_taille
be2bf515
DL
526 # gérer la date de naissance
527 if gros_dico.get("naissance","") != "":
528 gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"])
2dc9eb43 529 # Calcul de toutes les dates de données
32b3d061
D
530 l_dates_poids = [convertit_date_vers_texte( config["naissance"] + datetime.timedelta(days=round(jours)) ) for jours in l_jours]
531 l_dates_taille = [convertit_date_vers_texte( config["naissance"] + datetime.timedelta(days=round(jours)) ) for jours in l_jourst]
2dc9eb43
DL
532 gros_dico["data_dates_poids"]= l_dates_poids
533 gros_dico["data_dates_taille"] = l_dates_taille
534
535
be2bf515
DL
536 # gérer l'age maxi
537 gros_dico["maxi"] = convertit_age_vers_texte(gros_dico["maxi"])
6ac2173a
DL
538 # Gérer les repères
539 for i in range(len(gros_dico["liste_reperes"])):
540 gros_dico["liste_reperes"][i]["donnee"] = convertit_age_vers_texte(gros_dico["liste_reperes"][i]["donnee"])
fd69b6b5 541 # gérer les couleurs
915e90bb
DL
542 for clecouleur in DEFAUT["couleurs"]:
543 gros_dico["couleurs"][clecouleur] = tuple_vers_rgb(gros_dico["couleurs"][clecouleur])
fd69b6b5 544
8b5845ff
DL
545 # Enlever ce qui ne se sauvegarde pas si y'a
546 if "non_sauve" in gros_dico:
547 del gros_dico["non_sauve"]
5679dfd0 548
be2bf515 549 return json.dumps(gros_dico, indent=2,ensure_ascii=False )
5679dfd0 550
2dc9eb43 551def fusionne_donnees(listes_jours,listes_donnees, listes_dates):
8b5845ff
DL
552 """ prend en argument deux dicos de listes. Chaque liste de jours est associée à une liste
553 de données (par la même clé de type de données). Il faut les fusionner pour avoir une liste de dictionnaires, de type
2dc9eb43
DL
554 {"age":truc, "donnee1":truc, "donnee2":truc, ...} triée par ordre de jours. Si jamais une des données est vide,
555 le champ du dictionnaire n'est pas rempli
556 Le troisième paquet de listes (les dates) peut être vide ou bien simiaire : même clés."""
a680b2f7 557
8b5845ff
DL
558 def fini(lj):
559 """ teste si les listes sont toutes vides """
560 for l in lj.values():
561 if l!=[]:
562 return False
563 return True
564
565 def mini(lj):
566 """ renvoie la clé de la liste où il y a le min """
567 cle_mini = CONFIG["liste_typedonnees"][0]
568 for (cle,liste) in lj.items():
569 if lj[cle_mini]== []:
570 cle_mini = cle
571 elif lj[cle] != []:
b5ac625b 572 if convertit_jours_vers_python(lj[cle][0],initialise_erreurs())<convertit_jours_vers_python(lj[cle_mini][0],initialise_erreurs()):
8b5845ff
DL
573 cle_mini = cle
574 return cle_mini
575
576 liste_f = []
577 while not(fini(listes_jours)):
578 typedonnee = mini(listes_jours)
579 # On extrait les données dans les deux listes (jours et données)
580 jour = listes_jours[typedonnee].pop(0)
581 donnee = listes_donnees[typedonnee].pop(0)
2dc9eb43 582
8b5845ff
DL
583 if liste_f == [] or jour != liste_f[-1]["age"]: # Si le jour est un "nouveau" jour
584 liste_f.append({"age":jour})
2dc9eb43 585 # On met à jour l'élément (ou on l'ajoute)
8b5845ff
DL
586 liste_f[-1][typedonnee] = donnee
587
2dc9eb43
DL
588 # Si il y a une date associée, on la met !
589 if listes_dates[typedonnee] != []:
590 date = listes_dates[typedonnee].pop(0)
591 liste_f[-1]["date"] = convertit_date_vers_texte(date)
592
593
8b5845ff
DL
594 return liste_f
595
5679dfd0 596
a680b2f7 597### COnversion json vers formulaire
8b5845ff 598# Json -> formulaire HTML
d03279e7 599def fichier_json_vers_configdonnees(chaine,liste_err):
a680b2f7
DL
600 """ prend le json importé (chaine) et l'exporte vers les valeurs du formulaire
601 Renvoyé sous forme de dictionnaire (mais adapté au formulaire web)"""
d03279e7
DL
602 debug("json vers config : Prêt à interpréter le json",liste_err)
603 try:
604 valform = json.loads(chaine)
605 except :
606 erreur("Impossible de lire le fichier json !",liste_err)
607 return {}
be2bf515
DL
608 # Il faut maintenant récupérer les l_jours et l_poids puis les remettre
609 # sous forme de age_i et poids_i
8b5845ff
DL
610
611 listes_jours = {}
612 listes_donnees = {}
2dc9eb43 613 listes_dates = {}
8b5845ff
DL
614 for typed in CONFIG["liste_typedonnees"]:
615 if typed == "poids": # pour la rétrocompatibilité
616 listes_jours[typed] = valform.get("data_j",[])
617 listes_donnees[typed] = valform.get("data_p",[])
2dc9eb43 618 listes_dates[typed] = valform.get("data_dates_"+typed,[])
8b5845ff
DL
619 else:
620 listes_jours[typed] = valform.get("data_jours_"+typed,[])
621 listes_donnees[typed] = valform.get("data_"+typed,[])
2dc9eb43
DL
622 listes_dates[typed] = valform.get("data_dates_"+typed,[])
623
8b5845ff
DL
624
625 debug("Avant fusion : listes jours "+str(listes_jours),liste_err)
2dc9eb43 626 liste_donnees = fusionne_donnees(listes_jours,listes_donnees, listes_dates)
8b5845ff
DL
627 debug("Fusion de listes ok. Liste moche : "+str(liste_donnees),liste_err)
628 for i in range(len(liste_donnees)):
629 for (cle,val) in liste_donnees[i].items():
630 valform[cle+"_"+str(i)] = val
be2bf515 631
8b5845ff 632 valform["nb_data"] = max(len(liste_donnees) +2,DEFAUT["nb_data"])
5679dfd0 633
be2bf515 634 return valform
5679dfd0 635
5679dfd0 636
ca61f310
DL
637
638#### Pour l'insertion d'une 2e (ou plus) courbe sur le graphique, ue fonction qui sépare tout ça
38b5e10a 639def eclate_donnees_additionnelles(conf, ljours, ldonnees, symb, couleur):
ca61f310
DL
640 """ conf est la config (on ne garde que le nom) pour un enfant additionnel,
641 ljours et ldonnees les dictionnaires de listes contenant les données.
642 symb est le symbole choisi pour cette courbe additionnelle (déjà vérifié)
e4ec2d3d 643 On fabrique un joli dictionnaire typed -> (conf, lj, ldonnee) avec le nom de l'enfant,
ca61f310 644 et les données pour chaque typed"""
e4ec2d3d 645 #print("test conf avant "+str(ldonnees)+str(ljours))
ca61f310
DL
646
647 retour = {}
648 conf["symbole"] = symb # On ajoute le symbole additionnel
38b5e10a 649 conf["couleurcourbe"] = couleur # la couleur
ca61f310
DL
650 for typed in CONFIG["liste_typedonnees"]:
651 retour[typed] = (conf, ljours[typed], ldonnees[typed])
652
e4ec2d3d 653 #print("test "+str(retour))
ca61f310 654 return retour