1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2024 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 même 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"
55 # ==============================================================================
56 class PlatformInfo(object):
58 Rassemblement des informations sur le code et la plateforme
67 "Retourne le nom de l'application"
68 import daCore.version as dav
72 "Retourne le numéro de la version"
73 import daCore.version as dav
77 "Retourne la date de création de la version"
78 import daCore.version as dav
82 "Retourne l'année de création de la version"
83 import daCore.version as dav
86 def getSystemInformation(self, __prefix=""):
88 __msg += "\n%s%30s : %s" %(__prefix,"platform.system",platform.system())
89 __msg += "\n%s%30s : %s" %(__prefix,"sys.platform",sys.platform)
90 __msg += "\n%s%30s : %s" %(__prefix,"platform.version",platform.version())
91 __msg += "\n%s%30s : %s" %(__prefix,"platform.platform",platform.platform())
92 __msg += "\n%s%30s : %s" %(__prefix,"platform.machine",platform.machine())
93 if len(platform.processor())>0:
94 __msg += "\n%s%30s : %s" %(__prefix,"platform.processor",platform.processor())
96 if sys.platform.startswith('linux'):
97 if hasattr(platform, 'linux_distribution'):
98 __msg += "\n%s%30s : %s" %(__prefix,
99 "platform.linux_distribution",str(platform.linux_distribution()))
100 elif hasattr(platform, 'dist'):
101 __msg += "\n%s%30s : %s" %(__prefix,
102 "platform.dist",str(platform.dist()))
103 elif sys.platform.startswith('darwin'):
104 if hasattr(platform, 'mac_ver'):
105 # https://fr.wikipedia.org/wiki/MacOS
107 '0' : 'Cheetah', '1' : 'Puma', '2' : 'Jaguar',
108 '3' : 'Panther', '4' : 'Tiger', '5' : 'Leopard',
109 '6' : 'Snow Leopard', '7' : 'Lion', '8' : 'Mountain Lion',
110 '9' : 'Mavericks', '10': 'Yosemite', '11': 'El Capitan',
111 '12': 'Sierra', '13': 'High Sierra', '14': 'Mojave',
114 for key in __macosxv10:
115 __details = platform.mac_ver()[0].split('.')
116 if (len(__details)>0) and (__details[1] == key):
117 __msg += "\n%s%30s : %s" %(__prefix,
118 "platform.mac_ver",str(platform.mac_ver()[0]+"(" + __macosxv10[key]+")"))
120 '11': 'Big Sur', '12': 'Monterey', '13': 'Ventura',
123 for key in __macosxv11:
124 __details = platform.mac_ver()[0].split('.')
125 if (__details[0] == key):
126 __msg += "\n%s%30s : %s" %(__prefix,
127 "platform.mac_ver",str(platform.mac_ver()[0]+"(" + __macosxv11[key]+")"))
128 elif hasattr(platform, 'dist'):
129 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
130 elif os.name == 'nt':
131 __msg += "\n%s%30s : %s" %(__prefix,"platform.win32_ver",platform.win32_ver()[1])
134 __msg += "\n%s%30s : %s" %(__prefix,"platform.python_implementation",platform.python_implementation())
135 __msg += "\n%s%30s : %s" %(__prefix,"sys.executable",sys.executable)
136 __msg += "\n%s%30s : %s" %(__prefix,"sys.version",sys.version.replace('\n',''))
137 __msg += "\n%s%30s : %s" %(__prefix,"sys.getfilesystemencoding",str(sys.getfilesystemencoding()))
138 if sys.version_info.major == 3 and sys.version_info.minor < 11: # Python 3.10
139 __msg += "\n%s%30s : %s" %(__prefix,"locale.getdefaultlocale",str(locale.getdefaultlocale()))
141 __msg += "\n%s%30s : %s" %(__prefix,"locale.getlocale",str(locale.getlocale()))
143 __msg += "\n%s%30s : %s" %(__prefix,"os.cpu_count",os.cpu_count())
144 if hasattr(os, 'sched_getaffinity'):
145 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))",len(os.sched_getaffinity(0)))
147 __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))","Unsupported on this platform")
149 __msg += "\n%s%30s : %s" %(__prefix,"platform.node",platform.node())
150 __msg += "\n%s%30s : %s" %(__prefix,"socket.getfqdn",socket.getfqdn())
151 __msg += "\n%s%30s : %s" %(__prefix,"os.path.expanduser",os.path.expanduser('~'))
154 def getApplicationInformation(self, __prefix=""):
156 __msg += "\n%s%30s : %s" %(__prefix,"ADAO version",self.getVersion())
158 __msg += "\n%s%30s : %s" %(__prefix,"Python version",self.getPythonVersion())
159 __msg += "\n%s%30s : %s" %(__prefix,"Numpy version",self.getNumpyVersion())
160 __msg += "\n%s%30s : %s" %(__prefix,"Scipy version",self.getScipyVersion())
161 __msg += "\n%s%30s : %s" %(__prefix,"NLopt version",self.getNloptVersion())
162 __msg += "\n%s%30s : %s" %(__prefix,"MatplotLib version",self.getMatplotlibVersion())
163 __msg += "\n%s%30s : %s" %(__prefix,"GnuplotPy version",self.getGnuplotVersion())
164 __msg += "\n%s%30s : %s" %(__prefix,"Sphinx version",self.getSphinxVersion())
165 __msg += "\n%s%30s : %s" %(__prefix,"Fmpy version",self.getFmpyVersion())
168 def getAllInformation(self, __prefix="", __title="Whole system information"):
171 __msg += "\n"+"="*80+"\n"+__title+"\n"+"="*80+"\n"
172 __msg += self.getSystemInformation(__prefix)
174 __msg += self.getApplicationInformation(__prefix)
177 def getPythonVersion(self):
178 "Retourne la version de python disponible"
179 return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
181 def getNumpyVersion(self):
182 "Retourne la version de numpy disponible"
184 return numpy.version.version
186 def getScipyVersion(self):
187 "Retourne la version de scipy disponible"
189 __version = scipy.version.version
194 def getMatplotlibVersion(self):
195 "Retourne la version de matplotlib disponible"
197 __version = matplotlib.__version__
202 def getGnuplotVersion(self):
203 "Retourne la version de gnuplotpy disponible"
205 __version = Gnuplot.__version__
210 def getSphinxVersion(self):
211 "Retourne la version de sphinx disponible"
213 __version = sphinx.__version__
218 def getNloptVersion(self):
219 "Retourne la version de nlopt disponible"
221 __version = "%s.%s.%s"%(
222 nlopt.version_major(),
223 nlopt.version_minor(),
224 nlopt.version_bugfix(),
230 def getSdfVersion(self):
231 "Retourne la version de sdf disponible"
233 __version = sdf.__version__
238 def getFmpyVersion(self):
239 "Retourne la version de fmpy disponible"
241 __version = fmpy.__version__
246 def getCurrentMemorySize(self):
247 "Retourne la taille mémoire courante utilisée"
250 def MaximumPrecision(self):
251 "Retourne la precision maximale flottante pour Numpy"
254 numpy.array([1.,], dtype='float128')
260 def MachinePrecision(self):
261 # Alternative sans module :
265 # eps = (1.0 + eps/2) - 1.0
266 return sys.float_info.epsilon
269 import daCore.version as dav
270 return "%s %s (%s)"%(dav.name,dav.version,dav.date)
272 # ==============================================================================
273 # Tests d'importation de modules système
279 raise ImportError("Numpy is not available, despites the fact it is mandatory.")
284 import scipy.optimize
291 has_matplotlib = True
293 has_matplotlib = False
319 has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
320 has_yacs = bool( "YACS_ROOT_DIR" in os.environ )
321 has_adao = bool( "ADAO_ROOT_DIR" in os.environ )
322 has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
324 # ==============================================================================
325 def uniq( __sequence ):
327 Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
330 return [x for x in __sequence if x not in __seen and not __seen.add(x)]
333 "Version transformée pour comparaison robuste, obtenue comme un tuple"
335 for sv in re.split("[_.+-]", __version):
336 serie.append(sv.zfill(6))
339 def isIterable( __sequence, __check = False, __header = "" ):
341 Vérification que l'argument est un itérable interne.
342 Remarque : pour permettre le test correct en MultiFonctions,
343 - Ne pas accepter comme itérable un "numpy.ndarray"
344 - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
346 if isinstance( __sequence, (list, tuple, map, dict) ):
348 elif type(__sequence).__name__ in ('generator','range'):
350 elif "_iterator" in type(__sequence).__name__:
352 elif "itertools" in str(type(__sequence)):
356 if __check and not __isOk:
357 raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
360 def date2int( __date, __lang="FR" ):
362 Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
364 __date = __date.strip()
365 if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
366 d,m,y = __date.split("/")
367 __number = (10**4)*int(y)+(10**2)*int(m)+int(d)
368 elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
369 part1, part2 = __date.split()
370 d,m,y = part1.strip().split("/")
371 h,n = part2.strip().split(":")
372 __number = (10**8)*int(y)+(10**6)*int(m)+(10**4)*int(d)+(10**2)*int(h)+int(n)
374 raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
377 def vfloat(__value :numpy.ndarray):
379 Conversion en flottant d'un vecteur de taille 1 et de dimensions quelconques
381 if hasattr(__value,"size") and __value.size == 1:
382 return float(__value.flat[0])
383 elif isinstance(__value, (float,int)):
384 return float(__value)
386 raise ValueError("Error in converting multiple float values from array when waiting for only one")
388 def strvect2liststr( __strvect ):
390 Fonction de secours, conversion d'une chaîne de caractères de
391 représentation de vecteur en une liste de chaînes de caractères de
392 représentation de flottants
394 for s in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
395 __strvect = __strvect.replace(s,"") # Rien
397 __strvect = __strvect.replace(s," ") # Blanc
398 return __strvect.split()
400 def strmatrix2liststr( __strvect ):
402 Fonction de secours, conversion d'une chaîne de caractères de
403 représentation de matrice en une liste de chaînes de caractères de
404 représentation de flottants
406 for s in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
407 __strvect = __strvect.replace(s,"") # Rien
408 __strvect = __strvect.replace(","," ") # Blanc
410 __strvect = __strvect.replace(s,";") # "]" et ")" par ";"
411 __strvect = re.sub(r';\s*;',r';',__strvect)
412 __strvect = __strvect.rstrip(";") # Après ^ et avant v
413 __strmat = [__l.split() for __l in __strvect.split(";")]
416 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
417 if sys.platform.startswith("win") and len(__filename) > 256:
419 __msg = (" For some shared or older file systems on Windows, a file "+\
420 "name longer than 256 characters can lead to access problems."+\
421 "\n The name of the file in question is the following:"+\
422 "\n %s")%(__filename,)
423 if __warnInsteadOfPrint: logging.warning(__msg)
430 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
431 if str(__filename).count(".") > 1:
433 __msg = (" The file name contains %i point(s) before the extension "+\
434 "separator, which can potentially lead to problems when "+\
435 "importing this file into Python, as it can then be recognized "+\
436 "as a sub-module (generating a \"ModuleNotFoundError\"). If it "+\
437 "is intentional, make sure that there is no module with the "+\
438 "same name as the part before the first point, and that there is "+\
439 "no \"__init__.py\" file in the same directory."+\
440 "\n The name of the file in question is the following:"+\
441 "\n %s")%(int(str(__filename).count(".")-1), __filename)
442 if __warnInsteadOfPrint is None: pass
443 elif __warnInsteadOfPrint: logging.warning(__msg)
450 # ==============================================================================
451 class PathManagement(object):
453 Mise à jour du path système pour les répertoires d'outils
455 __slots__ = ("__paths")
458 "Déclaration des répertoires statiques"
459 parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
461 self.__paths["daNumerics"] = os.path.join(parent,"daNumerics")
463 for v in self.__paths.values():
464 if os.path.isdir(v): sys.path.insert(0, v )
466 # Conserve en unique exemplaire chaque chemin
467 sys.path = uniq( sys.path )
472 Renvoie le dictionnaire des chemins ajoutés
476 # ==============================================================================
477 class SystemUsage(object):
479 Permet de récupérer les différentes tailles mémoires du process courant
483 # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
484 # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
486 _proc_status = '/proc/%d/status' % os.getpid()
487 _memo_status = '/proc/meminfo'
489 'o' : 1.0, # Multiples SI de l'octet
493 'kio': 1024.0, # Multiples binaires de l'octet
494 'Mio': 1024.0*1024.0,
495 'Gio': 1024.0*1024.0*1024.0,
496 'B': 1.0, # Multiples binaires du byte=octet
498 'MB' : 1024.0*1024.0,
499 'GB' : 1024.0*1024.0*1024.0,
506 def _VmA(self, VmKey, unit):
507 "Lecture des paramètres mémoire de la machine"
509 t = open(self._memo_status)
513 return 0.0 # non-Linux?
514 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
515 v = v[i:].split(None, 3) # whitespace
517 return 0.0 # invalid format?
518 # convert Vm value to bytes
519 mem = float(v[1]) * self._scale[v[2]]
520 return mem / self._scale[unit]
522 def getAvailablePhysicalMemory(self, unit="o"):
523 "Renvoie la mémoire physique utilisable en octets"
524 return self._VmA('MemTotal:', unit)
526 def getAvailableSwapMemory(self, unit="o"):
527 "Renvoie la mémoire swap utilisable en octets"
528 return self._VmA('SwapTotal:', unit)
530 def getAvailableMemory(self, unit="o"):
531 "Renvoie la mémoire totale (physique+swap) utilisable en octets"
532 return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
534 def getUsableMemory(self, unit="o"):
535 """Renvoie la mémoire utilisable en octets
536 Rq : il n'est pas sûr que ce décompte soit juste...
538 return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
539 self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
541 def _VmB(self, VmKey, unit):
542 "Lecture des paramètres mémoire du processus"
544 t = open(self._proc_status)
548 return 0.0 # non-Linux?
549 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
550 v = v[i:].split(None, 3) # whitespace
552 return 0.0 # invalid format?
553 # convert Vm value to bytes
554 mem = float(v[1]) * self._scale[v[2]]
555 return mem / self._scale[unit]
557 def getUsedMemory(self, unit="o"):
558 "Renvoie la mémoire résidente utilisée en octets"
559 return self._VmB('VmRSS:', unit)
561 def getVirtualMemory(self, unit="o"):
562 "Renvoie la mémoire totale utilisée en octets"
563 return self._VmB('VmSize:', unit)
565 def getUsedStacksize(self, unit="o"):
566 "Renvoie la taille du stack utilisé en octets"
567 return self._VmB('VmStk:', unit)
569 def getMaxUsedMemory(self, unit="o"):
570 "Renvoie la mémoire résidente maximale mesurée"
571 return self._VmB('VmHWM:', unit)
573 def getMaxVirtualMemory(self, unit="o"):
574 "Renvoie la mémoire totale maximale mesurée"
575 return self._VmB('VmPeak:', unit)
577 # ==============================================================================
578 # Tests d'importation de modules locaux
587 # ==============================================================================
588 if __name__ == "__main__":
589 print("\n AUTODIAGNOSTIC\n")