distro review
distro turns the host's release files and commands into a small Python API for Linux and BSD identity. It can return a normalized ID such as `ubuntu`, a display name, version parts, codename, and the `ID_LIKE` family list. Version 1.9.0 changed `distro.info()` to return the typed `InfoDict` and stopped treating `/etc/board-release` and `/etc/ec2_version` as distribution release files. Our Python 3.12 install stayed small and imported successfully, which fits its job as an early bootstrap dependency.
Install distro when Linux-family and fallback detection affect real setup logic, especially on mixed fleets. Skip it for a Python 3.10+ service that only reads standard `os-release` fields or for any cross-platform hardware inventory tool.
We installed it
| Install | ✓ · 0.3s | 1 package on disk · 1 MB |
| Import | ✓ | import distro in 0.18s · pure Python · py.typed · requires Python >=3.6 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does distro install cleanly?
Yes. In a fresh container with an empty cache, pip install distro finished in 0.3s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does distro need to run?
Python >=3.6, and nothing compiled: it is pure Python. In our run import distro succeeded in 0.18s, and the package ships py.typed for type checkers.
distro or psutil: which should you use?
psutil: Choose it when the report needs CPU, memory, disks, network interfaces, and processes in addition to platform identity. Install distro when Linux-family and fallback detection affect real setup logic, especially on mixed fleets.
When should you not use distro?
You only support Python 3.10 or newer and only read /etc/os-release; platform.freedesktop_os_release() already handles that file in the standard library.
Discussed on
- hnTiny Core Linux: a 23 MB Linux distro with graphical desktop527 points
- hnSnakeware – Linux distro with Python userspace inspired by Commodore 64436 points
- hnJingOS: Linux Distro Inspired by the iPad435 points
- hnShow HN: CoreOS, a Linux distro for containers417 points
- hnKali Linux 2023.1 introduces 'Purple' distro for defensive security380 points
Use it if
- Your installer must choose apt, dnf, or another path from a normalized Linux distribution ID.
- You need `ID_LIKE` family matching so a derivative can follow its Debian, Ubuntu, Fedora, or RHEL parent path.
- Your support bundle needs a JSON-ready set of distribution name, version, codename, and family fields.
- You must inspect older or unusual hosts where reading only `/etc/os-release` is insufficient.
- You only support Python 3.10 or newer and only read `/etc/os-release`; `platform.freedesktop_os_release()` already handles that file in the standard library.
- Your code must identify Windows or macOS. The README limits current support to Linux and BSD, so empty fields need explicit handling elsewhere.
- You need CPU, memory, process, disk, or virtualization facts. distro reports the operating-system distribution, not the machine around it; use psutil for those measurements.
- You need Debian or Ubuntu lifecycle dates rather than the identity of the current host. `distro-info` is built around release metadata and support periods.
- You expect every host to provide a codename or numeric version. Rolling releases and stripped containers can leave those values empty because distro can only report what its sources expose.
Setup reality
We installed distro 1.9.0 in a fresh unprivileged Python 3.12 Bookworm container. Installation succeeded in 0.3 seconds and left one package using 1 MB on disk. It has no direct dependencies, is pure Python, includes py.typed, and requires Python 3.6 or newer. import distro worked in 0.18 seconds. pip-audit found 0 known vulnerabilities.
There are no credentials or config files. The data comes from the host: /etc/os-release, then lsb_release, distribution release files, and uname for BSD. A minimal container may omit lsb_release, while a bind-mounted or custom os-release file can describe the image rather than the physical host. Treat the result as the current runtime environment.
Fields are not equally dependable. id() is the safest branch value, while name(pretty=True), codename(), and version parts may be empty or vary with the available source. version(best=True) deliberately searches for the most detailed version and can differ from the normal precedence result. Module-level calls use a cached LinuxDistribution instance, so tests that replace release files should construct their own instance with explicit paths.
The project also permits copying distro.py into bootstrap code that cannot install dependencies yet. Vendoring transfers update responsibility to you. Version 1.9.0 ignores /etc/board-release and /etc/ec2_version, which avoids false identification on systems where those files describe hardware or an EC2 image rather than the distribution.
Patterns
Read the normalized distribution ID get-distro-id
import distro
os_id = distro.id()
if os_id == "ubuntu":
configure_ubuntu()Branch on `id()`, not the display name. Unsupported systems or missing data can produce an empty string.
Match a distribution and its parent families match-distro-family
import distro
family = {distro.id(), *distro.like().split()}
if family & {"debian", "ubuntu"}:
package_manager = "apt"
elif family & {"fedora", "rhel", "centos"}:
package_manager = "dnf"`like()` returns the space-separated `ID_LIKE` value. Keep the distribution's own ID in the set because the field may be empty.
Format a readable name for diagnostics display-distro-name
import distro
label = distro.name(pretty=True) or distro.id() or "unknown"
print(f"Distribution: {label}")The pretty value may include a version or codename and should not be used as a stable comparison key.
Read version parts without assuming they exist read-version-parts
import distro
major, minor, build = distro.version_parts(best=True)
if distro.id() == "ubuntu" and major.isdigit() and int(major) >= 22:
enable_new_repository_layout()Version parts are strings. Rolling releases and sparse release files can return empty strings, so guard numeric conversion.
Attach distribution details to a support report collect-distro-info
import json
import distro
report = {
"distribution": distro.info(pretty=False, best=True),
}
print(json.dumps(report, indent=2))In 1.9.0 `info()` returns the typed `InfoDict`; its values are suitable for JSON serialization.
Read an os-release field outside the high-level API read-raw-os-release
import distro
variant = distro.os_release_attr("variant_id")
build = distro.os_release_attr("build_id")Pass the lowercase form of the os-release key. Missing attributes return an empty string.
Inspect release files under another root use-custom-root
from distro import LinuxDistribution
target = LinuxDistribution(
root_dir="/mnt/image",
include_lsb=False,
include_uname=False,
include_oslevel=False,
)
print(target.info())With `root_dir`, command-based sources default off because they would describe the running host rather than the mounted image.
Read distribution data from a shell script use-cli-json
python -m distro --json
python -m distro --json | jq -r '.id'Use `python -m distro` when the virtual environment's console-script directory may not be on `PATH`.
Use the standard library for os-release only prefer-stdlib
import platform
try:
release = platform.freedesktop_os_release()
except OSError:
release = {}
os_id = release.get("ID", "")This Python 3.10+ API reads freedesktop os-release data but does not add distro's `lsb_release`, release-file, or BSD fallbacks.
Fall back when os-release is unavailable fallback-to-distro
import platform
try:
os_id = platform.freedesktop_os_release().get("ID", "")
except (AttributeError, OSError):
import distro
os_id = distro.id()Keep the package only if the extra fallbacks or Python versions below 3.10 are part of your support matrix.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| psutil | PyPI | Choose it when the report needs CPU, memory, disks, network interfaces, and processes in addition to platform identity. |
| distro-info | PyPI | Choose it for Debian and Ubuntu release names, support status, and lifecycle data rather than local-host detection. |
| platformdirs | PyPI | Choose it when the actual task is finding platform-specific config, cache, log, or data directories. |
More infra guides
boto3 · opentelemetry-api · @opentelemetry/api · psutil · @aws-sdk/client-s3 · google-cloud-storage · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

