Salome HOME
Documentation update with features and review corrections
[modules/adao.git] / src / daComposant / daCore / PlatformInfo.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2024 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 même 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 socket
51 import locale
52 import logging
53 import re
54 import numpy
55
56 # ==============================================================================
57 def uniq( __sequence ):
58     """
59     Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
60     """
61     __seen = set()
62     return [x for x in __sequence if x not in __seen and not __seen.add(x)]
63
64 class PathManagement(object):
65     """
66     Mise à jour du path système pour les répertoires d'outils
67     """
68     __slots__ = ("__paths")
69
70     def __init__(self):
71         "Déclaration des répertoires statiques"
72         parent = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
73         self.__paths = {}
74         self.__paths["daNumerics"] = os.path.join(parent, "daNumerics")
75         #
76         for v in self.__paths.values():
77             if os.path.isdir(v):
78                 sys.path.insert(0, v )
79         #
80         # Conserve en unique exemplaire chaque chemin
81         sys.path = uniq( sys.path )
82         del parent
83
84     def getpaths(self):
85         """
86         Renvoie le dictionnaire des chemins ajoutés
87         """
88         return self.__paths
89
90 # ==============================================================================
91 class PlatformInfo(object):
92     """
93     Rassemblement des informations sur le code et la plateforme
94     """
95     __slots__ = ("has_salome", "has_yacs", "has_adao", "has_eficas")
96
97     def __init__(self):
98         "Sans effet"
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 )
103         PathManagement()
104
105     def getName(self):
106         "Retourne le nom de l'application"
107         import daCore.version as dav
108         return dav.name
109
110     def getVersion(self):
111         "Retourne le numéro de la version"
112         import daCore.version as dav
113         return dav.version
114
115     def getDate(self):
116         "Retourne la date de création de la version"
117         import daCore.version as dav
118         return dav.date
119
120     def getYear(self):
121         "Retourne l'année de création de la version"
122         import daCore.version as dav
123         return dav.year
124
125     def getSystemInformation(self, __prefix=""):
126         __msg  = ""
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())
134         #
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
145                 __macosxv10 = {
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
151                     '15': 'Catalina',
152                 }
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
158                 __macosxv11 = {
159                     '11': 'Big Sur',      '12': 'Monterey',    '13': 'Ventura',  # noqa: E241
160                     '14': 'Sonoma',
161                 }
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])
171         #
172         __msg += "\n"
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()))
179         else:
180             __msg += "\n%s%30s : %s"%(__prefix, "locale.getlocale", str(locale.getlocale()))
181         __msg += "\n"
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)))
185         else:
186             __msg += "\n%s%30s : %s"%(__prefix, "len(os.sched_getaffinity(0))", "Unsupported on this platform")
187         __msg += "\n"
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('~'))
191         return __msg
192
193     def getApplicationInformation(self, __prefix=""):
194         __msg  = ""
195         __msg += "\n%s%30s : %s"%(__prefix, "ADAO version", self.getVersion())
196         __msg += "\n"
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"
204         __msg += "\n%s%30s : %s"%(__prefix, "Pandas version", self.getPandasVersion())
205         __msg += "\n%s%30s : %s"%(__prefix, "Fmpy version", self.getFmpyVersion())
206         __msg += "\n%s%30s : %s"%(__prefix, "Sphinx version", self.getSphinxVersion())
207         return __msg
208
209     def getAllInformation(self, __prefix="", __title="Whole system information"):
210         __msg  = ""
211         if len(__title) > 0:
212             __msg += "\n" + "=" * 80 + "\n" + __title + "\n" + "=" * 80 + "\n"
213         __msg += self.getSystemInformation(__prefix)
214         __msg += "\n"
215         __msg += self.getApplicationInformation(__prefix)
216         return __msg
217
218     def getPythonVersion(self):
219         "Retourne la version de python disponible"
220         return ".".join([str(x) for x in sys.version_info[0:3]])  # map(str,sys.version_info[0:3]))
221
222     # Tests des modules système
223
224     def _has_numpy(self):
225         try:
226             import numpy  # noqa: F401
227             has_numpy = True
228         except ImportError:
229             raise ImportError("Numpy is not available, despites the fact it is mandatory.")
230         return has_numpy
231     has_numpy = property(fget = _has_numpy)
232
233     def _has_scipy(self):
234         try:
235             import scipy
236             import scipy.version
237             import scipy.optimize  # noqa: F401
238             has_scipy = True
239         except ImportError:
240             has_scipy = False
241         return has_scipy
242     has_scipy = property(fget = _has_scipy)
243
244     def _has_matplotlib(self):
245         try:
246             import matplotlib  # noqa: F401
247             has_matplotlib = True
248         except ImportError:
249             has_matplotlib = False
250         return has_matplotlib
251     has_matplotlib = property(fget = _has_matplotlib)
252
253     def _has_sphinx(self):
254         try:
255             import sphinx  # noqa: F401
256             has_sphinx = True
257         except ImportError:
258             has_sphinx = False
259         return has_sphinx
260     has_sphinx = property(fget = _has_sphinx)
261
262     def _has_nlopt(self):
263         try:
264             import nlopt  # noqa: F401
265             has_nlopt = True
266         except ImportError:
267             has_nlopt = False
268         return has_nlopt
269     has_nlopt = property(fget = _has_nlopt)
270
271     def _has_pandas(self):
272         try:
273             import pandas  # noqa: F401
274             has_pandas = True
275         except ImportError:
276             has_pandas = False
277         return has_pandas
278     has_pandas = property(fget = _has_pandas)
279
280     def _has_sdf(self):
281         try:
282             import sdf  # noqa: F401
283             has_sdf = True
284         except ImportError:
285             has_sdf = False
286         return has_sdf
287     has_sdf = property(fget = _has_sdf)
288
289     def _has_fmpy(self):
290         try:
291             import fmpy  # noqa: F401
292             has_fmpy = True
293         except ImportError:
294             has_fmpy = False
295         return has_fmpy
296     has_fmpy = property(fget = _has_fmpy)
297
298     def _has_buildingspy(self):
299         try:
300             import buildingspy  # noqa: F401
301             has_buildingspy = True
302         except ImportError:
303             has_buildingspy = False
304         return has_buildingspy
305     has_buildingspy = property(fget = _has_buildingspy)
306
307     def _has_control(self):
308         try:
309             import control  # noqa: F401
310             has_control = True
311         except ImportError:
312             has_control = False
313         return has_control
314     has_control = property(fget = _has_control)
315
316     def _has_modelicares(self):
317         try:
318             import modelicares  # noqa: F401
319             has_modelicares = True
320         except ImportError:
321             has_modelicares = False
322         return has_modelicares
323     has_modelicares = property(fget = _has_modelicares)
324
325     # Tests des modules locaux
326
327     def _has_gnuplot(self):
328         try:
329             import Gnuplot  # noqa: F401
330             has_gnuplot = True
331         except ImportError:
332             has_gnuplot = False
333         return has_gnuplot
334     has_gnuplot = property(fget = _has_gnuplot)
335
336     def _has_models(self):
337         try:
338             import Models  # noqa: F401
339             has_models = True
340         except ImportError:
341             has_models = False
342         return has_models
343     has_models = property(fget = _has_models)
344
345     def _has_pst4mod(self):
346         try:
347             import pst4mod  # noqa: F401
348             has_pst4mod = True
349         except ImportError:
350             has_pst4mod = False
351         return has_pst4mod
352     has_pst4mod = property(fget = _has_pst4mod)
353
354     # Versions
355
356     def getNumpyVersion(self):
357         "Retourne la version de numpy disponible"
358         import numpy.version
359         return numpy.version.version
360
361     def getScipyVersion(self):
362         "Retourne la version de scipy disponible"
363         if self.has_scipy:
364             import scipy
365             __version = scipy.version.version
366         else:
367             __version = "0.0.0"
368         return __version
369
370     def getNloptVersion(self):
371         "Retourne la version de nlopt disponible"
372         if self.has_nlopt:
373             import nlopt
374             __version = "%s.%s.%s"%(
375                 nlopt.version_major(),
376                 nlopt.version_minor(),
377                 nlopt.version_bugfix(),
378             )
379         else:
380             __version = "0.0.0"
381         return __version
382
383     def getMatplotlibVersion(self):
384         "Retourne la version de matplotlib disponible"
385         if self.has_matplotlib:
386             import matplotlib
387             __version = matplotlib.__version__
388         else:
389             __version = "0.0.0"
390         return __version
391
392     def getPandasVersion(self):
393         "Retourne la version de pandas disponible"
394         if self.has_pandas:
395             import pandas
396             __version = pandas.__version__
397         else:
398             __version = "0.0.0"
399         return __version
400
401     def getGnuplotVersion(self):
402         "Retourne la version de gnuplotpy disponible"
403         if self.has_gnuplot:
404             import Gnuplot
405             __version = Gnuplot.__version__
406         else:
407             __version = "0.0"
408         return __version
409
410     def getFmpyVersion(self):
411         "Retourne la version de fmpy disponible"
412         if self.has_fmpy:
413             import fmpy
414             __version = fmpy.__version__
415         else:
416             __version = "0.0.0"
417         return __version
418
419     def getSdfVersion(self):
420         "Retourne la version de sdf disponible"
421         if self.has_sdf:
422             import sdf
423             __version = sdf.__version__
424         else:
425             __version = "0.0.0"
426         return __version
427
428     def getSphinxVersion(self):
429         "Retourne la version de sphinx disponible"
430         if self.has_sphinx:
431             import sphinx
432             __version = sphinx.__version__
433         else:
434             __version = "0.0.0"
435         return __version
436
437     def getCurrentMemorySize(self):
438         "Retourne la taille mémoire courante utilisée"
439         return 1
440
441     def MaximumPrecision(self):
442         "Retourne la précision maximale flottante pour Numpy"
443         import numpy
444         try:
445             numpy.array([1.,], dtype='float128')
446             mfp = 'float128'
447         except Exception:
448             mfp = 'float64'
449         return mfp
450
451     def MachinePrecision(self):
452         # Alternative sans module :
453         # eps = 2.38
454         # while eps > 0:
455         #     old_eps = eps
456         #     eps = (1.0 + eps/2) - 1.0
457         return sys.float_info.epsilon
458
459     def __str__(self):
460         import daCore.version as dav
461         return "%s %s (%s)"%(dav.name, dav.version, dav.date)
462
463 # ==============================================================================
464 def vt( __version ):
465     "Version transformée pour comparaison robuste, obtenue comme un tuple"
466     serie = []
467     for sv in re.split("[_.+-]", __version):
468         serie.append(sv.zfill(6))
469     return tuple(serie)
470
471 def isIterable( __sequence, __check = False, __header = "" ):
472     """
473     Vérification que l'argument est un itérable interne.
474     Remarque : pour permettre le test correct en MultiFonctions,
475     - Ne pas accepter comme itérable un "numpy.ndarray"
476     - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
477     """
478     if isinstance( __sequence, (list, tuple, map, dict) ):
479         __isOk = True
480     elif type(__sequence).__name__ in ('generator', 'range'):
481         __isOk = True
482     elif "_iterator" in type(__sequence).__name__:
483         __isOk = True
484     elif "itertools" in str(type(__sequence)):
485         __isOk = True
486     else:
487         __isOk = False
488     if __check and not __isOk:
489         raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
490     return __isOk
491
492 def date2int( __date: str, __lang="FR" ):
493     """
494     Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
495     """
496     __date = __date.strip()
497     if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
498         d, m, y = __date.split("/")
499         __number = (10**4) * int(y) + (10**2) * int(m) + int(d)
500     elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
501         part1, part2 = __date.split()
502         d, m, y = part1.strip().split("/")
503         h, n = part2.strip().split(":")
504         __number = (10**8) * int(y) + (10**6) * int(m) + (10**4) * int(d) + (10**2) * int(h) + int(n)
505     else:
506         raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%__date)
507     return __number
508
509 def vfloat(__value: numpy.ndarray):
510     """
511     Conversion en flottant d'un vecteur de taille 1 et de dimensions quelconques
512     """
513     if hasattr(__value, "size") and __value.size == 1:
514         return float(__value.flat[0])
515     elif isinstance(__value, (float, int)):
516         return float(__value)
517     else:
518         raise ValueError("Error in converting multiple float values from array when waiting for only one")
519
520 def strvect2liststr( __strvect ):
521     """
522     Fonction de secours, conversion d'une chaîne de caractères de
523     représentation de vecteur en une liste de chaînes de caractères de
524     représentation de flottants
525     """
526     for st in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
527         __strvect = __strvect.replace(st, "")  # Rien
528     for st in (",", ";"):
529         __strvect = __strvect.replace(st, " ")  # Blanc
530     return __strvect.split()
531
532 def strmatrix2liststr( __strvect ):
533     """
534     Fonction de secours, conversion d'une chaîne de caractères de
535     représentation de matrice en une liste de chaînes de caractères de
536     représentation de flottants
537     """
538     for st in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
539         __strvect = __strvect.replace(st, "")  # Rien
540     __strvect = __strvect.replace(",", " ")  # Blanc
541     for st in ("]", ")"):
542         __strvect = __strvect.replace(st, ";")  # "]" et ")" par ";"
543     __strvect = re.sub(r';\s*;', r';', __strvect)
544     __strvect = __strvect.rstrip(";")  # Après ^ et avant v
545     __strmat = [__l.split() for __l in __strvect.split(";")]
546     return __strmat
547
548 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
549     if sys.platform.startswith("win") and len(__filename) > 256:
550         __conform = False
551         __msg = (
552             " For some shared or older file systems on Windows, a file " + \
553             "name longer than 256 characters can lead to access problems." + \
554             "\n  The name of the file in question is the following:" + \
555             "\n  %s")%(__filename,)
556         if __warnInsteadOfPrint:
557             logging.warning(__msg)
558         else:
559             print(__msg)
560     else:
561         __conform = True
562     #
563     return __conform
564
565 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
566     if str(__filename).count(".") > 1:
567         __conform = False
568         __msg = (
569             " The file name contains %i point(s) before the extension " + \
570             "separator, which can potentially lead to problems when " + \
571             "importing this file into Python, as it can then be recognized " + \
572             "as a sub-module (generating a \"ModuleNotFoundError\"). If it " + \
573             "is intentional, make sure that there is no module with the " + \
574             "same name as the part before the first point, and that there is " + \
575             "no \"__init__.py\" file in the same directory." + \
576             "\n  The name of the file in question is the following:" + \
577             "\n  %s")%(int(str(__filename).count(".") - 1), __filename)
578         if __warnInsteadOfPrint is None:
579             pass
580         elif __warnInsteadOfPrint:
581             logging.warning(__msg)
582         else:
583             print(__msg)
584     else:
585         __conform = True
586     #
587     return __conform
588
589 # ==============================================================================
590 class SystemUsage(object):
591     """
592     Permet de récupérer les différentes tailles mémoires du process courant
593     """
594     __slots__ = ()
595     #
596     # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
597     # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
598     #
599     _proc_status = '/proc/%d/status' % os.getpid()
600     _memo_status = '/proc/meminfo'
601     _scale = {
602         'o'  : 1.0,     # Multiples SI de l'octet          # noqa: E203
603         'ko' : 1.e3,                                       # noqa: E203
604         'Mo' : 1.e6,                                       # noqa: E203
605         'Go' : 1.e9,                                       # noqa: E203
606         'kio': 1024.0,  # Multiples binaires de l'octet    # noqa: E203
607         'Mio': 1024.0 * 1024.0,                            # noqa: E203
608         'Gio': 1024.0 * 1024.0 * 1024.0,                   # noqa: E203
609         'B'  : 1.0,     # Multiples binaires du byte=octet # noqa: E203
610         'kB' : 1024.0,                                     # noqa: E203
611         'MB' : 1024.0 * 1024.0,                            # noqa: E203
612         'GB' : 1024.0 * 1024.0 * 1024.0,                   # noqa: E203
613     }
614
615     def __init__(self):
616         "Sans effet"
617         pass
618
619     def _VmA(self, VmKey, unit):
620         "Lecture des paramètres mémoire de la machine"
621         try:
622             t = open(self._memo_status)
623             v = t.read()
624             t.close()
625         except IOError:
626             return 0.0            # non-Linux?
627         i = v.index(VmKey)        # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
628         v = v[i:].split(None, 3)  # whitespace
629         if len(v) < 3:
630             return 0.0            # invalid format?
631         # convert Vm value to bytes
632         mem = float(v[1]) * self._scale[v[2]]
633         return mem / self._scale[unit]
634
635     def getAvailablePhysicalMemory(self, unit="o"):
636         "Renvoie la mémoire physique utilisable en octets"
637         return self._VmA('MemTotal:', unit)
638
639     def getAvailableSwapMemory(self, unit="o"):
640         "Renvoie la mémoire swap utilisable en octets"
641         return self._VmA('SwapTotal:', unit)
642
643     def getAvailableMemory(self, unit="o"):
644         "Renvoie la mémoire totale (physique+swap) utilisable en octets"
645         return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
646
647     def getUsableMemory(self, unit="o"):
648         """Renvoie la mémoire utilisable en octets
649         Rq : il n'est pas sûr que ce décompte soit juste...
650         """
651         return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
652             self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
653
654     def _VmB(self, VmKey, unit):
655         "Lecture des paramètres mémoire du processus"
656         try:
657             t = open(self._proc_status)
658             v = t.read()
659             t.close()
660         except IOError:
661             return 0.0            # non-Linux?
662         i = v.index(VmKey)        # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
663         v = v[i:].split(None, 3)  # whitespace
664         if len(v) < 3:
665             return 0.0            # invalid format?
666         # convert Vm value to bytes
667         mem = float(v[1]) * self._scale[v[2]]
668         return mem / self._scale[unit]
669
670     def getUsedMemory(self, unit="o"):
671         "Renvoie la mémoire résidente utilisée en octets"
672         return self._VmB('VmRSS:', unit)
673
674     def getVirtualMemory(self, unit="o"):
675         "Renvoie la mémoire totale utilisée en octets"
676         return self._VmB('VmSize:', unit)
677
678     def getUsedStacksize(self, unit="o"):
679         "Renvoie la taille du stack utilisé en octets"
680         return self._VmB('VmStk:', unit)
681
682     def getMaxUsedMemory(self, unit="o"):
683         "Renvoie la mémoire résidente maximale mesurée"
684         return self._VmB('VmHWM:', unit)
685
686     def getMaxVirtualMemory(self, unit="o"):
687         "Renvoie la mémoire totale maximale mesurée"
688         return self._VmB('VmPeak:', unit)
689
690 # ==============================================================================
691 if __name__ == "__main__":
692     print("\n AUTODIAGNOSTIC\n")