1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2023 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 Informations sur le code et la plateforme, et mise à jour des chemins.
26 La classe "PlatformInfo" permet de récupérer les informations générales sur
27 le code et la plateforme sous forme de strings, ou d'afficher directement
28 les informations disponibles par les méthodes. L'impression directe d'un
29 objet de cette classe affiche les informations minimales. Par exemple :
31 print(PlatformInfo().getVersion())
32 created = PlatformInfo().getDate()
34 La classe "PathManagement" permet de mettre à jour les chemins système pour
35 ajouter les outils numériques, matrices... On l'utilise en instanciant
36 simplement cette classe, sans meme récupérer d'objet :
39 La classe "SystemUsage" permet de sous Unix les différentes tailles
40 mémoires du process courant. Ces tailles peuvent être assez variables et
41 dépendent de la fiabilité des informations du système dans le suivi des
44 __author__ = "Jean-Philippe ARGAUD"
54 # ==============================================================================
55 class PlatformInfo(object):
57 Rassemblement des informations sur le code et la plateforme
66 "Retourne le nom de l'application"
67 import daCore.version as dav
71 "Retourne le numéro de la version"
72 import daCore.version as dav
76 "Retourne la date de création de la version"
77 import daCore.version as dav
81 "Retourne l'année de création de la version"
82 import daCore.version as dav
85 def getSystemInformation(self, __prefix=""):
87 __msg += "\n%s%30s : %s" %(__prefix,"platform.system",platform.system())
88 __msg += "\n%s%30s : %s" %(__prefix,"sys.platform",sys.platform)
89 __msg += "\n%s%30s : %s" %(__prefix,"platform.version",platform.version())
90 __msg += "\n%s%30s : %s" %(__prefix,"platform.platform",platform.platform())
91 __msg += "\n%s%30s : %s" %(__prefix,"platform.machine",platform.machine())
92 if len(platform.processor())>0:
93 __msg += "\n%s%30s : %s" %(__prefix,"platform.processor",platform.processor())
95 if sys.platform.startswith('linux'):
96 if hasattr(platform, 'linux_distribution'):
97 __msg += "\n%s%30s : %s" %(__prefix,
98 "platform.linux_distribution",str(platform.linux_distribution()))
99 elif hasattr(platform, 'dist'):
100 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
101 elif sys.platform.startswith('darwin'):
102 if hasattr(platform, 'mac_ver'):
104 '0' : 'Cheetah', '1' : 'Puma', '2' : 'Jaguar',
105 '3' : 'Panther', '4' : 'Tiger', '5' : 'Leopard',
106 '6' : 'Snow Leopard', '7' : 'Lion', '8' : 'Mountain Lion',
107 '9' : 'Mavericks', '10': 'Yosemite', '11': 'El Capitan',
108 '12': 'Sierra', '13': 'High Sierra', '14': 'Mojave',
109 '15': 'Catalina', '16': 'Big Sur', '17': 'Monterey',
111 for key in __macosxv:
112 if (platform.mac_ver()[0].split('.')[1] == key):
113 __msg += "\n%s%30s : %s" %(__prefix,
114 "platform.mac_ver",str(platform.mac_ver()[0]+"(" + __macosxv[key]+")"))
115 elif hasattr(platform, 'dist'):
116 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
117 elif os.name == 'nt':
118 __msg += "\n%s%30s : %s" %(__prefix,"platform.win32_ver",platform.win32_ver()[1])
121 __msg += "\n%s%30s : %s" %(__prefix,"platform.python_implementation",platform.python_implementation())
122 __msg += "\n%s%30s : %s" %(__prefix,"sys.executable",sys.executable)
123 __msg += "\n%s%30s : %s" %(__prefix,"sys.version",sys.version.replace('\n',''))
124 __msg += "\n%s%30s : %s" %(__prefix,"sys.getfilesystemencoding",str(sys.getfilesystemencoding()))
125 if sys.version_info.major == 3 and sys.version_info.minor < 11: # Python 3.10
126 __msg += "\n%s%30s : %s" %(__prefix,"locale.getdefaultlocale",str(locale.getdefaultlocale()))
128 __msg += "\n%s%30s : %s" %(__prefix,"locale.getlocale",str(locale.getlocale()))
130 __msg += "\n%s%30s : %s" %(__prefix,"os.cpu_count",os.cpu_count())
131 if hasattr(os, 'sched_getaffinity'):
132 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))",len(os.sched_getaffinity(0)))
134 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))","Unsupported on this platform")
136 __msg += "\n%s%30s : %s" %(__prefix,"platform.node",platform.node())
137 __msg += "\n%s%30s : %s" %(__prefix,"os.path.expanduser",os.path.expanduser('~'))
140 def getApplicationInformation(self, __prefix=""):
142 __msg += "\n%s%30s : %s" %(__prefix,"ADAO version",self.getVersion())
144 __msg += "\n%s%30s : %s" %(__prefix,"Python version",self.getPythonVersion())
145 __msg += "\n%s%30s : %s" %(__prefix,"Numpy version",self.getNumpyVersion())
146 __msg += "\n%s%30s : %s" %(__prefix,"Scipy version",self.getScipyVersion())
147 __msg += "\n%s%30s : %s" %(__prefix,"NLopt version",self.getNloptVersion())
148 __msg += "\n%s%30s : %s" %(__prefix,"MatplotLib version",self.getMatplotlibVersion())
149 __msg += "\n%s%30s : %s" %(__prefix,"GnuplotPy version",self.getGnuplotVersion())
150 __msg += "\n%s%30s : %s" %(__prefix,"Sphinx version",self.getSphinxVersion())
151 __msg += "\n%s%30s : %s" %(__prefix,"Fmpy version",self.getFmpyVersion())
154 def getAllInformation(self, __prefix="", __title="Whole system information"):
157 __msg += "\n"+"="*80+"\n"+__title+"\n"+"="*80+"\n"
158 __msg += self.getSystemInformation(__prefix)
160 __msg += self.getApplicationInformation(__prefix)
163 def getPythonVersion(self):
164 "Retourne la version de python disponible"
165 return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
167 def getNumpyVersion(self):
168 "Retourne la version de numpy disponible"
170 return numpy.version.version
172 def getScipyVersion(self):
173 "Retourne la version de scipy disponible"
175 __version = scipy.version.version
180 def getMatplotlibVersion(self):
181 "Retourne la version de matplotlib disponible"
183 __version = matplotlib.__version__
188 def getGnuplotVersion(self):
189 "Retourne la version de gnuplotpy disponible"
191 __version = Gnuplot.__version__
196 def getSphinxVersion(self):
197 "Retourne la version de sphinx disponible"
199 __version = sphinx.__version__
204 def getNloptVersion(self):
205 "Retourne la version de nlopt disponible"
207 __version = "%s.%s.%s"%(
208 nlopt.version_major(),
209 nlopt.version_minor(),
210 nlopt.version_bugfix(),
216 def getSdfVersion(self):
217 "Retourne la version de sdf disponible"
219 __version = sdf.__version__
224 def getFmpyVersion(self):
225 "Retourne la version de fmpy disponible"
227 __version = fmpy.__version__
232 def getCurrentMemorySize(self):
233 "Retourne la taille mémoire courante utilisée"
236 def MaximumPrecision(self):
237 "Retourne la precision maximale flottante pour Numpy"
240 numpy.array([1.,], dtype='float128')
246 def MachinePrecision(self):
247 # Alternative sans module :
251 # eps = (1.0 + eps/2) - 1.0
252 return sys.float_info.epsilon
255 import daCore.version as dav
256 return "%s %s (%s)"%(dav.name,dav.version,dav.date)
258 # ==============================================================================
263 raise ImportError("Numpy is not available, despites the fact it is mandatory.")
268 import scipy.optimize
275 has_matplotlib = True
277 has_matplotlib = False
309 has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
310 has_yacs = bool( "YACS_ROOT_DIR" in os.environ )
311 has_adao = bool( "ADAO_ROOT_DIR" in os.environ )
312 has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
314 # ==============================================================================
315 def uniq( __sequence ):
317 Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
320 return [x for x in __sequence if x not in __seen and not __seen.add(x)]
323 "Version transformée pour comparaison robuste, obtenue comme un tuple"
325 for sv in re.split("[_.+-]", __version):
326 serie.append(sv.zfill(6))
329 def isIterable( __sequence, __check = False, __header = "" ):
331 Vérification que l'argument est un itérable interne.
332 Remarque : pour permettre le test correct en MultiFonctions,
333 - Ne pas accepter comme itérable un "numpy.ndarray"
334 - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
336 if isinstance( __sequence, (list, tuple, map, dict) ):
338 elif type(__sequence).__name__ in ('generator','range'):
340 elif "_iterator" in type(__sequence).__name__:
342 elif "itertools" in str(type(__sequence)):
346 if __check and not __isOk:
347 raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
350 def date2int( __date, __lang="FR" ):
352 Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
354 __date = __date.strip()
355 if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
356 d,m,y = __date.split("/")
357 __number = (10**4)*int(y)+(10**2)*int(m)+int(d)
358 elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
359 part1, part2 = __date.split()
360 d,m,y = part1.strip().split("/")
361 h,n = part2.strip().split(":")
362 __number = (10**8)*int(y)+(10**6)*int(m)+(10**4)*int(d)+(10**2)*int(h)+int(n)
364 raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
367 def vfloat(__value :numpy.ndarray):
369 Conversion en flottant d'un vecteur de taille 1 et de dimensions quelconques
371 if hasattr(__value,"size") and __value.size == 1:
372 return float(__value.flat[0])
373 elif isinstance(__value, (float,int)):
374 return float(__value)
376 raise ValueError("Error in converting multiple float values from array when waiting for only one")
378 def strvect2liststr( __strvect ):
380 Fonction de secours, conversion d'une chaîne de caractères de
381 représentation de vecteur en une liste de chaînes de caractères de
382 représentation de flottants
384 for s in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
385 __strvect = __strvect.replace(s,"") # Rien
387 __strvect = __strvect.replace(s," ") # Blanc
388 return __strvect.split()
390 def strmatrix2liststr( __strvect ):
392 Fonction de secours, conversion d'une chaîne de caractères de
393 représentation de matrice en une liste de chaînes de caractères de
394 représentation de flottants
396 for s in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
397 __strvect = __strvect.replace(s,"") # Rien
398 __strvect = __strvect.replace(","," ") # Blanc
400 __strvect = __strvect.replace(s,";") # "]" et ")" par ";"
401 __strvect = re.sub(r';\s*;',r';',__strvect)
402 __strvect = __strvect.rstrip(";") # Après ^ et avant v
403 __strmat = [__l.split() for __l in __strvect.split(";")]
406 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
407 if sys.platform.startswith("win") and len(__filename) > 256:
409 __msg = (" For some shared or older file systems on Windows, a file "+\
410 "name longer than 256 characters can lead to access problems."+\
411 "\n The name of the file in question is the following:"+\
412 "\n %s")%(__filename,)
413 if __warnInsteadOfPrint: logging.warning(__msg)
420 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
421 if str(__filename).count(".") > 1:
423 __msg = (" The file name contains %i point(s) before the extension "+\
424 "separator, which can potentially lead to problems when "+\
425 "importing this file into Python, as it can then be recognized "+\
426 "as a sub-module (generating a \"ModuleNotFoundError\"). If it "+\
427 "is intentional, make sure that there is no module with the "+\
428 "same name as the part before the first point, and that there is "+\
429 "no \"__init__.py\" file in the same directory."+\
430 "\n The name of the file in question is the following:"+\
431 "\n %s")%(int(str(__filename).count(".")-1), __filename)
432 if __warnInsteadOfPrint is None: pass
433 elif __warnInsteadOfPrint: logging.warning(__msg)
440 # ==============================================================================
441 class PathManagement(object):
443 Mise à jour du path système pour les répertoires d'outils
445 __slots__ = ("__paths")
448 "Déclaration des répertoires statiques"
449 parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
451 self.__paths["daNumerics"] = os.path.join(parent,"daNumerics")
453 for v in self.__paths.values():
454 if os.path.isdir(v): sys.path.insert(0, v )
456 # Conserve en unique exemplaire chaque chemin
457 sys.path = uniq( sys.path )
462 Renvoie le dictionnaire des chemins ajoutés
466 # ==============================================================================
467 class SystemUsage(object):
469 Permet de récupérer les différentes tailles mémoires du process courant
473 # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
474 # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
476 _proc_status = '/proc/%d/status' % os.getpid()
477 _memo_status = '/proc/meminfo'
479 'o' : 1.0, # Multiples SI de l'octet
483 'kio': 1024.0, # Multiples binaires de l'octet
484 'Mio': 1024.0*1024.0,
485 'Gio': 1024.0*1024.0*1024.0,
486 'B': 1.0, # Multiples binaires du byte=octet
488 'MB' : 1024.0*1024.0,
489 'GB' : 1024.0*1024.0*1024.0,
496 def _VmA(self, VmKey, unit):
497 "Lecture des paramètres mémoire de la machine"
499 t = open(self._memo_status)
503 return 0.0 # non-Linux?
504 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
505 v = v[i:].split(None, 3) # whitespace
507 return 0.0 # invalid format?
508 # convert Vm value to bytes
509 mem = float(v[1]) * self._scale[v[2]]
510 return mem / self._scale[unit]
512 def getAvailablePhysicalMemory(self, unit="o"):
513 "Renvoie la mémoire physique utilisable en octets"
514 return self._VmA('MemTotal:', unit)
516 def getAvailableSwapMemory(self, unit="o"):
517 "Renvoie la mémoire swap utilisable en octets"
518 return self._VmA('SwapTotal:', unit)
520 def getAvailableMemory(self, unit="o"):
521 "Renvoie la mémoire totale (physique+swap) utilisable en octets"
522 return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
524 def getUsableMemory(self, unit="o"):
525 """Renvoie la mémoire utilisable en octets
526 Rq : il n'est pas sûr que ce décompte soit juste...
528 return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
529 self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
531 def _VmB(self, VmKey, unit):
532 "Lecture des paramètres mémoire du processus"
534 t = open(self._proc_status)
538 return 0.0 # non-Linux?
539 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
540 v = v[i:].split(None, 3) # whitespace
542 return 0.0 # invalid format?
543 # convert Vm value to bytes
544 mem = float(v[1]) * self._scale[v[2]]
545 return mem / self._scale[unit]
547 def getUsedMemory(self, unit="o"):
548 "Renvoie la mémoire résidente utilisée en octets"
549 return self._VmB('VmRSS:', unit)
551 def getVirtualMemory(self, unit="o"):
552 "Renvoie la mémoire totale utilisée en octets"
553 return self._VmB('VmSize:', unit)
555 def getUsedStacksize(self, unit="o"):
556 "Renvoie la taille du stack utilisé en octets"
557 return self._VmB('VmStk:', unit)
559 def getMaxUsedMemory(self, unit="o"):
560 "Renvoie la mémoire résidente maximale mesurée"
561 return self._VmB('VmHWM:', unit)
563 def getMaxVirtualMemory(self, unit="o"):
564 "Renvoie la mémoire totale maximale mesurée"
565 return self._VmB('VmPeak:', unit)
567 # ==============================================================================
568 if __name__ == "__main__":
569 print('\n AUTODIAGNOSTIC\n')