1 #-*-coding:iso-8859-1-*-
3 # Copyright (C) 2008-2017 EDF R&D
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
24 Définit des outils de persistence et d'enregistrement de séries de valeurs
25 pour analyse ultérieure ou utilisation de calcul.
27 __author__ = "Jean-Philippe ARGAUD"
32 from PlatformInfo import PathManagement ; PathManagement()
34 # ==============================================================================
35 class Persistence(object):
37 Classe générale de persistence définissant les accesseurs nécessaires
40 def __init__(self, name="", unit="", basetype=str):
44 basetype : type de base de l'objet stocké à chaque pas
46 La gestion interne des données est exclusivement basée sur les variables
47 initialisées ici (qui ne sont pas accessibles depuis l'extérieur des
48 objets comme des attributs) :
49 __basetype : le type de base de chaque valeur, sous la forme d'un type
50 permettant l'instanciation ou le casting Python
51 __values : les valeurs de stockage. Par défaut, c'est None
53 self.__name = str(name)
54 self.__unit = str(unit)
56 self.__basetype = basetype
61 self.__dynamic = False
68 self.__dataobservers = []
70 def basetype(self, basetype=None):
72 Renvoie ou met en place le type de base des objets stockés
75 return self.__basetype
77 self.__basetype = basetype
79 def store(self, value=None, **kwargs):
81 Stocke une valeur avec ses informations de filtrage.
83 if value is None: raise ValueError("Value argument required")
85 self.__values.append(copy.copy(self.__basetype(value)))
86 self.__tags.append(kwargs)
88 if self.__dynamic: self.__replots()
89 __step = len(self.__values) - 1
90 for hook, parameters, scheduler in self.__dataobservers:
91 if __step in scheduler:
92 hook( self, parameters )
94 def pop(self, item=None):
96 Retire une valeur enregistree par son index de stockage. Sans argument,
97 retire le dernier objet enregistre.
101 self.__values.pop(__index)
102 self.__tags.pop(__index)
109 Renvoie la taille sous forme numpy du dernier objet stocké. Si c'est un
110 objet numpy, renvoie le shape. Si c'est un entier, un flottant, un
111 complexe, renvoie 1. Si c'est une liste ou un dictionnaire, renvoie la
112 longueur. Par défaut, renvoie 1.
114 if len(self.__values) > 0:
115 if self.__basetype in [numpy.matrix, numpy.array, numpy.ravel]:
116 return self.__values[-1].shape
117 elif self.__basetype in [int, float]:
119 elif self.__basetype in [list, dict]:
120 return (len(self.__values[-1]),)
124 raise ValueError("Object has no shape before its first storage")
126 # ---------------------------------------------------------
128 "x.__str__() <==> str(x)"
129 msg = " Index Value Tags\n"
130 for i,v in enumerate(self.__values):
131 msg += " i=%05i %10s %s\n"%(i,v,self.__tags[i])
135 "x.__len__() <==> len(x)"
136 return len(self.__values)
138 def __getitem__(self, index=None ):
139 "x.__getitem__(y) <==> x[y]"
140 return copy.copy(self.__values[index])
142 def count(self, value):
143 "L.count(value) -> integer -- return number of occurrences of value"
144 return self.__values.count(value)
146 def index(self, value, start=0, stop=None):
147 "L.index(value, [start, [stop]]) -> integer -- return first index of value."
148 if stop is None : stop = len(self.__values)
149 return self.__values.index(value, start, stop)
151 # ---------------------------------------------------------
152 def __filteredIndexes(self, **kwargs):
153 "Function interne filtrant les index"
154 __indexOfFilteredItems = range(len(self.__tags))
155 __filteringKwTags = kwargs.keys()
156 if len(__filteringKwTags) > 0:
157 for tagKey in __filteringKwTags:
159 for i in __indexOfFilteredItems:
160 if tagKey in self.__tags[i]:
161 if self.__tags[i][tagKey] == kwargs[tagKey]:
163 elif isinstance(kwargs[tagKey],(list,tuple)) and self.__tags[i][tagKey] in kwargs[tagKey]:
165 __indexOfFilteredItems = __tmp
166 if len(__indexOfFilteredItems) == 0: break
167 return __indexOfFilteredItems
169 # ---------------------------------------------------------
170 def values(self, **kwargs):
171 "D.values() -> list of D's values"
172 __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
173 return [self.__values[i] for i in __indexOfFilteredItems]
175 def keys(self, keyword=None , **kwargs):
176 "D.keys() -> list of D's keys"
177 __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
179 for i in __indexOfFilteredItems:
180 if keyword in self.__tags[i]:
181 __keys.append( self.__tags[i][keyword] )
183 __keys.append( None )
186 def items(self, keyword=None , **kwargs):
187 "D.items() -> list of D's (key, value) pairs, as 2-tuples"
188 __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
190 for i in __indexOfFilteredItems:
191 if keyword in self.__tags[i]:
192 __pairs.append( (self.__tags[i][keyword], self.__values[i]) )
194 __pairs.append( (None, self.__values[i]) )
198 "D.tagkeys() -> list of D's tag keys"
200 for dicotags in self.__tags:
201 __allKeys.extend( dicotags.keys() )
202 __allKeys = list(set(__allKeys))
206 # def valueserie(self, item=None, allSteps=True, **kwargs):
207 # if item is not None:
208 # return self.__values[item]
210 # __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
211 # if not allSteps and len(__indexOfFilteredItems) > 0:
212 # return self.__values[__indexOfFilteredItems[0]]
214 # return [self.__values[i] for i in __indexOfFilteredItems]
216 def tagserie(self, item=None, withValues=False, outputTag=None, **kwargs):
217 "D.tagserie() -> list of D's tag serie"
219 __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
221 __indexOfFilteredItems = [item,]
223 # Dans le cas où la sortie donne les valeurs d'un "outputTag"
224 if outputTag is not None and isinstance(outputTag,str) :
226 for index in __indexOfFilteredItems:
227 if outputTag in self.__tags[index].keys():
228 outputValues.append( self.__tags[index][outputTag] )
229 outputValues = list(set(outputValues))
233 # Dans le cas où la sortie donne les tags satisfaisants aux conditions
236 return [self.__tags[index] for index in __indexOfFilteredItems]
239 for index in __indexOfFilteredItems:
240 allTags.update( self.__tags[index] )
241 allKeys = allTags.keys()
245 # ---------------------------------------------------------
247 def stepnumber(self):
249 return len(self.__values)
252 def stepserie(self, **kwargs):
253 "Nombre de pas filtrés"
254 __indexOfFilteredItems = self.__filteredIndexes(**kwargs)
255 return __indexOfFilteredItems
257 # ---------------------------------------------------------
260 Renvoie la série, contenant à chaque pas, la valeur moyenne des données
261 au pas. Il faut que le type de base soit compatible avec les types
265 return [numpy.matrix(item).mean() for item in self.__values]
267 raise TypeError("Base type is incompatible with numpy")
269 def stds(self, ddof=0):
271 Renvoie la série, contenant à chaque pas, l'écart-type des données
272 au pas. Il faut que le type de base soit compatible avec les types
275 ddof : c'est le nombre de degrés de liberté pour le calcul de
276 l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1
279 if numpy.version.version >= '1.1.0':
280 return [numpy.matrix(item).std(ddof=ddof) for item in self.__values]
282 return [numpy.matrix(item).std() for item in self.__values]
284 raise TypeError("Base type is incompatible with numpy")
288 Renvoie la série, contenant à chaque pas, la somme des données au pas.
289 Il faut que le type de base soit compatible avec les types élémentaires
293 return [numpy.matrix(item).sum() for item in self.__values]
295 raise TypeError("Base type is incompatible with numpy")
299 Renvoie la série, contenant à chaque pas, le minimum des données au pas.
300 Il faut que le type de base soit compatible avec les types élémentaires
304 return [numpy.matrix(item).min() for item in self.__values]
306 raise TypeError("Base type is incompatible with numpy")
310 Renvoie la série, contenant à chaque pas, la maximum des données au pas.
311 Il faut que le type de base soit compatible avec les types élémentaires
315 return [numpy.matrix(item).max() for item in self.__values]
317 raise TypeError("Base type is incompatible with numpy")
324 geometry = "600x400",
328 "Préparation des plots"
330 # Vérification de la disponibilité du module Gnuplot
333 self.__gnuplot = Gnuplot
335 raise ImportError("The Gnuplot module is required to plot the object.")
337 # Vérification et compléments sur les paramètres d'entrée
339 self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry
341 self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -geometry '+geometry
344 self.__g = self.__gnuplot.Gnuplot() # persist=1
345 self.__g('set terminal '+self.__gnuplot.GnuplotOpts.default_term)
346 self.__g('set style data lines')
348 self.__g('set autoscale')
349 self.__g('set xlabel "'+str(xlabel).encode('ascii','replace')+'"')
350 self.__g('set ylabel "'+str(ylabel).encode('ascii','replace')+'"')
352 self.__ltitle = ltitle
363 geometry = "600x400",
370 Renvoie un affichage de la valeur à chaque pas, si elle est compatible
371 avec un affichage Gnuplot (donc essentiellement un vecteur). Si
372 l'argument "step" existe dans la liste des pas de stockage effectués,
373 renvoie l'affichage de la valeur stockée à ce pas "step". Si l'argument
374 "item" est correct, renvoie l'affichage de la valeur stockée au numéro
375 "item". Par défaut ou en l'absence de "step" ou "item", renvoie un
376 affichage successif de tous les pas.
379 - step : valeur du pas à afficher
380 - item : index de la valeur à afficher
381 - steps : liste unique des pas de l'axe des X, ou None si c'est
382 la numérotation par défaut
383 - title : base du titre général, qui sera automatiquement
384 complétée par la mention du pas
385 - xlabel : label de l'axe des X
386 - ylabel : label de l'axe des Y
387 - ltitle : titre associé au vecteur tracé
388 - geometry : taille en pixels de la fenêtre et position du coin haut
389 gauche, au format X11 : LxH+X+Y (défaut : 600x400)
390 - filename : base de nom de fichier Postscript pour une sauvegarde,
391 qui est automatiquement complétée par le numéro du
392 fichier calculé par incrément simple de compteur
393 - dynamic : effectue un affichage des valeurs à chaque stockage
394 (au-delà du second). La méthode "plots" permet de
395 déclarer l'affichage dynamique, et c'est la méthode
396 "__replots" qui est utilisée pour l'effectuer
397 - persist : booléen indiquant que la fenêtre affichée sera
398 conservée lors du passage au dessin suivant
399 Par défaut, persist = False
400 - pause : booléen indiquant une pause après chaque tracé, et
402 Par défaut, pause = True
405 if not self.__dynamic:
406 self.__preplots(title, xlabel, ylabel, ltitle, geometry, persist, pause )
408 self.__dynamic = True
409 if len(self.__values) == 0: return 0
411 # Tracé du ou des vecteurs demandés
413 if step is not None and step < len(self.__values):
415 elif item is not None and item < len(self.__values):
418 indexes = indexes + range(len(self.__values))
421 for index in indexes:
422 self.__g('set title "'+str(title).encode('ascii','replace')+' (pas '+str(index)+')"')
423 if isinstance(steps,list) or isinstance(steps,numpy.ndarray):
426 Steps = range(len(self.__values[index]))
428 self.__g.plot( self.__gnuplot.Data( Steps, self.__values[index], title=ltitle ) )
432 stepfilename = "%s_%03i.ps"%(filename,i)
433 if os.path.isfile(stepfilename):
434 raise ValueError("Error: a file with this name \"%s\" already exists."%stepfilename)
435 self.__g.hardcopy(filename=stepfilename, color=1)
437 raw_input('Please press return to continue...\n')
441 Affichage dans le cas du suivi dynamique de la variable
443 if self.__dynamic and len(self.__values) < 2: return 0
445 self.__g('set title "'+str(self.__title).encode('ascii','replace'))
446 Steps = range(len(self.__values))
447 self.__g.plot( self.__gnuplot.Data( Steps, self.__values, title=self.__ltitle ) )
450 raw_input('Please press return to continue...\n')
452 # ---------------------------------------------------------
455 Renvoie la moyenne sur toutes les valeurs sans tenir compte de la
456 longueur des pas. Il faut que le type de base soit compatible avec
457 les types élémentaires numpy.
460 if self.__basetype in [int, float]:
461 return float( numpy.array(self.__values).mean() )
463 return numpy.array(self.__values).mean(axis=0)
465 raise TypeError("Base type is incompatible with numpy")
467 def std(self, ddof=0):
469 Renvoie l'écart-type de toutes les valeurs sans tenir compte de la
470 longueur des pas. Il faut que le type de base soit compatible avec
471 les types élémentaires numpy.
473 ddof : c'est le nombre de degrés de liberté pour le calcul de
474 l'écart-type, qui est dans le diviseur. Inutile avant Numpy 1.1
477 if numpy.version.version >= '1.1.0':
478 return numpy.array(self.__values).std(ddof=ddof,axis=0)
480 return numpy.array(self.__values).std(axis=0)
482 raise TypeError("Base type is incompatible with numpy")
486 Renvoie la somme de toutes les valeurs sans tenir compte de la
487 longueur des pas. Il faut que le type de base soit compatible avec
488 les types élémentaires numpy.
491 return numpy.array(self.__values).sum(axis=0)
493 raise TypeError("Base type is incompatible with numpy")
497 Renvoie le minimum de toutes les valeurs sans tenir compte de la
498 longueur des pas. Il faut que le type de base soit compatible avec
499 les types élémentaires numpy.
502 return numpy.array(self.__values).min(axis=0)
504 raise TypeError("Base type is incompatible with numpy")
508 Renvoie le maximum de toutes les valeurs sans tenir compte de la
509 longueur des pas. Il faut que le type de base soit compatible avec
510 les types élémentaires numpy.
513 return numpy.array(self.__values).max(axis=0)
515 raise TypeError("Base type is incompatible with numpy")
519 Renvoie la somme cumulée de toutes les valeurs sans tenir compte de la
520 longueur des pas. Il faut que le type de base soit compatible avec
521 les types élémentaires numpy.
524 return numpy.array(self.__values).cumsum(axis=0)
526 raise TypeError("Base type is incompatible with numpy")
528 # On pourrait aussi utiliser les autres attributs d'une "matrix", comme
537 geometry = "600x400",
543 Renvoie un affichage unique pour l'ensemble des valeurs à chaque pas, si
544 elles sont compatibles avec un affichage Gnuplot (donc essentiellement
545 un vecteur). Si l'argument "step" existe dans la liste des pas de
546 stockage effectués, renvoie l'affichage de la valeur stockée à ce pas
547 "step". Si l'argument "item" est correct, renvoie l'affichage de la
548 valeur stockée au numéro "item".
551 - steps : liste unique des pas de l'axe des X, ou None si c'est
552 la numérotation par défaut
553 - title : base du titre général, qui sera automatiquement
554 complétée par la mention du pas
555 - xlabel : label de l'axe des X
556 - ylabel : label de l'axe des Y
557 - ltitle : titre associé au vecteur tracé
558 - geometry : taille en pixels de la fenêtre et position du coin haut
559 gauche, au format X11 : LxH+X+Y (défaut : 600x400)
560 - filename : nom de fichier Postscript pour une sauvegarde
561 - persist : booléen indiquant que la fenêtre affichée sera
562 conservée lors du passage au dessin suivant
563 Par défaut, persist = False
564 - pause : booléen indiquant une pause après chaque tracé, et
566 Par défaut, pause = True
569 # Vérification de la disponibilité du module Gnuplot
572 self.__gnuplot = Gnuplot
574 raise ImportError("The Gnuplot module is required to plot the object.")
576 # Vérification et compléments sur les paramètres d'entrée
578 self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -persist -geometry '+geometry
580 self.__gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot -geometry '+geometry
583 if isinstance(steps,list) or isinstance(steps, numpy.ndarray):
586 Steps = range(len(self.__values[0]))
587 self.__g = self.__gnuplot.Gnuplot() # persist=1
588 self.__g('set terminal '+self.__gnuplot.GnuplotOpts.default_term)
589 self.__g('set style data lines')
591 self.__g('set autoscale')
592 self.__g('set title "'+str(title).encode('ascii','replace') +'"')
593 self.__g('set xlabel "'+str(xlabel).encode('ascii','replace')+'"')
594 self.__g('set ylabel "'+str(ylabel).encode('ascii','replace')+'"')
596 # Tracé du ou des vecteurs demandés
597 indexes = range(len(self.__values))
598 self.__g.plot( self.__gnuplot.Data( Steps, self.__values[indexes.pop(0)], title=ltitle+" (pas 0)" ) )
599 for index in indexes:
600 self.__g.replot( self.__gnuplot.Data( Steps, self.__values[index], title=ltitle+" (pas %i)"%index ) )
603 self.__g.hardcopy(filename=filename, color=1)
605 raw_input('Please press return to continue...\n')
607 # ---------------------------------------------------------
608 def setDataObserver(self, HookFunction = None, HookParameters = None, Scheduler = None):
610 Association à la variable d'un triplet définissant un observer
612 Le Scheduler attendu est une fréquence, une simple liste d'index ou un
616 # Vérification du Scheduler
617 # -------------------------
619 if isinstance(Scheduler,int): # Considéré comme une fréquence à partir de 0
620 Schedulers = xrange( 0, maxiter, int(Scheduler) )
621 elif isinstance(Scheduler,xrange): # Considéré comme un itérateur
622 Schedulers = Scheduler
623 elif isinstance(Scheduler,list): # Considéré comme des index explicites
624 Schedulers = [long(i) for i in Scheduler] # map( long, Scheduler )
625 else: # Dans tous les autres cas, activé par défaut
626 Schedulers = xrange( 0, maxiter )
628 # Stockage interne de l'observer dans la variable
629 # -----------------------------------------------
630 self.__dataobservers.append( [HookFunction, HookParameters, Schedulers] )
632 def removeDataObserver(self, HookFunction = None):
634 Suppression d'un observer nommé sur la variable.
636 On peut donner dans HookFunction la meme fonction que lors de la
637 définition, ou un simple string qui est le nom de la fonction.
639 if hasattr(HookFunction,"func_name"):
640 name = str( HookFunction.func_name )
641 elif isinstance(HookFunction,str):
642 name = str( HookFunction )
648 for [hf, hp, hs] in self.__dataobservers:
650 if name is hf.func_name: index_to_remove.append( i )
651 index_to_remove.reverse()
652 for i in index_to_remove:
653 self.__dataobservers.pop( i )
655 # ==============================================================================
656 class OneScalar(Persistence):
658 Classe définissant le stockage d'une valeur unique réelle (float) par pas.
660 Le type de base peut être changé par la méthode "basetype", mais il faut que
661 le nouveau type de base soit compatible avec les types par éléments de
662 numpy. On peut même utiliser cette classe pour stocker des vecteurs/listes
663 ou des matrices comme dans les classes suivantes, mais c'est déconseillé
664 pour conserver une signification claire des noms.
666 def __init__(self, name="", unit="", basetype = float):
667 Persistence.__init__(self, name, unit, basetype)
669 class OneIndex(Persistence):
671 Classe définissant le stockage d'une valeur unique entière (int) par pas.
673 def __init__(self, name="", unit="", basetype = int):
674 Persistence.__init__(self, name, unit, basetype)
676 class OneVector(Persistence):
678 Classe de stockage d'une liste de valeurs numériques homogènes par pas. Ne
679 pas utiliser cette classe pour des données hétérogènes, mais "OneList".
681 def __init__(self, name="", unit="", basetype = numpy.ravel):
682 Persistence.__init__(self, name, unit, basetype)
684 class OneMatrix(Persistence):
686 Classe de stockage d'une matrice de valeurs (numpy.matrix) par pas.
688 def __init__(self, name="", unit="", basetype = numpy.matrix):
689 Persistence.__init__(self, name, unit, basetype)
691 class OneList(Persistence):
693 Classe de stockage d'une liste de valeurs hétérogènes (list) par pas. Ne pas
694 utiliser cette classe pour des données numériques homogènes, mais
697 def __init__(self, name="", unit="", basetype = list):
698 Persistence.__init__(self, name, unit, basetype)
701 "Fonction transparente, sans effet sur son argument"
704 class OneNoType(Persistence):
706 Classe de stockage d'un objet sans modification (cast) de type. Attention,
707 selon le véritable type de l'objet stocké à chaque pas, les opérations
708 arithmétiques à base de numpy peuvent être invalides ou donner des résultats
709 inattendus. Cette classe n'est donc à utiliser qu'à bon escient
710 volontairement, et pas du tout par défaut.
712 def __init__(self, name="", unit="", basetype = NoType):
713 Persistence.__init__(self, name, unit, basetype)
715 # ==============================================================================
716 class CompositePersistence(object):
718 Structure de stockage permettant de rassembler plusieurs objets de
721 Des objets par défaut sont prévus, et des objets supplémentaires peuvent
724 def __init__(self, name="", defaults=True):
728 La gestion interne des données est exclusivement basée sur les variables
729 initialisées ici (qui ne sont pas accessibles depuis l'extérieur des
730 objets comme des attributs) :
731 __StoredObjects : objets de type persistence collectés dans cet objet
733 self.__name = str(name)
735 self.__StoredObjects = {}
737 # Definition des objets par defaut
738 # --------------------------------
740 self.__StoredObjects["Informations"] = OneNoType("Informations")
741 self.__StoredObjects["Background"] = OneVector("Background", basetype=numpy.array)
742 self.__StoredObjects["BackgroundError"] = OneMatrix("BackgroundError")
743 self.__StoredObjects["Observation"] = OneVector("Observation", basetype=numpy.array)
744 self.__StoredObjects["ObservationError"] = OneMatrix("ObservationError")
745 self.__StoredObjects["Analysis"] = OneVector("Analysis", basetype=numpy.array)
746 self.__StoredObjects["AnalysisError"] = OneMatrix("AnalysisError")
747 self.__StoredObjects["Innovation"] = OneVector("Innovation", basetype=numpy.array)
748 self.__StoredObjects["KalmanGainK"] = OneMatrix("KalmanGainK")
749 self.__StoredObjects["OperatorH"] = OneMatrix("OperatorH")
750 self.__StoredObjects["RmsOMA"] = OneScalar("RmsOMA")
751 self.__StoredObjects["RmsOMB"] = OneScalar("RmsOMB")
752 self.__StoredObjects["RmsBMA"] = OneScalar("RmsBMA")
755 def store(self, name=None, value=None, **kwargs):
757 Stockage d'une valeur "value" pour le "step" dans la variable "name".
759 if name is None: raise ValueError("Storable object name is required for storage.")
760 if name not in self.__StoredObjects.keys():
761 raise ValueError("No such name '%s' exists in storable objects."%name)
762 self.__StoredObjects[name].store( value=value, **kwargs )
764 def add_object(self, name=None, persistenceType=Persistence, basetype=None ):
766 Ajoute dans les objets stockables un nouvel objet défini par son nom, son
767 type de Persistence et son type de base à chaque pas.
769 if name is None: raise ValueError("Object name is required for adding an object.")
770 if name in self.__StoredObjects.keys():
771 raise ValueError("An object with the same name '%s' already exists in storable objects. Choose another one."%name)
773 self.__StoredObjects[name] = persistenceType( name=str(name) )
775 self.__StoredObjects[name] = persistenceType( name=str(name), basetype=basetype )
777 def get_object(self, name=None ):
779 Renvoie l'objet de type Persistence qui porte le nom demandé.
781 if name is None: raise ValueError("Object name is required for retrieving an object.")
782 if name not in self.__StoredObjects.keys():
783 raise ValueError("No such name '%s' exists in stored objects."%name)
784 return self.__StoredObjects[name]
786 def set_object(self, name=None, objet=None ):
788 Affecte directement un 'objet' qui porte le nom 'name' demandé.
789 Attention, il n'est pas effectué de vérification sur le type, qui doit
790 comporter les méthodes habituelles de Persistence pour que cela
793 if name is None: raise ValueError("Object name is required for setting an object.")
794 if name in self.__StoredObjects.keys():
795 raise ValueError("An object with the same name '%s' already exists in storable objects. Choose another one."%name)
796 self.__StoredObjects[name] = objet
798 def del_object(self, name=None ):
800 Supprime un objet de la liste des objets stockables.
802 if name is None: raise ValueError("Object name is required for retrieving an object.")
803 if name not in self.__StoredObjects.keys():
804 raise ValueError("No such name '%s' exists in stored objects."%name)
805 del self.__StoredObjects[name]
807 # ---------------------------------------------------------
808 # Méthodes d'accès de type dictionnaire
809 def __getitem__(self, name=None ):
810 "x.__getitem__(y) <==> x[y]"
811 return self.get_object( name )
813 def __setitem__(self, name=None, objet=None ):
814 "x.__setitem__(i, y) <==> x[i]=y"
815 self.set_object( name, objet )
818 "D.keys() -> list of D's keys"
819 return self.get_stored_objects(hideVoidObjects = False)
822 "D.values() -> list of D's values"
823 return self.__StoredObjects.values()
826 "D.items() -> list of D's (key, value) pairs, as 2-tuples"
827 return self.__StoredObjects.items()
829 # ---------------------------------------------------------
830 def get_stored_objects(self, hideVoidObjects = False):
831 "Renvoie la liste des objets présents"
832 objs = self.__StoredObjects.keys()
837 if len(self.__StoredObjects[k]) > 0: usedObjs.append( k )
844 # ---------------------------------------------------------
845 def save_composite(self, filename=None, mode="pickle", compress="gzip"):
847 Enregistre l'objet dans le fichier indiqué selon le "mode" demandé,
848 et renvoi le nom du fichier
852 if compress == "gzip":
853 filename = os.tempnam( os.getcwd(), 'dacp' ) + ".pkl.gz"
854 elif compress == "bzip2":
855 filename = os.tempnam( os.getcwd(), 'dacp' ) + ".pkl.bz2"
857 filename = os.tempnam( os.getcwd(), 'dacp' ) + ".pkl"
859 filename = os.path.abspath( filename )
863 if compress == "gzip":
865 output = gzip.open( filename, 'wb')
866 elif compress == "bzip2":
868 output = bz2.BZ2File( filename, 'wb')
870 output = open( filename, 'wb')
871 cPickle.dump(self, output)
874 raise ValueError("Save mode '%s' unknown. Choose another one."%mode)
878 def load_composite(self, filename=None, mode="pickle", compress="gzip"):
880 Recharge un objet composite sauvé en fichier
884 raise ValueError("A file name if requested to load a composite.")
886 filename = os.path.abspath( filename )
890 if compress == "gzip":
892 pkl_file = gzip.open( filename, 'rb')
893 elif compress == "bzip2":
895 pkl_file = bz2.BZ2File( filename, 'rb')
897 pkl_file = open(filename, 'rb')
898 output = cPickle.load(pkl_file)
899 for k in output.keys():
902 raise ValueError("Load mode '%s' unknown. Choose another one."%mode)
906 # ==============================================================================
907 if __name__ == "__main__":
908 print('\n AUTODIAGNOSTIC \n')