summaryrefslogtreecommitdiff
path: root/eclass/python-utils-r1.eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass/python-utils-r1.eclass')
-rw-r--r--eclass/python-utils-r1.eclass148
1 files changed, 103 insertions, 45 deletions
diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass
index c47565fa1db2..555b6c561a18 100644
--- a/eclass/python-utils-r1.eclass
+++ b/eclass/python-utils-r1.eclass
@@ -23,14 +23,14 @@
# 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
-if [[ ! ${_PYTHON_UTILS_R1_ECLASS} ]]; then
-_PYTHON_UTILS_R1_ECLASS=1
-
[[ ${EAPI} == 7 ]] && inherit eapi8-dosym
inherit multiprocessing toolchain-funcs
@@ -41,6 +41,7 @@ inherit multiprocessing toolchain-funcs
_PYTHON_ALL_IMPLS=(
pypy3
python3_{10..13}
+ python3_13t
)
readonly _PYTHON_ALL_IMPLS
@@ -75,7 +76,7 @@ readonly _PYTHON_HISTORICAL_IMPLS
# 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} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
local impl pattern
for pattern; do
@@ -136,7 +137,7 @@ _python_set_impls() {
# please keep them in sync with _PYTHON_ALL_IMPLS
# and _PYTHON_HISTORICAL_IMPLS
case ${i} in
- pypy3|python3_9|python3_1[0-3])
+ pypy3|python3_9|python3_1[0-3]|python3_13t)
;;
jython2_7|pypy|pypy1_[89]|pypy2_0|python2_[5-7]|python3_[1-9])
obsolete+=( "${i}" )
@@ -232,7 +233,7 @@ _python_impl_matches() {
return 0
;;
3.8|3.9|3.1[1-3])
- [[ ${impl} == python${pattern/./_} ]] && return 0
+ [[ ${impl%t} == python${pattern/./_} ]] && return 0
;;
*)
# unify value style to allow lax matching
@@ -298,7 +299,7 @@ _python_impl_matches() {
# PYTHON_SITEDIR. They are described more completely in the eclass
# variable documentation.
_python_export() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
local impl var
@@ -332,6 +333,17 @@ _python_export() {
export PYTHON=${BROOT-${EPREFIX}}/usr/bin/${impl}
debug-print "${FUNCNAME}: PYTHON = ${PYTHON}"
;;
+ PYTHON_STDLIB)
+ [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
+ PYTHON_STDLIB=$(
+ "${PYTHON}" - "${EPREFIX}/usr" <<-EOF || die
+ import sys, sysconfig
+ print(sysconfig.get_path("stdlib", vars={"installed_base": sys.argv[1]}))
+ EOF
+ )
+ export PYTHON_STDLIB
+ debug-print "${FUNCNAME}: PYTHON_STDLIB = ${PYTHON_STDLIB}"
+ ;;
PYTHON_SITEDIR)
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
PYTHON_SITEDIR=$(
@@ -424,7 +436,7 @@ _python_export() {
or "")
EOF
)
- val=${PYTHON}${flags}-config
+ val=${PYTHON%t}${flags}-config
;;
*)
die "${impl}: obtaining ${var} not supported"
@@ -466,6 +478,18 @@ _python_export() {
done
}
+# @FUNCTION: python_get_stdlib
+# @USAGE: [<impl>]
+# @DESCRIPTION:
+# Obtain and print the 'stdlib' path for the given implementation. If no
+# implementation is provided, ${EPYTHON} will be used.
+python_get_stdlib() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ _python_export "${@}" PYTHON_STDLIB
+ echo "${PYTHON_STDLIB}"
+}
+
# @FUNCTION: python_get_sitedir
# @USAGE: [<impl>]
# @DESCRIPTION:
@@ -473,7 +497,7 @@ _python_export() {
# implementation. If no implementation is provided, ${EPYTHON} will
# be used.
python_get_sitedir() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_SITEDIR
echo "${PYTHON_SITEDIR}"
@@ -485,7 +509,7 @@ python_get_sitedir() {
# Obtain and print the include path for the given implementation. If no
# implementation is provided, ${EPYTHON} will be used.
python_get_includedir() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_INCLUDEDIR
echo "${PYTHON_INCLUDEDIR}"
@@ -500,7 +524,7 @@ python_get_includedir() {
# Please note that this function can be used with CPython only. Use
# in another implementation will result in a fatal failure.
python_get_library_path() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_LIBPATH
echo "${PYTHON_LIBPATH}"
@@ -517,7 +541,7 @@ python_get_library_path() {
# It requires Python and pkg-config installed, and therefore proper
# build-time dependencies need be added to the ebuild.
python_get_CFLAGS() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_CFLAGS
echo "${PYTHON_CFLAGS}"
@@ -534,7 +558,7 @@ python_get_CFLAGS() {
# It requires Python and pkg-config installed, and therefore proper
# build-time dependencies need be added to the ebuild.
python_get_LIBS() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_LIBS
echo "${PYTHON_LIBS}"
@@ -551,7 +575,7 @@ python_get_LIBS() {
# It requires Python installed, and therefore proper build-time
# dependencies need be added to the ebuild.
python_get_PYTHON_CONFIG() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_CONFIG
echo "${PYTHON_CONFIG}"
@@ -564,7 +588,7 @@ python_get_PYTHON_CONFIG() {
# implementation. If no implementation is provided, ${EPYTHON} will
# be used.
python_get_scriptdir() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_export "${@}" PYTHON_SCRIPTDIR
echo "${PYTHON_SCRIPTDIR}"
@@ -577,7 +601,7 @@ python_get_scriptdir() {
# paths). If no directories are provided, the default system paths
# are used (prepended with ${D}).
python_optimize() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
@@ -594,8 +618,8 @@ python_optimize() {
# 2) skip paths which do not exist
# (python2.6 complains about them verbosely)
- if [[ ${f} == /* && -d ${D%/}${f} ]]; then
- set -- "${D%/}${f}" "${@}"
+ if [[ ${f} == /* && -d ${D}${f} ]]; then
+ set -- "${D}${f}" "${@}"
fi
done < <(
"${PYTHON}" - <<-EOF || die
@@ -611,7 +635,7 @@ python_optimize() {
local d
for d; do
# make sure to get a nice path without //
- local instpath=${d#${D%/}}
+ local instpath=${d#${D}}
instpath=/${instpath##/}
einfo "Optimize Python modules for ${instpath}"
@@ -654,7 +678,7 @@ python_optimize() {
# }
# @CODE
python_scriptinto() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_PYTHON_SCRIPTROOT=${1}
}
@@ -668,7 +692,7 @@ python_scriptinto() {
# The executable will be wrapped properly for the Python implementation,
# though no shebang mangling will be performed.
python_doexe() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EBUILD_PHASE} != install ]] &&
die "${FUNCNAME} can only be used in src_install"
@@ -689,7 +713,7 @@ python_doexe() {
# though no shebang mangling will be performed. It will be renamed
# to <new-name>.
python_newexe() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EBUILD_PHASE} != install ]] &&
die "${FUNCNAME} can only be used in src_install"
@@ -718,7 +742,7 @@ python_newexe() {
# don't use this at home, just call python_doscript() instead
if [[ ${_PYTHON_REWRITE_SHEBANG} ]]; then
- python_fix_shebang -q "${ED%/}/${d}/${newfn}"
+ python_fix_shebang -q "${ED}${d}/${newfn}"
fi
}
@@ -739,7 +763,7 @@ python_newexe() {
# }
# @CODE
python_doscript() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EBUILD_PHASE} != install ]] &&
die "${FUNCNAME} can only be used in src_install"
@@ -766,7 +790,7 @@ python_doscript() {
# }
# @CODE
python_newscript() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EBUILD_PHASE} != install ]] &&
die "${FUNCNAME} can only be used in src_install"
@@ -804,7 +828,7 @@ python_newscript() {
# }
# @CODE
python_moduleinto() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_PYTHON_MODULEROOT=${1}
}
@@ -829,7 +853,7 @@ python_moduleinto() {
# }
# @CODE
python_domodule() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
@@ -849,15 +873,15 @@ python_domodule() {
insinto "${d}"
doins -r "${@}" || return ${?}
)
- python_optimize "${ED%/}/${d}"
+ python_optimize "${ED}${d}"
elif [[ -n ${BUILD_DIR} ]]; then
local dest=${BUILD_DIR}/install${EPREFIX}/${d}
mkdir -p "${dest}" || die
cp -pR "${@}" "${dest}/" || die
(
- cd "${dest}" &&
- chmod -R a+rX "${@##*/}"
- ) || die
+ cd "${dest}" || die
+ chmod -R a+rX "${@##*/}" || die
+ )
else
die "${FUNCNAME} can only be used in src_install or with BUILD_DIR set"
fi
@@ -877,7 +901,7 @@ python_domodule() {
# }
# @CODE
python_doheader() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EBUILD_PHASE} != install ]] &&
die "${FUNCNAME} can only be used in src_install"
@@ -909,7 +933,7 @@ python_doheader() {
# setup will be done. If wrapper update is requested, the directory
# shall be removed first.
_python_wrapper_setup() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
local workdir=${1:-${T}/${EPYTHON}}
local impl=${2:-${EPYTHON}}
@@ -1011,7 +1035,7 @@ _python_wrapper_setup() {
# Python version (but not non-Python shebangs). --quiet causes
# the function not to list modified files verbosely.
python_fix_shebang() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)"
@@ -1080,17 +1104,17 @@ python_fix_shebang() {
fi
if [[ ! ${quiet} ]]; then
- einfo "Fixing shebang in ${f#${D%/}}."
+ einfo "Fixing shebang in ${f#${D}}."
fi
if [[ ! ${error} ]]; then
- debug-print "${FUNCNAME}: in file ${f#${D%/}}"
+ debug-print "${FUNCNAME}: in file ${f#${D}}"
debug-print "${FUNCNAME}: rewriting shebang: ${shebang}"
sed -i -e "1s@${from}@#!${EPREFIX}/usr/bin/${EPYTHON}@" "${f}" || die
any_fixed=1
else
eerror "The file has incompatible shebang:"
- eerror " file: ${f#${D%/}}"
+ eerror " file: ${f#${D}}"
eerror " current shebang: ${shebang}"
eerror " requested impl: ${EPYTHON}"
die "${FUNCNAME}: conversion of incompatible shebang requested"
@@ -1098,7 +1122,7 @@ python_fix_shebang() {
done < <(find -H "${path}" -type f -print0 || die)
if [[ ! ${any_fixed} ]]; then
- eerror "QA error: ${FUNCNAME}, ${path#${D%/}} did not match any fixable files."
+ eerror "QA error: ${FUNCNAME}, ${path#${D}} did not match any fixable files."
eerror "There are no Python files in specified directory."
die "${FUNCNAME} did not match any fixable files"
fi
@@ -1131,7 +1155,7 @@ _python_check_locale_sanity() {
# nothing if LC_ALL is defined, or if the current locale uses a UTF-8 charmap.
# This may be used to work around the quirky open() behavior of python3.
python_export_utf8_locale() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
# If the locale program isn't available, just return.
type locale &>/dev/null || return 0
@@ -1183,7 +1207,7 @@ python_export_utf8_locale() {
# to be taken to run einstalldocs from the same directory
# (usually ${S}).
build_sphinx() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ ${#} -eq 1 ]] || die "${FUNCNAME} takes 1 arg: <directory>"
local dir=${1}
@@ -1229,7 +1253,7 @@ _python_check_EPYTHON() {
# package sources that would block installed packages from being used
# (and effectively e.g. make it impossible to load compiled extensions).
_python_check_occluded_packages() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
[[ -z ${BUILD_DIR} || ! -d ${BUILD_DIR}/install ]] && return
@@ -1339,7 +1363,7 @@ _python_check_occluded_packages() {
#
# This command dies on failure and respects nonfatal.
epytest() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_check_EPYTHON
_python_check_occluded_packages
@@ -1467,7 +1491,7 @@ epytest() {
#
# This command dies on failure and respects nonfatal.
eunittest() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
_python_check_EPYTHON
_python_check_occluded_packages
@@ -1492,7 +1516,7 @@ eunittest() {
# code. Checks whether the interpreter is installed, runs
# python_check_deps() if declared.
_python_run_check_deps() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
local impl=${1}
@@ -1524,7 +1548,7 @@ _python_run_check_deps() {
# The wrapper accepts multiple package specifications. For the check
# to succeed, *all* specified atoms must match.
python_has_version() {
- debug-print-function ${FUNCNAME} "${@}"
+ debug-print-function ${FUNCNAME} "$@"
local root_arg=( -b )
case ${1} in
@@ -1544,4 +1568,38 @@ python_has_version() {
return 0
}
+# @FUNCTION: _python_sanity_checks
+# @INTERNAL
+# @DESCRIPTION:
+# Perform additional environment sanity checks.
+_python_sanity_checks() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ [[ ${_PYTHON_SANITY_CHECKED} ]] && return
+
+ if [[ -v PYTHONPATH ]]; then
+ local x paths=()
+ mapfile -d ':' -t paths <<<${PYTHONPATH}
+
+ for x in "${paths[@]}"; do
+ if [[ ${x} != /* ]]; then
+ eerror "Relative path found in PYTHONPATH:"
+ eerror
+ eerror " PYTHONPATH=${PYTHONPATH@Q}"
+ eerror
+ eerror "This is guaranteed to cause random breakage. Please make sure that"
+ eerror "your PYTHONPATH contains absolute paths only (and only if necessary)."
+ eerror "Note that empty values (including ':' at either end and an empty"
+ eerror "PYTHONPATH) count as the current directory. If no PYTHONPATH"
+ eerror "is intended, it needs to be unset instead."
+ die "Relative paths in PYTHONPATH are forbidden: ${x@Q}"
+ fi
+ done
+
+ elog "PYTHONPATH=${PYTHONPATH@Q}"
+ fi
+
+ _PYTHON_SANITY_CHECKED=1
+}
+
fi