1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2022 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
64 "Retourne le nom de l'application"
65 import daCore.version as dav
69 "Retourne le numéro de la version"
70 import daCore.version as dav
74 "Retourne la date de création de la version"
75 import daCore.version as dav
79 "Retourne l'année de création de la version"
80 import daCore.version as dav
83 def getSystemInformation(self, __prefix=""):
85 __msg += "\n%s%30s : %s" %(__prefix,"platform.system",platform.system())
86 __msg += "\n%s%30s : %s" %(__prefix,"sys.platform",sys.platform)
87 __msg += "\n%s%30s : %s" %(__prefix,"platform.version",platform.version())
88 __msg += "\n%s%30s : %s" %(__prefix,"platform.platform",platform.platform())
89 __msg += "\n%s%30s : %s" %(__prefix,"platform.machine",platform.machine())
90 if len(platform.processor())>0:
91 __msg += "\n%s%30s : %s" %(__prefix,"platform.processor",platform.processor())
93 if sys.platform.startswith('linux'):
94 if hasattr(platform, 'linux_distribution'):
95 __msg += "\n%s%30s : %s" %(__prefix,
96 "platform.linux_distribution",str(platform.linux_distribution()))
97 elif hasattr(platform, 'dist'):
98 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
99 elif sys.platform.startswith('darwin'):
100 if hasattr(platform, 'mac_ver'):
102 '0' : 'Cheetah', '1' : 'Puma', '2' : 'Jaguar',
103 '3' : 'Panther', '4' : 'Tiger', '5' : 'Leopard',
104 '6' : 'Snow Leopard', '7' : 'Lion', '8' : 'Mountain Lion',
105 '9' : 'Mavericks', '10': 'Yosemite', '11': 'El Capitan',
106 '12': 'Sierra', '13': 'High Sierra', '14': 'Mojave',
107 '15': 'Catalina', '16': 'Big Sur', '17': 'Monterey',
109 for key in __macosxv:
110 if (platform.mac_ver()[0].split('.')[1] == key):
111 __msg += "\n%s%30s : %s" %(__prefix,
112 "platform.mac_ver",str(platform.mac_ver()[0]+"(" + __macosxv[key]+")"))
113 elif hasattr(platform, 'dist'):
114 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
115 elif os.name == 'nt':
116 __msg += "\n%s%30s : %s" %(__prefix,"platform.win32_ver",platform.win32_ver()[1])
119 __msg += "\n%s%30s : %s" %(__prefix,"platform.python_implementation",platform.python_implementation())
120 __msg += "\n%s%30s : %s" %(__prefix,"sys.executable",sys.executable)
121 __msg += "\n%s%30s : %s" %(__prefix,"sys.version",sys.version.replace('\n',''))
122 __msg += "\n%s%30s : %s" %(__prefix,"sys.getfilesystemencoding",str(sys.getfilesystemencoding()))
123 __msg += "\n%s%30s : %s" %(__prefix,"locale.getdefaultlocale",str(locale.getdefaultlocale()))
125 __msg += "\n%s%30s : %s" %(__prefix,"os.cpu_count",os.cpu_count())
126 if hasattr(os, 'sched_getaffinity'):
127 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))",len(os.sched_getaffinity(0)))
129 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))","Unsupported on this platform")
131 __msg += "\n%s%30s : %s" %(__prefix,"platform.node",platform.node())
132 __msg += "\n%s%30s : %s" %(__prefix,"os.path.expanduser",os.path.expanduser('~'))
135 def getPythonVersion(self):
136 "Retourne la version de python disponible"
137 return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
139 def getNumpyVersion(self):
140 "Retourne la version de numpy disponible"
142 return numpy.version.version
144 def getScipyVersion(self):
145 "Retourne la version de scipy disponible"
147 __version = scipy.version.version
152 def getMatplotlibVersion(self):
153 "Retourne la version de matplotlib disponible"
155 __version = matplotlib.__version__
160 def getGnuplotVersion(self):
161 "Retourne la version de gnuplotpy disponible"
163 __version = Gnuplot.__version__
168 def getSphinxVersion(self):
169 "Retourne la version de sphinx disponible"
171 __version = sphinx.__version__
176 def getNloptVersion(self):
177 "Retourne la version de nlopt disponible"
179 __version = "%s.%s.%s"%(
180 nlopt.version_major(),
181 nlopt.version_minor(),
182 nlopt.version_bugfix(),
188 def getSdfVersion(self):
189 "Retourne la version de sdf disponible"
191 __version = sdf.__version__
196 def getCurrentMemorySize(self):
197 "Retourne la taille mémoire courante utilisée"
200 def MaximumPrecision(self):
201 "Retourne la precision maximale flottante pour Numpy"
204 numpy.array([1.,], dtype='float128')
210 def MachinePrecision(self):
211 # Alternative sans module :
215 # eps = (1.0 + eps/2) - 1.0
216 return sys.float_info.epsilon
219 import daCore.version as dav
220 return "%s %s (%s)"%(dav.name,dav.version,dav.date)
223 # ==============================================================================
227 import scipy.optimize
234 has_matplotlib = True
236 has_matplotlib = False
262 has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
263 has_yacs = bool( "YACS_ROOT_DIR" in os.environ )
264 has_adao = bool( "ADAO_ROOT_DIR" in os.environ )
265 has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
267 # ==============================================================================
268 def uniq( __sequence ):
270 Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
273 return [x for x in __sequence if x not in __seen and not __seen.add(x)]
275 def isIterable( __sequence, __check = False, __header = "" ):
277 Vérification que l'argument est un itérable interne.
278 Remarque : pour permettre le test correct en MultiFonctions,
279 - Ne pas accepter comme itérable un "numpy.ndarray"
280 - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
282 if isinstance( __sequence, (list, tuple, map, dict) ):
284 elif type(__sequence).__name__ in ('generator','range'):
286 elif "_iterator" in type(__sequence).__name__:
290 if __check and not __isOk:
291 raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
294 def date2int( __date, __lang="FR" ):
296 Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
298 __date = __date.strip()
299 if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
300 d,m,y = __date.split("/")
301 __number = (10**4)*int(y)+(10**2)*int(m)+int(d)
302 elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
303 part1, part2 = __date.split()
304 d,m,y = part1.strip().split("/")
305 h,n = part2.strip().split(":")
306 __number = (10**8)*int(y)+(10**6)*int(m)+(10**4)*int(d)+(10**2)*int(h)+int(n)
308 raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
311 def strvect2liststr( __strvect ):
313 Fonction de secours, conversion d'une chaîne de caractères de
314 représentation de vecteur en une liste de chaînes de caractères de
315 représentation de flottants
317 for s in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
318 __strvect = __strvect.replace(s,"") # Rien
320 __strvect = __strvect.replace(s," ") # Blanc
321 return __strvect.split()
323 def strmatrix2liststr( __strvect ):
325 Fonction de secours, conversion d'une chaîne de caractères de
326 représentation de matrice en une liste de chaînes de caractères de
327 représentation de flottants
329 for s in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
330 __strvect = __strvect.replace(s,"") # Rien
331 __strvect = __strvect.replace(","," ") # Blanc
333 __strvect = __strvect.replace(s,";") # "]" et ")" par ";"
334 __strvect = re.sub(r';\s*;',r';',__strvect)
335 __strvect = __strvect.rstrip(";") # Après ^ et avant v
336 __strmat = [__l.split() for __l in __strvect.split(";")]
339 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
340 if sys.platform.startswith("win") and len(__filename) > 256:
342 __msg = (" For some shared or older file systems on Windows, a file "+\
343 "name longer than 256 characters can lead to access problems."+\
344 "\n The name of the file in question is the following:"+\
345 "\n %s")%(__filename,)
346 if __warnInsteadOfPrint: logging.warning(__msg)
353 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
354 if str(__filename).count(".") > 1:
356 __msg = (" The file name contains %i point(s) before the extension "+\
357 "separator, which can potentially lead to problems when "+\
358 "importing this file into Python, as it can then be recognized "+\
359 "as a sub-module (generating a \"ModuleNotFoundError\"). If it "+\
360 "is intentional, make sure that there is no module with the "+\
361 "same name as the part before the first point, and that there is "+\
362 "no \"__init__.py\" file in the same directory."+\
363 "\n The name of the file in question is the following:"+\
364 "\n %s")%(int(str(__filename).count(".")-1), __filename)
365 if __warnInsteadOfPrint is None: pass
366 elif __warnInsteadOfPrint: logging.warning(__msg)
373 # ==============================================================================
374 class PathManagement(object):
376 Mise à jour du path système pour les répertoires d'outils
379 "Déclaration des répertoires statiques"
380 parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
382 self.__paths["daNumerics"] = os.path.join(parent,"daNumerics")
384 for v in self.__paths.values():
385 if os.path.isdir(v): sys.path.insert(0, v )
387 # Conserve en unique exemplaire chaque chemin
388 sys.path = uniq( sys.path )
393 Renvoie le dictionnaire des chemins ajoutés
397 # ==============================================================================
398 class SystemUsage(object):
400 Permet de récupérer les différentes tailles mémoires du process courant
403 # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
404 # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
406 _proc_status = '/proc/%d/status' % os.getpid()
407 _memo_status = '/proc/meminfo'
409 'o' : 1.0, # Multiples SI de l'octet
413 'kio': 1024.0, # Multiples binaires de l'octet
414 'Mio': 1024.0*1024.0,
415 'Gio': 1024.0*1024.0*1024.0,
416 'B': 1.0, # Multiples binaires du byte=octet
418 'MB' : 1024.0*1024.0,
419 'GB' : 1024.0*1024.0*1024.0,
426 def _VmA(self, VmKey, unit):
427 "Lecture des paramètres mémoire de la machine"
429 t = open(self._memo_status)
433 return 0.0 # non-Linux?
434 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
435 v = v[i:].split(None, 3) # whitespace
437 return 0.0 # invalid format?
438 # convert Vm value to bytes
439 mem = float(v[1]) * self._scale[v[2]]
440 return mem / self._scale[unit]
442 def getAvailablePhysicalMemory(self, unit="o"):
443 "Renvoie la mémoire physique utilisable en octets"
444 return self._VmA('MemTotal:', unit)
446 def getAvailableSwapMemory(self, unit="o"):
447 "Renvoie la mémoire swap utilisable en octets"
448 return self._VmA('SwapTotal:', unit)
450 def getAvailableMemory(self, unit="o"):
451 "Renvoie la mémoire totale (physique+swap) utilisable en octets"
452 return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
454 def getUsableMemory(self, unit="o"):
455 """Renvoie la mémoire utilisable en octets
456 Rq : il n'est pas sûr que ce décompte soit juste...
458 return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
459 self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
461 def _VmB(self, VmKey, unit):
462 "Lecture des paramètres mémoire du processus"
464 t = open(self._proc_status)
468 return 0.0 # non-Linux?
469 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
470 v = v[i:].split(None, 3) # whitespace
472 return 0.0 # invalid format?
473 # convert Vm value to bytes
474 mem = float(v[1]) * self._scale[v[2]]
475 return mem / self._scale[unit]
477 def getUsedMemory(self, unit="o"):
478 "Renvoie la mémoire résidente utilisée en octets"
479 return self._VmB('VmRSS:', unit)
481 def getVirtualMemory(self, unit="o"):
482 "Renvoie la mémoire totale utilisée en octets"
483 return self._VmB('VmSize:', unit)
485 def getUsedStacksize(self, unit="o"):
486 "Renvoie la taille du stack utilisé en octets"
487 return self._VmB('VmStk:', unit)
489 def getMaxUsedMemory(self, unit="o"):
490 "Renvoie la mémoire résidente maximale mesurée"
491 return self._VmB('VmHWM:', unit)
493 def getMaxVirtualMemory(self, unit="o"):
494 "Renvoie la mémoire totale maximale mesurée"
495 return self._VmB('VmPeak:', unit)
498 # ==============================================================================
499 if __name__ == "__main__":
500 print('\n AUTODIAGNOSTIC\n')