Check Linux distribution name
Question:
I have to get the Linux distribution name from a Python script. There is a dist
method in the platform module:
import platform
platform.dist()
But under my Arch Linux it returns:
>>> platform.dist()
('', '', '')
Why? How can I get the name?
PS. I have to check whether the distribution is Debian-based.
Update: I found here Python site, that dist() is deprecated since 2.6.
>>> platform.linux_distribution()
('', '', '')
Answers:
Here‘s what I found:
platform.linux_distribution
Tries to determine the name of the
Linux OS distribution name.
It says platform.dist
is deprecated since 2.6, you have to use platform.linux_distribution
in Python 2 (but it is also deprecated in Python 3.5).
Two options for you:
-
Use
import platform
platform.linux_distribution()
# Something like (‘Ubuntu’, ‘9.10’, ‘karmic’)
-
Or you could just read the contents of /etc/debian_version (“squeeze/sid”) or /etc/lsb-release which would give:
DISTRIB_ID=Ubunt
DISTRIB_RELEASE=9.10
DISTRIB_CODENAME=karmic
DISTRIB_DESCRIPTION="Ubuntu 9.10"
This works for me on Ubuntu:
('Ubuntu', '10.04', 'lucid')
I then used strace
to find out what exactly the platform module is doing to find the distribution, and it is this part:
open("/etc/lsb-release", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=102, ...}) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=102, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76b1000
read(3, "DISTRIB_ID=UbuntunDISTRIB_RELEAS"..., 8192) = 102
read(3, "", 4096) = 0
read(3, "", 8192) = 0
close(3) = 0
So, there is /etc/lsb-release
containing this information, which comes from Ubuntu’s Debian base-files package.
It works here. And no, Arch Linux is not Debian-based.
>>> import platform
>>> platform.dist()
('SuSE', '11.2', 'x86_64')
So Python does not know how to get the Arch Linux release information, and it has hardcoded looking for /etc/redhat-release and /etc/SuSE-release.
platform.dist() is an obsolete function. You should use platform.linux_distribution()
Actually, on my system it yields a different result:
>>> platform.linux_distribution()
('openSUSE ', '11.2', 'x86_64')
platform.linux_distribution() looks in /etc files containing “release” or “version” as string. It also looks in the standard LSB release file. If at the end that did not work, it resorts to a _dist_try_harder function which tries to get the information from other places.
So it is up to Arch Linux to provide a standard LSB release information or to patch Python to use their “way”.
You’ll probably have to resort to:
if platform.linux_distribution() == ('', '', ''):
# do something specific to look for Arch
or you could always augment lib/python2.6/platform.py and send in your changes.
This worked for me under Ubuntu and Manjaro:
def get_distro():
"""
Name of your Linux distro (in lowercase).
"""
with open("/etc/issue") as f:
return f.read().lower().split()[0]
Python 2 does not properly detect Arch Linux. This has been fixed in Python 3.3+, but was never back-ported to Python 2. Here are a couple of official bug reports:
https://bugs.python.org/issue20454
https://bugs.python.org/issue11678
A workaround for this issue in Python 2 is fairly simple. You just need to tell the platform module that “arch” is a supported distribution:
>>> import platform
>>> platform.linux_distribution(supported_dists=platform._supported_dists + ('arch',))
('arch', '', '')
Note that Arch Linux is a rolling release, so it does not have a version or id.
The supported_dists
argument is documented here, although I don’t find the documentation very clear. You don’t want to overwrite _supported_dists
because then your code will only work on Arch Linux. You want to append to the tuple.
In fact, if you print out the value of platform._supported_dists
, you’ll see that the only difference between Python 2.7.12 and Python 3.5.1 is the addition of ('arch', 'mageia')
. Fun fact: you can also append 'system'
for platform detection on Amazon Linux.
The reason because of which platform.linux_distribution
does not identify some distributions is the non-standardized way distributions provide version-related information on themselves.
I’ve written a package called distro
(now used by pip
) which aims to replace distro.linux_distribution
. It works on many distributions which might return weird or empty tuples when using platform
.
https://github.com/nir0s/distro (distro
, on pypi)
It provides a much more elaborate API to retrieve distribution related information.
$ python
Python 2.7.12 (default, Nov 7 2016, 11:55:55)
[GCC 6.2.1 20160830] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import distro
>>> distro.linux_distribution()
(u'Antergos Linux', '', u'ARCHCODE')
By the way, platform.linux_distribution
is to be removed in Python 3.7.
If you want user readable data but still detailed, you can use platform.platform()
>>> import platform
>>> platform.platform()
'Linux-3.3.0-8.fc16.x86_64-x86_64-with-fedora-16-Verne'
Here’s a few different possible calls you can make to identify where you are
import platform
import sys
def linux_distribution():
try:
return platform.linux_distribution()
except:
return "N/A"
print("""Python version: %s
dist: %s
linux_distribution: %s
system: %s
machine: %s
platform: %s
uname: %s
version: %s
mac_ver: %s
""" % (
sys.version.split('n'),
str(platform.dist()),
linux_distribution(),
platform.system(),
platform.machine(),
platform.platform(),
platform.uname(),
platform.version(),
platform.mac_ver(),
))
The outputs of this script ran on a few different systems (Linux, Windows, Solaris, MacOS) and architectures (x86, x64, Itanium, power pc, sparc) is available here: https://github.com/hpcugent/easybuild/wiki/OS_flavor_name_version
To get a linux distribution name in python:
import distro
print(distro.id())
I am running Arch Linux, so this will return:
arch
For available distro id values see documenteation: https://distro.readthedocs.io/en/latest/
Here:
import sys, platform
print(sys.platform, platform.platform())
OUT [1]: linux Linux-5.4.44-1-MANJARO-x86_64-with-glibc2.2.5
None of the above platform
answers work with latest Python versions. I’ve tested with Python 3.8.10
. I found following methods instead.
Using platform:
>>> import platform
>>> platform.version()
'#29~20.04.1-Ubuntu SMP Wed Aug 11 15:58:17 UTC 2021'
Using distro:
>>> import distro
>>> distro.id()
'ubuntu'
Ref: https://docs.python.org/3/library/platform.html#platform.linux_distribution
Up to date answer:
>>> import platform
>>>
>>> platform.uname()
uname_result(system='Linux', node='debian', release='5.10.0-15-amd64', version='#1 SMP Debian 5.10.120-1 (2022-06-09)', machine='x86_64')
>>>
>>> # or seperately
>>> platform.system()
'Linux'
>>> platform.node()
'debian'
>>> platform.release()
'5.10.0-15-amd64'
>>> platform.version()
'#1 SMP Debian 5.10.120-1 (2022-06-09)'
>>> platform.machine()
'x86_64'
>>>
>>> # and also
>>> platform.platform()
'Linux-5.10.0-15-amd64-x86_64-with-glibc2.31'
>>> platform.architecture()
('64bit', 'ELF')
Now there is the platform.freedesktop_os_release()
method that you can use. To my knowledge, it provides support for every Linux distribution, including Arch.
>>> import platform
>>> platform.freedesktop_os_release()
{'NAME': 'Arch Linux', 'ID': 'arch', 'PRETTY_NAME': 'Arch Linux', 'BUILD_ID': 'rolling', 'ANSI_COLOR': '38;2;23;147;209', 'HOME_URL': 'https://archlinux.org/', 'DOCUMENTATION_URL': 'https://wiki.archlinux.org/', 'SUPPORT_URL': 'https://bbs.archlinux.org/', 'BUG_REPORT_URL': 'https://bugs.archlinux.org/', 'LOGO': 'archlinux-logo'}
You should be using the NAME or ID entry in order to check for the distribution. Values can be changed on any Linux system, but these values are available by default.
Many of the solutions do not work when executing inside a Container (The result is the host distro instead.)
A less elegant but container friendly approach:
from typing import Dict
def parse_env_file(path: str) -> Dict[str, str]:
with open(path, 'r') as f:
return dict(tuple(line.replace('n', '').split('=')) for line in f.readlines() if not line.startswith('#'))
print(parse_env_file("/etc/os-release")["NAME"])
I have to get the Linux distribution name from a Python script. There is a dist
method in the platform module:
import platform
platform.dist()
But under my Arch Linux it returns:
>>> platform.dist()
('', '', '')
Why? How can I get the name?
PS. I have to check whether the distribution is Debian-based.
Update: I found here Python site, that dist() is deprecated since 2.6.
>>> platform.linux_distribution()
('', '', '')
Here‘s what I found:
platform.linux_distribution
Tries to determine the name of the
Linux OS distribution name.
It says platform.dist
is deprecated since 2.6, you have to use platform.linux_distribution
in Python 2 (but it is also deprecated in Python 3.5).
Two options for you:
-
Use
import platform
platform.linux_distribution()
# Something like (‘Ubuntu’, ‘9.10’, ‘karmic’) -
Or you could just read the contents of /etc/debian_version (“squeeze/sid”) or /etc/lsb-release which would give:
DISTRIB_ID=Ubunt DISTRIB_RELEASE=9.10 DISTRIB_CODENAME=karmic DISTRIB_DESCRIPTION="Ubuntu 9.10"
This works for me on Ubuntu:
('Ubuntu', '10.04', 'lucid')
I then used strace
to find out what exactly the platform module is doing to find the distribution, and it is this part:
open("/etc/lsb-release", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=102, ...}) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=102, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76b1000
read(3, "DISTRIB_ID=UbuntunDISTRIB_RELEAS"..., 8192) = 102
read(3, "", 4096) = 0
read(3, "", 8192) = 0
close(3) = 0
So, there is /etc/lsb-release
containing this information, which comes from Ubuntu’s Debian base-files package.
It works here. And no, Arch Linux is not Debian-based.
>>> import platform
>>> platform.dist()
('SuSE', '11.2', 'x86_64')
So Python does not know how to get the Arch Linux release information, and it has hardcoded looking for /etc/redhat-release and /etc/SuSE-release.
platform.dist() is an obsolete function. You should use platform.linux_distribution()
Actually, on my system it yields a different result:
>>> platform.linux_distribution()
('openSUSE ', '11.2', 'x86_64')
platform.linux_distribution() looks in /etc files containing “release” or “version” as string. It also looks in the standard LSB release file. If at the end that did not work, it resorts to a _dist_try_harder function which tries to get the information from other places.
So it is up to Arch Linux to provide a standard LSB release information or to patch Python to use their “way”.
You’ll probably have to resort to:
if platform.linux_distribution() == ('', '', ''):
# do something specific to look for Arch
or you could always augment lib/python2.6/platform.py and send in your changes.
This worked for me under Ubuntu and Manjaro:
def get_distro():
"""
Name of your Linux distro (in lowercase).
"""
with open("/etc/issue") as f:
return f.read().lower().split()[0]
Python 2 does not properly detect Arch Linux. This has been fixed in Python 3.3+, but was never back-ported to Python 2. Here are a couple of official bug reports:
https://bugs.python.org/issue20454
https://bugs.python.org/issue11678
A workaround for this issue in Python 2 is fairly simple. You just need to tell the platform module that “arch” is a supported distribution:
>>> import platform
>>> platform.linux_distribution(supported_dists=platform._supported_dists + ('arch',))
('arch', '', '')
Note that Arch Linux is a rolling release, so it does not have a version or id.
The supported_dists
argument is documented here, although I don’t find the documentation very clear. You don’t want to overwrite _supported_dists
because then your code will only work on Arch Linux. You want to append to the tuple.
In fact, if you print out the value of platform._supported_dists
, you’ll see that the only difference between Python 2.7.12 and Python 3.5.1 is the addition of ('arch', 'mageia')
. Fun fact: you can also append 'system'
for platform detection on Amazon Linux.
The reason because of which platform.linux_distribution
does not identify some distributions is the non-standardized way distributions provide version-related information on themselves.
I’ve written a package called distro
(now used by pip
) which aims to replace distro.linux_distribution
. It works on many distributions which might return weird or empty tuples when using platform
.
https://github.com/nir0s/distro (distro
, on pypi)
It provides a much more elaborate API to retrieve distribution related information.
$ python
Python 2.7.12 (default, Nov 7 2016, 11:55:55)
[GCC 6.2.1 20160830] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import distro
>>> distro.linux_distribution()
(u'Antergos Linux', '', u'ARCHCODE')
By the way, platform.linux_distribution
is to be removed in Python 3.7.
If you want user readable data but still detailed, you can use platform.platform()
>>> import platform
>>> platform.platform()
'Linux-3.3.0-8.fc16.x86_64-x86_64-with-fedora-16-Verne'
Here’s a few different possible calls you can make to identify where you are
import platform
import sys
def linux_distribution():
try:
return platform.linux_distribution()
except:
return "N/A"
print("""Python version: %s
dist: %s
linux_distribution: %s
system: %s
machine: %s
platform: %s
uname: %s
version: %s
mac_ver: %s
""" % (
sys.version.split('n'),
str(platform.dist()),
linux_distribution(),
platform.system(),
platform.machine(),
platform.platform(),
platform.uname(),
platform.version(),
platform.mac_ver(),
))
The outputs of this script ran on a few different systems (Linux, Windows, Solaris, MacOS) and architectures (x86, x64, Itanium, power pc, sparc) is available here: https://github.com/hpcugent/easybuild/wiki/OS_flavor_name_version
To get a linux distribution name in python:
import distro
print(distro.id())
I am running Arch Linux, so this will return:
arch
For available distro id values see documenteation: https://distro.readthedocs.io/en/latest/
Here:
import sys, platform
print(sys.platform, platform.platform())
OUT [1]: linux Linux-5.4.44-1-MANJARO-x86_64-with-glibc2.2.5
None of the above platform
answers work with latest Python versions. I’ve tested with Python 3.8.10
. I found following methods instead.
Using platform:
>>> import platform
>>> platform.version()
'#29~20.04.1-Ubuntu SMP Wed Aug 11 15:58:17 UTC 2021'
Using distro:
>>> import distro
>>> distro.id()
'ubuntu'
Ref: https://docs.python.org/3/library/platform.html#platform.linux_distribution
Up to date answer:
>>> import platform
>>>
>>> platform.uname()
uname_result(system='Linux', node='debian', release='5.10.0-15-amd64', version='#1 SMP Debian 5.10.120-1 (2022-06-09)', machine='x86_64')
>>>
>>> # or seperately
>>> platform.system()
'Linux'
>>> platform.node()
'debian'
>>> platform.release()
'5.10.0-15-amd64'
>>> platform.version()
'#1 SMP Debian 5.10.120-1 (2022-06-09)'
>>> platform.machine()
'x86_64'
>>>
>>> # and also
>>> platform.platform()
'Linux-5.10.0-15-amd64-x86_64-with-glibc2.31'
>>> platform.architecture()
('64bit', 'ELF')
Now there is the platform.freedesktop_os_release()
method that you can use. To my knowledge, it provides support for every Linux distribution, including Arch.
>>> import platform
>>> platform.freedesktop_os_release()
{'NAME': 'Arch Linux', 'ID': 'arch', 'PRETTY_NAME': 'Arch Linux', 'BUILD_ID': 'rolling', 'ANSI_COLOR': '38;2;23;147;209', 'HOME_URL': 'https://archlinux.org/', 'DOCUMENTATION_URL': 'https://wiki.archlinux.org/', 'SUPPORT_URL': 'https://bbs.archlinux.org/', 'BUG_REPORT_URL': 'https://bugs.archlinux.org/', 'LOGO': 'archlinux-logo'}
You should be using the NAME or ID entry in order to check for the distribution. Values can be changed on any Linux system, but these values are available by default.
Many of the solutions do not work when executing inside a Container (The result is the host distro instead.)
A less elegant but container friendly approach:
from typing import Dict
def parse_env_file(path: str) -> Dict[str, str]:
with open(path, 'r') as f:
return dict(tuple(line.replace('n', '').split('=')) for line in f.readlines() if not line.startswith('#'))
print(parse_env_file("/etc/os-release")["NAME"])