Salome HOME
Minor improvements and fixes for internal variables
[modules/adao.git] / src / daComposant / daCore / PlatformInfo.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2021 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
53 # ==============================================================================
54 class PlatformInfo(object):
55     """
56     Rassemblement des informations sur le code et la plateforme
57     """
58     def __init__(self):
59         "Sans effet"
60         pass
61
62     def getName(self):
63         "Retourne le nom de l'application"
64         import daCore.version as dav
65         return dav.name
66
67     def getVersion(self):
68         "Retourne le numéro de la version"
69         import daCore.version as dav
70         return dav.version
71
72     def getDate(self):
73         "Retourne la date de création de la version"
74         import daCore.version as dav
75         return dav.date
76
77     def getYear(self):
78         "Retourne l'année de création de la version"
79         import daCore.version as dav
80         return dav.year
81
82     def getSystemInformation(self, __prefix=""):
83         __msg  = ""
84         __msg += "\n%s%30s : %s" %(__prefix,"platform.system",platform.system())
85         __msg += "\n%s%30s : %s" %(__prefix,"sys.platform",sys.platform)
86         __msg += "\n%s%30s : %s" %(__prefix,"platform.version",platform.version())
87         __msg += "\n%s%30s : %s" %(__prefix,"platform.platform",platform.platform())
88         __msg += "\n%s%30s : %s" %(__prefix,"platform.machine",platform.machine())
89         if len(platform.processor())>0:
90             __msg += "\n%s%30s : %s" %(__prefix,"platform.processor",platform.processor())
91         #
92         if sys.platform.startswith('linux'):
93             if hasattr(platform, 'linux_distribution'):
94                 __msg += "\n%s%30s : %s" %(__prefix,
95                     "platform.linux_distribution",str(platform.linux_distribution()))
96             elif hasattr(platform, 'dist'):
97                 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
98         elif sys.platform.startswith('darwin'):
99             if hasattr(platform, 'mac_ver'):
100                 __macosxv = {'5': 'Leopard',       '6': 'Snow Leopard', '7': 'Lion',
101                              '8': 'Mountain Lion', '9': 'Mavericks',   '10': 'Yosemite',
102                              '11': 'El Capitan',  '12': 'Sierra'}
103                 for key in __macosxv:
104                     if (platform.mac_ver()[0].split('.')[1] == key):
105                         __msg += "\n%s%30s : %s" %(__prefix,
106                             "platform.mac_ver",str(platform.mac_ver()[0]+"(" + macosx_dict[key]+")"))
107             elif hasattr(platform, 'dist'):
108                 __msg += "\n%s%30s : %s" %(__prefix,"platform.dist",str(platform.dist()))
109         elif os.name == 'nt':
110             __msg += "\n%s%30s : %s" %(__prefix,"platform.win32_ver",platform.win32_ver()[1])
111         #
112         __msg += "\n"
113         __msg += "\n%s%30s : %s" %(__prefix,"platform.python_implementation",platform.python_implementation())
114         __msg += "\n%s%30s : %s" %(__prefix,"sys.executable",sys.executable)
115         __msg += "\n%s%30s : %s" %(__prefix,"sys.version",sys.version.replace('\n',''))
116         __msg += "\n%s%30s : %s" %(__prefix,"sys.getfilesystemencoding",str(sys.getfilesystemencoding()))
117         __msg += "\n%s%30s : %s" %(__prefix,"locale.getdefaultlocale",str(locale.getdefaultlocale()))
118         __msg += "\n"
119         __msg += "\n%s%30s : %s" %(__prefix,"os.cpu_count",os.cpu_count())
120         if hasattr(os, 'sched_getaffinity'):
121             __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))",len(os.sched_getaffinity(0)))
122         else:
123             __msg += "\n%s%30s : %s" %(__prefix,"len(os.sched_getaffinity(0))","Unsupported on this platform")
124         __msg += "\n"
125         __msg += "\n%s%30s : %s" %(__prefix,"platform.node",platform.node())
126         __msg += "\n%s%30s : %s" %(__prefix,"os.path.expanduser",os.path.expanduser('~'))
127         return __msg
128
129     def getPythonVersion(self):
130         "Retourne la version de python disponible"
131         return ".".join([str(x) for x in sys.version_info[0:3]]) # map(str,sys.version_info[0:3]))
132
133     def getNumpyVersion(self):
134         "Retourne la version de numpy disponible"
135         import numpy.version
136         return numpy.version.version
137
138     def getScipyVersion(self):
139         "Retourne la version de scipy disponible"
140         if has_scipy:
141             __version = scipy.version.version
142         else:
143             __version = "0.0.0"
144         return __version
145
146     def getMatplotlibVersion(self):
147         "Retourne la version de matplotlib disponible"
148         if has_matplotlib:
149             __version = matplotlib.__version__
150         else:
151             __version = "0.0.0"
152         return __version
153
154     def getGnuplotVersion(self):
155         "Retourne la version de gnuplotpy disponible"
156         if has_gnuplot:
157             __version = Gnuplot.__version__
158         else:
159             __version = "0.0"
160         return __version
161
162     def getSphinxVersion(self):
163         "Retourne la version de sphinx disponible"
164         if has_sphinx:
165             __version = sphinx.__version__
166         else:
167             __version = "0.0.0"
168         return __version
169
170     def getNloptVersion(self):
171         "Retourne la version de nlopt disponible"
172         if has_nlopt:
173             __version = "%s.%s.%s"%(
174                 nlopt.version_major(),
175                 nlopt.version_minor(),
176                 nlopt.version_bugfix(),
177                 )
178         else:
179             __version = "0.0.0"
180         return __version
181
182     def getCurrentMemorySize(self):
183         "Retourne la taille mémoire courante utilisée"
184         return 1
185
186     def MaximumPrecision(self):
187         "Retourne la precision maximale flottante pour Numpy"
188         import numpy
189         try:
190             numpy.array([1.,], dtype='float128')
191             mfp = 'float128'
192         except Exception:
193             mfp = 'float64'
194         return mfp
195
196     def MachinePrecision(self):
197         # Alternative sans module :
198         # eps = 2.38
199         # while eps > 0:
200         #     old_eps = eps
201         #     eps = (1.0 + eps/2) - 1.0
202         return sys.float_info.epsilon
203
204     def __str__(self):
205         import daCore.version as dav
206         return "%s %s (%s)"%(dav.name,dav.version,dav.date)
207
208 # ==============================================================================
209 try:
210     import scipy
211     import scipy.version
212     import scipy.optimize
213     has_scipy = True
214 except ImportError:
215     has_scipy = False
216
217 try:
218     import matplotlib
219     has_matplotlib = True
220 except ImportError:
221     has_matplotlib = False
222
223 try:
224     import Gnuplot
225     has_gnuplot = True
226 except ImportError:
227     has_gnuplot = False
228
229 try:
230     import sphinx
231     has_sphinx = True
232 except ImportError:
233     has_sphinx = False
234
235 try:
236     import nlopt
237     has_nlopt = True
238 except ImportError:
239     has_nlopt = False
240
241 try:
242     import sdf
243     has_sdf = True
244 except ImportError:
245     has_sdf = False
246
247 has_salome = bool( "ROOT_SALOME"   in os.environ )
248 has_yacs   = bool( "YACS_ROOT_DIR" in os.environ )
249 has_adao   = bool( "ADAO_ROOT_DIR" in os.environ )
250 has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
251
252 # ==============================================================================
253 def uniq( __sequence ):
254     """
255     Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
256     """
257     __seen = set()
258     return [x for x in __sequence if x not in __seen and not __seen.add(x)]
259
260 def isIterable( __sequence, __check = False, __header = "" ):
261     """
262     Vérification que l'argument est un itérable interne.
263     Remarque : pour permettre le test correct en MultiFonctions,
264     - Ne pas accepter comme itérable un "numpy.ndarray"
265     - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
266     """
267     if  isinstance( __sequence, (list, tuple, map, dict) ):
268         __isOk = True
269     elif type(__sequence).__name__ in ('generator','range'):
270         __isOk = True
271     elif "_iterator" in type(__sequence).__name__:
272         __isOk = True
273     else:
274         __isOk = False
275     if __check and not __isOk:
276         raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
277     return __isOk
278
279 def date2int( __date, __lang="FR" ):
280     """
281     Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
282     """
283     __date = __date.strip()
284     if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
285         d,m,y = __date.split("/")
286         __number = (10**4)*int(y)+(10**2)*int(m)+int(d)
287     elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
288         part1, part2 = __date.split()
289         d,m,y = part1.strip().split("/")
290         h,n   = part2.strip().split(":")
291         __number = (10**8)*int(y)+(10**6)*int(m)+(10**4)*int(d)+(10**2)*int(h)+int(n)
292     else:
293         raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%d)
294     return __number
295
296 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
297     if sys.platform.startswith("win") and len(__filename) > 256:
298         __conform = False
299         __msg = (" For some shared or older file systems on Windows, a file "+\
300             "name longer than 256 characters can lead to access problems."+\
301             "\n  The name of the file in question is the following:"+\
302             "\n  %s")%(__filename,)
303         if __warnInsteadOfPrint: logging.warning(__msg)
304         else:                    print(__msg)
305     else:
306         __conform = True
307     #
308     return __conform
309
310 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
311     if str(__filename).count(".") > 1:
312         __conform = False
313         __msg = (" The file name contains %i point(s) before the extension "+\
314             "separator, which can potentially lead to problems when "+\
315             "importing this file into Python, as it can then be recognized "+\
316             "as a sub-module (generating a \"ModuleNotFoundError\"). If it "+\
317             "is intentional, make sure that there is no module with the "+\
318             "same name as the part before the first point, and that there is "+\
319             "no \"__init__.py\" file in the same directory."+\
320             "\n  The name of the file in question is the following:"+\
321             "\n  %s")%(int(str(__filename).count(".")-1), __filename)
322         if __warnInsteadOfPrint is None: pass
323         elif __warnInsteadOfPrint:       logging.warning(__msg)
324         else:                            print(__msg)
325     else:
326         __conform = True
327     #
328     return __conform
329
330 # ==============================================================================
331 class PathManagement(object):
332     """
333     Mise à jour du path système pour les répertoires d'outils
334     """
335     def __init__(self):
336         "Déclaration des répertoires statiques"
337         parent = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
338         self.__paths = {}
339         self.__paths["daNumerics"]  = os.path.join(parent,"daNumerics")
340         #
341         for v in self.__paths.values():
342             sys.path.insert(0, v )
343         #
344         # Conserve en unique exemplaire chaque chemin
345         sys.path = uniq( sys.path )
346         del parent
347
348     def getpaths(self):
349         """
350         Renvoie le dictionnaire des chemins ajoutés
351         """
352         return self.__paths
353
354 # ==============================================================================
355 class SystemUsage(object):
356     """
357     Permet de récupérer les différentes tailles mémoires du process courant
358     """
359     #
360     # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
361     # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
362     #
363     _proc_status = '/proc/%d/status' % os.getpid()
364     _memo_status = '/proc/meminfo'
365     _scale = {
366         'o'  : 1.0,     # Multiples SI de l'octet
367         'ko' : 1.e3,
368         'Mo' : 1.e6,
369         'Go' : 1.e9,
370         'kio': 1024.0,  # Multiples binaires de l'octet
371         'Mio': 1024.0*1024.0,
372         'Gio': 1024.0*1024.0*1024.0,
373         'B':     1.0,   # Multiples binaires du byte=octet
374         'kB' : 1024.0,
375         'MB' : 1024.0*1024.0,
376         'GB' : 1024.0*1024.0*1024.0,
377         }
378     #
379     def __init__(self):
380         "Sans effet"
381         pass
382     #
383     def _VmA(self, VmKey, unit):
384         "Lecture des paramètres mémoire de la machine"
385         try:
386             t = open(self._memo_status)
387             v = t.read()
388             t.close()
389         except IOError:
390             return 0.0           # non-Linux?
391         i = v.index(VmKey)       # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
392         v = v[i:].split(None, 3) # whitespace
393         if len(v) < 3:
394             return 0.0           # invalid format?
395         # convert Vm value to bytes
396         mem = float(v[1]) * self._scale[v[2]]
397         return mem / self._scale[unit]
398     #
399     def getAvailablePhysicalMemory(self, unit="o"):
400         "Renvoie la mémoire physique utilisable en octets"
401         return self._VmA('MemTotal:', unit)
402     #
403     def getAvailableSwapMemory(self, unit="o"):
404         "Renvoie la mémoire swap utilisable en octets"
405         return self._VmA('SwapTotal:', unit)
406     #
407     def getAvailableMemory(self, unit="o"):
408         "Renvoie la mémoire totale (physique+swap) utilisable en octets"
409         return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
410     #
411     def getUsableMemory(self, unit="o"):
412         """Renvoie la mémoire utilisable en octets
413         Rq : il n'est pas sûr que ce décompte soit juste...
414         """
415         return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
416                self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
417     #
418     def _VmB(self, VmKey, unit):
419         "Lecture des paramètres mémoire du processus"
420         try:
421             t = open(self._proc_status)
422             v = t.read()
423             t.close()
424         except IOError:
425             return 0.0           # non-Linux?
426         i = v.index(VmKey)       # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
427         v = v[i:].split(None, 3) # whitespace
428         if len(v) < 3:
429             return 0.0           # invalid format?
430         # convert Vm value to bytes
431         mem = float(v[1]) * self._scale[v[2]]
432         return mem / self._scale[unit]
433     #
434     def getUsedMemory(self, unit="o"):
435         "Renvoie la mémoire résidente utilisée en octets"
436         return self._VmB('VmRSS:', unit)
437     #
438     def getVirtualMemory(self, unit="o"):
439         "Renvoie la mémoire totale utilisée en octets"
440         return self._VmB('VmSize:', unit)
441     #
442     def getUsedStacksize(self, unit="o"):
443         "Renvoie la taille du stack utilisé en octets"
444         return self._VmB('VmStk:', unit)
445     #
446     def getMaxUsedMemory(self, unit="o"):
447         "Renvoie la mémoire résidente maximale mesurée"
448         return self._VmB('VmHWM:', unit)
449     #
450     def getMaxVirtualMemory(self, unit="o"):
451         "Renvoie la mémoire totale maximale mesurée"
452         return self._VmB('VmPeak:', unit)
453
454 # ==============================================================================
455 if __name__ == "__main__":
456     print('\n AUTODIAGNOSTIC\n')