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 __msg += "\n%s%30s : %s" %(__prefix,"locale.getdefaultlocale",str(locale.getdefaultlocale()))
127 __msg += "\n%s%30s : %s" %(__prefix,"os.cpu_count",os.cpu_count())
128 if hasattr(os, 'sched_getaffinity'):
129 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))",len(os.sched_getaffinity(0)))
131 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))","Unsupported on this platform")
133 __msg += "\n%s%30s : %s" %(__prefix,"platform.node",platform.node())
134 __msg += "\n%s%30s : %s" %(__prefix,"os.path.expanduser",os.path.expanduser('~'))
137 def getPythonVersion(self):
138 "Retourne la version de python disponible"
139 return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
141 def getNumpyVersion(self):
142 "Retourne la version de numpy disponible"
144 return numpy.version.version
146 def getScipyVersion(self):
147 "Retourne la version de scipy disponible"
149 __version = scipy.version.version
154 def getMatplotlibVersion(self):
155 "Retourne la version de matplotlib disponible"
157 __version = matplotlib.__version__
162 def getGnuplotVersion(self):
163 "Retourne la version de gnuplotpy disponible"
165 __version = Gnuplot.__version__
170 def getSphinxVersion(self):
171 "Retourne la version de sphinx disponible"
173 __version = sphinx.__version__
178 def getNloptVersion(self):
179 "Retourne la version de nlopt disponible"
181 __version = "%s.%s.%s"%(
182 nlopt.version_major(),
183 nlopt.version_minor(),
184 nlopt.version_bugfix(),
190 def getSdfVersion(self):
191 "Retourne la version de sdf disponible"
193 __version = sdf.__version__
198 def getCurrentMemorySize(self):
199 "Retourne la taille mémoire courante utilisée"
202 def MaximumPrecision(self):
203 "Retourne la precision maximale flottante pour Numpy"
206 numpy.array([1.,], dtype='float128')
212 def MachinePrecision(self):
213 # Alternative sans module :
217 # eps = (1.0 + eps/2) - 1.0
218 return sys.float_info.epsilon
221 import daCore.version as dav
222 return "%s %s (%s)"%(dav.name,dav.version,dav.date)
224 # ==============================================================================
229 raise ImportError("Numpy is not available, despites the fact it is mandatory.")
234 import scipy.optimize
241 has_matplotlib = True
243 has_matplotlib = False
269 has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
270 has_yacs = bool( "YACS_ROOT_DIR" in os.environ )
271 has_adao = bool( "ADAO_ROOT_DIR" in os.environ )
272 has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
274 # ==============================================================================
275 def uniq( __sequence ):
277 Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
280 return [x for x in __sequence if x not in __seen and not __seen.add(x)]
283 "Version transformée pour comparaison robuste, obtenue comme un tuple"
285 for sv in re.split("[_.+-]", __version):
286 serie.append(sv.zfill(6))
289 def isIterable( __sequence, __check = False, __header = "" ):
291 Vérification que l'argument est un itérable interne.
292 Remarque : pour permettre le test correct en MultiFonctions,
293 - Ne pas accepter comme itérable un "numpy.ndarray"
294 - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
296 if isinstance( __sequence, (list, tuple, map, dict) ):
298 elif type(__sequence).__name__ in ('generator','range'):
300 elif "_iterator" in type(__sequence).__name__:
302 elif "itertools" in str(type(__sequence)):
306 if __check and not __isOk:
307 raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
310 def date2int( __date, __lang="FR" ):
312 Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
314 __date = __date.strip()
315 if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
316 d,m,y = __date.split("/")
317 __number = (10**4)*int(y)+(10**2)*int(m)+int(d)
318 elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
319 part1, part2 = __date.split()
320 d,m,y = part1.strip().split("/")
321 h,n = part2.strip().split(":")
322 __number = (10**8)*int(y)+(10**6)*int(m)+(10**4)*int(d)+(10**2)*int(h)+int(n)
324 raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
327 def strvect2liststr( __strvect ):
329 Fonction de secours, conversion d'une chaîne de caractères de
330 représentation de vecteur en une liste de chaînes de caractères de
331 représentation de flottants
333 for s in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
334 __strvect = __strvect.replace(s,"") # Rien
336 __strvect = __strvect.replace(s," ") # Blanc
337 return __strvect.split()
339 def strmatrix2liststr( __strvect ):
341 Fonction de secours, conversion d'une chaîne de caractères de
342 représentation de matrice en une liste de chaînes de caractères de
343 représentation de flottants
345 for s in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
346 __strvect = __strvect.replace(s,"") # Rien
347 __strvect = __strvect.replace(","," ") # Blanc
349 __strvect = __strvect.replace(s,";") # "]" et ")" par ";"
350 __strvect = re.sub(r';\s*;',r';',__strvect)
351 __strvect = __strvect.rstrip(";") # Après ^ et avant v
352 __strmat = [__l.split() for __l in __strvect.split(";")]
355 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
356 if sys.platform.startswith("win") and len(__filename) > 256:
358 __msg = (" For some shared or older file systems on Windows, a file "+\
359 "name longer than 256 characters can lead to access problems."+\
360 "\n The name of the file in question is the following:"+\
361 "\n %s")%(__filename,)
362 if __warnInsteadOfPrint: logging.warning(__msg)
369 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
370 if str(__filename).count(".") > 1:
372 __msg = (" The file name contains %i point(s) before the extension "+\
373 "separator, which can potentially lead to problems when "+\
374 "importing this file into Python, as it can then be recognized "+\
375 "as a sub-module (generating a \"ModuleNotFoundError\"). If it "+\
376 "is intentional, make sure that there is no module with the "+\
377 "same name as the part before the first point, and that there is "+\
378 "no \"__init__.py\" file in the same directory."+\
379 "\n The name of the file in question is the following:"+\
380 "\n %s")%(int(str(__filename).count(".")-1), __filename)
381 if __warnInsteadOfPrint is None: pass
382 elif __warnInsteadOfPrint: logging.warning(__msg)
389 # ==============================================================================
390 class PathManagement(object):
392 Mise à jour du path système pour les répertoires d'outils
394 __slots__ = ("__paths")
397 "Déclaration des répertoires statiques"
398 parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
400 self.__paths["daNumerics"] = os.path.join(parent,"daNumerics")
402 for v in self.__paths.values():
403 if os.path.isdir(v): sys.path.insert(0, v )
405 # Conserve en unique exemplaire chaque chemin
406 sys.path = uniq( sys.path )
411 Renvoie le dictionnaire des chemins ajoutés
415 # ==============================================================================
416 class SystemUsage(object):
418 Permet de récupérer les différentes tailles mémoires du process courant
422 # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
423 # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
425 _proc_status = '/proc/%d/status' % os.getpid()
426 _memo_status = '/proc/meminfo'
428 'o' : 1.0, # Multiples SI de l'octet
432 'kio': 1024.0, # Multiples binaires de l'octet
433 'Mio': 1024.0*1024.0,
434 'Gio': 1024.0*1024.0*1024.0,
435 'B': 1.0, # Multiples binaires du byte=octet
437 'MB' : 1024.0*1024.0,
438 'GB' : 1024.0*1024.0*1024.0,
445 def _VmA(self, VmKey, unit):
446 "Lecture des paramètres mémoire de la machine"
448 t = open(self._memo_status)
452 return 0.0 # non-Linux?
453 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
454 v = v[i:].split(None, 3) # whitespace
456 return 0.0 # invalid format?
457 # convert Vm value to bytes
458 mem = float(v[1]) * self._scale[v[2]]
459 return mem / self._scale[unit]
461 def getAvailablePhysicalMemory(self, unit="o"):
462 "Renvoie la mémoire physique utilisable en octets"
463 return self._VmA('MemTotal:', unit)
465 def getAvailableSwapMemory(self, unit="o"):
466 "Renvoie la mémoire swap utilisable en octets"
467 return self._VmA('SwapTotal:', unit)
469 def getAvailableMemory(self, unit="o"):
470 "Renvoie la mémoire totale (physique+swap) utilisable en octets"
471 return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
473 def getUsableMemory(self, unit="o"):
474 """Renvoie la mémoire utilisable en octets
475 Rq : il n'est pas sûr que ce décompte soit juste...
477 return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
478 self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
480 def _VmB(self, VmKey, unit):
481 "Lecture des paramètres mémoire du processus"
483 t = open(self._proc_status)
487 return 0.0 # non-Linux?
488 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
489 v = v[i:].split(None, 3) # whitespace
491 return 0.0 # invalid format?
492 # convert Vm value to bytes
493 mem = float(v[1]) * self._scale[v[2]]
494 return mem / self._scale[unit]
496 def getUsedMemory(self, unit="o"):
497 "Renvoie la mémoire résidente utilisée en octets"
498 return self._VmB('VmRSS:', unit)
500 def getVirtualMemory(self, unit="o"):
501 "Renvoie la mémoire totale utilisée en octets"
502 return self._VmB('VmSize:', unit)
504 def getUsedStacksize(self, unit="o"):
505 "Renvoie la taille du stack utilisé en octets"
506 return self._VmB('VmStk:', unit)
508 def getMaxUsedMemory(self, unit="o"):
509 "Renvoie la mémoire résidente maximale mesurée"
510 return self._VmB('VmHWM:', unit)
512 def getMaxVirtualMemory(self, unit="o"):
513 "Renvoie la mémoire totale maximale mesurée"
514 return self._VmB('VmPeak:', unit)
516 # ==============================================================================
517 if __name__ == "__main__":
518 print('\n AUTODIAGNOSTIC\n')