Search code examples
pythonlinuxlsb

Why does platform.linux_distribution() returns different results on one OS?


I have 2 versions of python installed on some virtual machine 2.7.9 and 2.7.6. 2.7.6 is installed from system package while 2.7.9 is installed from sources. This machine is running on Ubuntu 14.04.

I wanted to use platform module to get information about linux distribution. However it turned out that in these 2 versions I got different results of platform.linux_distribution().

Python 2.7.9 (...) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.linux_distribution()
('debian', 'jessie/sid', '')


Python 2.7.6 (...) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.linux_distribution()
('Ubuntu', '14.04', 'trusty')

Any idea why it is so? Or more generally how does platform module get information about linux distribution. Is it based on lsb_relase or some other system command or is it hardcoded somewhere?


Solution

  • Ubuntu 14.04 includes two release files:

    # cat /etc/os-release 
    NAME="Ubuntu"
    VERSION="14.04.3 LTS, Trusty Tahr"
    ID=ubuntu
    ID_LIKE=debian
    PRETTY_NAME="Ubuntu 14.04.3 LTS"
    VERSION_ID="14.04"
    HOME_URL="http://www.ubuntu.com/"
    SUPPORT_URL="http://help.ubuntu.com/"
    BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
    
    root@yeni2:/# cat /etc/debian_version 
    jessie/sid
    

    Both are used by the function platform.linux_distribution() However, this function is patched by Ubuntu to return the Ubuntu OS name, see also the comment in the code (right is the file installed by Ubuntu, left is the file from the sources found in Python 2.7.10):

    Python-2.7.10 # diff Lib/platform.py /mnt/ubu/\@/usr/lib/python2.7/platform.py
    1c1
    < #!/usr/bin/env python
    ---
    > #! /usr/bin/python2.7
    262c262
    <     'UnitedLinux', 'turbolinux')
    ---
    >     'UnitedLinux', 'turbolinux', 'Ubuntu')
    290a291,294
    > _distributor_id_file_re = re.compile("(?:DISTRIB_ID\s*=)\s*(.*)", re.I)
    > _release_file_re = re.compile("(?:DISTRIB_RELEASE\s*=)\s*(.*)", re.I)
    > _codename_file_re = re.compile("(?:DISTRIB_CODENAME\s*=)\s*(.*)", re.I)
    > 
    314a319,337
    >     # check for the LSB /etc/lsb-release file first, needed so
    >     # that the distribution doesn't get identified as Debian.
    >     try:
    >         with open("/etc/lsb-release", "rU") as etclsbrel:
    >             for line in etclsbrel:
    >                 m = _distributor_id_file_re.search(line)
    >                 if m:
    >                     _u_distname = m.group(1).strip()
    >                 m = _release_file_re.search(line)
    >                 if m:
    >                     _u_version = m.group(1).strip()
    >                 m = _codename_file_re.search(line)
    >                 if m:
    >                     _u_id = m.group(1).strip()
    >             if _u_distname and _u_version:
    >                 return (_u_distname, _u_version, _u_id)
    >     except (EnvironmentError, UnboundLocalError):
    >         pass
    > 
    

    Your python 2.7.9 compiled the source, does not contain the patch from Ubuntu, that is why it is returning the content of /etc/debian_version