Salome HOME
Minor corrections and change in example version level
[modules/adao.git] / src / daComposant / daCore / Aidsm.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2018 EDF R&D
4 #
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.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 """
24     Normalized interface for ADAO scripting (generic API)
25 """
26 __author__ = "Jean-Philippe ARGAUD"
27 __all__ = ["Aidsm"]
28
29 import os
30 import sys
31 #
32 from daCore.BasicObjects import State, Covariance, FullOperator, Operator
33 from daCore.BasicObjects import AlgorithmAndParameters, DataObserver
34 from daCore.BasicObjects import CaseLogger
35 from daCore import PlatformInfo
36 #
37 from daCore import ExtendedLogging ; ExtendedLogging.ExtendedLogging() # A importer en premier
38 import logging
39
40 # ==============================================================================
41 class Aidsm(object):
42     """ ADAO Internal Data Structure Model """
43     def __init__(self, name = "", addViewers=None):
44         self.__name = str(name)
45         self.__directory    = None
46         self.__case = CaseLogger(self.__name, "case", addViewers)
47         #
48         self.__adaoObject   = {}
49         self.__StoredInputs = {}
50         #
51         self.__Concepts = [
52             "AlgorithmParameters",
53             "Background",
54             "CheckingPoint",
55             "ControlInput",
56             "Observation",
57             "Controls",
58             "BackgroundError",
59             "ObservationError",
60             "EvolutionError",
61             "ObservationOperator",
62             "EvolutionModel",
63             "ControlModel",
64             "Debug",
65             "NoDebug",
66             "Observer",
67             ]
68         #
69         for ename in self.__Concepts:
70             self.__adaoObject[ename] = None
71         for ename in ("ObservationOperator", "EvolutionModel", "ControlModel"):
72             self.__adaoObject[ename] = {}
73         for ename in ("Observer",):
74             self.__adaoObject[ename]   = []
75             self.__StoredInputs[ename] = []
76         #
77         # Récupère le chemin du répertoire parent et l'ajoute au path
78         # (Cela complète l'action de la classe PathManagement dans PlatformInfo,
79         # qui est activée dans Persistence)
80         self.__parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
81         sys.path.insert(0, self.__parent)
82         sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
83
84     def set(self,
85             Concept              = None, # Premier argument
86             Algorithm            = None,
87             AppliedInXb          = None,
88             AvoidRC              = True,
89             Checked              = False,
90             DiagonalSparseMatrix = None,
91             Info                 = None,
92             Matrix               = None,
93             ObjectFunction       = None,
94             ObjectMatrix         = None,
95             OneFunction          = None,
96             Parameters           = None,
97             ScalarSparseMatrix   = None,
98             Scheduler            = None,
99             Script               = None,
100             Stored               = False,
101             String               = None,
102             Template             = None,
103             ThreeFunctions       = None,
104             Variable             = None,
105             Vector               = None,
106             VectorSerie          = None,
107             ):
108         "Interface unique de definition de variables d'entrees par argument"
109         self.__case.register("set",dir(),locals(),None,True)
110         try:
111             if   Concept in ("Background", "CheckingPoint", "ControlInput", "Observation", "Controls"):
112                 commande = getattr(self,"set"+Concept)
113                 commande(Vector, VectorSerie, Script, Stored, Scheduler, Checked )
114             elif Concept in ("BackgroundError", "ObservationError", "EvolutionError"):
115                 commande = getattr(self,"set"+Concept)
116                 commande(Matrix, ScalarSparseMatrix, DiagonalSparseMatrix,
117                          Script, Stored, ObjectMatrix, Checked )
118             elif Concept == "AlgorithmParameters":
119                 self.setAlgorithmParameters( Algorithm, Parameters, Script )
120             elif Concept == "Debug":
121                 self.setDebug()
122             elif Concept == "NoDebug":
123                 self.setNoDebug()
124             elif Concept == "Observer":
125                 self.setObserver( Variable, Template, String, Script, Info, ObjectFunction, Scheduler )
126             elif Concept == "ObservationOperator":
127                 self.setObservationOperator(
128                     Matrix, OneFunction, ThreeFunctions, AppliedInXb,
129                     Parameters, Script, Stored, AvoidRC, Checked )
130             elif Concept in ("EvolutionModel", "ControlModel"):
131                 commande = getattr(self,"set"+Concept)
132                 commande(
133                     Matrix, OneFunction, ThreeFunctions,
134                     Parameters, Script, Scheduler, Stored, AvoidRC, Checked )
135
136             else:
137                 raise ValueError("the variable named '%s' is not allowed."%str(Concept))
138         except Exception as e:
139             if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
140             else: msg = ""
141             raise ValueError(("during settings, the following error occurs:\n"+\
142                               "\n%s %s\n\nSee also the potential messages, "+\
143                               "which can show the origin of the above error, "+\
144                               "in the launching terminal.")%(str(e),msg))
145
146     # -----------------------------------------------------------
147
148     def setBackground(self,
149             Vector         = None,
150             VectorSerie    = None,
151             Script         = None,
152             Stored         = False,
153             Scheduler      = None,
154             Checked        = False):
155         "Definition d'un concept de calcul"
156         Concept = "Background"
157         self.__case.register("set"+Concept, dir(), locals())
158         self.__adaoObject[Concept] = State(
159             name               = Concept,
160             asVector           = Vector,
161             asPersistentVector = VectorSerie,
162             asScript           = Script,
163             scheduledBy        = Scheduler,
164             toBeChecked        = Checked,
165             )
166         if Stored:
167             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
168         return 0
169
170     def setCheckingPoint(self,
171             Vector         = None,
172             VectorSerie    = None,
173             Script         = None,
174             Stored         = False,
175             Scheduler      = None,
176             Checked        = False):
177         "Definition d'un concept de calcul"
178         Concept = "CheckingPoint"
179         self.__case.register("set"+Concept, dir(), locals())
180         self.__adaoObject[Concept] = State(
181             name               = Concept,
182             asVector           = Vector,
183             asPersistentVector = VectorSerie,
184             asScript           = Script,
185             scheduledBy        = Scheduler,
186             toBeChecked        = Checked,
187             )
188         if Stored:
189             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
190         return 0
191
192     def setControlInput(self,
193             Vector         = None,
194             VectorSerie    = None,
195             Script         = None,
196             Stored         = False,
197             Scheduler      = None,
198             Checked        = False):
199         "Definition d'un concept de calcul"
200         Concept = "ControlInput"
201         self.__case.register("set"+Concept, dir(), locals())
202         self.__adaoObject[Concept] = State(
203             name               = Concept,
204             asVector           = Vector,
205             asPersistentVector = VectorSerie,
206             asScript           = Script,
207             scheduledBy        = Scheduler,
208             toBeChecked        = Checked,
209             )
210         if Stored:
211             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
212         return 0
213
214     def setObservation(self,
215             Vector         = None,
216             VectorSerie    = None,
217             Script         = None,
218             Stored         = False,
219             Scheduler      = None,
220             Checked        = False):
221         "Definition d'un concept de calcul"
222         Concept = "Observation"
223         self.__case.register("set"+Concept, dir(), locals())
224         self.__adaoObject[Concept] = State(
225             name               = Concept,
226             asVector           = Vector,
227             asPersistentVector = VectorSerie,
228             asScript           = self.with_directory(Script),
229             scheduledBy        = Scheduler,
230             toBeChecked        = Checked,
231             )
232         if Stored:
233             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
234         return 0
235
236     def setBackgroundError(self,
237             Matrix               = None,
238             ScalarSparseMatrix   = None,
239             DiagonalSparseMatrix = None,
240             Script               = None,
241             Stored               = False,
242             ObjectMatrix         = None,
243             Checked              = False):
244         "Definition d'un concept de calcul"
245         Concept = "BackgroundError"
246         self.__case.register("set"+Concept, dir(), locals())
247         self.__adaoObject[Concept] = Covariance(
248             name          = Concept,
249             asCovariance  = Matrix,
250             asEyeByScalar = ScalarSparseMatrix,
251             asEyeByVector = DiagonalSparseMatrix,
252             asCovObject   = ObjectMatrix,
253             asScript      = Script,
254             toBeChecked   = Checked,
255             )
256         if Stored:
257             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
258         return 0
259
260     def setObservationError(self,
261             Matrix               = None,
262             ScalarSparseMatrix   = None,
263             DiagonalSparseMatrix = None,
264             Script               = None,
265             Stored               = False,
266             ObjectMatrix         = None,
267             Checked              = False):
268         "Definition d'un concept de calcul"
269         Concept = "ObservationError"
270         self.__case.register("set"+Concept, dir(), locals())
271         self.__adaoObject[Concept] = Covariance(
272             name          = Concept,
273             asCovariance  = Matrix,
274             asEyeByScalar = ScalarSparseMatrix,
275             asEyeByVector = DiagonalSparseMatrix,
276             asCovObject   = ObjectMatrix,
277             asScript      = Script,
278             toBeChecked   = Checked,
279             )
280         if Stored:
281             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
282         return 0
283
284     def setEvolutionError(self,
285             Matrix               = None,
286             ScalarSparseMatrix   = None,
287             DiagonalSparseMatrix = None,
288             Script               = None,
289             Stored               = False,
290             ObjectMatrix         = None,
291             Checked              = False):
292         "Definition d'un concept de calcul"
293         Concept = "EvolutionError"
294         self.__case.register("set"+Concept, dir(), locals())
295         self.__adaoObject[Concept] = Covariance(
296             name          = Concept,
297             asCovariance  = Matrix,
298             asEyeByScalar = ScalarSparseMatrix,
299             asEyeByVector = DiagonalSparseMatrix,
300             asCovObject   = ObjectMatrix,
301             asScript      = Script,
302             toBeChecked   = Checked,
303             )
304         if Stored:
305             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
306         return 0
307
308     def setObservationOperator(self,
309             Matrix         = None,
310             OneFunction    = None,
311             ThreeFunctions = None,
312             AppliedInXb    = None,
313             Parameters     = None,
314             Script         = None,
315             Stored         = False,
316             AvoidRC        = True,
317             Checked        = False):
318         "Definition d'un concept de calcul"
319         Concept = "ObservationOperator"
320         self.__case.register("set"+Concept, dir(), locals())
321         self.__adaoObject[Concept] = FullOperator(
322             name             = Concept,
323             asMatrix         = Matrix,
324             asOneFunction    = OneFunction,
325             asThreeFunctions = ThreeFunctions,
326             asScript         = Script,
327             asDict           = Parameters,
328             appliedInX       = AppliedInXb,
329             avoidRC          = AvoidRC,
330             scheduledBy      = None,
331             toBeChecked      = Checked,
332             )
333         if Stored:
334             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
335         return 0
336
337     def setEvolutionModel(self,
338             Matrix         = None,
339             OneFunction    = None,
340             ThreeFunctions = None,
341             Parameters     = None,
342             Script         = None,
343             Stored         = False,
344             Scheduler      = None,
345             AvoidRC        = True,
346             Checked        = False):
347         "Definition d'un concept de calcul"
348         Concept = "EvolutionModel"
349         self.__case.register("set"+Concept, dir(), locals())
350         self.__adaoObject[Concept] = FullOperator(
351             name             = Concept,
352             asMatrix         = Matrix,
353             asOneFunction    = OneFunction,
354             asThreeFunctions = ThreeFunctions,
355             asScript         = Script,
356             asDict           = Parameters,
357             appliedInX       = None,
358             avoidRC          = AvoidRC,
359             scheduledBy      = Scheduler,
360             toBeChecked      = Checked,
361             )
362         if Stored:
363             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
364         return 0
365
366     def setControlModel(self,
367             Matrix         = None,
368             OneFunction    = None,
369             ThreeFunctions = None,
370             Parameters     = None,
371             Script         = None,
372             Stored         = False,
373             Scheduler      = None,
374             AvoidRC        = True,
375             Checked        = False):
376         "Definition d'un concept de calcul"
377         Concept = "ControlModel"
378         self.__case.register("set"+Concept, dir(), locals())
379         self.__adaoObject[Concept] = FullOperator(
380             name             = Concept,
381             asMatrix         = Matrix,
382             asOneFunction    = OneFunction,
383             asThreeFunctions = ThreeFunctions,
384             asScript         = Script,
385             asDict           = Parameters,
386             appliedInX       = None,
387             avoidRC          = AvoidRC,
388             scheduledBy      = Scheduler,
389             toBeChecked      = Checked,
390             )
391         if Stored:
392             self.__StoredInputs[Concept] = self.__adaoObject[Concept].getO()
393         return 0
394
395     def setDebug(self, __level = 10):
396         "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
397         self.__case.register("setDebug",dir(),locals())
398         log = logging.getLogger()
399         log.setLevel( __level )
400         self.__StoredInputs["Debug"]   = __level
401         self.__StoredInputs["NoDebug"] = False
402         return 0
403
404     def setNoDebug(self):
405         "NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50"
406         self.__case.register("setNoDebug",dir(),locals())
407         log = logging.getLogger()
408         log.setLevel( logging.WARNING )
409         self.__StoredInputs["Debug"]   = logging.WARNING
410         self.__StoredInputs["NoDebug"] = True
411         return 0
412
413     def setAlgorithmParameters(self,
414             Algorithm  = None,
415             Parameters = None,
416             Script     = None):
417         "Definition d'un concept de calcul"
418         Concept = "AlgorithmParameters"
419         self.__case.register("set"+Concept, dir(), locals())
420         self.__adaoObject[Concept] = AlgorithmAndParameters(
421             name          = Concept,
422             asAlgorithm   = Algorithm,
423             asDict        = Parameters,
424             asScript      = Script,
425             )
426         return 0
427
428     def updateAlgorithmParameters(self,
429             Parameters = None,
430             Script     = None):
431         "Mise a jour d'un concept de calcul"
432         if "AlgorithmParameters" not in self.__adaoObject:
433             raise ValueError("No algorithm registred, ask for one before updating parameters")
434         self.__adaoObject["AlgorithmParameters"].updateParameters(
435             asDict        = Parameters,
436             asScript      = Script,
437             )
438         return 0
439
440     def setObserver(self,
441             Variable       = None,
442             Template       = None,
443             String         = None,
444             Script         = None,
445             Info           = None,
446             ObjectFunction = None,
447             Scheduler      = None):
448         "Definition d'un concept de calcul"
449         Concept = "Observer"
450         self.__case.register("set"+Concept, dir(), locals())
451         self.__adaoObject[Concept].append( DataObserver(
452             name        = Concept,
453             onVariable  = Variable,
454             asTemplate  = Template,
455             asString    = String,
456             asScript    = Script,
457             asObsObject = ObjectFunction,
458             withInfo    = Info,
459             scheduledBy = Scheduler,
460             withAlgo    = self.__adaoObject["AlgorithmParameters"]
461             ))
462         return 0
463
464     def removeObserver(self,
465             Variable       = None,
466             ObjectFunction = None,
467             ):
468         "Permet de retirer un observer à une ou des variable nommée"
469         if "AlgorithmParameters" not in self.__adaoObject:
470             raise ValueError("No algorithm registred, ask for one before removing observers")
471         #
472         # Vérification du nom de variable et typage
473         # -----------------------------------------
474         if isinstance(Variable, str):
475             VariableNames = (Variable,)
476         elif isinstance(Variable, list):
477             VariableNames = tuple(map( str, Variable ))
478         else:
479             raise ValueError("The observer requires a name or a list of names of variables.")
480         #
481         # Association interne de l'observer à la variable
482         # -----------------------------------------------
483         for ename in VariableNames:
484             if ename not in self.__adaoObject["AlgorithmParameters"]:
485                 raise ValueError("An observer requires to be removed on a variable named %s which does not exist."%ename)
486             else:
487                 return self.__adaoObject["AlgorithmParameters"].removeObserver( ename, ObjectFunction )
488
489     # -----------------------------------------------------------
490
491     def get(self, Concept=None, noDetails=True ):
492         "Recuperation d'une sortie du calcul"
493         if Concept is not None:
494             try:
495                 self.__case.register("get", dir(), locals(), Concept) # Break pickle in Python 2
496             except Exception:
497                 pass
498             if Concept in self.__StoredInputs:
499                 return self.__StoredInputs[Concept]
500                 #
501             elif self.__adaoObject["AlgorithmParameters"] is not None and Concept == "AlgorithmParameters":
502                 return self.__adaoObject["AlgorithmParameters"].get()
503                 #
504             elif self.__adaoObject["AlgorithmParameters"] is not None and Concept in self.__adaoObject["AlgorithmParameters"]:
505                 return self.__adaoObject["AlgorithmParameters"].get( Concept )
506                 #
507             elif Concept == "AlgorithmRequiredParameters" and self.__adaoObject["AlgorithmParameters"] is not None:
508                 return self.__adaoObject["AlgorithmParameters"].getAlgorithmRequiredParameters(noDetails)
509                 #
510             else:
511                 raise ValueError("The requested key \"%s\" does not exists as an input or a stored variable."%Concept)
512         else:
513             allvariables = {}
514             allvariables.update( {"AlgorithmParameters":self.__adaoObject["AlgorithmParameters"].get()} )
515             # allvariables.update( self.__adaoObject["AlgorithmParameters"].get() )
516             allvariables.update( self.__StoredInputs )
517             allvariables.pop('Observer', None)
518             return allvariables
519
520     # -----------------------------------------------------------
521
522     def get_available_variables(self):
523         """
524         Renvoie les variables potentiellement utilisables pour l'étude,
525         initialement stockées comme données d'entrées ou dans les algorithmes,
526         identifiés par les chaînes de caractères. L'algorithme doit avoir été
527         préalablement choisi sinon la méthode renvoie "None".
528         """
529         if len(list(self.__adaoObject["AlgorithmParameters"].keys())) == 0 and \
530             len(list(self.__StoredInputs.keys())) == 0:
531             return None
532         else:
533             variables = []
534             if len(list(self.__adaoObject["AlgorithmParameters"].keys())) > 0:
535                 variables.extend(list(self.__adaoObject["AlgorithmParameters"].keys()))
536             if len(list(self.__StoredInputs.keys())) > 0:
537                 variables.extend( list(self.__StoredInputs.keys()) )
538             variables.remove('Observer')
539             variables.sort()
540             return variables
541
542     def get_available_algorithms(self):
543         """
544         Renvoie la liste des algorithmes potentiellement utilisables, identifiés
545         par les chaînes de caractères.
546         """
547         files = []
548         for directory in sys.path:
549             trypath = os.path.join(directory,"daAlgorithms")
550             if os.path.isdir(trypath):
551                 for fname in os.listdir(trypath):
552                     if os.path.isfile(os.path.join(trypath,fname)):
553                         fc = open(os.path.join(trypath,fname)).read()
554                         iselal = bool("class ElementaryAlgorithm" in fc)
555                         root, ext = os.path.splitext(fname)
556                         if iselal and ext == '.py' and root != '__init__':
557                             files.append(root)
558         files.sort()
559         return files
560
561
562     def get_algorithms_main_path(self):
563         """
564         Renvoie le chemin pour le répertoire principal contenant les algorithmes
565         """
566         return self.__parent
567
568     def add_algorithms_path(self, Path=None):
569         """
570         Ajoute au chemin de recherche des algorithmes un répertoire dans lequel
571         se trouve un sous-répertoire "daAlgorithms"
572         """
573         if not os.path.isdir(Path):
574             raise ValueError("The given "+Path+" argument must exist as a directory")
575         if not os.path.isdir(os.path.join(Path,"daAlgorithms")):
576             raise ValueError("The given \""+Path+"\" argument must contain a subdirectory named \"daAlgorithms\"")
577         if not os.path.isfile(os.path.join(Path,"daAlgorithms","__init__.py")):
578             raise ValueError("The given \""+Path+"/daAlgorithms\" path must contain a file named \"__init__.py\"")
579         sys.path.insert(0, os.path.abspath(Path))
580         sys.path = PlatformInfo.uniq( sys.path ) # Conserve en unique exemplaire chaque chemin
581         return 0
582
583     # -----------------------------------------------------------
584
585     def execute(self, Executor=None, SaveCaseInFile=None):
586         "Lancement du calcul"
587         self.__case.register("execute",dir(),locals(),None,True)
588         Operator.CM.clearCache()
589         try:
590             if   Executor == "YACS": self.__executeYACSScheme( SaveCaseInFile )
591             else:                    self.__executePythonScheme( SaveCaseInFile )
592         except Exception as e:
593             if isinstance(e, SyntaxError): msg = "at %s: %s"%(e.offset, e.text)
594             else: msg = ""
595             raise ValueError(("during execution, the following error occurs:\n"+\
596                              "\n%s %s\n\nSee also the potential messages, "+\
597                              "which can show the origin of the above error, "+\
598                              "in the launching terminal.\n")%(str(e),msg))
599         return 0
600
601     def __executePythonScheme(self, FileName=None):
602         "Lancement du calcul"
603         self.__case.register("executePythonScheme", dir(), locals())
604         if FileName is not None:
605             self.dump( FileName, "TUI")
606         self.__adaoObject["AlgorithmParameters"].executePythonScheme( self.__adaoObject )
607         return 0
608
609     def __executeYACSScheme(self, FileName=None):
610         "Lancement du calcul"
611         self.__case.register("executeYACSScheme", dir(), locals())
612         self.dump( FileName, "YACS")
613         self.__adaoObject["AlgorithmParameters"].executeYACSScheme( FileName )
614         return 0
615
616     # -----------------------------------------------------------
617
618     def dump(self, FileName=None, Formater="TUI"):
619         "Restitution normalisée des commandes"
620         return self.__case.dump(FileName, Formater)
621
622     def load(self, FileName=None, Formater="TUI"):
623         "Chargement normalisé des commandes"
624         __commands = self.__case.load(FileName, Formater)
625         from numpy import array, matrix
626         for __command in __commands:
627             exec("self."+__command)
628         return self
629
630     def clear(self):
631         "Effacement du contenu du cas en cours"
632         self.__init__(self.__name)
633
634     # -----------------------------------------------------------
635
636     def __dir__(self):
637         "Clarifie la visibilité des méthodes"
638         return ['set', 'get', 'execute', '__doc__', '__init__', '__module__']
639
640     def prepare_to_pickle(self):
641         "Retire les variables non pickelisables, avec recopie efficace"
642         if self.__adaoObject['AlgorithmParameters'] is not None:
643             for k in self.__adaoObject['AlgorithmParameters'].keys():
644                 if k == "Algorithm": continue
645                 if k in self.__StoredInputs:
646                     raise ValueError("the key \"%s\s to be transfered for pickling will overwrite an existing one.")
647                 if self.__adaoObject['AlgorithmParameters'].hasObserver( k ):
648                     self.__adaoObject['AlgorithmParameters'].removeObserver( k, "", True )
649                 self.__StoredInputs[k] = self.__adaoObject['AlgorithmParameters'].pop(k, None)
650         if sys.version_info[0] == 2:
651             del self.__adaoObject # Because it breaks pickle in Python 2. Not required for Python 3
652             del self.__case       # Because it breaks pickle in Python 2. Not required for Python 3
653         return 0
654
655 # ==============================================================================
656 if __name__ == "__main__":
657     print('\n AUTODIAGNOSTIC \n')