228a7cb352bbc982d326c0ea0cdefd926025e97c
[perso/Denise/oms.git] / gestion_donnees.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 from configuration import *
5 from gestion_erreurs import *
6 from gestion_couleurs import *
7 import datetime
8 import json
9 import unidecode
10 import copy
11
12
13 ############ Fonctions de conversion
14
15 def convertit_jours_vers_python(chaine,liste_err):
16 """ convertit une chaine de type 1a 3m 1s 10j en jours
17 Renvoie un nombre de jours en float
18 Si un des caractères n'est ni un nombre, ni une lettre "autorisée" ni une espace,
19 on affiche un warning et on ignore ce caractère
20 """
21 chainenombre = ""
22 agejours = 0.
23 for lettre in chaine:
24 if lettre.isdigit():
25 chainenombre += lettre
26 else:
27 if lettre == 'a' or lettre == 'A':
28 # On a trouvé l'année, on ajoute tout ce qui est trouvé jusque là
29 agejours += int(chainenombre)*jours_dans_annee
30 chainenombre = ""
31 elif lettre == 'm' or lettre == 'M':
32 # On a trouvé le mois
33 agejours += int(chainenombre)*jours_dans_mois
34 chainenombre = ""
35 elif lettre == 's' or lettre == 'S':
36 # la semaine
37 agejours += int(chainenombre)*jours_dans_semaine
38 chainenombre = ""
39 elif lettre == 'j' or lettre == 'J':
40 # On a trouvé le jour
41 agejours += int(chainenombre)
42 chainenombre = ""
43 elif lettre != ' ':
44 # autre caractère : bizarre ?
45 warning("convertit_jour_vers_python : caractère invalide : "+lettre,liste_err)
46 # à la fin s'il reste qqch on le garde dans les jours
47 if chainenombre != "":
48 agejours += int(chainenombre)
49 if agejours<0:
50 warning("L'âge est négatif !",liste_err)
51 agejours = 0
52 return agejours
53
54 def convertit_age_vers_texte(nombre):
55 """ convertit un nombre de jours en un truc plus lisible en mois, années, jours
56 et renvoie une chaîne sous la forme 3a2m1j par exemple"""
57 annees = int(nombre / jours_dans_annee)
58 restant = nombre - annees*jours_dans_annee
59 mois = int(restant/jours_dans_mois)
60 jours= round(nombre - mois*jours_dans_mois - annees*jours_dans_annee)
61
62 chaine = ""
63 if annees >0:
64 chaine += str(annees)+"a"
65 if mois >0:
66 chaine += str(mois)+"m"
67 if jours>0 or nombre ==0: # si c'est la naissance, faut beien écrire 0j quand même
68 chaine += str(jours)+"j"
69 return chaine
70 ##########################
71
72
73 def simplifie_nom(chaine):
74 """ simplifie le nom chaine afin d'en faire une extension
75 pour le nom du fichier. Met tout en minuscules et vire les caractères spéciaux
76 et max 15 caractères"""
77 chaine2 = ""
78 for l in chaine:
79 if l.isalpha():
80 chaine2+=l
81 chaine2 = unidecode.unidecode(chaine2)
82 return chaine2[:15]
83
84 def convertit_poids_vers_python(chaine,liste_err):
85 """ convertit une chaine vers un float qui est le poids.
86 On gère notamment la virgule, et on enlève les espaces
87 Un poids invalide -> on renvoie 0 avec un warning"""
88 chaine2 = chaine.replace(",",".")
89 chaine2 = chaine2.replace(" ","")
90
91 try:
92 poids = float(chaine2)
93 except:
94 warning("Poids impossible à lire : "+chaine,liste_err)
95 poids = 0
96 if not( 0<=poids<poids_maxi):
97 warning("Poids incohérent : "+str(poids),liste_err)
98 poids = 0
99 return poids
100
101 #def convertit_poids_vers_texte(poids):
102 # """ convertit un poids vers du texte. Rien à dire là pour l'instant """
103 # return str(poids)
104
105 #########################
106
107 def convertit_date_vers_python(chaine,liste_err):
108 """ prend une chaine comme renvoyée par un champ de formulaire date
109 aaaa-mm-jj et en fait une date python
110 renvoie "" si ne marche pas"""
111 liste = chaine.split("-")
112 if len(liste) != 3:
113 warning("La date : "+chaine+" est invalide !",liste_err)
114 return ""
115 else:
116 try:
117 date = datetime.date(int(liste[0]),int(liste[1]),int(liste[2]))
118 except:
119 date = ""
120 warning("Impossible de lire la date "+chaine,liste_err)
121 return date
122
123 def convertit_date_vers_texte(date):
124 """ convertit une date python en format texte aaaa-mm-jj"""
125 if date == "":
126 return ""
127 else:
128 return (str(date.year)+"-"+str(date.month)+"-"+str(date.day))
129
130
131 def delta_date(date1,datenaissance):
132 """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
133 datenaissance est supposée antérieure. Erreur sinon."""
134 d = date1 - datenaissance
135 jours = d.days
136 if jours<0:
137 erreur_continue("La différence entre les dates est négative... :/")
138 return -1
139 return jours
140
141
142 ########### Fonctions qui gèretn les données
143
144
145 def gere_configuration(data,liste_err):
146 """ prend en argument le dictionnaire de requête (configuration imparfaite), et
147 construit le dictionnaire de configuration qui va bien.
148 Vérifie que chaque entrée est cohérente évidemment."""
149 configuration = {}
150
151 # Pour le nom, osef qu'il soit vide
152 nom = data.get("nom","")
153 # Par contre s'il est trop long on le tronque
154 configuration["nom"] = nom[:longueur_max_nom_bebe]
155
156 sexe = data.get("sexe","")
157 if not (sexe in ["F","M","N"]):
158 warning("Le sexe de l'enfant est invalide ! "+sexe,liste_err)
159 sexe = "N"
160 configuration["sexe"] = sexe
161
162 naissance = data.get("naissance","")
163 if naissance !="":
164 naissance = convertit_date_vers_python(naissance,liste_err)
165 configuration["naissance"] = naissance
166
167 # Type de courbe. Au pire on met P
168 tyc = data.get("typecourbe","")
169 if not (tyc in ["P","Z"]):
170 tyc = "P"
171 configuration["typecourbe"] = tyc
172
173 # unité
174 unite = data.get("unite","")
175
176 if not (unite in CONFIG["liste_unites"]):
177 unite = ""
178 #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
179 configuration["unite"] = unite
180
181 # grille
182 grille = data.get("grille","")
183 if grille != "on":
184 configuration["grille"] = ""
185 else:
186 configuration["grille"] = "oui"
187
188 # maxi. 0 signifie qu'on veut pas de maxi
189 maxi = data.get("maxi","")
190 if maxi == "":
191 configuration["maxi"] = 0
192 else:
193 configuration["maxi"] = convertit_jours_vers_python(maxi,liste_err)
194
195 # dimensions du graphique
196 largeur = data.get("largeur","")
197 if largeur == "":
198 largeur = DEFAUT["largeur_graphique"]
199 else:
200 try:
201 largeur = int(largeur)
202 except:
203 warning("La largeur "+largeur+"est invalide !",liste_err)
204 largeur = DEFAUT["largeur_graphique"]
205 if largeur > largeur_graphique_max:
206 largeur = largeur_graphique_max
207 warning("Largeur trop grande !",liste_err)
208 elif largeur < largeur_graphique_min:
209 largeur = largeur_graphique_min
210 warning("Largeur trop petite !",liste_err)
211 configuration["largeur"] = largeur
212
213 hauteur = data.get("hauteur","")
214 if hauteur == "":
215 hauteur = DEFAUT["hauteur_graphique"]
216 else:
217 try:
218 hauteur = int(hauteur)
219 except:
220 warning("La hauteur "+hauteur+"est invalide !",liste_err)
221 hauteur = DEFAUT["hauteur_graphique"]
222 if hauteur > hauteur_graphique_max:
223 hauteur = hauteur_graphique_max
224 warning("Hauteur trop grande !",liste_err)
225 elif hauteur < hauteur_graphique_min:
226 hauteur = hauteur_graphique_min
227 warning("Hauteur trop petite !",liste_err)
228 configuration["hauteur"] = hauteur
229
230 # existence et position de la légende
231 legende = data.get("legende","")
232 if legende =="":
233 legende = "non"
234 elif legende=="on":
235 legende = "oui"
236 else:
237 legende = "oui"
238 configuration["legende"] = legende
239
240 positionlegende = data.get("positionlegende","")
241 if not(positionlegende in ['upper left','upper right','lower left','lower right']):
242 positionlegende = "upper left"
243 configuration["positionlegende"] = positionlegende
244
245 #warning("bla"+data["couleur1"],liste_err)
246 # coul1 = rgb_vers_tuple(data.get("couleur1",""),couleur_defaut_1_tuple,liste_err)
247 # coul2 = rgb_vers_tuple(data.get("couleur2",""),couleur_defaut_2_tuple,liste_err)
248 # coul3 = rgb_vers_tuple(data.get("couleur3",""),couleur_defaut_3_tuple,liste_err)
249 # #warning("bla2"+str(coul1),liste_err)
250 # configuration["couleur1"] = coul1
251 # configuration["couleur2"] = coul2
252 # configuration["couleur3"] = coul3
253
254 configuration["couleurs"] = {}
255 # gérer les couleurs
256 #warning("data : "+str(data),liste_err)
257 for clecouleur in DEFAUT["couleurs"]:
258 coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),CONFIG["couleurs"][clecouleur],liste_err)
259 configuration["couleurs"][clecouleur] = coul
260
261 #warning("config : "+str(configuration["couleurs"]),liste_err)
262 # couleur de fond
263 # coul_fond = rgb_vers_tuple(data.get("couleur_fond",""),couleur_defaut_fond_tuple,liste_err)
264 # configuration["couleur_fond"] = coul_fond
265 #
266 # # couleur d'axes et de texte
267 # coul_cadretxt = rgb_vers_tuple(data.get("couleur_cadretxt",""),couleur_defaut_cadretxt_tuple,liste_err)
268 # configuration["couleur_cadretxt"] = coul_cadretxt
269 #
270 # # couleur de la grille
271 # coul_grille = rgb_vers_tuple(data.get("couleur_grille",""),couleur_defaut_grille_tuple,liste_err)
272 # configuration["couleur_grille"] = coul_grille
273 #warning(str(configuration["couleur1"]),liste_err)
274
275 return configuration
276
277
278 def gere_donneespoids(data,naissance,liste_err):
279 """ prend en argument le dictionnaire de requête, et la date de naissance
280 (éventuellement vide) et construit les deux listes l_jours et l_poids"""
281
282 # On construit la liste des couples
283 liste_donnees = []
284
285 i = 0
286 # On va chercher si y'a des données à poids_i
287 while "poids_"+str(i) in data.keys():
288 if data["poids_"+str(i)] != "":
289 poids = convertit_poids_vers_python(data["poids_"+str(i)],liste_err)
290 age = data.get("age_"+str(i),"")
291 if age !="":
292 age = convertit_jours_vers_python(age,liste_err)
293 liste_donnees.append((age,poids))
294 else:
295 date = data.get("date_"+str(i),"")
296 datep = convertit_date_vers_python(date,liste_err)
297 # on vérifie la date
298 if naissance == "":
299 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)
300 elif datep != "": # la date est valide et on a une date de naissance
301 age = delta_date(datep,naissance)
302 liste_donnees.append((age,poids))
303 i+=1
304
305 # Trier la liste
306 liste_donnees.sort(key=lambda x : x[0])
307
308 # splitter la liste
309 l_jours = [x[0] for x in liste_donnees]
310 l_poids = [x[1] for x in liste_donnees]
311
312 return (l_jours,l_poids)
313
314
315
316
317 def donnees_vers_json(l_jours,l_poids,config):
318 """ retourne le json à renvoyer"""
319 gros_dico = copy.deepcopy(config)
320 l_jours2 = [convertit_age_vers_texte(d) for d in l_jours]
321 gros_dico["data_j"] = l_jours2
322 gros_dico["data_p"] = l_poids
323 # gérer la date de naissance
324 if gros_dico.get("naissance","") != "":
325 gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"])
326 # gérer l'age maxi
327 gros_dico["maxi"] = convertit_age_vers_texte(gros_dico["maxi"])
328 # gérer les couleurs
329 # for cle in ["couleur1", "couleur2", "couleur3", "couleur_fond","couleur_grille","couleur_cadretxt"]:
330 # gros_dico[cle] = tuple_vers_rgb(gros_dico[cle])
331 for clecouleur in DEFAUT["couleurs"]:
332 gros_dico["couleurs"][clecouleur] = tuple_vers_rgb(gros_dico["couleurs"][clecouleur])
333
334
335
336 return json.dumps(gros_dico, indent=2,ensure_ascii=False )
337
338
339 def fichier_json_vers_configdonnees(fichier,liste_err):
340 """ prend le json importé et l'exporte vers les valeurs du formulaire """
341 chaine = fichier.read()
342 valform = json.loads(chaine)
343 # Il faut maintenant récupérer les l_jours et l_poids puis les remettre
344 # sous forme de age_i et poids_i
345 l_jours= valform.get("data_j",[])
346 l_poids=valform.get("data_p",[])
347 if len(l_poids) != len(l_jours):
348 warning("Lecture du json : les données sont incohérentes (listes de taille différentes et/ou pb de lecture")
349 long = min(len(l_jours),len(l_poids))
350 else:
351 long = len(l_jours)
352 for i in range(long):
353 valform["age_"+str(i)] = l_jours[i]
354 valform["poids_"+str(i)] = l_poids[i]
355
356 valform["nb_data"] = max(long +2,DEFAUT["nb_data"])
357
358 return valform
359
360
361