# Copyright 1999-2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: python-utils-r1.eclass
# @MAINTAINER:
# Python team <python@gentoo.org>
# @AUTHOR:
# Author: Michał Górny <mgorny@gentoo.org>
# Based on work of: Krzysztof Pawlik <nelchael@gentoo.org>
# @SUPPORTED_EAPIS: 7 8
# @BLURB: Utility functions for packages with Python parts.
# @DESCRIPTION:
# A utility eclass providing functions to query Python implementations,
# install Python modules and scripts.
#
# This eclass does not set any metadata variables nor export any phase
# functions. It can be inherited safely.
#
# For more information, please see the Python Guide:
# https://projects.gentoo.org/python/guide/
# NOTE: When dropping support for EAPIs here, we need to update
# metadata/install-qa-check.d/60python-pyc
# See bug #704286, bug #781878
if [[ -z ${_PYTHON_UTILS_R1_ECLASS} ]]; then
_PYTHON_UTILS_R1_ECLASS=1
case ${EAPI} in
7|8) ;;
*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac
[[ ${EAPI} == 7 ]] && inherit eapi8-dosym
inherit multiprocessing toolchain-funcs
# @ECLASS_VARIABLE: _PYTHON_ALL_IMPLS
# @INTERNAL
# @DESCRIPTION:
# All supported Python implementations, most preferred last.
_PYTHON_ALL_IMPLS=(
pypy3_11
python3_{13..14}t
python3_{11..14}
)
readonly _PYTHON_ALL_IMPLS
# @ECLASS_VARIABLE: _PYTHON_HISTORICAL_IMPLS
# @INTERNAL
# @DESCRIPTION:
# All historical Python implementations that are no longer supported.
_PYTHON_HISTORICAL_IMPLS=(
jython2_7
pypy pypy1_{8,9} pypy2_0 pypy3
python2_{5..7}
python3_{1..10}
)
readonly _PYTHON_HISTORICAL_IMPLS
# @ECLASS_VARIABLE: PYTHON_COMPAT_NO_STRICT
# @INTERNAL
# @DESCRIPTION:
# Set to a non-empty value in order to make eclass tolerate (ignore)
# unknown implementations in PYTHON_COMPAT.
#
# This is intended to be set by the user when using ebuilds that may
# have unknown (newer) implementations in PYTHON_COMPAT. The assumption
# is that the ebuilds are intended to be used within multiple contexts
# which can involve revisions of this eclass that support a different
# set of Python implementations.
# @FUNCTION: _python_verify_patterns
# @USAGE: <pattern>...
# @INTERNAL
# @DESCRIPTION:
# Verify whether the patterns passed to the eclass function are correct
# (i.e. can match any valid implementation). Dies on wrong pattern.
_python_verify_patterns() {
debug-print-function ${FUNCNAME} "$@"
local impl pattern
for pattern; do
case ${pattern} in
-[23]|3.[89]|3.1[0-4])
continue
;;
esac
for impl in "${_PYTHON_ALL_IMPLS[@]}" "${_PYTHON_HISTORICAL_IMPLS[@]}"
do
[[ ${impl} == ${pattern/./_} ]] && continue 2
done
die "Invalid implementation pattern: ${pattern}"
done
}
# @FUNCTION: _python_set_impls
# @INTERNAL
# @DESCRIPTION:
# Check PYTHON_COMPAT for well-formedness and validity, then set
# two global variables:
#
# - _PYTHON_SUPPORTED_IMPLS containing valid implementations supported
# by the ebuild (PYTHON_COMPAT - dead implementations),
#
# - and _PYTHON_UNSUPPORTED_IMPLS containing valid implementations that
# are not supported by the ebuild.
#
# Implementations in both variables are ordered using the pre-defined
# eclass implementation ordering.
#
# This function must be called once in global scope by an eclass
# utilizing PYTHON_COMPAT.
_python_set_impls() {
local i
# TODO: drop BASH_VERSINFO check when we require EAPI 8
if [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
[[ ${PYTHON_COMPAT@a} == *a* ]]
else
[[ $(declare -p PYTHON_COMPAT) == "declare -a"* ]]
fi
if [[ ${?} -ne 0 ]]; then
if ! declare -p PYTHON_COMPAT &>/dev/null; then
die 'PYTHON_COMPAT not declared.'
else
die 'PYTHON_COMPAT must be an array.'
fi
fi
local obsolete=()
if [[ ! ${PYTHON_COMPAT_NO_STRICT} ]]; then
for i in "${PYTHON_COMPAT[@]}"; do
# check for incorrect implementations
# we're