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 getPythonVersion(self):
141 "Retourne la version de python disponible"
142 return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
144 def getNumpyVersion(self):
145 "Retourne la version de numpy disponible"
147 return numpy.version.version
149 def getScipyVersion(self):
150 "Retourne la version de scipy disponible"
152 __version = scipy.version.version
157 def getMatplotlibVersion(self):
158 "Retourne la version de matplotlib disponible"
160 __version = matplotlib.__version__
165 def getGnuplotVersion(self):
166 "Retourne la version de gnuplotpy disponible"
168 __version = Gnuplot.__version__
173 def getSphinxVersion(self):
174 "Retourne la version de sphinx disponible"
176 __version = sphinx.__version__
181 def getNloptVersion(self):
182 "Retourne la version de nlopt disponible"
184 __version = "%s.%s.%s"%(
185 nlopt.version_major(),
186 nlopt.version_minor(),
187 nlopt.version_bugfix(),
193 def getSdfVersion(self):
194 "Retourne la version de sdf disponible"
196 __version = sdf.__version__
201 def getCurrentMemorySize(self):
202 "Retourne la taille mémoire courante utilisée"
205 def MaximumPrecision(self):
206 "Retourne la precision maximale flottante pour Numpy"
209 numpy.array([1.,], dtype='float128')
215 def MachinePrecision(self):
216 # Alternative sans module :
220 # eps = (1.0 + eps/2) - 1.0
221 return sys.float_info.epsilon
224 import daCore.version as dav
225 return "%s %s (%s)"%(dav.name,dav.version,dav.date)
227 # ==============================================================================
232 raise ImportError("Numpy is not available, despites the fact it is mandatory.")
237 import scipy.optimize
244 has_matplotlib = True
246 has_matplotlib = False
272 has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
273 has_yacs = bool( "YACS_ROOT_DIR" in os.environ )
274 has_adao = bool( "ADAO_ROOT_DIR" in os.environ )
275 has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
277 # ==============================================================================
278 def uniq( __sequence ):
280 Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
283 return [x for x in __sequence if x not in __seen and not __seen.add(x)]
286 "Version transformée pour comparaison robuste, obtenue comme un tuple"
288 for sv in re.split("[_.+-]", __version):
289 serie.append(sv.zfill(6))
292 def isIterable( __sequence, __check = False, __header = "" ):
294 Vérification que l'argument est un itérable interne.
295 Remarque : pour permettre le test correct en MultiFonctions,
296 - Ne pas accepter comme itérable un "numpy.ndarray"
297 - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
299 if isinstance( __sequence, (list, tuple, map, dict) ):
301 elif type(__sequence).__name__ in ('generator','range'):
303 elif "_iterator" in type(__sequence).__name__:
305 elif "itertools" in str(type(__sequence)):
309 if __check and not __isOk:
310 raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
313 def date2int( __date, __lang="FR" ):
315 Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
317 __date = __date.strip()
318 if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
319 d,m,y = __date.split("/")
320 __number = (10**4)*int(y)+(10**2)*int(m)+int(d)
321 elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
322 part1, part2 = __date.split()
323 d,m,y = part1.strip().split("/")
324 h,n = part2.strip().split(":")
325 __number = (10**8)*int(y)+(10**6)*int(m)+(10**4)*int(d)+(10**2)*int(h)+int(n)
327 raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
330 def strvect2liststr( __strvect ):
332 Fonction de secours, conversion d'une chaîne de caractères de
333 représentation de vecteur en une liste de chaînes de caractères de
334 représentation de flottants
336 for s in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
337 __strvect = __strvect.replace(s,"") # Rien
339 __strvect = __strvect.replace(s," ") # Blanc
340 return __strvect.split()
342 def strmatrix2liststr( __strvect ):
344 Fonction de secours, conversion d'une chaîne de caractères de
345 représentation de matrice en une liste de chaînes de caractères de
346 représentation de flottants
348 for s in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
349 __strvect = __strvect.replace(s,"") # Rien
350 __strvect = __strvect.replace(","," ") # Blanc
352 __strvect = __strvect.replace(s,";") # "]" et ")" par ";"
353 __strvect = re.sub(r';\s*;',r';',__strvect)
354 __strvect = __strvect.rstrip(";") # Après ^ et avant v
355 __strmat = [__l.split() for __l in __strvect.split(";")]
358 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
359 if sys.platform.startswith("win") and len(__filename) > 256:
361 __msg = (" For some shared or older file systems on Windows, a file "+\
362 "name longer than 256 characters can lead to access problems."+\
363 "\n The name of the file in question is the following:"+\
364 "\n %s")%(__filename,)
365 if __warnInsteadOfPrint: logging.warning(__msg)
372 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
373 if str(__filename).count(".") > 1:
375 __msg = (" The file name contains %i point(s) before the extension "+\
376 "separator, which can potentially lead to problems when "+\
377 "importing this file into Python, as it can then be recognized "+\
378 "as a sub-module (generating a \"ModuleNotFoundError\"). If it "+\
379 "is intentional, make sure that there is no module with the "+\
380 "same name as the part before the first point, and that there is "+\
381 "no \"__init__.py\" file in the same directory."+\
382 "\n The name of the file in question is the following:"+\
383 "\n %s")%(int(str(__filename).count(".")-1), __filename)
384 if __warnInsteadOfPrint is None: pass
385 elif __warnInsteadOfPrint: logging.warning(__msg)
392 # ==============================================================================
393 class PathManagement(object):
395 Mise à jour du path système pour les répertoires d'outils
397 __slots__ = ("__paths")
400 "Déclaration des répertoires statiques"
401 parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
403 self.__paths["daNumerics"] = os.path.join(parent,"daNumerics")
405 for v in self.__paths.values():
406 if os.path.isdir(v): sys.path.insert(0, v )
408 # Conserve en unique exemplaire chaque chemin
409 sys.path = uniq( sys.path )
414 Renvoie le dictionnaire des chemins ajoutés
418 # ==============================================================================
419 class SystemUsage(object):
421 Permet de récupérer les différentes tailles mémoires du process courant
425 # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
426 # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
428 _proc_status = '/proc/%d/status' % os.getpid()
429 _memo_status = '/proc/meminfo'
431 'o' : 1.0, # Multiples SI de l'octet
435 'kio': 1024.0, # Multiples binaires de l'octet
436 'Mio': 1024.0*1024.0,
437 'Gio': 1024.0*1024.0*1024.0,
438 'B': 1.0, # Multiples binaires du byte=octet
440 'MB' : 1024.0*1024.0,
441 'GB' : 1024.0*1024.0*1024.0,
448 def _VmA(self, VmKey, unit):
449 "Lecture des paramètres mémoire de la machine"
451 t = open(self._memo_status)
455 return 0.0 # non-Linux?
456 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
457 v = v[i:].split(None, 3) # whitespace
459 return 0.0 # invalid format?
460 # convert Vm value to bytes
461 mem = float(v[1]) * self._scale[v[2]]
462 return mem / self._scale[unit]
464 def getAvailablePhysicalMemory(self, unit="o"):
465 "Renvoie la mémoire physique utilisable en octets"
466 return self._VmA('MemTotal:', unit)
468 def getAvailableSwapMemory(self, unit="o"):
469 "Renvoie la mémoire swap utilisable en octets"
470 return self._VmA('SwapTotal:', unit)
472 def getAvailableMemory(self, unit="o"):
473 "Renvoie la mémoire totale (physique+swap) utilisable en octets"
474 return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
476 def getUsableMemory(self, unit="o"):
477 """Renvoie la mémoire utilisable en octets
478 Rq : il n'est pas sûr que ce décompte soit juste...
480 return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
481 self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
483 def _VmB(self, VmKey, unit):
484 "Lecture des paramètres mémoire du processus"
486 t = open(self._proc_status)
490 return 0.0 # non-Linux?
491 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
492 v = v[i:].split(None, 3) # whitespace
494 return 0.0 # invalid format?
495 # convert Vm value to bytes
496 mem = float(v[1]) * self._scale[v[2]]
497 return mem / self._scale[unit]
499 def getUsedMemory(self, unit="o"):
500 "Renvoie la mémoire résidente utilisée en octets"
501 return self._VmB('VmRSS:', unit)
503 def getVirtualMemory(self, unit="o"):
504 "Renvoie la mémoire totale utilisée en octets"
505 return self._VmB('VmSize:', unit)
507 def getUsedStacksize(self, unit="o"):
508 "Renvoie la taille du stack utilisé en octets"
509 return self._VmB('VmStk:', unit)
511 def getMaxUsedMemory(self, unit="o"):
512 "Renvoie la mémoire résidente maximale mesurée"
513 return self._VmB('VmHWM:', unit)
515 def getMaxVirtualMemory(self, unit="o"):
516 "Renvoie la mémoire totale maximale mesurée"
517 return self._VmB('VmPeak:', unit)
519 # ==============================================================================
520 if __name__ == "__main__":
521 print('\n AUTODIAGNOSTIC\n')