2

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?

running.t
  • 5,329
  • 3
  • 32
  • 50
  • It is possible that this part of Python is customized by Ubuntu to correctly determine Ubuntu (as opposed to more generic `debian`) as the distribution. When you build 2.7.9 from sources, you don't get the distro-specific patch. You should be able to find distro modifications by inspecting the [source package](http://packages.ubuntu.com/trusty/python). – user4815162342 Nov 30 '15 at 10:33

3 Answers3

4

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

oz123
  • 27,559
  • 27
  • 125
  • 187
  • Apart from answering this question I was also looking into code of platform module and find exactly the same thing. I indeed have both `/etc/debian_version` and `/etc/os_release` on this machine. Thanks. – running.t Nov 30 '15 at 13:57
2

Looking at the source code for linux_distribution()

  • It lists all file in /etc,
  • search for file with a name matching r'(\w+)[-_](release|version)'. On my OS it choose debian_version file.
  • It then takes the first match of the regex (debian) and see if it is in the supported list (a static array: platform._supported_dists)
  • If it is, it reads the information from the file.
  • If not, it will runs _dist_try_harder(distname,version,id). Which will return the version from /var/adm/inst-log/info, /etc/.installed or /usr/lib/setup (in that order, first file present is parsed and returned).

So you may encounter different output based on where linux_distribution() reads the information.

Cyrbil
  • 6,341
  • 1
  • 24
  • 40
1

platform.linux_distribution()

platform.linux_distribution(distname='', version='', id='', supported_dists=('SuSE', 'debian', 'redhat', 'mandrake', ...), full_distribution_name=1)

Tries to determine the name of the Linux OS distribution name.

Supported_dists may be given to define the set of Linux distributions to look for. It defaults to a list of currently supported Linux distributions identified by their release file name.

If full_distribution_name is true (default), the full distribution read from the OS is returned. Otherwise the short name taken from supported_dists is used.

Returns a tuple (distname,version,id) which defaults to the args given as parameters. id is the item in parentheses after the version number. It is usually the version codename.

https://docs.python.org/2/library/platform.html?highlight=platform.linux_distribution#platform.linux_distribution

On your 2.7.9 result the command was unable to determine the full_distribution_name from the OS (as it's showing blank), so it went with supported_dists instead.

Community
  • 1
  • 1
l'L'l
  • 44,951
  • 10
  • 95
  • 146