Salome HOME
Code improvements, review and simplifications (4)
[modules/adao.git] / src / daComposant / daCore / PlatformInfo.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2022 EDF R&D
4 #
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.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 """
24     Informations sur le code et la plateforme, et mise à jour des chemins.
25
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 :
30         print(PlatformInfo())
31         print(PlatformInfo().getVersion())
32         created = PlatformInfo().getDate()
33
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 :
37         PathManagement()
38
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
42     process.
43 """
44 __author__ = "Jean-Philippe ARGAUD"
45 __all__ = []
46
47 import os
48 import sys
49 import platform
50 import locale
51 import logging
52 import re
53
54 # ==============================================================================
55 class PlatformInfo(object):
56     """
57     Rassemblement des informations sur le code et la plateforme
58     """
59     def __init__(self):
60         "Sans effet"
61         pass
62
63     def getName(self):
64         "Retourne le nom de l'application"
65         import daCore.version as dav
66         return dav.name
67
68     def getVersion(self):
69         "Retourne le numéro de la version"
70         import daCore.version as dav
71         return dav.version
72
73     def getDate(self):
74         "Retourne la date de création de la version"
75         import daCore.version as dav
76         return dav.date
77
78     def getYear(self):
79         "Retourne l'année de création de la version"
80         import daCore.version as dav
81         return dav.year
82
83     def getSystemInformation(self, __prefix=""):
84         __msg  = ""
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())
92         #
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'):
101                 __macosxv = {
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',
108                     }
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])
117         #
118         __msg += "\n"
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()))
124         __msg += "\n"
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)))
128         else:
129             __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))","Unsupported on this platform")
130         __msg += "\n"
131         __msg += "\n%s%30s : %s" %(__prefix,"platform.node",platform.node())
132         __msg += "\n%s%30s : %s" %(__prefix,"os.path.expanduser",os.path.expanduser('~'))
133         return __msg
134
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]))
138
139     def getNumpyVersion(self):
140         "Retourne la version de numpy disponible"
141         import numpy.version
142         return numpy.version.version
143
144     def getScipyVersion(self):
145         "Retourne la version de scipy disponible"
146         if has_scipy:
147             __version = scipy.version.version
148         else:
149             __version = "0.0.0"
150         return __version
151
152     def getMatplotlibVersion(self):
153         "Retourne la version de matplotlib disponible"
154         if has_matplotlib:
155             __version = matplotlib.__version__
156         else:
157             __version = "0.0.0"
158         return __version
159
160     def getGnuplotVersion(self):
161         "Retourne la version de gnuplotpy disponible"
162         if has_gnuplot:
163             __version = Gnuplot.__version__
164         else:
165             __version = "0.0"
166         return __version
167
168     def getSphinxVersion(self):
169         "Retourne la version de sphinx disponible"
170         if has_sphinx:
171             __version = sphinx.__version__
172         else:
173             __version = "0.0.0"
174         return __version
175
176     def getNloptVersion(self):
177         "Retourne la version de nlopt disponible"
178         if has_nlopt:
179             __version = "%s.%s.%s"%(
180                 nlopt.version_major(),
181                 nlopt.version_minor(),
182                 nlopt.version_bugfix(),
183                 )
184         else:
185             __version = "0.0.0"
186         return __version
187
188     def getSdfVersion(self):
189         "Retourne la version de sdf disponible"
190         if has_sdf:
191             __version = sdf.__version__
192         else:
193             __version = "0.0.0"
194         return __version
195
196     def getCurrentMemorySize(self):
197         "Retourne la taille mémoire courante utilisée"
198         return 1
199
200     def MaximumPrecision(self):
201         "Retourne la precision maximale flottante pour Numpy"
202         import numpy
203         try:
204             numpy.array([1.,], dtype='float128')
205             mfp = 'float128'
206         except Exception:
207             mfp = 'float64'
208         return mfp
209
210     def MachinePrecision(self):
211         # Alternative sans module :
212         # eps = 2.38
213         # while eps > 0:
214         #     old_eps = eps
215         #     eps = (1.0 + eps/2) - 1.0
216         return sys.float_info.epsilon
217
218     def __str__(self):
219         import daCore.version as dav
220         return "%s %s (%s)"%(dav.name,dav.version,dav.date)
221
222
223 # ==============================================================================
224 try:
225     import scipy
226     import scipy.version
227     import scipy.optimize
228     has_scipy = True
229 except ImportError:
230     has_scipy = False
231
232 try:
233     import matplotlib
234     has_matplotlib = True
235 except ImportError:
236     has_matplotlib = False
237
238 try:
239     import Gnuplot
240     has_gnuplot = True
241 except ImportError:
242     has_gnuplot = False
243
244 try:
245     import sphinx
246     has_sphinx = True
247 except ImportError:
248     has_sphinx = False
249
250 try:
251     import nlopt
252     has_nlopt = True
253 except ImportError:
254     has_nlopt = False
255
256 try:
257     import sdf
258     has_sdf = True
259 except ImportError:
260     has_sdf = False
261
262 has_salome = bool( "ROOT_SALOME"   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 )
266
267 # ==============================================================================
268 def uniq( __sequence ):
269     """
270     Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
271     """
272     __seen = set()
273     return [x for x in __sequence if x not in __seen and not __seen.add(x)]
274
275 def isIterable( __sequence, __check = False, __header = "" ):
276     """
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__")
281     """
282     if  isinstance( __sequence, (list, tuple, map, dict) ):
283         __isOk = True
284     elif type(__sequence).__name__ in ('generator','range'):
285         __isOk = True
286     elif "_iterator" in type(__sequence).__name__:
287         __isOk = True
288     else:
289         __isOk = False
290     if __check and not __isOk:
291         raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
292     return __isOk
293
294 def date2int( __date, __lang="FR" ):
295     """
296     Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
297     """
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)
307     else:
308         raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
309     return __number
310
311 def strvect2liststr( __strvect ):
312     """
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
316     """
317     for s in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
318         __strvect = __strvect.replace(s,"")  # Rien
319     for s in (",", ";"):
320         __strvect = __strvect.replace(s," ") # Blanc
321     return __strvect.split()
322
323 def strmatrix2liststr( __strvect ):
324     """
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
328     """
329     for s in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
330         __strvect = __strvect.replace(s,"")  # Rien
331     __strvect = __strvect.replace(","," ") # Blanc
332     for s in ("]", ")"):
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(";")]
337     return __strmat
338
339 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
340     if sys.platform.startswith("win") and len(__filename) > 256:
341         __conform = False
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)
347         else:                    print(__msg)
348     else:
349         __conform = True
350     #
351     return __conform
352
353 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
354     if str(__filename).count(".") > 1:
355         __conform = False
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)
367         else:                            print(__msg)
368     else:
369         __conform = True
370     #
371     return __conform
372
373 # ==============================================================================
374 class PathManagement(object):
375     """
376     Mise à jour du path système pour les répertoires d'outils
377     """
378     def __init__(self):
379         "Déclaration des répertoires statiques"
380         parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
381         self.__paths = {}
382         self.__paths["daNumerics"]  = os.path.join(parent,"daNumerics")
383         #
384         for v in self.__paths.values():
385             if os.path.isdir(v): sys.path.insert(0, v )
386         #
387         # Conserve en unique exemplaire chaque chemin
388         sys.path = uniq( sys.path )
389         del parent
390
391     def getpaths(self):
392         """
393         Renvoie le dictionnaire des chemins ajoutés
394         """
395         return self.__paths
396
397 # ==============================================================================
398 class SystemUsage(object):
399     """
400     Permet de récupérer les différentes tailles mémoires du process courant
401     """
402     #
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
405     #
406     _proc_status = '/proc/%d/status' % os.getpid()
407     _memo_status = '/proc/meminfo'
408     _scale = {
409         'o'  : 1.0,     # Multiples SI de l'octet
410         'ko' : 1.e3,
411         'Mo' : 1.e6,
412         'Go' : 1.e9,
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
417         'kB' : 1024.0,
418         'MB' : 1024.0*1024.0,
419         'GB' : 1024.0*1024.0*1024.0,
420         }
421     #
422     def __init__(self):
423         "Sans effet"
424         pass
425     #
426     def _VmA(self, VmKey, unit):
427         "Lecture des paramètres mémoire de la machine"
428         try:
429             t = open(self._memo_status)
430             v = t.read()
431             t.close()
432         except IOError:
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
436         if len(v) < 3:
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]
441     #
442     def getAvailablePhysicalMemory(self, unit="o"):
443         "Renvoie la mémoire physique utilisable en octets"
444         return self._VmA('MemTotal:', unit)
445     #
446     def getAvailableSwapMemory(self, unit="o"):
447         "Renvoie la mémoire swap utilisable en octets"
448         return self._VmA('SwapTotal:', unit)
449     #
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)
453     #
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...
457         """
458         return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
459                self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
460     #
461     def _VmB(self, VmKey, unit):
462         "Lecture des paramètres mémoire du processus"
463         try:
464             t = open(self._proc_status)
465             v = t.read()
466             t.close()
467         except IOError:
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
471         if len(v) < 3:
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]
476     #
477     def getUsedMemory(self, unit="o"):
478         "Renvoie la mémoire résidente utilisée en octets"
479         return self._VmB('VmRSS:', unit)
480     #
481     def getVirtualMemory(self, unit="o"):
482         "Renvoie la mémoire totale utilisée en octets"
483         return self._VmB('VmSize:', unit)
484     #
485     def getUsedStacksize(self, unit="o"):
486         "Renvoie la taille du stack utilisé en octets"
487         return self._VmB('VmStk:', unit)
488     #
489     def getMaxUsedMemory(self, unit="o"):
490         "Renvoie la mémoire résidente maximale mesurée"
491         return self._VmB('VmHWM:', unit)
492     #
493     def getMaxVirtualMemory(self, unit="o"):
494         "Renvoie la mémoire totale maximale mesurée"
495         return self._VmB('VmPeak:', unit)
496
497
498 # ==============================================================================
499 if __name__ == "__main__":
500     print('\n AUTODIAGNOSTIC\n')