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