38
38
import subprocess
39
39
40
40
41
- if not sys .platform .startswith ('linux' ):
42
- raise ImportError ('Unsupported platform: {0}' .format (sys .platform ))
43
-
44
41
_UNIXCONFDIR = os .environ .get ('UNIXCONFDIR' , '/etc' )
45
42
_OS_RELEASE_BASENAME = 'os-release'
46
43
@@ -511,6 +508,21 @@ def distro_release_attr(attribute):
511
508
return _distro .distro_release_attr (attribute )
512
509
513
510
511
+ class cached_property (object ):
512
+ """A version of @property which caches the value. On access, it calls the
513
+ underlying function and sets the value in `__dict__` so future accesses
514
+ will not re-call the property.
515
+ """
516
+ def __init__ (self , f ):
517
+ self ._fname = f .__name__
518
+ self ._f = f
519
+
520
+ def __get__ (self , obj , owner ):
521
+ assert obj is not None , 'call {} on an instance' .format (self ._fname )
522
+ ret = obj .__dict__ [self ._fname ] = self ._f (obj )
523
+ return ret
524
+
525
+
514
526
class LinuxDistribution (object ):
515
527
"""
516
528
Provides information about a Linux distribution.
@@ -576,6 +588,9 @@ def __init__(self,
576
588
`distro release file`_ that is actually used as a data source. The
577
589
empty string if no distro release file is used as a data source.
578
590
591
+ * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter.
592
+ This controls whether the lsb information will be loaded.
593
+
579
594
Raises:
580
595
581
596
* :py:exc:`IOError`: Some I/O issue with an os-release file or distro
@@ -591,26 +606,20 @@ def __init__(self,
591
606
self .os_release_file = os_release_file or \
592
607
os .path .join (_UNIXCONFDIR , _OS_RELEASE_BASENAME )
593
608
self .distro_release_file = distro_release_file or '' # updated later
594
- self ._os_release_info = self ._get_os_release_info ()
595
- self ._lsb_release_info = self ._get_lsb_release_info () \
596
- if include_lsb else {}
597
- self ._distro_release_info = self ._get_distro_release_info ()
609
+ self .include_lsb = include_lsb
598
610
599
611
def __repr__ (self ):
600
612
"""Return repr of all info
601
613
"""
602
614
return \
603
615
"LinuxDistribution(" \
604
- "os_release_file={0!r}, " \
605
- "distro_release_file={1!r}, " \
606
- "_os_release_info={2!r}, " \
607
- "_lsb_release_info={3!r}, " \
608
- "_distro_release_info={4!r})" .format (
609
- self .os_release_file ,
610
- self .distro_release_file ,
611
- self ._os_release_info ,
612
- self ._lsb_release_info ,
613
- self ._distro_release_info )
616
+ "os_release_file={self.os_release_file!r}, " \
617
+ "distro_release_file={self.distro_release_file!r}, " \
618
+ "include_lsb={self.include_lsb!r}, " \
619
+ "_os_release_info={self._os_release_info!r}, " \
620
+ "_lsb_release_info={self._lsb_release_info!r}, " \
621
+ "_distro_release_info={self._distro_release_info!r})" .format (
622
+ self = self )
614
623
615
624
def linux_distribution (self , full_distribution_name = True ):
616
625
"""
@@ -835,7 +844,8 @@ def distro_release_attr(self, attribute):
835
844
"""
836
845
return self ._distro_release_info .get (attribute , '' )
837
846
838
- def _get_os_release_info (self ):
847
+ @cached_property
848
+ def _os_release_info (self ):
839
849
"""
840
850
Get the information items from the specified os-release file.
841
851
@@ -907,34 +917,24 @@ def _parse_os_release_content(lines):
907
917
pass
908
918
return props
909
919
910
- def _get_lsb_release_info (self ):
920
+ @cached_property
921
+ def _lsb_release_info (self ):
911
922
"""
912
923
Get the information items from the lsb_release command output.
913
924
914
925
Returns:
915
926
A dictionary containing all information items.
916
927
"""
917
- cmd = 'lsb_release -a'
918
- process = subprocess .Popen (
919
- cmd ,
920
- shell = True ,
921
- stdout = subprocess .PIPE ,
922
- stderr = subprocess .PIPE )
923
- stdout , stderr = process .communicate ()
924
- stdout , stderr = stdout .decode ('utf-8' ), stderr .decode ('utf-8' )
925
- code = process .returncode
926
- if code == 0 :
927
- content = stdout .splitlines ()
928
- return self ._parse_lsb_release_content (content )
929
- elif code == 127 : # Command not found
928
+ if not self .include_lsb :
930
929
return {}
931
- else :
932
- if sys .version_info [:2 ] >= (3 , 5 ):
933
- raise subprocess .CalledProcessError (code , cmd , stdout , stderr )
934
- elif sys .version_info [:2 ] >= (2 , 7 ):
935
- raise subprocess .CalledProcessError (code , cmd , stdout )
936
- elif sys .version_info [:2 ] == (2 , 6 ):
937
- raise subprocess .CalledProcessError (code , cmd )
930
+ with open (os .devnull , 'w' ) as devnull :
931
+ try :
932
+ cmd = ('lsb_release' , '-a' )
933
+ stdout = subprocess .check_output (cmd , stderr = devnull )
934
+ except OSError : # Command not found
935
+ return {}
936
+ content = stdout .decode (sys .getfilesystemencoding ()).splitlines ()
937
+ return self ._parse_lsb_release_content (content )
938
938
939
939
@staticmethod
940
940
def _parse_lsb_release_content (lines ):
@@ -952,7 +952,6 @@ def _parse_lsb_release_content(lines):
952
952
"""
953
953
props = {}
954
954
for line in lines :
955
- line = line .decode ('utf-8' ) if isinstance (line , bytes ) else line
956
955
kv = line .strip ('\n ' ).split (':' , 1 )
957
956
if len (kv ) != 2 :
958
957
# Ignore lines without colon.
@@ -961,7 +960,8 @@ def _parse_lsb_release_content(lines):
961
960
props .update ({k .replace (' ' , '_' ).lower (): v .strip ()})
962
961
return props
963
962
964
- def _get_distro_release_info (self ):
963
+ @cached_property
964
+ def _distro_release_info (self ):
965
965
"""
966
966
Get the information items from the specified distro release file.
967
967
@@ -1001,6 +1001,9 @@ def _get_distro_release_info(self):
1001
1001
'fedora-release' ,
1002
1002
'gentoo-release' ,
1003
1003
'mageia-release' ,
1004
+ 'mandrake-release' ,
1005
+ 'mandriva-release' ,
1006
+ 'mandrivalinux-release' ,
1004
1007
'manjaro-release' ,
1005
1008
'oracle-release' ,
1006
1009
'redhat-release' ,
0 commit comments