summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root@alpha.trunkmasters.com>2026-05-31 21:38:10 -0500
committerroot <root@alpha.trunkmasters.com>2026-05-31 21:38:10 -0500
commit008c6bb5dee069ebd21087839198b81fae584fe0 (patch)
tree709deeecc07b9d2aca5e272eb59bf8c2d61a89dc
parentaf1749663d24ec0e6ef538ae11a18829edb8ac22 (diff)
downloadbaldeagleos-repo-008c6bb5dee069ebd21087839198b81fae584fe0.tar.gz
baldeagleos-repo-008c6bb5dee069ebd21087839198b81fae584fe0.tar.xz
baldeagleos-repo-008c6bb5dee069ebd21087839198b81fae584fe0.zip
eclass: sync python-utils-r1 from upstream, add python3_15
-rw-r--r--eclass/python-utils-r1.eclass205
1 files changed, 134 insertions, 71 deletions
diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass
index b50834480e19..6230cba30d92 100644
--- a/eclass/python-utils-r1.eclass
+++ b/eclass/python-utils-r1.eclass
@@ -1,4 +1,4 @@
-# Copyright 1999-2025 Gentoo Authors
+# Copyright 1999-2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: python-utils-r1.eclass
@@ -27,7 +27,7 @@ if [[ -z ${_PYTHON_UTILS_R1_ECLASS} ]]; then
_PYTHON_UTILS_R1_ECLASS=1
case ${EAPI} in
- 7|8) ;;
+ 7|8) inherit eapi9-pipestatus ;;
*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac
@@ -40,8 +40,8 @@ inherit multiprocessing toolchain-funcs
# All supported Python implementations, most preferred last.
_PYTHON_ALL_IMPLS=(
pypy3_11
- python3_{9..14}t
- python3_{9..14}
+ python3_{13..15}t
+ python3_{11..15}
)
readonly _PYTHON_ALL_IMPLS
@@ -53,7 +53,7 @@ _PYTHON_HISTORICAL_IMPLS=(
jython2_7
pypy pypy1_{8,9} pypy2_0 pypy3
python2_{5..7}
- python3_{1..8}
+ python3_{1..10}
)
readonly _PYTHON_HISTORICAL_IMPLS
@@ -81,7 +81,7 @@ _python_verify_patterns() {
local impl pattern
for pattern; do
case ${pattern} in
- -[23]|3.[89]|3.1[0-4])
+ -[23]|3.[89]|3.1[0-5])
continue
;;
esac
@@ -137,9 +137,9 @@ _python_set_impls() {
# please keep them in sync with _PYTHON_ALL_IMPLS
# and _PYTHON_HISTORICAL_IMPLS
case ${i} in
- pypy3_11|python3_9|python3_1[0-4]|python3_1[3-4]t)
+ pypy3_11|python3_9|python3_1[1-5]|python3_1[3-5]t)
;;
- jython2_7|pypy|pypy1_[89]|pypy2_0|pypy3|python2_[5-7]|python3_[1-8])
+ jython2_7|pypy|pypy1_[89]|pypy2_0|pypy3|python2_[5-7]|python3_[1-9]|python3_10)
obsolete+=( "${i}" )
;;
*)
@@ -230,7 +230,7 @@ _python_impl_matches() {
fi
return 0
;;
- 3.[89]|3.1[0-4])
+ 3.[89]|3.1[0-5])
[[ ${impl%t} == python${pattern/./_} || ${impl} == pypy${pattern/./_} ]] &&
return 0
;;
@@ -602,7 +602,7 @@ python_optimize() {
# default to sitedir
[[ ${#} -eq 0 ]] && set -- "${D}$(python_get_sitedir)"
- local jobs=$(makeopts_jobs)
+ local jobs=$(get_makeopts_jobs)
local d
for d; do
einfo "Optimizing Python modules in ${d#${D}}"
@@ -679,7 +679,7 @@ python_newexe() {
local newfn=${2}
local scriptdir=$(python_get_scriptdir)
- local d=${scriptdir#${EPREFIX}}
+ local d=${scriptdir#"${EPREFIX}"}
(
dodir "${wrapd}"
@@ -817,7 +817,7 @@ python_domodule() {
else
# relative to site-packages
local sitedir=$(python_get_sitedir)
- d=${sitedir#${EPREFIX}}/${_PYTHON_MODULEROOT//.//}
+ d=${sitedir#"${EPREFIX}"}/${_PYTHON_MODULEROOT//.//}
fi
if [[ ${EBUILD_PHASE} == install ]]; then
@@ -929,8 +929,12 @@ _python_wrapper_setup() {
chmod +x "${workdir}/bin/python-config" \
"${workdir}/bin/python3-config" || die
- # Python 2.6+.
- ln -s "${PYTHON/python/2to3-}" "${workdir}"/bin/2to3 || die
+ # Python 2.6+. Deprecated in 3.11, removed in 3.13.
+ if ver_test ${EPYTHON#python} -lt 3.13; then
+ ln -s "${PYTHON/python/2to3-}" "${workdir}"/bin/2to3 || die
+ else
+ nonsupp+=( 2to3 )
+ fi
# Python 2.7+.
ln -s "${EPREFIX}"/usr/$(get_libdir)/pkgconfig/${EPYTHON/n/n-}.pc \
@@ -1227,12 +1231,12 @@ _python_check_occluded_packages() {
comm -1 -3 <(
find "${fn}" -type f -not -path '*/__pycache__/*' |
sort
- assert
+ pipestatus || die
) <(
cd "${sitedir}" &&
find "${fn}" -type f -not -path '*/__pycache__/*' |
sort
- assert
+ pipestatus || die
)
)
@@ -1288,9 +1292,9 @@ _python_check_occluded_packages() {
# Defaults to an empty list.
#
# The eclasses explicitly handle a number of pytest plugins, and assume
-# the default of "dev-python/${package}" and "-p ${package}" for others.
-# If this is incorrect for some plugin package, please report a bug
-# to have it added.
+# the default of "dev-python/${package}" and obtain "-p" via entry
+# points. If this is incorrect for some plugin package, please report
+# a bug.
#
# This is not a perfect solution, and may not be sufficient for some
# packages. In these cases, either plugin autoloading should be used
@@ -1312,6 +1316,15 @@ _python_check_occluded_packages() {
# The recommended way to disable it in EAPI 8 or earlier is to set
# EPYTEST_PLUGINS (possibly to an empty array).
+# @ECLASS_VARIABLE: EPYTEST_PLUGIN_LOAD_VIA_ENV
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a non-empty value, plugins will be loaded via PYTEST_PLUGINS
+# environment variable rather than explicit "-p" options. This ensures
+# that plugins are passed down to subprocess, which may be necessary
+# when testing pytest plugins. However, this is also more likely
+# to cause duplicate plugin errors.
+
# @FUNCTION: _set_epytest_plugins
# @INTERNAL
# @DESCRIPTION:
@@ -1345,6 +1358,16 @@ _set_epytest_plugins() {
fi
}
+# @ECLASS_VARIABLE: EPYTEST_RERUNS
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a non-empty value, enables pytest-rerunfailures plugin
+# and sets rerun count to the specified value. This variable can be
+# either set in ebuilds with flaky tests, or by user to try if it helps.
+# If this variable is set prior to calling distutils_enable_tests
+# in distutils-r1, a test dependency on dev-python/pytest-rerunfailures
+# is added automatically.
+
# @ECLASS_VARIABLE: EPYTEST_TIMEOUT
# @DEFAULT_UNSET
# @DESCRIPTION:
@@ -1397,7 +1420,7 @@ epytest() {
[[ ${NO_COLOR} ]] && color=no
mkdir -p "${T}/pytest-xml" || die
- local junit_xml=$(mktemp "${T}/pytest-xml/${EPYTHON}-XXX.xml" || die)
+ local junit_xml=$(mktemp "${T}/pytest-xml/${EPYTHON}-XXXXXX.xml" || die)
local args=(
# verbose progress reporting and tracebacks
@@ -1441,57 +1464,43 @@ epytest() {
fi
if [[ ${PYTEST_DISABLE_PLUGIN_AUTOLOAD} ]]; then
- local plugin
- for plugin in "${EPYTEST_PLUGINS[@]}"; do
- case ${plugin} in
- # special cases
- hypothesis)
- plugin=hypothesispytest
- ;;
- noseofyeti)
- plugin=nose_of_yeti
- ;;
- pytest-helpers-namespace)
- plugin=helpers_namespace
- ;;
- pytest-lazy-fixtures)
- plugin=pytest_lazyfixture
- ;;
- pytest-testinfra)
- plugin=pytest11.testinfra
- ;;
- # "generic" cases
- betamax)
- plugin=pytest-${plugin}
- ;;
- pyfakefs)
- plugin=pytest_${plugin}
- ;;
- # pytest-x-y-z -> x-y-z
- pytest-aiohttp | pytest-asyncio | pytest-check | \
- pytest-console-scripts | pytest-django | pytest-env | \
- pytest-freezer | pytest-home | pytest-httpbin | \
- pytest-import-check | pytest-localftpserver | \
- pytest-localserver | pytest-plus | pytest-recording | \
- pytest-regressions | pytest-repeat | pytest-reraise | \
- pytest-rerunfailures | pytest-reserial | \
- pytest-shell-utilities | pytest-skip-markers | \
- pytest-subtests | pytest-timeout | pytest-tornasync | \
- pytest-trio | pytext-xdist | pytest-xprocess | \
- pytest-xvfb )
- plugin=${plugin#pytest-}
- ;;
- # foo-bar-baz unchanged
- pytest-datadir | pytest-qt | pytest-subprocess)
- ;;
- # foo-bar-baz -> foo_bar_baz
- *)
- plugin=${plugin//-/_}
- ;;
- esac
+ if [[ ${EPYTEST_PLUGINS[@]} ]]; then
+ if [[ ${EPYTEST_PLUGIN_LOAD_VIA_ENV} ]]; then
+ local -x PYTEST_PLUGINS=$(
+ "${EPYTHON}" - "${EPYTEST_PLUGINS[@]}" <<-EOF || die
+ import sys
+ from importlib.metadata import distribution, entry_points
- args+=( -p "${plugin}" )
- done
+ packages = {distribution(x).name for x in sys.argv[1:]}
+ # In packages defining multiple entry points, we must
+ # list them in the same order!
+ plugins = (
+ x.value for x in entry_points(group="pytest11")
+ if x.dist.name in packages
+ )
+ sys.stdout.write(",".join(plugins))
+ EOF
+ )
+ else
+ local plugin_args=()
+ readarray -t -d '' plugin_args < <(
+ "${EPYTHON}" - "${EPYTEST_PLUGINS[@]}" <<-EOF || die
+ import os
+ import sys
+ from importlib.metadata import distribution, entry_points
+
+ env_plugins = os.environ.get("PYTEST_PLUGINS", "").split(",")
+ packages = {distribution(x).name for x in sys.argv[1:]}
+ eps = {
+ f"-p{x.name}" for x in entry_points(group="pytest11")
+ if x.dist.name in packages and x.value not in env_plugins
+ }
+ sys.stdout.write("\\0".join(sorted(eps)))
+ EOF
+ )
+ args+=( "${plugin_args[@]}" )
+ fi
+ fi
else
args+=(
# disable the undesirable-dependency plugins by default to
@@ -1522,6 +1531,26 @@ epytest() {
)
fi
+ if [[ -n ${EPYTEST_RERUNS} ]]; then
+ if [[ ${PYTEST_PLUGINS} != *pytest_rerunfailures* ]]; then
+ args+=(
+ -p rerunfailures
+ )
+ fi
+
+ if has_version ">=dev-python/pytest-rerunfailures-16.1"; then
+ args+=(
+ # --reruns only adds N reruns for tests not marked for reruns
+ # --force-reruns overrides the rerun count for all tests
+ "--force-reruns=${EPYTEST_RERUNS}"
+ )
+ else
+ args+=(
+ "--reruns=${EPYTEST_RERUNS}"
+ )
+ fi
+ fi
+
if [[ -n ${EPYTEST_TIMEOUT} ]]; then
if [[ ${PYTEST_PLUGINS} != *pytest_timeout* ]]; then
args+=(
@@ -1532,10 +1561,19 @@ epytest() {
args+=(
"--timeout=${EPYTEST_TIMEOUT}"
)
+
+ if [[ -n ${EPYTEST_RERUNS} ]]; then
+ # This option helps with hangs in some cases when these plugins are used together.
+ # https://github.com/pytest-dev/pytest-timeout/issues/18
+ # https://github.com/pytest-dev/pytest-rerunfailures/issues/99
+ args+=(
+ -o timeout_func_only=true
+ )
+ fi
fi
if [[ ${EPYTEST_XDIST} ]]; then
- local jobs=${EPYTEST_JOBS:-$(makeopts_jobs)}
+ local jobs=${EPYTEST_JOBS:-$(get_makeopts_jobs)}
if [[ ${jobs} -gt 1 ]]; then
if [[ ${PYTEST_PLUGINS} != *xdist.plugin* ]]; then
args+=(
@@ -1550,9 +1588,31 @@ epytest() {
# jobs are unevenly distributed
--dist=worksteal
)
+
+ if [[ ${MAKEFLAGS} == *--jobserver-auth=* ]]; then
+ if has_version "dev-python/pytest-jobserver[${PYTHON_USEDEP}]"
+ then
+ args+=( -p jobserver )
+ elif [[ ! ${_EPYTEST_JOBSERVER_WARNED} ]]; then
+ ewarn "Jobserver found under pytest-xdist, but cannot be used without:"
+ ewarn " dev-python/pytest-jobserver"
+ _EPYTEST_JOBSERVER_WARNED=1
+ fi
+ fi
fi
fi
+ # If we are using hypothesis (require use via EPYTEST_PLUGINS, since
+ # ebuilds may disable autoloading manually) *and* hypothesis-gentoo
+ # is available, use it to disable all health checks, to prevent the tests
+ # from failing randomly under load.
+ if has hypothesis "${EPYTEST_PLUGINS[@]}" &&
+ "${EPYTHON}" -c 'import hypothesis_gentoo' 2>/dev/null &&
+ [[ ! ${HYPOTHESIS_NO_PLUGINS} ]]
+ then
+ args+=( --hypothesis-profile=gentoo )
+ fi
+
local x
for x in "${EPYTEST_DESELECT[@]}"; do
args+=( --deselect "${x}" )
@@ -1562,6 +1622,9 @@ epytest() {
done
set -- "${EPYTHON}" -m pytest "${args[@]}" "${@}" ${EPYTEST_FLAGS}
+ if [[ ${PYTEST_PLUGINS} ]]; then
+ einfo "PYTEST_PLUGINS=${PYTEST_PLUGINS}"
+ fi
echo "${@}" >&2
"${@}"
local ret=${?}