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"
56 # ==============================================================================
57 def uniq( __sequence ):
59 Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
62 return [x for x in __sequence if x not in __seen and not __seen.add(x)]
64 class PathManagement(object):
66 Mise à jour du path système pour les répertoires d'outils
68 __slots__ = ("__paths")
71 "Déclaration des répertoires statiques"
72 parent = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
74 self.__paths["daNumerics"] = os.path.join(parent, "daNumerics")
76 for v in self.__paths.values():
78 sys.path.insert(0, v )
80 # Conserve en unique exemplaire chaque chemin
81 sys.path = uniq( sys.path )
86 Renvoie le dictionnaire des chemins ajoutés
90 # ==============================================================================
91 class PlatformInfo(object):
93 Rassemblement des informations sur le code et la plateforme
95 __slots__ = ("has_salome", "has_yacs", "has_adao", "has_eficas")
99 self.has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
100 self.has_yacs = bool( "YACS_ROOT_DIR" in os.environ )
101 self.has_adao = bool( "ADAO_ROOT_DIR" in os.environ )
102 self.has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
106 "Retourne le nom de l'application"
107 import daCore.version as dav
110 def getVersion(self):
111 "Retourne le numéro de la version"
112 import daCore.version as dav
116 "Retourne la date de création de la version"
117 import daCore.version as dav
121 "Retourne l'année de création de la version"
122 import daCore.version as dav
125 def getSystemInformation(self, __prefix=""):
127 __msg += "\n%s%30s : %s"%(__prefix, "platform.system", platform.system())
128 __msg += "\n%s%30s : %s"%(__prefix, "sys.platform", sys.platform)
129 __msg += "\n%s%30s : %s"%(__prefix, "platform.version", platform.version())
130 __msg += "\n%s%30s : %s"%(__prefix, "platform.platform", platform.platform())
131 __msg += "\n%s%30s : %s"%(__prefix, "platform.machine", platform.machine())
132 if len(platform.processor()) > 0:
133 __msg += "\n%s%30s : %s"%(__prefix, "platform.processor", platform.processor())
135 if sys.platform.startswith('linux'):
136 if hasattr(platform, 'linux_distribution'):
137 __msg += "\n%s%30s : %s"%(__prefix,
138 "platform.linux_distribution", str(platform.linux_distribution())) # noqa: E128
139 elif hasattr(platform, 'dist'):
140 __msg += "\n%s%30s : %s"%(__prefix,
141 "platform.dist", str(platform.dist())) # noqa: E128
142 elif sys.platform.startswith('darwin'):
143 if hasattr(platform, 'mac_ver'):
144 # https://fr.wikipedia.org/wiki/MacOS
146 '0' : 'Cheetah', '1' : 'Puma', '2' : 'Jaguar', # noqa: E241,E203
147 '3' : 'Panther', '4' : 'Tiger', '5' : 'Leopard', # noqa: E241,E203
148 '6' : 'Snow Leopard', '7' : 'Lion', '8' : 'Mountain Lion', # noqa: E241,E203
149 '9' : 'Mavericks', '10': 'Yosemite', '11': 'El Capitan', # noqa: E241,E203
150 '12': 'Sierra', '13': 'High Sierra', '14': 'Mojave', # noqa: E241,E203
153 for key in __macosxv10:
154 __details = platform.mac_ver()[0].split('.')
155 if (len(__details) > 0) and (__details[1] == key):
156 __msg += "\n%s%30s : %s"%(__prefix,
157 "platform.mac_ver", str(platform.mac_ver()[0] + "(" + __macosxv10[key] + ")")) # noqa: E128
159 '11': 'Big Sur', '12': 'Monterey', '13': 'Ventura', # noqa: E241
162 for key in __macosxv11:
163 __details = platform.mac_ver()[0].split('.')
164 if (__details[0] == key):
165 __msg += "\n%s%30s : %s"%(__prefix,
166 "platform.mac_ver", str(platform.mac_ver()[0] + "(" + __macosxv11[key] + ")")) # noqa: E128
167 elif hasattr(platform, 'dist'):
168 __msg += "\n%s%30s : %s"%(__prefix, "platform.dist", str(platform.dist()))
169 elif os.name == 'nt':
170 __msg += "\n%s%30s : %s"%(__prefix, "platform.win32_ver", platform.win32_ver()[1])
173 __msg += "\n%s%30s : %s"%(__prefix, "platform.python_implementation", platform.python_implementation())
174 __msg += "\n%s%30s : %s"%(__prefix, "sys.executable", sys.executable)
175 __msg += "\n%s%30s : %s"%(__prefix, "sys.version", sys.version.replace('\n', ''))
176 __msg += "\n%s%30s : %s"%(__prefix, "sys.getfilesystemencoding", str(sys.getfilesystemencoding()))
177 if sys.version_info.major == 3 and sys.version_info.minor < 11: # Python 3.10
178 __msg += "\n%s%30s : %s"%(__prefix, "locale.getdefaultlocale", str(locale.getdefaultlocale()))
180 __msg += "\n%s%30s : %s"%(__prefix, "locale.getlocale", str(locale.getlocale()))
182 __msg += "\n%s%30s : %s"%(__prefix, "os.cpu_count", os.cpu_count())
183 if hasattr(os, 'sched_getaffinity'):
184 __msg += "\n%s%30s : %s"%(__prefix, "len(os.sched_getaffinity(0))", len(os.sched_getaffinity(0)))
186 __msg += "\n%s%30s : %s"%(__prefix, "len(os.sched_getaffinity(0))", "Unsupported on this platform")
188 __msg += "\n%s%30s : %s"%(__prefix, "platform.node", platform.node())
189 __msg += "\n%s%30s : %s"%(__prefix, "socket.getfqdn", socket.getfqdn())
190 __msg += "\n%s%30s : %s"%(__prefix, "os.path.expanduser", os.path.expanduser('~'))
193 def getApplicationInformation(self, __prefix=""):
195 __msg += "\n%s%30s : %s"%(__prefix, "ADAO version", self.getVersion())
197 __msg += "\n%s%30s : %s"%(__prefix, "Python version", self.getPythonVersion())
198 __msg += "\n%s%30s : %s"%(__prefix, "Numpy version", self.getNumpyVersion())
199 __msg += "\n%s%30s : %s"%(__prefix, "Scipy version", self.getScipyVersion())
200 __msg += "\n%s%30s : %s"%(__prefix, "NLopt version", self.getNloptVersion())
201 __msg += "\n%s%30s : %s"%(__prefix, "MatplotLib version", self.getMatplotlibVersion())
202 __msg += "\n%s%30s : %s"%(__prefix, "GnuplotPy version", self.getGnuplotVersion())
203 __msg += "\n%s%30s : %s"%(__prefix, "Sphinx version", self.getSphinxVersion())
204 __msg += "\n%s%30s : %s"%(__prefix, "Fmpy version", self.getFmpyVersion())
207 def getAllInformation(self, __prefix="", __title="Whole system information"):
210 __msg += "\n" + "=" * 80 + "\n" + __title + "\n" + "=" * 80 + "\n"
211 __msg += self.getSystemInformation(__prefix)
213 __msg += self.getApplicationInformation(__prefix)
216 def getPythonVersion(self):
217 "Retourne la version de python disponible"
218 return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
220 # Tests des modules système
222 def _has_numpy(self):
224 import numpy # noqa: F401
227 raise ImportError("Numpy is not available, despites the fact it is mandatory.")
229 has_numpy = property(fget = _has_numpy)
231 def _has_scipy(self):
235 import scipy.optimize # noqa: F401
240 has_scipy = property(fget = _has_scipy)
242 def _has_matplotlib(self):
244 import matplotlib # noqa: F401
245 has_matplotlib = True
247 has_matplotlib = False
248 return has_matplotlib
249 has_matplotlib = property(fget = _has_matplotlib)
251 def _has_sphinx(self):
253 import sphinx # noqa: F401
258 has_sphinx = property(fget = _has_sphinx)
260 def _has_nlopt(self):
262 import nlopt # noqa: F401
267 has_nlopt = property(fget = _has_nlopt)
271 import sdf # noqa: F401
276 has_sdf = property(fget = _has_sdf)
280 import fmpy # noqa: F401
285 has_fmpy = property(fget = _has_fmpy)
287 def _has_buildingspy(self):
289 import buildingspy # noqa: F401
290 has_buildingspy = True
292 has_buildingspy = False
293 return has_buildingspy
294 has_buildingspy = property(fget = _has_buildingspy)
296 def _has_control(self):
298 import control # noqa: F401
303 has_control = property(fget = _has_control)
305 def _has_modelicares(self):
307 import modelicares # noqa: F401
308 has_modelicares = True
310 has_modelicares = False
311 return has_modelicares
312 has_modelicares = property(fget = _has_modelicares)
314 # Tests des modules locaux
316 def _has_gnuplot(self):
318 import Gnuplot # noqa: F401
323 has_gnuplot = property(fget = _has_gnuplot)
325 def _has_models(self):
327 import Models # noqa: F401
332 has_models = property(fget = _has_models)
334 def _has_linkmod(self):
336 import LinkMod # noqa: F401
341 has_linkmod = property(fget = _has_linkmod)
345 def getNumpyVersion(self):
346 "Retourne la version de numpy disponible"
348 return numpy.version.version
350 def getScipyVersion(self):
351 "Retourne la version de scipy disponible"
354 __version = scipy.version.version
359 def getMatplotlibVersion(self):
360 "Retourne la version de matplotlib disponible"
361 if self.has_matplotlib:
363 __version = matplotlib.__version__
368 def getGnuplotVersion(self):
369 "Retourne la version de gnuplotpy disponible"
372 __version = Gnuplot.__version__
377 def getSphinxVersion(self):
378 "Retourne la version de sphinx disponible"
381 __version = sphinx.__version__
386 def getNloptVersion(self):
387 "Retourne la version de nlopt disponible"
390 __version = "%s.%s.%s"%(
391 nlopt.version_major(),
392 nlopt.version_minor(),
393 nlopt.version_bugfix(),
399 def getSdfVersion(self):
400 "Retourne la version de sdf disponible"
403 __version = sdf.__version__
408 def getFmpyVersion(self):
409 "Retourne la version de fmpy disponible"
412 __version = fmpy.__version__
417 def getCurrentMemorySize(self):
418 "Retourne la taille mémoire courante utilisée"
421 def MaximumPrecision(self):
422 "Retourne la précision maximale flottante pour Numpy"
425 numpy.array([1.,], dtype='float128')
431 def MachinePrecision(self):
432 # Alternative sans module :
436 # eps = (1.0 + eps/2) - 1.0
437 return sys.float_info.epsilon
440 import daCore.version as dav
441 return "%s %s (%s)"%(dav.name, dav.version, dav.date)
443 # ==============================================================================
445 "Version transformée pour comparaison robuste, obtenue comme un tuple"
447 for sv in re.split("[_.+-]", __version):
448 serie.append(sv.zfill(6))
451 def isIterable( __sequence, __check = False, __header = "" ):
453 Vérification que l'argument est un itérable interne.
454 Remarque : pour permettre le test correct en MultiFonctions,
455 - Ne pas accepter comme itérable un "numpy.ndarray"
456 - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
458 if isinstance( __sequence, (list, tuple, map, dict) ):
460 elif type(__sequence).__name__ in ('generator', 'range'):
462 elif "_iterator" in type(__sequence).__name__:
464 elif "itertools" in str(type(__sequence)):
468 if __check and not __isOk:
469 raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
472 def date2int( __date: str, __lang="FR" ):
474 Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
476 __date = __date.strip()
477 if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
478 d, m, y = __date.split("/")
479 __number = (10**4) * int(y) + (10**2) * int(m) + int(d)
480 elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
481 part1, part2 = __date.split()
482 d, m, y = part1.strip().split("/")
483 h, n = part2.strip().split(":")
484 __number = (10**8) * int(y) + (10**6) * int(m) + (10**4) * int(d) + (10**2) * int(h) + int(n)
486 raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%__date)
489 def vfloat(__value: numpy.ndarray):
491 Conversion en flottant d'un vecteur de taille 1 et de dimensions quelconques
493 if hasattr(__value, "size") and __value.size == 1:
494 return float(__value.flat[0])
495 elif isinstance(__value, (float, int)):
496 return float(__value)
498 raise ValueError("Error in converting multiple float values from array when waiting for only one")
500 def strvect2liststr( __strvect ):
502 Fonction de secours, conversion d'une chaîne de caractères de
503 représentation de vecteur en une liste de chaînes de caractères de
504 représentation de flottants
506 for st in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
507 __strvect = __strvect.replace(st, "") # Rien
508 for st in (",", ";"):
509 __strvect = __strvect.replace(st, " ") # Blanc
510 return __strvect.split()
512 def strmatrix2liststr( __strvect ):
514 Fonction de secours, conversion d'une chaîne de caractères de
515 représentation de matrice en une liste de chaînes de caractères de
516 représentation de flottants
518 for st in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
519 __strvect = __strvect.replace(st, "") # Rien
520 __strvect = __strvect.replace(",", " ") # Blanc
521 for st in ("]", ")"):
522 __strvect = __strvect.replace(st, ";") # "]" et ")" par ";"
523 __strvect = re.sub(r';\s*;', r';', __strvect)
524 __strvect = __strvect.rstrip(";") # Après ^ et avant v
525 __strmat = [__l.split() for __l in __strvect.split(";")]
528 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
529 if sys.platform.startswith("win") and len(__filename) > 256:
532 " For some shared or older file systems on Windows, a file " + \
533 "name longer than 256 characters can lead to access problems." + \
534 "\n The name of the file in question is the following:" + \
535 "\n %s")%(__filename,)
536 if __warnInsteadOfPrint:
537 logging.warning(__msg)
545 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
546 if str(__filename).count(".") > 1:
549 " The file name contains %i point(s) before the extension " + \
550 "separator, which can potentially lead to problems when " + \
551 "importing this file into Python, as it can then be recognized " + \
552 "as a sub-module (generating a \"ModuleNotFoundError\"). If it " + \
553 "is intentional, make sure that there is no module with the " + \
554 "same name as the part before the first point, and that there is " + \
555 "no \"__init__.py\" file in the same directory." + \
556 "\n The name of the file in question is the following:" + \
557 "\n %s")%(int(str(__filename).count(".") - 1), __filename)
558 if __warnInsteadOfPrint is None:
560 elif __warnInsteadOfPrint:
561 logging.warning(__msg)
569 # ==============================================================================
570 class SystemUsage(object):
572 Permet de récupérer les différentes tailles mémoires du process courant
576 # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
577 # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
579 _proc_status = '/proc/%d/status' % os.getpid()
580 _memo_status = '/proc/meminfo'
582 'o' : 1.0, # Multiples SI de l'octet # noqa: E203
583 'ko' : 1.e3, # noqa: E203
584 'Mo' : 1.e6, # noqa: E203
585 'Go' : 1.e9, # noqa: E203
586 'kio': 1024.0, # Multiples binaires de l'octet # noqa: E203
587 'Mio': 1024.0 * 1024.0, # noqa: E203
588 'Gio': 1024.0 * 1024.0 * 1024.0, # noqa: E203
589 'B' : 1.0, # Multiples binaires du byte=octet # noqa: E203
590 'kB' : 1024.0, # noqa: E203
591 'MB' : 1024.0 * 1024.0, # noqa: E203
592 'GB' : 1024.0 * 1024.0 * 1024.0, # noqa: E203
599 def _VmA(self, VmKey, unit):
600 "Lecture des paramètres mémoire de la machine"
602 t = open(self._memo_status)
606 return 0.0 # non-Linux?
607 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
608 v = v[i:].split(None, 3) # whitespace
610 return 0.0 # invalid format?
611 # convert Vm value to bytes
612 mem = float(v[1]) * self._scale[v[2]]
613 return mem / self._scale[unit]
615 def getAvailablePhysicalMemory(self, unit="o"):
616 "Renvoie la mémoire physique utilisable en octets"
617 return self._VmA('MemTotal:', unit)
619 def getAvailableSwapMemory(self, unit="o"):
620 "Renvoie la mémoire swap utilisable en octets"
621 return self._VmA('SwapTotal:', unit)
623 def getAvailableMemory(self, unit="o"):
624 "Renvoie la mémoire totale (physique+swap) utilisable en octets"
625 return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
627 def getUsableMemory(self, unit="o"):
628 """Renvoie la mémoire utilisable en octets
629 Rq : il n'est pas sûr que ce décompte soit juste...
631 return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
632 self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
634 def _VmB(self, VmKey, unit):
635 "Lecture des paramètres mémoire du processus"
637 t = open(self._proc_status)
641 return 0.0 # non-Linux?
642 i = v.index(VmKey) # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
643 v = v[i:].split(None, 3) # whitespace
645 return 0.0 # invalid format?
646 # convert Vm value to bytes
647 mem = float(v[1]) * self._scale[v[2]]
648 return mem / self._scale[unit]
650 def getUsedMemory(self, unit="o"):
651 "Renvoie la mémoire résidente utilisée en octets"
652 return self._VmB('VmRSS:', unit)
654 def getVirtualMemory(self, unit="o"):
655 "Renvoie la mémoire totale utilisée en octets"
656 return self._VmB('VmSize:', unit)
658 def getUsedStacksize(self, unit="o"):
659 "Renvoie la taille du stack utilisé en octets"
660 return self._VmB('VmStk:', unit)
662 def getMaxUsedMemory(self, unit="o"):
663 "Renvoie la mémoire résidente maximale mesurée"
664 return self._VmB('VmHWM:', unit)
666 def getMaxVirtualMemory(self, unit="o"):
667 "Renvoie la mémoire totale maximale mesurée"
668 return self._VmB('VmPeak:', unit)
670 # ==============================================================================
671 if __name__ == "__main__":
672 print("\n AUTODIAGNOSTIC\n")