Création du dépôt, site à peu près fonctionnel
[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 - int(annees*jours_dans_annee)
55 mois = int(restant/jours_dans_mois)
56 jours= restant - int(mois*jours_dans_mois)
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 return datetime.date(int(liste[0]),int(liste[1]),int(liste[2]))
101
102 def convertit_date_vers_texte(date):
103 """ convertit une date python en format texte aaaa-mm-jj"""
104 if date == "":
105 return ""
106 else:
107 return (str(date.year)+"-"+str(date.month)+"-"+str(date.day))
108
109
110 def delta_date(date1,datenaissance):
111 """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
112 datenaissance est supposée antérieure. Erreur sinon."""
113 d = date1 - datenaissance
114 jours = d.days
115 if jours<0:
116 erreur_continue("La différence entre les dates est négative... :/")
117 return -1
118 return jours
119
120
121 ########### Fonctions qui gèretn les données
122
123
124 def gere_configuration(data,liste_err):
125 """ prend en argument le dictionnaire de requête (configuratio imparfaite), et
126 construit le dictionnaire de configuration qui va bien.
127 Vérifie que chaque entrée est cohérente évidemment."""
128 configuration = {}
129
130 # Pour le nom, osef qu'il soit vide
131 nom = data.get("nom","")
132 # Par contre s'il est trop long on le tronque
133 configuration["nom"] = nom[:longueur_max_nom_bebe]
134
135 sexe = data.get("sexe","")
136 if not (sexe in ["F","M"]):
137 warning("Le sexe de l'enfant est invalide ! "+sexe,liste_err)
138 sexe = "F"
139 configuration["sexe"] = sexe
140
141 naissance = data.get("naissance","")
142 if naissance !="":
143 naissance = convertit_date_vers_python(naissance,liste_err)
144 configuration["naissance"] = naissance
145
146 # Type de courbe. Au pire on met P
147 tyc = data.get("typecourbe","")
148 if not (tyc in ["P","Z"]):
149 tyc = "P"
150 configuration["typecourbe"] = tyc
151
152 # unité
153 unite = data.get("unite","")
154 if not (unite in liste_unites_valides):
155 unite = ""
156 #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
157 configuration["unite"] = unite
158
159 # grille
160 grille = data.get("grille","")
161 if grille != "on":
162 configuration["grille"] = ""
163 else:
164 configuration["grille"] = "oui"
165
166 # maxi. 0 signifie qu'on veut pas de maxi
167 maxi = data.get("maxi","")
168 if maxi == "":
169 configuration["maxi"] = 0
170 else:
171 configuration["maxi"] = convertit_jours_vers_python(maxi,liste_err)
172
173 # dimensions du graphique
174 largeur = data.get("largeur")
175 if largeur == "":
176 largeur = largeur_graphique
177 else:
178 try:
179 largeur = int(largeur)
180 except:
181 warning("La largeur "+largeur+"est invalide !",liste_err)
182 largeur = largeur_graphique
183 if largeur > largeur_graphique_max:
184 largeur = largeur_graphique_max
185 warning("Largeur trop grande !",liste_err)
186 elif largeur < largeur_graphique_min:
187 largeur = largeur_graphique_min
188 warning("Largeur trop petite !",liste_err)
189 configuration["largeur"] = largeur
190
191 hauteur = data.get("hauteur")
192 if hauteur == "":
193 hauteur = hauteur_graphique
194 else:
195 try:
196 hauteur = int(hauteur)
197 except:
198 warning("La hauteur "+hauteur+"est invalide !",liste_err)
199 hauteur = hauteur_graphique
200 if hauteur > hauteur_graphique_max:
201 hauteur = hauteur_graphique_max
202 warning("Hauteur trop grande !",liste_err)
203 elif hauteur < hauteur_graphique_min:
204 hauteur = hauteur_graphique_min
205 warning("Hauteur trop petite !",liste_err)
206 configuration["hauteur"] = hauteur
207
208 # existence et position de la légende
209 legende = data.get("legende","")
210 if legende =="":
211 legende = "non"
212 elif legende=="on":
213 legende = "oui"
214 else:
215 legende = "oui"
216 configuration["legende"] = legende
217
218 positionlegende = data.get("positionlegende","")
219 if not(positionlegende in ['upper left','upper right','lower left','lower right']):
220 positionlegende = "upper left"
221 configuration["positionlegende"] = positionlegende
222
223
224
225 return configuration
226
227 def configuration_vers_texte(config):
228 """ exporte le texte associé à une configuration
229 on dumpe simplement sauf pour maxi """
230 texte = "# Section configuration\n"
231 for (cle,val) in config.items():
232 if cle != "maxi":
233 texte+= cle + "=" + str(val) + "\n"
234 else:
235 texte+= cle + "=" + convertit_age_vers_texte(val)+"\n"
236 texte +="\n"
237 return texte
238
239
240 def gere_donneespoids(data,naissance,liste_err):
241 """ prend en argument le dictionnaire de requête, et la date de naissance
242 (éventuellement vide) et construit les deux listes l_jours et l_poids"""
243
244 # On construit la liste des couples
245 liste_donnees = []
246
247 i = 0
248 # On va chercher si y'a des données à poids_i
249 while "poids_"+str(i) in data.keys():
250 if data["poids_"+str(i)] != "":
251 poids = convertit_poids_vers_python(data["poids_"+str(i)],liste_err)
252 age = data.get("age_"+str(i),"")
253 if age !="":
254 age = convertit_jours_vers_python(age,liste_err)
255 liste_donnees.append((age,poids))
256 else:
257 date = data.get("date_"+str(i),"")
258 datep = convertit_date_vers_python(date,liste_err)
259 # on vérifie la date
260 if naissance == "":
261 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)
262 elif datep != "": # la date est valide et on a une date de naissance
263 age = delta_date(datep,naissance)
264 liste_donnees.append((age,poids))
265 i+=1
266
267 # Trier la liste
268 liste_donnees.sort(key=lambda x : x[0])
269
270 # splitter la liste
271 l_jours = [x[0] for x in liste_donnees]
272 l_poids = [x[1] for x in liste_donnees]
273
274 return (l_jours,l_poids)
275
276
277 def donnees_poids_vers_texte(l_jours,l_poids):
278 """ retourne le texte correspondant aux données de poids """
279 texte = "# Section données\n"
280
281 for i in range(len(l_poids)):
282 texte +=convertit_age_vers_texte(l_jours[i])+","+convertit_poids_vers_texte(l_poids[i])+"\n"
283
284 texte+="\n"
285 return texte
286
287
288 def fichier_texte_vers_configdonnees(fichier,liste_err):
289 """ prend le texte importé et l'exporte vers configuration et données
290 sous forme de valeurs du formulaire """
291
292 valform = {}
293 indice_formulaire = 0 # l'indice du formulaire pour les données : age_1, date_1, poids_1 etc
294 num_ligne = 0
295 lignes = fichier.readlines()
296 for ligne in lignes:
297 num_ligne +=1
298 ligne = str(ligne,"utf8")
299 ligne = ligne.rstrip("\n")
300 if ligne != "" and ligne[0] != "#" and not(ligne.isspace()): # les lignes commençant par # sont des commentaires
301 # On essaie de partitionner pour voir
302 (var,egal,val) = ligne.partition("=")
303 if egal == "=": # c'est une ligne de config
304 valform[var] = val
305 else:
306 (age,virgule,poids) = ligne.partition(",") # On partitionne avec ,
307 if virgule == ",":
308 # c'est une ligne de data
309 valform["age_"+str(indice_formulaire)] = age
310 valform["poids_"+str(indice_formulaire)] = poids
311 indice_formulaire +=1
312
313 else:
314 warning("La ligne "+str(num_ligne)+" n'est pas reconnue et sera ignorée : <"+ligne+">",liste_err)
315
316 #le nb max du formulaire
317 valform["nb_data"] = indice_formulaire +2
318
319 return valform