2 # -*- coding: utf-8 -*-
4 from configuration
import CONFIG
,DEFAUT
5 from gestion_erreurs
import debug
, warning
, erreur
, initialise_erreurs
6 from gestion_couleurs
import rgb_vers_tuple
, tuple_vers_rgb
7 from gestion_unites
import choix_unite
13 ### Les données "tournent" selon :
14 ### python -> json -> (export/import) -> formulaire HTML -> données POST -> python etc
16 ############ Fonctions de conversion
18 def convertit_jours_vers_python(chaine
,liste_err
):
19 """ convertit une chaine de type 1a 3m 1s 10j en jours
20 Renvoie un nombre de jours en float
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
24 # debug("conversion de "+chaine+" vers un nb de jours",liste_err)
29 chainenombre
+= lettre
31 if lettre
== 'a' or lettre
== 'A':
32 # On a trouvé l'année, on ajoute tout ce qui est trouvé jusque là
33 agejours
+= int(chainenombre
)*CONFIG
["jours_dans_annee"]
35 elif lettre
== 'm' or lettre
== 'M':
37 agejours
+= int(chainenombre
)*CONFIG
["jours_dans_mois"]
39 elif lettre
== 's' or lettre
== 'S':
41 agejours
+= int(chainenombre
)*CONFIG
["jours_dans_semaine"]
43 elif lettre
== 'j' or lettre
== 'J':
45 agejours
+= int(chainenombre
)
48 # autre caractère : bizarre ?
49 warning("problème à la conversion de "+chaine
+". Caractère invalide : "+lettre
,liste_err
)
50 # à la fin s'il reste qqch on le garde dans les jours
51 if chainenombre
!= "":
52 agejours
+= int(chainenombre
)
54 warning("L'âge est négatif !",liste_err
)
56 # debug("On a convertit ! Résultat : "+str(agejours),liste_err)
60 def 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"""
63 annees
= int(nombre
/ CONFIG
["jours_dans_annee"])
64 restant
= nombre
- annees
*CONFIG
["jours_dans_annee"]
65 mois
= int(restant
/CONFIG
["jours_dans_mois"])
66 jours
= round(nombre
- mois
*CONFIG
["jours_dans_mois"] - annees
*CONFIG
["jours_dans_annee"])
70 chaine
+= str(annees
)+"a"
72 chaine
+= str(mois
)+"m"
73 if jours
>0 or nombre
==0: # si c'est la naissance, faut beien écrire 0j quand même
74 chaine
+= str(jours
)+"j"
77 ##########################
79 # fonction qui calcule "auto" le maxi du graphique en fonction du max
80 def calcule_max_graphique(l_jours
):
81 """ calcule l'age maxi sur le graphique"""
83 return CONFIG
["jours_defaut_donneesvides"]
85 jour_maxi
= max(l_jours
)# pas la peine d'aller très au delà du jour max
86 jour_maxi
= int(jour_maxi
* 1.2)+3 # on rajoute un peu
90 def simplifie_nom(chaine
):
91 """ simplifie le nom chaine afin d'en faire une extension
92 pour le nom du fichier. Met tout en minuscules et vire les caractères spéciaux
93 et max 15 caractères"""
98 chaine2
= unidecode
.unidecode(chaine2
)
101 def convertit_donnee_vers_python(chaine
,typedonnee
,liste_err
):
102 """ convertit une chaine vers un float qui est le type donnee voulu.
103 La virgule peut être . ou , et on vire d'éventuels espaces.
104 Taille invalide : on renvoie 0 avec un warning.
105 Si la chaine est en fait déjà au format float, on laisse tel quel"""
106 if type(chaine
) == float:
108 chaine2
= chaine
.replace(",",".")
109 chaine2
= chaine2
.replace(" ","")
113 donnee
= float(chaine2
)
115 warning(typedonnee
+" impossible à lire : "+chaine
,liste_err
)
118 # Pour le poids, un cas particulier
119 if typedonnee
== "poids" and donnee
> CONFIG
["poids_maxi_conversion"]:
120 donnee
= donnee
/1000 # conversion en grammes
121 if not( 0<=donnee
<CONFIG
[typedonnee
+"_maxi"]):
122 warning(typedonnee
+" incohérent(e) : "+str(donnee
),liste_err
)
127 #########################
130 def convertit_date_vers_python(chaine
,liste_err
):
131 """ prend une chaine comme renvoyée par un champ de formulaire date
132 aaaa-mm-jj et en fait une date python
133 renvoie "" si ne marche pas.
134 Si jamais la date est au format avec des / ça devrait passer aussi."""
136 liste
= chaine
.split("/")
138 liste
= chaine
.split("-")
140 warning("La date : "+chaine
+" est invalide !",liste_err
)
143 debug("Conversion de la date "+chaine
+". Découpage : "+str(liste
),liste_err
)
145 date
= datetime
.date(int(liste
[0]),int(liste
[1]),int(liste
[2]))
148 warning("Impossible de lire la date "+chaine
+". Format accepté : aaaa-mm-jj",liste_err
)
152 def convertit_date_vers_texte(date
):
153 """ convertit une date python en format texte aaaa-mm-jj"""
157 #return (str(date.year)+"-"+str(date.month)+"-"+str(date.day))
160 def delta_date(date1
,datenaissance
):
161 """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
162 datenaissance est supposée antérieure. Erreur sinon."""
163 d
= date1
- datenaissance
166 warning("La différence entre les dates est négative... :/")
172 ################### On regroupe tout ce qui gère les données en une fonction
174 def web_vers_python(data
,liste_err
, court
=False):
175 """ prend en argument le dictionnaire de requête et renvoie la config, et les
177 court : si True est précisé, on ne met que le nom dans la config (enfant
180 # Régler la configuration
181 config
= gere_configuration(data
,liste_err
, court
)
183 # récupérer les données
186 for typed
in CONFIG
["liste_typedonnees"]:
187 listes_jours
[typed
],listes_donnees
[typed
] = gere_donnees(data
,config
["naissance"],typed
,liste_err
)
189 # Si on veut extrapoler au-delà du jour maxi, on adapte
191 # Si on a choisi la même échelle de données
192 if config
.get("memechelle") == "oui":
193 config
["non_sauve"]["maxi"] = calcule_max_graphique([j
for lj
in listes_jours
.values() for j
in lj
])
194 # En cas d'extrapolation, on prend le maxi
195 if config
["non_sauve"]["calculextradata_type"] !="" and config
["non_sauve"]["calculextradata_age"]>config
["non_sauve"]["maxi"]:
196 config
["non_sauve"]["maxi"] = int(config
["non_sauve"]["calculextradata_age"]) +1
197 config
["non_sauve"]["unite"] = choix_unite(config
["non_sauve"]["maxi"])
199 return (config
,listes_jours
,listes_donnees
)
203 ########### Fonctions qui gèretn les données web vers python
205 def gere_checkbox(chaine
):
206 """ prend en arg une chaine, et renvoie "oui" si c'est "on" (sortie de la checkbox)
207 et chaîne vide si n'importe quoi d'autre"""
213 def gere_symbole(chaine
):
214 """ prend en arg une chaîne genre "o", ">" et vérifie si c'est un symbole valide.
215 Renvoie ce symbole-là ou le défaut"""
216 if chaine
in CONFIG
["liste_symboles"]:
219 return DEFAUT
["symbole"]
221 def gere_configuration(data
,liste_err
, court
=False):
222 """ prend en argument le dictionnaire de requête (configuration imparfaite), et
223 construit le dictionnaire de configuration qui va bien.
224 Vérifie que chaque entrée est cohérente évidemment.
225 court : si mis à True, on ne met que le nom dans la configuraion,
226 ainsi que la date de naissance et le sexe"""
228 configuration
= {"non_sauve": {}
}
230 # Pour le nom, osef qu'il soit vide
231 nom
= data
.get("nom","")
232 # Par contre s'il est trop long on le tronque
233 configuration
["nom"] = nom
[:CONFIG
["longueur_max_nom_bebe"]]
235 naissance
= data
.get("naissance","")
237 naissance
= convertit_date_vers_python(naissance
,liste_err
)
238 configuration
["naissance"] = naissance
240 sexe
= data
.get("sexe","")
241 if not (sexe
in ["F","M","N"]):
242 warning("Le sexe de l'enfant est invalide. "+sexe
,liste_err
)
244 configuration
["sexe"] = sexe
248 prematurite
= data
.get("prematurite","")
249 j
= convertit_jours_vers_python(prematurite
,liste_err
)
250 configuration
["prematurite"] = convertit_age_vers_texte(j
)
252 configuration
["agecorrige"] = gere_checkbox(data
.get("agecorrige",""))
254 # Type de courbe. Au pire on met P
255 tyc
= data
.get("typecourbe","")
256 if not (tyc
in ["P","Z"]):
258 configuration
["typecourbe"] = tyc
261 unite
= data
.get("unite","")
262 if not (unite
in CONFIG
["liste_unites"]):
264 #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
265 configuration
["unite"] = unite
268 configuration
["grille"] = gere_checkbox(data
.get("grille",""))
270 # tracer ou non les courbes vides
271 configuration
["tracevide"] = gere_checkbox(data
.get("tracevide",""))
273 # Même échelle sur tous les graphiques
274 configuration
["memechelle"] = gere_checkbox(data
.get("memechelle",""))
277 # maxi. 0 signifie qu'on veut pas de maxi
278 maxi
= data
.get("maxi","")
280 configuration
["maxi"] = 0
282 configuration
["maxi"] = int(convertit_jours_vers_python(maxi
,liste_err
))
284 # dimensions du graphique
285 largeur
= data
.get("largeur","")
287 largeur
= DEFAUT
["largeur_graphique"]
290 largeur
= int(largeur
)
292 warning("La largeur "+largeur
+"est invalide !",liste_err
)
293 largeur
= DEFAUT
["largeur_graphique"]
294 if largeur
> CONFIG
["largeur_graphique_max"]:
295 largeur
= CONFIG
["largeur_graphique_max"]
296 warning("Largeur du graphique trop grande !",liste_err
)
297 elif largeur
< CONFIG
["largeur_graphique_min"]:
298 largeur
= CONFIG
["largeur_graphique_min"]
299 warning("Largeur du graphique trop petite !",liste_err
)
300 configuration
["largeur"] = largeur
302 hauteur
= data
.get("hauteur","")
304 hauteur
= DEFAUT
["hauteur_graphique"]
307 hauteur
= int(hauteur
)
309 warning("La hauteur "+hauteur
+"est invalide !",liste_err
)
310 hauteur
= DEFAUT
["hauteur_graphique"]
311 if hauteur
> CONFIG
["hauteur_graphique_max"]:
312 hauteur
= CONFIG
["hauteur_graphique_max"]
313 warning("Hauteur du graphique trop grande !",liste_err
)
314 elif hauteur
< CONFIG
["hauteur_graphique_min"]:
315 hauteur
= CONFIG
["hauteur_graphique_min"]
316 warning("Hauteur du graphique trop petite !",liste_err
)
317 configuration
["hauteur"] = hauteur
319 # existence et position de la légende
320 configuration
["legende"] = gere_checkbox(data
.get("legende",""))
322 positionlegende
= data
.get("positionlegende","")
323 if not(positionlegende
in ['upper left','upper right','lower left','lower right']):
324 positionlegende
= "upper left"
325 configuration
["positionlegende"] = positionlegende
327 configuration
["couleurs"] = {}
329 for clecouleur
in DEFAUT
["couleurs"]:
330 coul
= rgb_vers_tuple(data
.get("couleur_"+clecouleur
,""),DEFAUT
["couleurs"].get(clecouleur
, ""),liste_err
)
331 configuration
["couleurs"][clecouleur
] = coul
334 configuration
["symbole"] = gere_symbole( data
.get("symbole", ""))
336 configuration
["non_sauve"]["grilleamelio"] = gere_checkbox(data
.get("grilleamelio",""))
339 #### La partie extrapolation n'a pas besoin d'être sauvée
340 configuration
["non_sauve"]["prolongercourbes"] = gere_checkbox(data
.get("prolongercourbes",""))
342 # Valeur par défaut : 1
343 debug(data
.get("nbextradata", "aaargh"), liste_err
)
344 nbextradata
= data
.get("nbextradata",1)
346 nbextradata
= int(nbextradata
)
348 warning("Le nombre de données sur lequel on extrapole est invalide : "+nbextradata
, liste_err
)
350 configuration
["non_sauve"]["nbextradata"] = nbextradata
352 if data
.get("calculextradata_type","") in CONFIG
["liste_typedonnees"]:
353 configuration
["non_sauve"]["calculextradata_type"] = data
.get("calculextradata_type","")
354 configuration
["non_sauve"]["calculextradata_age"] = convertit_jours_vers_python(data
.get("calculextradata_age","0j"),liste_err
)
356 configuration
["non_sauve"]["calculextradata_type"] = ""
357 # On ne met rien dans l'âge, pas la peine
359 ctyped
= data
.get("calculextratemps_type","")
360 if ctyped
in CONFIG
["liste_typedonnees"]:
361 configuration
["non_sauve"]["calculextratemps_type"] = ctyped
362 configuration
["non_sauve"]["calculextratemps_val"] = convertit_donnee_vers_python(data
.get("calculextratemps_val",""), ctyped
, liste_err
)
364 configuration
["non_sauve"]["calculextratemps_type"] = ""
366 # Tracer les calculs sur la grille
367 configuration
["non_sauve"]["calculextradata_trace"] = gere_checkbox(data
.get("calculextradata_trace"))
368 configuration
["non_sauve"]["calculextratemps_trace"] = gere_checkbox(data
.get("calculextratemps_trace"))
371 ### Gestion des repères additionnels
372 configuration
["liste_reperes"] = []
374 while "repere_texte_"+str(i
) in data
: # Tant qu'il y a des trucs définis
375 debug("Repère trouvé", liste_err
)
376 age
=data
.get("repere_age_"+str(i
), "")
377 trace
=gere_checkbox(data
.get("repere_trace_"+str(i
), ""))
379 agec
=convertit_jours_vers_python(age
, liste_err
)
380 texte
= data
.get("repere_texte_"+str(i
), "") # Même si le texte est vide, osef
381 configuration
["liste_reperes"].append({"typed": "age", "donnee": agec, "texte": texte, "trace": trace}
)
388 ## web vers python : données
389 def gere_donnees(data
,naissance
,typedonnee
,liste_err
):
390 """ prend en argument le dictionnaire de requête, et la date de
391 naissance (éventuellement vide), et construit deux listes :
392 l_jours et l_data correspondantes.
393 Il faut donner en argument le type de données : voir
394 CONFIG["liste_typedonnees"]"""
395 if typedonnee
not in CONFIG
["liste_typedonnees"]:
396 warning("gere_donnees : le type de données : "+typedonnee
+" est invalide !! Types acceptés : "+str(CONFIG
["liste_typedonnees"]),liste_err
)
399 # On construit une liste de couples d'abord
403 # On va chercher si y'a des données à donnee_i
404 while "age_"+str(i
) in data
.keys():
405 if data
.get(typedonnee
+"_"+str(i
), "") != "": # si la donne de ce type existe
406 donnee
= convertit_donnee_vers_python(data
[typedonnee
+"_"+str(i
)],typedonnee
,liste_err
)
407 age
= data
.get("age_"+str(i
),"")
409 age
= convertit_jours_vers_python(age
,liste_err
)
410 liste_donnees
.append((age
,donnee
))
412 date
= data
.get("date_"+str(i
),"")
413 datep
= convertit_date_vers_python(date
,liste_err
)
416 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
)
417 elif datep
!= "": # la date est valide et on a une date de naissance
418 age
= delta_date(datep
,naissance
)
419 liste_donnees
.append((age
,donnee
))
423 liste_donnees
.sort(key
=lambda x
: x
[0])
426 l_jours
= [x
[0] for x
in liste_donnees
]
427 l_donnee
= [x
[1] for x
in liste_donnees
]
429 return (l_jours
,l_donnee
)
431 # web vers python : enfants additionnels
432 def gere_enfants_additionnels(data
, files
, liste_err
):
433 """ data est le dictionnaire de requête.
434 files est le dictionnaire des fichiers (flask.request.files).
435 Renvoie les enfants additionnels sous forme de liste de dictionnaires :
436 {typed: (conf, lj, ldonnees)}
437 Dans conf y'a les infos qu'il faut pour tracer la courbe additionnelle voulue.
440 enfants_add
= [] # Enfants additionnels
441 # Les enfants additionnels commencent à 2 (puis 3, 4, etc)
443 while "couleur_donnees_"+str(i
) in data
: # Tant qu'il y a des données de ce type
444 if 'fichier_donnees_'+str(i
) in files
: # Un enfant à ajouter
445 fichier
= files
["fichier_donnees_"+str(i
)]
446 chaine
= fichier
.read() # On récupère la chaîne
447 if len(chaine
)>=5: # Si elle a une longueur à peu près raisonnable
448 debug("Un fichier de données additionnel trouvé", liste_err
)
449 formulaire_2
= fichier_json_vers_configdonnees(chaine
, liste_err
)
450 if formulaire_2
=={}:
451 warning("Le fichier de données additionnel est vide ou mal formaté", liste_err
)
453 debug("Form 2 : "+str(formulaire_2
), liste_err
)
454 # Récupérer sous forme python
455 conf2
, ljours2
, listes_donnees2
= web_vers_python(formulaire_2
,liste_err
, court
=True)
456 debug("Form 2 données travaillées "+str(ljours2
)+str(listes_donnees2
), liste_err
)
457 # Le symbole et la couleur
458 symb2
= gere_symbole(data
.get("symbole_donnees_"+str(i
)))
459 coul2
= rgb_vers_tuple(data
.get("couleur_donnees_"+str(i
),""),CONFIG
["couleurs"]["cadretxt"],liste_err
)
460 enfant2
= eclate_donnees_additionnelles(conf2
, ljours2
, listes_donnees2
, symb2
, coul2
)
461 enfants_add
.append(enfant2
)
471 #### export vers json
473 def donnees_vers_json(l_jours
,l_poids
,l_jourst
,l_taille
,config
):
474 """ retourne le json à renvoyer"""
475 gros_dico
= copy
.deepcopy(config
)
476 gros_dico
["version"] = CONFIG
["version"]
477 l_jours2
= [convertit_age_vers_texte(d
) for d
in l_jours
]
478 l_jourst2
= [convertit_age_vers_texte(d
) for d
in l_jourst
]
479 gros_dico
["data_j"] = l_jours2
480 gros_dico
["data_p"] = l_poids
481 gros_dico
["data_jours_taille"] = l_jourst2
482 gros_dico
["data_taille"] = l_taille
483 # gérer la date de naissance
484 if gros_dico
.get("naissance","") != "":
485 gros_dico
["naissance"] = convertit_date_vers_texte(gros_dico
["naissance"])
486 # Calcul de toutes les dates de données
487 l_dates_poids
= [convertit_date_vers_texte( config
["naissance"] + datetime
.timedelta(days
=jours
) ) for jours
in l_jours
]
488 l_dates_taille
= [convertit_date_vers_texte( config
["naissance"] + datetime
.timedelta(days
=jours
) ) for jours
in l_jourst
]
489 gros_dico
["data_dates_poids"]= l_dates_poids
490 gros_dico
["data_dates_taille"] = l_dates_taille
494 gros_dico
["maxi"] = convertit_age_vers_texte(gros_dico
["maxi"])
496 for i
in range(len(gros_dico
["liste_reperes"])):
497 gros_dico
["liste_reperes"][i
]["donnee"] = convertit_age_vers_texte(gros_dico
["liste_reperes"][i
]["donnee"])
499 for clecouleur
in DEFAUT
["couleurs"]:
500 gros_dico
["couleurs"][clecouleur
] = tuple_vers_rgb(gros_dico
["couleurs"][clecouleur
])
502 # Enlever ce qui ne se sauvegarde pas si y'a
503 if "non_sauve" in gros_dico
:
504 del gros_dico
["non_sauve"]
506 return json
.dumps(gros_dico
, indent
=2,ensure_ascii
=False )
508 def fusionne_donnees(listes_jours
,listes_donnees
, listes_dates
):
509 """ prend en argument deux dicos de listes. Chaque liste de jours est associée à une liste
510 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
511 {"age":truc, "donnee1":truc, "donnee2":truc, ...} triée par ordre de jours. Si jamais une des données est vide,
512 le champ du dictionnaire n'est pas rempli
513 Le troisième paquet de listes (les dates) peut être vide ou bien simiaire : même clés."""
516 """ teste si les listes sont toutes vides """
517 for l
in lj
.values():
523 """ renvoie la clé de la liste où il y a le min """
524 cle_mini
= CONFIG
["liste_typedonnees"][0]
525 for (cle
,liste
) in lj
.items():
526 if lj
[cle_mini
]== []:
529 if convertit_jours_vers_python(lj
[cle
][0],initialise_erreurs())<convertit_jours_vers_python(lj
[cle_mini
][0],initialise_erreurs()):
534 while not(fini(listes_jours
)):
535 typedonnee
= mini(listes_jours
)
536 # On extrait les données dans les deux listes (jours et données)
537 jour
= listes_jours
[typedonnee
].pop(0)
538 donnee
= listes_donnees
[typedonnee
].pop(0)
540 if liste_f
== [] or jour
!= liste_f
[-1]["age"]: # Si le jour est un "nouveau" jour
541 liste_f
.append({"age":jour}
)
542 # On met à jour l'élément (ou on l'ajoute)
543 liste_f
[-1][typedonnee
] = donnee
545 # Si il y a une date associée, on la met !
546 if listes_dates
[typedonnee
] != []:
547 date
= listes_dates
[typedonnee
].pop(0)
548 liste_f
[-1]["date"] = convertit_date_vers_texte(date
)
554 ### COnversion json vers formulaire
555 # Json -> formulaire HTML
556 def fichier_json_vers_configdonnees(chaine
,liste_err
):
557 """ prend le json importé (chaine) et l'exporte vers les valeurs du formulaire
558 Renvoyé sous forme de dictionnaire (mais adapté au formulaire web)"""
559 debug("json vers config : Prêt à interpréter le json",liste_err
)
561 valform
= json
.loads(chaine
)
563 erreur("Impossible de lire le fichier json !",liste_err
)
565 # Il faut maintenant récupérer les l_jours et l_poids puis les remettre
566 # sous forme de age_i et poids_i
571 for typed
in CONFIG
["liste_typedonnees"]:
572 if typed
== "poids": # pour la rétrocompatibilité
573 listes_jours
[typed
] = valform
.get("data_j",[])
574 listes_donnees
[typed
] = valform
.get("data_p",[])
575 listes_dates
[typed
] = valform
.get("data_dates_"+typed
,[])
577 listes_jours
[typed
] = valform
.get("data_jours_"+typed
,[])
578 listes_donnees
[typed
] = valform
.get("data_"+typed
,[])
579 listes_dates
[typed
] = valform
.get("data_dates_"+typed
,[])
582 debug("Avant fusion : listes jours "+str(listes_jours
),liste_err
)
583 liste_donnees
= fusionne_donnees(listes_jours
,listes_donnees
, listes_dates
)
584 debug("Fusion de listes ok. Liste moche : "+str(liste_donnees
),liste_err
)
585 for i
in range(len(liste_donnees
)):
586 for (cle
,val
) in liste_donnees
[i
].items():
587 valform
[cle
+"_"+str(i
)] = val
589 valform
["nb_data"] = max(len(liste_donnees
) +2,DEFAUT
["nb_data"])
595 #### Pour l'insertion d'une 2e (ou plus) courbe sur le graphique, ue fonction qui sépare tout ça
596 def eclate_donnees_additionnelles(conf
, ljours
, ldonnees
, symb
, couleur
):
597 """ conf est la config (on ne garde que le nom) pour un enfant additionnel,
598 ljours et ldonnees les dictionnaires de listes contenant les données.
599 symb est le symbole choisi pour cette courbe additionnelle (déjà vérifié)
600 On fabrique un joli dictionnaire typed -> (conf, lj, ldonnee) avec le nom de l'enfant,
601 et les données pour chaque typed"""
602 #print("test conf avant "+str(ldonnees)+str(ljours))
605 conf
["symbole"] = symb
# On ajoute le symbole additionnel
606 conf
["couleurcourbe"] = couleur
# la couleur
607 for typed
in CONFIG
["liste_typedonnees"]:
608 retour
[typed
] = (conf
, ljours
[typed
], ldonnees
[typed
])
610 #print("test "+str(retour))