Check Debian's Python 3 Support with py3versions

Before you write a build matrix, ask py3versions what Debian thinks is default, supported and installed. It also checks a version constraint straight out of a Debian control file. Every command here is read-only. Allow about ten minutes, with the python3-minimal package installed and a shell handy.

This guide was checked against Ubuntu's python3-minimal package version 3.12.3-0ubuntu2.1, with the command at /usr/bin/py3versions. The version list is distribution data, so your own output will shift as Ubuntu's Python policy shifts.

1. Confirm the command and package

Start with ordinary, unprivileged checks. Nothing here installs anything or needs sudo:

$ command -v py3versions
/usr/bin/py3versions
$ dpkg-query -W -f='${Package} ${Version}\n' python3-minimal
python3-minimal 3.12.3-0ubuntu2.1

This reports Debian's packaging view of Python versions. It is not a general interpreter finder, and it will not list every Python binary that happens to sit on PATH.

Checkpoint: if command -v finds nothing, stop and repair the package through your normal package-management process rather than copying a script from another machine.

2. Find the default and the supported set

Ask for the default runtime, then the full supported list:

$ py3versions --default
python3.12
$ py3versions --supported
python3.12

3. Compare supported versions against what is actually installed

--installed narrows the answer to supported interpreters that are actually present:

$ py3versions --installed
python3.12
$ py3versions --min-supported
python3.12
$ py3versions --max-supported
python3.12

Minimum and maximum describe the supported set, not the oldest and newest binary a filesystem scan happens to turn up. That distinction stops a retired interpreter from getting mistaken for a legitimate build target.

Reach for --version, or -v, when something else needs bare version numbers without the python prefix:

$ py3versions --supported --version
3.12
$ py3versions --installed --version
3.12

Checkpoint: for a build matrix, compare --supported against --installed. A supported version that is missing from installed is a packaging or host-coverage decision, not automatically a broken Python setup.

4. Test an X-Python3-Version constraint

Debian source packages can carry an X-Python3-Version field in the Source: section of debian/control. Pass either the raw field value or a control-file path to --requested. This example uses a temporary file, so no real package metadata is touched:

$ control_file=$(mktemp /tmp/example-control.XXXXXX)
$ printf '%s\n' 'Source: example-package' 'X-Python3-Version: >= 3.10, << 3.13' '' 'Package: example-package' > "$control_file"
$ py3versions --requested "$control_file"
python3.12
$ py3versions --requested '>= 3.10, << 3.13' --version
3.12

The syntax accepts an exact minor version, or a lower and upper bound. The installed implementation ignores Python 2 versions entirely, along with the keywords all, current and current_ext. It returns only versions that are both requested and supported, in the same order as --supported.

That mktemp call is the only state change here, all under /tmp. Remove it afterwards using the exact path mktemp printed, not a broad wildcard.

5. Check a real control file without touching it

For a source tree, point the command straight at its actual metadata:

$ py3versions --requested debian/control
python3.12

The command reads the source section. If the field is absent, the documented fallback is the supported Python 3 list after checking debian/control. A malformed value, a file that is not a control file, or a constraint matching no supported version all produce an error and a non-zero exit status.

Calling --requested with no argument is not a way to ask for the default; use --default for that. Keep the two questions separate: requested versions come from package metadata, the default comes from the system's own Python configuration.

6. Use the result in a script

Capture the exit status when a failed version check needs to stop a build. Do not treat an empty variable as a success:

requested=$(py3versions --requested debian/control --version) || {
    printf '%s\n' 'X-Python3-Version could not be resolved' >&2
    exit 1
}
printf 'supported requested versions: %s\n' "$requested"

Nothing in this workflow needs elevated privileges. Do not run it under sudo unless your source tree or control file has deliberately restricted permissions; privilege cannot fix malformed metadata or make an unsupported Python version supported.

Done means