diff --git a/news/distro.vendor b/news/distro.vendor index a113787baaf..114ffabea2a 100644 --- a/news/distro.vendor +++ b/news/distro.vendor @@ -1 +1 @@ -Upgraded distro to 1.0.4. +Upgraded distro to 1.2.0. diff --git a/src/pip/_vendor/distro.py b/src/pip/_vendor/distro.py index b63451640a4..39bfce79791 100644 --- a/src/pip/_vendor/distro.py +++ b/src/pip/_vendor/distro.py @@ -38,9 +38,6 @@ import subprocess -if not sys.platform.startswith('linux'): - raise ImportError('Unsupported platform: {0}'.format(sys.platform)) - _UNIXCONFDIR = os.environ.get('UNIXCONFDIR', '/etc') _OS_RELEASE_BASENAME = 'os-release' @@ -511,6 +508,21 @@ def distro_release_attr(attribute): return _distro.distro_release_attr(attribute) +class cached_property(object): + """A version of @property which caches the value. On access, it calls the + underlying function and sets the value in `__dict__` so future accesses + will not re-call the property. + """ + def __init__(self, f): + self._fname = f.__name__ + self._f = f + + def __get__(self, obj, owner): + assert obj is not None, 'call {} on an instance'.format(self._fname) + ret = obj.__dict__[self._fname] = self._f(obj) + return ret + + class LinuxDistribution(object): """ Provides information about a Linux distribution. @@ -576,6 +588,9 @@ def __init__(self, `distro release file`_ that is actually used as a data source. The empty string if no distro release file is used as a data source. + * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. + This controls whether the lsb information will be loaded. + Raises: * :py:exc:`IOError`: Some I/O issue with an os-release file or distro @@ -591,26 +606,20 @@ def __init__(self, self.os_release_file = os_release_file or \ os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME) self.distro_release_file = distro_release_file or '' # updated later - self._os_release_info = self._get_os_release_info() - self._lsb_release_info = self._get_lsb_release_info() \ - if include_lsb else {} - self._distro_release_info = self._get_distro_release_info() + self.include_lsb = include_lsb def __repr__(self): """Return repr of all info """ return \ "LinuxDistribution(" \ - "os_release_file={0!r}, " \ - "distro_release_file={1!r}, " \ - "_os_release_info={2!r}, " \ - "_lsb_release_info={3!r}, " \ - "_distro_release_info={4!r})".format( - self.os_release_file, - self.distro_release_file, - self._os_release_info, - self._lsb_release_info, - self._distro_release_info) + "os_release_file={self.os_release_file!r}, " \ + "distro_release_file={self.distro_release_file!r}, " \ + "include_lsb={self.include_lsb!r}, " \ + "_os_release_info={self._os_release_info!r}, " \ + "_lsb_release_info={self._lsb_release_info!r}, " \ + "_distro_release_info={self._distro_release_info!r})".format( + self=self) def linux_distribution(self, full_distribution_name=True): """ @@ -835,7 +844,8 @@ def distro_release_attr(self, attribute): """ return self._distro_release_info.get(attribute, '') - def _get_os_release_info(self): + @cached_property + def _os_release_info(self): """ Get the information items from the specified os-release file. @@ -907,34 +917,24 @@ def _parse_os_release_content(lines): pass return props - def _get_lsb_release_info(self): + @cached_property + def _lsb_release_info(self): """ Get the information items from the lsb_release command output. Returns: A dictionary containing all information items. """ - cmd = 'lsb_release -a' - process = subprocess.Popen( - cmd, - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = process.communicate() - stdout, stderr = stdout.decode('utf-8'), stderr.decode('utf-8') - code = process.returncode - if code == 0: - content = stdout.splitlines() - return self._parse_lsb_release_content(content) - elif code == 127: # Command not found + if not self.include_lsb: return {} - else: - if sys.version_info[:2] >= (3, 5): - raise subprocess.CalledProcessError(code, cmd, stdout, stderr) - elif sys.version_info[:2] >= (2, 7): - raise subprocess.CalledProcessError(code, cmd, stdout) - elif sys.version_info[:2] == (2, 6): - raise subprocess.CalledProcessError(code, cmd) + with open(os.devnull, 'w') as devnull: + try: + cmd = ('lsb_release', '-a') + stdout = subprocess.check_output(cmd, stderr=devnull) + except OSError: # Command not found + return {} + content = stdout.decode(sys.getfilesystemencoding()).splitlines() + return self._parse_lsb_release_content(content) @staticmethod def _parse_lsb_release_content(lines): @@ -952,7 +952,6 @@ def _parse_lsb_release_content(lines): """ props = {} for line in lines: - line = line.decode('utf-8') if isinstance(line, bytes) else line kv = line.strip('\n').split(':', 1) if len(kv) != 2: # Ignore lines without colon. @@ -961,7 +960,8 @@ def _parse_lsb_release_content(lines): props.update({k.replace(' ', '_').lower(): v.strip()}) return props - def _get_distro_release_info(self): + @cached_property + def _distro_release_info(self): """ Get the information items from the specified distro release file. @@ -1001,6 +1001,9 @@ def _get_distro_release_info(self): 'fedora-release', 'gentoo-release', 'mageia-release', + 'mandrake-release', + 'mandriva-release', + 'mandrivalinux-release', 'manjaro-release', 'oracle-release', 'redhat-release', diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index 5597bd99049..2bb2ca293a9 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -1,6 +1,6 @@ appdirs==1.4.3 distlib==0.2.6 -distro==1.0.4 +distro==1.2.0 html5lib==1.0b10 six==1.11.0 colorama==0.3.9