mise à jour de la licence pour être réglo + petit ajustement pour les saisies bugguée...
[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 import datetime
7
8
9 ############ Fonctions de conversion
10
11 def convertit_jours_vers_python(chaine,liste_err):
12 """ convertit une chaine de type 1a 3m 1s 10j en jours
13 Renvoie un nombre de jours en entiers.
14 Si un des caractères n'est ni un nombre, ni une lettre "autorisée" ni une espace,
15 on affiche un warning et on ignore ce caractère
16 """
17 chainenombre = ""
18 agejours = 0.
19 for lettre in chaine:
20 if lettre.isdigit():
21 chainenombre += lettre
22 else:
23 if lettre == 'a' or lettre == 'A':
24 # On a trouvé l'année, on ajoute tout ce qui est trouvé jusque là
25 agejours += int(chainenombre)*jours_dans_annee
26 chainenombre = ""
27 elif lettre == 'm' or lettre == 'M':
28 # On a trouvé le mois
29 agejours += int(chainenombre)*jours_dans_mois
30 chainenombre = ""
31 elif lettre == 's' or lettre == 'S':
32 # la semaine
33 agejours += int(chainenombre)*jours_dans_semaine
34 chainenombre = ""
35 elif lettre == 'j' or lettre == 'J':
36 # On a trouvé le jour
37 agejours += int(chainenombre)
38 chainenombre = ""
39 elif lettre != ' ':
40 # autre caractère : bizarre ?
41 warning("convertit_jour_vers_python : caractère invalide : "+lettre,liste_err)
42 # à la fin s'il reste qqch on le garde dans les jours
43 if chainenombre != "":
44 agejour += int(chainenombre)
45 if agejours<0:
46 warning("L'âge est négatif !",liste_err)
47 agejours = 0
48 return round(agejours)
49
50 def convertit_age_vers_texte(nombre):
51 """ convertit un nombre de jours en un truc plus lisible en mois, années, jours
52 et renvoie une chaîne sous la forme 3a2m1j par exemple"""
53 annees = int(nombre / jours_dans_annee)
54 restant = nombre - round(annees*jours_dans_annee)
55 mois = int(restant/jours_dans_mois)
56 jours= nombre - round(mois*jours_dans_mois + annees*jours_dans_annee)
57
58 chaine = ""
59 if annees >0:
60 chaine += str(annees)+"a"
61 if mois >0:
62 chaine += str(mois)+"m"
63 if jours>0 or nombre ==0: # si c'est la naissance, faut beien écrire 0j quand même
64 chaine += str(jours)+"j"
65 return chaine
66 ##########################
67
68 def convertit_poids_vers_python(chaine,liste_err):
69 """ convertit une chaine vers un float qui est le poids.
70 On gère notamment la virgule, et on enlève les espaces
71 Un poids invalide -> on renvoie 0 avec un warning"""
72 chaine2 = chaine.replace(",",".")
73 chaine2 = chaine2.replace(" ","")
74
75 try:
76 poids = float(chaine)
77 except:
78 warning("Poids impossible à lire : "+chaine,liste_err)
79 poids = 0
80 if not( 0<poids<poids_maxi):
81 warning("Poids incohérent : "+poids)
82 poids = 0
83 return poids
84
85 def convertit_poids_vers_texte(poids):
86 """ convertit un poids vers du texte. Rien à dire là pour l'instant """
87 return str(poids)
88
89 #########################
90
91 def convertit_date_vers_python(chaine,liste_err):
92 """ prend une chaine comme renvoyée par un champ de formulaire date
93 aaaa-mm-jj et en fait une date python
94 renvoie "" si ne marche pas"""
95 liste = chaine.split("-")
96 if len(liste) != 3:
97 warning("La date : "+chaine+" est invalide !",liste_err)
98 return ""
99 else:
100 try:
101 date = datetime.date(int(liste[0]),int(liste[1]),int(liste[2]))
102 except:
103 date = ""
104 warning("Impossible de lire la date "+chaine)
105 return date
106
107 def convertit_date_vers_texte(date):
108 """ convertit une date python en format texte aaaa-mm-jj"""
109 if date == "":
110 return ""
111 else:
112 return (str(date.year)+"-"+str(date.month)+"-"+str(date.day))
113
114
115 def delta_date(date1,datenaissance):
116 """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
117 datenaissance est supposée antérieure. Erreur sinon."""
118 d = date1 - datenaissance
119 jours = d.days
120 if jours<0:
121 erreur_continue("La différence entre les dates est négative... :/")
122 return -1
123 return jours
124
125
126 ########### Fonctions qui gèretn les données
127
128
129 def gere_configuration(data,liste_err):
130 """ prend en argument le dictionnaire de requête (configuratio imparfaite), et
131 construit le dictionnaire de configuration qui va bien.
132 Vérifie que chaque entrée est cohérente évidemment."""
133 configuration = {}
134
135 # Pour le nom, osef qu'il soit vide
136 nom = data.get("nom","")
137 # Par contre s'il est trop long on le tronque
138 configuration["nom"] = nom[:longueur_max_nom_bebe]
139
140 sexe = data.get("sexe","")
141 if not (sexe in ["F","M"]):
142 warning("Le sexe de l'enfant est invalide ! "+sexe,liste_err)
143 sexe = "F"
144 configuration["sexe"] = sexe
145
146 naissance = data.get("naissance","")
147 if naissance !="":
148 naissance = convertit_date_vers_python(naissance,liste_err)
149 configuration["naissance"] = naissance
150
151 # Type de courbe. Au pire on met P
152 tyc = data.get("typecourbe","")
153 if not (tyc in ["P","Z"]):
154 tyc = "P"
155 configuration["typecourbe"] = tyc
156
157 # unité
158 unite = data.get("unite","")
159 if not (unite in liste_unites_valides):
160 unite = ""
161 #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
162 configuration["unite"] = unite
163
164 # grille
165 grille = data.get("grille","")
166 if grille != "on":
167 configuration["grille"] = ""
168 else:
169 configuration["grille"] = "oui"
170
171 # maxi. 0 signifie qu'on veut pas de maxi
172 maxi = data.get("maxi","")
173 if maxi == "":
174 configuration["maxi"] = 0
175 else:
176 configuration["maxi"] = convertit_jours_vers_python(maxi,liste_err)
177
178 # dimensions du graphique
179 largeur = data.get("largeur")
180 if largeur == "":
181 largeur = largeur_graphique
182 else:
183 try:
184 largeur = int(largeur)
185 except:
186 warning("La largeur "+largeur+"est invalide !",liste_err)
187 largeur = largeur_graphique
188 if largeur > largeur_graphique_max:
189 largeur = largeur_graphique_max
190 warning("Largeur trop grande !",liste_err)
191 elif largeur < largeur_graphique_min:
192 largeur = largeur_graphique_min
193 warning("Largeur trop petite !",liste_err)
194 configuration["largeur"] = largeur
195
196 hauteur = data.get("hauteur")
197 if hauteur == "":
198 hauteur = hauteur_graphique
199 else:
200 try:
201 hauteur = int(hauteur)
202 except:
203 warning("La hauteur "+hauteur+"est invalide !",liste_err)
204 hauteur = hauteur_graphique
205 if hauteur > hauteur_graphique_max:
206 hauteur = hauteur_graphique_max
207 warning("Hauteur trop grande !",liste_err)
208 elif hauteur < hauteur_graphique_min:
209 hauteur = hauteur_graphique_min
210 warning("Hauteur trop petite !",liste_err)
211 configuration["hauteur"] = hauteur
212
213 # existence et position de la légende
214 legende = data.get("legende","")
215 if legende =="":
216 legende = "non"
217 elif legende=="on":
218 legende = "oui"
219 else:
220 legende = "oui"
221 configuration["legende"] = legende
222
223 positionlegende = data.get("positionlegende","")
224 if not(positionlegende in ['upper left','upper right','lower left','lower right']):
225 positionlegende = "upper left"
226 configuration["positionlegende"] = positionlegende
227
228
229
230 return configuration
231
232 def configuration_vers_texte(config):
233 """ exporte le texte associé à une configuration
234 on dumpe simplement sauf pour maxi """
235 texte = "# Section configuration\n"
236 for (cle,val) in config.items():
237 if cle != "maxi":
238 texte+= cle + "=" + str(val) + "\n"
239 else:
240 texte+= cle + "=" + convertit_age_vers_texte(val)+"\n"
241 texte +="\n"
242 return texte
243
244
245 def gere_donneespoids(data,naissance,liste_err):
246 """ prend en argument le dictionnaire de requête, et la date de naissance
247 (éventuellement vide) et construit les deux listes l_jours et l_poids"""
248
249 # On construit la liste des couples
250 liste_donnees = []
251
252 i = 0
253 # On va chercher si y'a des données à poids_i
254 while "poids_"+str(i) in data.keys():
255 if data["poids_"+str(i)] != "":
256 poids = convertit_poids_vers_python(data["poids_"+str(i)],liste_err)
257 age = data.get("age_"+str(i),"")
258 if age !="":
259 age = convertit_jours_vers_python(age,liste_err)
260 liste_donnees.append((age,poids))
261 else:
262 date = data.get("date_"+str(i),"")
263 datep = convertit_date_vers_python(date,liste_err)
264 # on vérifie la date
265 if naissance == "":
266 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)
267 elif datep != "": # la date est valide et on a une date de naissance
268 age = delta_date(datep,naissance)
269 liste_donnees.append((age,poids))
270 i+=1
271
272 # Trier la liste
273 liste_donnees.sort(key=lambda x : x[0])
274
275 # splitter la liste
276 l_jours = [x[0] for x in liste_donnees]
277 l_poids = [x[1] for x in liste_donnees]
278
279 return (l_jours,l_poids)
280
281
282 def donnees_poids_vers_texte(l_jours,l_poids):
283 """ retourne le texte correspondant aux données de poids """
284 texte = "# Section données\n"
285
286 for i in range(len(l_poids)):
287 texte +=convertit_age_vers_texte(l_jours[i])+","+convertit_poids_vers_texte(l_poids[i])+"\n"
288
289 texte+="\n"
290 return texte
291
292
293 def fichier_texte_vers_configdonnees(fichier,liste_err):
294 """ prend le texte importé et l'exporte vers configuration et données
295 sous forme de valeurs du formulaire """
296
297 valform = {}
298 indice_formulaire = 0 # l'indice du formulaire pour les données : age_1, date_1, poids_1 etc
299 num_ligne = 0
300 lignes = fichier.readlines()
301 for ligne in lignes:
302 num_ligne +=1
303 ligne = str(ligne,"utf8")
304 ligne = ligne.rstrip("\n")
305 if ligne != "" and ligne[0] != "#" and not(ligne.isspace()): # les lignes commençant par # sont des commentaires
306 # On essaie de partitionner pour voir
307 (var,egal,val) = ligne.partition("=")
308 if egal == "=": # c'est une ligne de config
309 valform[var] = val
310 else:
311 (age,virgule,poids) = ligne.partition(",") # On partitionne avec ,
312 if virgule == ",":
313 # c'est une ligne de data
314 valform["age_"+str(indice_formulaire)] = age
315 valform["poids_"+str(indice_formulaire)] = poids
316 indice_formulaire +=1
317
318 else:
319 warning("La ligne "+str(num_ligne)+" n'est pas reconnue et sera ignorée : <"+ligne+">",liste_err)
320
321 #le nb max du formulaire
322 valform["nb_data"] = indice_formulaire +2
323
324 return valform