diff options
Diffstat (limited to 'gestion_donnees.py')
-rw-r--r-- | gestion_donnees.py | 209 |
1 files changed, 151 insertions, 58 deletions
diff --git a/gestion_donnees.py b/gestion_donnees.py index 6abcd51..3523e7e 100644 --- a/gestion_donnees.py +++ b/gestion_donnees.py | |||
@@ -4,6 +4,7 @@ | |||
4 | from configuration import CONFIG,DEFAUT | 4 | from configuration import CONFIG,DEFAUT |
5 | from gestion_erreurs import * | 5 | from gestion_erreurs import * |
6 | from gestion_couleurs import * | 6 | from gestion_couleurs import * |
7 | from gestion_unites import * | ||
7 | import datetime | 8 | import datetime |
8 | import json | 9 | import json |
9 | import unidecode | 10 | import unidecode |
@@ -53,6 +54,7 @@ def convertit_jours_vers_python(chaine,liste_err): | |||
53 | agejours = 0 | 54 | agejours = 0 |
54 | return agejours | 55 | return agejours |
55 | 56 | ||
57 | # python -> json | ||
56 | def convertit_age_vers_texte(nombre): | 58 | def convertit_age_vers_texte(nombre): |
57 | """ convertit un nombre de jours en un truc plus lisible en mois, années, jours | 59 | """ convertit un nombre de jours en un truc plus lisible en mois, années, jours |
58 | et renvoie une chaîne sous la forme 3a2m1j par exemple""" | 60 | et renvoie une chaîne sous la forme 3a2m1j par exemple""" |
@@ -71,6 +73,16 @@ def convertit_age_vers_texte(nombre): | |||
71 | return chaine | 73 | return chaine |
72 | ########################## | 74 | ########################## |
73 | 75 | ||
76 | # fonction qui calcule "auto" le maxi du graphique en fonction du max | ||
77 | def calcule_max_graphique(l_jours): | ||
78 | """ calcule l'age maxi sur le graphique""" | ||
79 | if l_jours == []: | ||
80 | return CONFIG["jours_defaut_donneesvides"] | ||
81 | else: | ||
82 | jour_maxi = max(l_jours)# pas la peine d'aller très au delà du jour max | ||
83 | jour_maxi = int(jour_maxi* 1.1)+3 # on rajoute un peu | ||
84 | return jour_maxi | ||
85 | |||
74 | 86 | ||
75 | def simplifie_nom(chaine): | 87 | def simplifie_nom(chaine): |
76 | """ simplifie le nom chaine afin d'en faire une extension | 88 | """ simplifie le nom chaine afin d'en faire une extension |
@@ -83,29 +95,27 @@ def simplifie_nom(chaine): | |||
83 | chaine2 = unidecode.unidecode(chaine2) | 95 | chaine2 = unidecode.unidecode(chaine2) |
84 | return chaine2[:15] | 96 | return chaine2[:15] |
85 | 97 | ||
86 | def convertit_poids_vers_python(chaine,liste_err): | 98 | def convertit_donnee_vers_python(chaine,typedonnee,liste_err): |
87 | """ convertit une chaine vers un float qui est le poids. | 99 | """ convertit une chaine vers un float qui est le type donnee voulu. |
88 | On gère notamment la virgule, et on enlève les espaces | 100 | La virgule peut être . ou , et on vire d'éventuels espaces. |
89 | Un poids invalide -> on renvoie 0 avec un warning""" | 101 | Taille invalide : on renvoie 0 avec un warning.""" |
90 | chaine2 = chaine.replace(",",".") | 102 | chaine2 = chaine.replace(",",".") |
91 | chaine2 = chaine2.replace(" ","") | 103 | chaine2 = chaine2.replace(" ","") |
92 | 104 | ||
93 | try: | 105 | try: |
94 | poids = float(chaine2) | 106 | donnee = float(chaine2) |
95 | except: | 107 | except: |
96 | warning("Poids impossible à lire : "+chaine,liste_err) | 108 | warning(typedonnee+" impossible à lire : "+chaine,liste_err) |
97 | poids = 0 | 109 | donnee = 0 |
98 | if not( 0<=poids<CONFIG["poids_maxi"]): | 110 | if not( 0<=donnee<CONFIG[typedonnee+"_maxi"]): |
99 | warning("Poids incohérent : "+str(poids),liste_err) | 111 | warning(typedonnee+"incohérent(e) : "+str(donnee),liste_err) |
100 | poids = 0 | 112 | donnee = 0 |
101 | return poids | 113 | return donnee |
102 | 114 | ||
103 | #def convertit_poids_vers_texte(poids): | ||
104 | # """ convertit un poids vers du texte. Rien à dire là pour l'instant """ | ||
105 | # return str(poids) | ||
106 | 115 | ||
107 | ######################### | 116 | ######################### |
108 | 117 | ||
118 | # web -> python | ||
109 | def convertit_date_vers_python(chaine,liste_err): | 119 | def convertit_date_vers_python(chaine,liste_err): |
110 | """ prend une chaine comme renvoyée par un champ de formulaire date | 120 | """ prend une chaine comme renvoyée par un champ de formulaire date |
111 | aaaa-mm-jj et en fait une date python | 121 | aaaa-mm-jj et en fait une date python |
@@ -122,7 +132,8 @@ def convertit_date_vers_python(chaine,liste_err): | |||
122 | date = "" | 132 | date = "" |
123 | warning("Impossible de lire la date "+chaine+". Format accepté : aaaa-mm-jj",liste_err) | 133 | warning("Impossible de lire la date "+chaine+". Format accepté : aaaa-mm-jj",liste_err) |
124 | return date | 134 | return date |
125 | 135 | ||
136 | # python -> json | ||
126 | def convertit_date_vers_texte(date): | 137 | def convertit_date_vers_texte(date): |
127 | """ convertit une date python en format texte aaaa-mm-jj""" | 138 | """ convertit une date python en format texte aaaa-mm-jj""" |
128 | if date == "": | 139 | if date == "": |
@@ -142,8 +153,39 @@ def delta_date(date1,datenaissance): | |||
142 | return jours | 153 | return jours |
143 | 154 | ||
144 | 155 | ||
156 | ################### On regroupe tout ce qui gère les données en une fonction | ||
157 | |||
158 | def web_vers_python(data,liste_err): | ||
159 | """ prend en argument le dictionnaire de requête et renvoie la config, et les | ||
160 | tableaux de donnée""" | ||
161 | |||
162 | # Régler la configuration | ||
163 | config = gere_configuration(data,liste_err) | ||
164 | |||
165 | # récupérer les données | ||
166 | listes_jours = {} | ||
167 | listes_donnees = {} | ||
168 | for typed in CONFIG["liste_typedonnees"]: | ||
169 | listes_jours[typed],listes_donnees[typed] = gere_donnees(data,config["naissance"],typed,liste_err) | ||
170 | |||
171 | # Si on a choisi la même échelle de données | ||
172 | if config["memechelle"] == "oui": | ||
173 | config["non_sauve"]["maxi"] = calcule_max_graphique([j for lj in listes_jours.values() for j in lj]) | ||
174 | config["non_sauve"]["unite"] = choix_unite(config["non_sauve"]["maxi"]) | ||
175 | |||
176 | return (config,listes_jours,listes_donnees) | ||
177 | |||
178 | |||
179 | |||
145 | ########### Fonctions qui gèretn les données | 180 | ########### Fonctions qui gèretn les données |
146 | 181 | ||
182 | def gere_checkbox(chaine): | ||
183 | """ prend en arg une chaine, et renvoie "oui" si c'est "on" (sortie de la checkbox) | ||
184 | et chaîne vide si n'importe quoi d'autre""" | ||
185 | if chaine == "on": | ||
186 | return "oui" | ||
187 | else: | ||
188 | return "" | ||
147 | 189 | ||
148 | def gere_configuration(data,liste_err): | 190 | def gere_configuration(data,liste_err): |
149 | """ prend en argument le dictionnaire de requête (configuration imparfaite), et | 191 | """ prend en argument le dictionnaire de requête (configuration imparfaite), et |
@@ -175,19 +217,20 @@ def gere_configuration(data,liste_err): | |||
175 | 217 | ||
176 | # unité | 218 | # unité |
177 | unite = data.get("unite","") | 219 | unite = data.get("unite","") |
178 | |||
179 | if not (unite in CONFIG["liste_unites"]): | 220 | if not (unite in CONFIG["liste_unites"]): |
180 | unite = "" | 221 | unite = "" |
181 | #warning("L'unité "+unite+" n'est pas reconnue !",liste_err) | 222 | #warning("L'unité "+unite+" n'est pas reconnue !",liste_err) |
182 | configuration["unite"] = unite | 223 | configuration["unite"] = unite |
183 | 224 | ||
184 | # grille | 225 | # grille |
185 | grille = data.get("grille","") | 226 | configuration["grille"] = gere_checkbox(data.get("grille","")) |
186 | if grille != "on": | 227 | |
187 | configuration["grille"] = "" | 228 | # tracer ou non les courbes vides |
188 | else: | 229 | configuration["tracevide"] = gere_checkbox(data.get("tracevide","")) |
189 | configuration["grille"] = "oui" | ||
190 | 230 | ||
231 | # Même échelle sur tous les graphiques | ||
232 | configuration["memechelle"] = gere_checkbox(data.get("memechelle","")) | ||
233 | |||
191 | # maxi. 0 signifie qu'on veut pas de maxi | 234 | # maxi. 0 signifie qu'on veut pas de maxi |
192 | maxi = data.get("maxi","") | 235 | maxi = data.get("maxi","") |
193 | if maxi == "": | 236 | if maxi == "": |
@@ -231,14 +274,7 @@ def gere_configuration(data,liste_err): | |||
231 | configuration["hauteur"] = hauteur | 274 | configuration["hauteur"] = hauteur |
232 | 275 | ||
233 | # existence et position de la légende | 276 | # existence et position de la légende |
234 | legende = data.get("legende","") | 277 | configuration["legende"] = gere_checkbox(data.get("legende","")) |
235 | if legende =="": | ||
236 | legende = "non" | ||
237 | elif legende=="on": | ||
238 | legende = "oui" | ||
239 | else: | ||
240 | legende = "oui" | ||
241 | configuration["legende"] = legende | ||
242 | 278 | ||
243 | positionlegende = data.get("positionlegende","") | 279 | positionlegende = data.get("positionlegende","") |
244 | if not(positionlegende in ['upper left','upper right','lower left','lower right']): | 280 | if not(positionlegende in ['upper left','upper right','lower left','lower right']): |
@@ -252,26 +288,34 @@ def gere_configuration(data,liste_err): | |||
252 | coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),CONFIG["couleurs"][clecouleur],liste_err) | 288 | coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),CONFIG["couleurs"][clecouleur],liste_err) |
253 | configuration["couleurs"][clecouleur] = coul | 289 | configuration["couleurs"][clecouleur] = coul |
254 | 290 | ||
291 | # On y ajoute la partie "non sauvée" qui servira peut-être plus tard | ||
292 | configuration["non_sauve"] = {} | ||
255 | 293 | ||
256 | return configuration | 294 | return configuration |
257 | 295 | ||
258 | 296 | ||
259 | def gere_donneespoids(data,naissance,liste_err): | 297 | def gere_donnees(data,naissance,typedonnee,liste_err): |
260 | """ prend en argument le dictionnaire de requête, et la date de naissance | 298 | """ prend en argument le dictionnaire de requête, et la date de |
261 | (éventuellement vide) et construit les deux listes l_jours et l_poids""" | 299 | naissance (éventuellement vide), et construit deux listes : |
262 | 300 | l_jours et l_data correspondantes. | |
263 | # On construit la liste des couples | 301 | Il faut donner en argument le type de données : voir |
302 | CONFIG["liste_typedonnees"]""" | ||
303 | if typedonnee not in CONFIG["liste_typedonnees"]: | ||
304 | warning("gere_donnees : le type de données : "+typedonnee+" est invalide !! Types acceptés : "+str(CONFIG["liste_typedonnees"]),liste_err) | ||
305 | return ([],[]) | ||
306 | |||
307 | # On construit une liste de couples d'abord | ||
264 | liste_donnees = [] | 308 | liste_donnees = [] |
265 | 309 | ||
266 | i = 0 | 310 | i = 0 |
267 | # On va chercher si y'a des données à poids_i | 311 | # On va chercher si y'a des données à donnee_i |
268 | while "poids_"+str(i) in data.keys(): | 312 | while typedonnee+"_"+str(i) in data.keys(): |
269 | if data["poids_"+str(i)] != "": | 313 | if data[typedonnee+"_"+str(i)] != "": |
270 | poids = convertit_poids_vers_python(data["poids_"+str(i)],liste_err) | 314 | donnee = convertit_donnee_vers_python(data[typedonnee+"_"+str(i)],typedonnee,liste_err) |
271 | age = data.get("age_"+str(i),"") | 315 | age = data.get("age_"+str(i),"") |
272 | if age !="": | 316 | if age !="": |
273 | age = convertit_jours_vers_python(age,liste_err) | 317 | age = convertit_jours_vers_python(age,liste_err) |
274 | liste_donnees.append((age,poids)) | 318 | liste_donnees.append((age,donnee)) |
275 | else: | 319 | else: |
276 | date = data.get("date_"+str(i),"") | 320 | date = data.get("date_"+str(i),"") |
277 | datep = convertit_date_vers_python(date,liste_err) | 321 | datep = convertit_date_vers_python(date,liste_err) |
@@ -280,7 +324,7 @@ def gere_donneespoids(data,naissance,liste_err): | |||
280 | warning("La date de naissance n'a pas été précisée. Du coup on ne peut pas calculer l'âge de l'enfant le "+date,liste_err) | 324 | warning("La date de naissance n'a pas été précisée. Du coup on ne peut pas calculer l'âge de l'enfant le "+date,liste_err) |
281 | elif datep != "": # la date est valide et on a une date de naissance | 325 | elif datep != "": # la date est valide et on a une date de naissance |
282 | age = delta_date(datep,naissance) | 326 | age = delta_date(datep,naissance) |
283 | liste_donnees.append((age,poids)) | 327 | liste_donnees.append((age,donnee)) |
284 | i+=1 | 328 | i+=1 |
285 | 329 | ||
286 | # Trier la liste | 330 | # Trier la liste |
@@ -288,35 +332,77 @@ def gere_donneespoids(data,naissance,liste_err): | |||
288 | 332 | ||
289 | # splitter la liste | 333 | # splitter la liste |
290 | l_jours = [x[0] for x in liste_donnees] | 334 | l_jours = [x[0] for x in liste_donnees] |
291 | l_poids = [x[1] for x in liste_donnees] | 335 | l_donnee = [x[1] for x in liste_donnees] |
292 | 336 | ||
293 | return (l_jours,l_poids) | 337 | return (l_jours,l_donnee) |
294 | 338 | ||
295 | 339 | ||
340 | #### export vers json | ||
296 | 341 | ||
297 | 342 | def donnees_vers_json(l_jours,l_poids,l_jourst,l_taille,config): | |
298 | def donnees_vers_json(l_jours,l_poids,config): | ||
299 | """ retourne le json à renvoyer""" | 343 | """ retourne le json à renvoyer""" |
300 | gros_dico = copy.deepcopy(config) | 344 | gros_dico = copy.deepcopy(config) |
301 | l_jours2 = [convertit_age_vers_texte(d) for d in l_jours] | 345 | l_jours2 = [convertit_age_vers_texte(d) for d in l_jours] |
346 | l_jourst2 = [convertit_age_vers_texte(d) for d in l_jourst] | ||
302 | gros_dico["data_j"] = l_jours2 | 347 | gros_dico["data_j"] = l_jours2 |
303 | gros_dico["data_p"] = l_poids | 348 | gros_dico["data_p"] = l_poids |
349 | gros_dico["data_jours_taille"] = l_jourst2 | ||
350 | gros_dico["data_taille"] = l_taille | ||
304 | # gérer la date de naissance | 351 | # gérer la date de naissance |
305 | if gros_dico.get("naissance","") != "": | 352 | if gros_dico.get("naissance","") != "": |
306 | gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"]) | 353 | gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"]) |
307 | # gérer l'age maxi | 354 | # gérer l'age maxi |
308 | gros_dico["maxi"] = convertit_age_vers_texte(gros_dico["maxi"]) | 355 | gros_dico["maxi"] = convertit_age_vers_texte(gros_dico["maxi"]) |
309 | # gérer les couleurs | 356 | # gérer les couleurs |
310 | # for cle in ["couleur1", "couleur2", "couleur3", "couleur_fond","couleur_grille","couleur_cadretxt"]: | ||
311 | # gros_dico[cle] = tuple_vers_rgb(gros_dico[cle]) | ||
312 | for clecouleur in DEFAUT["couleurs"]: | 357 | for clecouleur in DEFAUT["couleurs"]: |
313 | gros_dico["couleurs"][clecouleur] = tuple_vers_rgb(gros_dico["couleurs"][clecouleur]) | 358 | gros_dico["couleurs"][clecouleur] = tuple_vers_rgb(gros_dico["couleurs"][clecouleur]) |
314 | 359 | ||
315 | 360 | # Enlever ce qui ne se sauvegarde pas si y'a | |
361 | if "non_sauve" in gros_dico: | ||
362 | del gros_dico["non_sauve"] | ||
316 | 363 | ||
317 | return json.dumps(gros_dico, indent=2,ensure_ascii=False ) | 364 | return json.dumps(gros_dico, indent=2,ensure_ascii=False ) |
318 | 365 | ||
366 | def fusionne_donnees(listes_jours,listes_donnees): | ||
367 | """ prend en argument deux dicos de listes. Chaque liste de jours est associée à une liste | ||
368 | 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 | ||
369 | ("age":truc, "donnee1":truc, "donnee2":truc, ...) triée par ordre de jours. Si jamais une des données est vide, | ||
370 | le champ du dictionnaire n'est pas rempli""" | ||
371 | # nb_donnees = len(listes_jours) | ||
372 | def fini(lj): | ||
373 | """ teste si les listes sont toutes vides """ | ||
374 | for l in lj.values(): | ||
375 | if l!=[]: | ||
376 | return False | ||
377 | return True | ||
378 | |||
379 | def mini(lj): | ||
380 | """ renvoie la clé de la liste où il y a le min """ | ||
381 | cle_mini = CONFIG["liste_typedonnees"][0] | ||
382 | for (cle,liste) in lj.items(): | ||
383 | if lj[cle_mini]== []: | ||
384 | cle_mini = cle | ||
385 | elif lj[cle] != []: | ||
386 | if convertit_jours_vers_python(lj[cle][0],[])<convertit_jours_vers_python(lj[cle_mini][0],[]): | ||
387 | cle_mini = cle | ||
388 | return cle_mini | ||
389 | |||
390 | liste_f = [] | ||
391 | while not(fini(listes_jours)): | ||
392 | typedonnee = mini(listes_jours) | ||
393 | # On extrait les données dans les deux listes (jours et données) | ||
394 | jour = listes_jours[typedonnee].pop(0) | ||
395 | donnee = listes_donnees[typedonnee].pop(0) | ||
396 | if liste_f == [] or jour != liste_f[-1]["age"]: # Si le jour est un "nouveau" jour | ||
397 | liste_f.append({"age":jour}) | ||
398 | # On met à jour l'élément | ||
399 | liste_f[-1][typedonnee] = donnee | ||
400 | |||
401 | return liste_f | ||
402 | |||
319 | 403 | ||
404 | |||
405 | # Json -> formulaire HTML | ||
320 | def fichier_json_vers_configdonnees(chaine,liste_err): | 406 | def fichier_json_vers_configdonnees(chaine,liste_err): |
321 | """ prend le json importé (chaine) et l'exporte vers les valeurs du formulaire """ | 407 | """ prend le json importé (chaine) et l'exporte vers les valeurs du formulaire """ |
322 | debug("json vers config : Prêt à interpréter le json",liste_err) | 408 | debug("json vers config : Prêt à interpréter le json",liste_err) |
@@ -327,18 +413,25 @@ def fichier_json_vers_configdonnees(chaine,liste_err): | |||
327 | return {} | 413 | return {} |
328 | # Il faut maintenant récupérer les l_jours et l_poids puis les remettre | 414 | # Il faut maintenant récupérer les l_jours et l_poids puis les remettre |
329 | # sous forme de age_i et poids_i | 415 | # sous forme de age_i et poids_i |
330 | l_jours= valform.get("data_j",[]) | 416 | |
331 | l_poids=valform.get("data_p",[]) | 417 | listes_jours = {} |
332 | if len(l_poids) != len(l_jours): | 418 | listes_donnees = {} |
333 | warning("Lecture du json : les données sont incohérentes (listes de taille différentes et/ou pb de lecture") | 419 | for typed in CONFIG["liste_typedonnees"]: |
334 | long = min(len(l_jours),len(l_poids)) | 420 | if typed == "poids": # pour la rétrocompatibilité |
335 | else: | 421 | listes_jours[typed] = valform.get("data_j",[]) |
336 | long = len(l_jours) | 422 | listes_donnees[typed] = valform.get("data_p",[]) |
337 | for i in range(long): | 423 | else: |
338 | valform["age_"+str(i)] = l_jours[i] | 424 | listes_jours[typed] = valform.get("data_jours_"+typed,[]) |
339 | valform["poids_"+str(i)] = l_poids[i] | 425 | listes_donnees[typed] = valform.get("data_"+typed,[]) |
426 | |||
427 | debug("Avant fusion : listes jours "+str(listes_jours),liste_err) | ||
428 | liste_donnees = fusionne_donnees(listes_jours,listes_donnees) | ||
429 | debug("Fusion de listes ok. Liste moche : "+str(liste_donnees),liste_err) | ||
430 | for i in range(len(liste_donnees)): | ||
431 | for (cle,val) in liste_donnees[i].items(): | ||
432 | valform[cle+"_"+str(i)] = val | ||
340 | 433 | ||
341 | valform["nb_data"] = max(long +2,DEFAUT["nb_data"]) | 434 | valform["nb_data"] = max(len(liste_donnees) +2,DEFAUT["nb_data"]) |
342 | 435 | ||
343 | return valform | 436 | return valform |
344 | 437 | ||