summaryrefslogtreecommitdiff
path: root/eclass/python-utils-r1.eclass
diff options
context:
space:
mode:
authorV3n3RiX <venerix@koprulu.sector>2022-03-20 00:40:44 +0000
committerV3n3RiX <venerix@koprulu.sector>2022-03-20 00:40:44 +0000
commit4cbcc855382a06088e2f016f62cafdbcb7e40665 (patch)
tree356496503d52354aa6d9f2d36126302fed5f3a73 /eclass/python-utils-r1.eclass
parentfcc5224904648a8e6eb528d7603154160a20022f (diff)
gentoo resync : 20.03.2022
Diffstat (limited to 'eclass/python-utils-r1.eclass')
-rw-r--r--eclass/python-utils-r1.eclass255
1 files changed, 163 insertions, 92 deletions
diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass
index c8367f8065f4..5f8c49298090 100644
--- a/eclass/python-utils-r1.eclass
+++ b/eclass/python-utils-r1.eclass
@@ -82,7 +82,11 @@ _python_verify_patterns() {
local impl pattern
for pattern; do
- [[ ${pattern} == -[23] ]] && continue
+ case ${pattern} in
+ -[23]|3.[89]|3.10)
+ continue
+ ;;
+ esac
for impl in "${_PYTHON_ALL_IMPLS[@]}" "${_PYTHON_HISTORICAL_IMPLS[@]}"
do
@@ -119,6 +123,8 @@ _python_set_impls() {
if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
die 'PYTHON_COMPAT must be an array.'
fi
+
+ local obsolete=()
if [[ ! ${PYTHON_COMPAT_NO_STRICT} ]]; then
for i in "${PYTHON_COMPAT[@]}"; do
# check for incorrect implementations
@@ -126,7 +132,10 @@ _python_set_impls() {
# please keep them in sync with _PYTHON_ALL_IMPLS
# and _PYTHON_HISTORICAL_IMPLS
case ${i} in
- jython2_7|pypy|pypy1_[89]|pypy2_0|pypy3|python2_[5-7]|python3_[1-9]|python3_10)
+ pypy3|python2_7|python3_[89]|python3_10)
+ ;;
+ jython2_7|pypy|pypy1_[89]|pypy2_0|python2_[5-6]|python3_[1-7])
+ obsolete+=( "${i}" )
;;
*)
if has "${i}" "${_PYTHON_ALL_IMPLS[@]}" \
@@ -140,6 +149,17 @@ _python_set_impls() {
done
fi
+ if [[ -n ${obsolete[@]} && ${EBUILD_PHASE} == setup ]]; then
+ # complain if people don't clean up old impls while touching
+ # the ebuilds recently. use the copyright year to infer last
+ # modification
+ # NB: this check doesn't have to work reliably
+ if [[ $(head -n 1 "${EBUILD}" 2>/dev/null) == *2022* ]]; then
+ eqawarn "Please clean PYTHON_COMPAT of obsolete implementations:"
+ eqawarn " ${obsolete[*]}"
+ fi
+ fi
+
local supp=() unsupp=()
for i in "${_PYTHON_ALL_IMPLS[@]}"; do
@@ -190,12 +210,14 @@ _python_set_impls() {
# Matches if no patterns are provided.
#
# <impl> can be in PYTHON_COMPAT or EPYTHON form. The patterns
-# are fnmatch-style.
+# can either be fnmatch-style or stdlib versions, e.g. "3.8", "3.9".
+# In the latter case, pypy3 will match if there is at least one pypy3
+# version matching the stdlib version.
_python_impl_matches() {
[[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter"
[[ ${#} -eq 1 ]] && return 0
- local impl=${1} pattern
+ local impl=${1/./_} pattern
shift
for pattern; do
@@ -218,9 +240,17 @@ _python_impl_matches() {
fi
return 0
;;
+ 3.8)
+ # the only unmasked pypy3 version is pypy3.8 atm
+ [[ ${impl} == python${pattern/./_} || ${impl} == pypy3 ]] &&
+ return 0
+ ;;
+ 3.9|3.10)
+ [[ ${impl} == python${pattern/./_} ]] && return 0
+ ;;
*)
# unify value style to allow lax matching
- [[ ${impl/./_} == ${pattern/./_} ]] && return 0
+ [[ ${impl} == ${pattern/./_} ]] && return 0
;;
esac
done
@@ -266,23 +296,6 @@ _python_impl_matches() {
# python2.7
# @CODE
-# @FUNCTION: python_export
-# @USAGE: [<impl>] <variables>...
-# @INTERNAL
-# @DESCRIPTION:
-# Backwards compatibility function. The relevant API is now considered
-# private, please use python_get* instead.
-python_export() {
- debug-print-function ${FUNCNAME} "${@}"
-
- eqawarn "python_export() is part of private eclass API."
- eqawarn "Please call python_get*() instead."
-
- [[ ${EAPI} == [67] ]] || die "${FUNCNAME} banned in EAPI ${EAPI}"
-
- _python_export "${@}"
-}
-
# @FUNCTION: _python_export
# @USAGE: [<impl>] <variables>...
# @INTERNAL
@@ -333,13 +346,23 @@ _python_export() {
;;
PYTHON_SITEDIR)
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
- PYTHON_SITEDIR=$("${PYTHON}" -c 'import sysconfig; print(sysconfig.get_path("purelib"))') || die
+ PYTHON_SITEDIR=$(
+ "${PYTHON}" - <<-EOF || die
+ import sysconfig
+ print(sysconfig.get_path("purelib"))
+ EOF
+ )
export PYTHON_SITEDIR
debug-print "${FUNCNAME}: PYTHON_SITEDIR = ${PYTHON_SITEDIR}"
;;
PYTHON_INCLUDEDIR)
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
- PYTHON_INCLUDEDIR=$("${PYTHON}" -c 'import sysconfig; print(sysconfig.get_path("platinclude"))') || die
+ PYTHON_INCLUDEDIR=$(
+ "${PYTHON}" - <<-EOF || die
+ import sysconfig
+ print(sysconfig.get_path("platinclude"))
+ EOF
+ )
export PYTHON_INCLUDEDIR
debug-print "${FUNCNAME}: PYTHON_INCLUDEDIR = ${PYTHON_INCLUDEDIR}"
@@ -350,7 +373,17 @@ _python_export() {
;;
PYTHON_LIBPATH)
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
- PYTHON_LIBPATH=$("${PYTHON}" -c 'import os.path, sysconfig; print(os.path.join(sysconfig.get_config_var("LIBDIR"), sysconfig.get_config_var("LDLIBRARY")) if sysconfig.get_config_var("LDLIBRARY") else "")') || die
+ PYTHON_LIBPATH=$(
+ "${PYTHON}" - <<-EOF || die
+ import os.path, sysconfig
+ print(
+ os.path.join(
+ sysconfig.get_config_var("LIBDIR"),
+ sysconfig.get_config_var("LDLIBRARY"))
+ if sysconfig.get_config_var("LDLIBRARY")
+ else "")
+ EOF
+ )
export PYTHON_LIBPATH
debug-print "${FUNCNAME}: PYTHON_LIBPATH = ${PYTHON_LIBPATH}"
@@ -400,7 +433,13 @@ _python_export() {
case "${impl}" in
python*)
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
- flags=$("${PYTHON}" -c 'import sysconfig; print(sysconfig.get_config_var("ABIFLAGS") or "")') || die
+ flags=$(
+ "${PYTHON}" - <<-EOF || die
+ import sysconfig
+ print(sysconfig.get_config_var("ABIFLAGS")
+ or "")
+ EOF
+ )
val=${PYTHON}${flags}-config
;;
*)
@@ -564,15 +603,6 @@ python_get_scriptdir() {
python_optimize() {
debug-print-function ${FUNCNAME} "${@}"
- if [[ ${EBUILD_PHASE} == pre* || ${EBUILD_PHASE} == post* ]]; then
- eerror "The new Python eclasses expect the compiled Python files to"
- eerror "be controlled by the Package Manager. For this reason,"
- eerror "the python_optimize function can be used only during src_* phases"
- eerror "(src_install most commonly) and not during pkg_* phases."
- echo
- die "python_optimize is not to be used in pre/post* phases"
- fi
-
[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
local PYTHON=${PYTHON}
@@ -591,7 +621,12 @@ python_optimize() {
if [[ ${f} == /* && -d ${D%/}${f} ]]; then
set -- "${D%/}${f}" "${@}"
fi
- done < <("${PYTHON}" -c 'import sys; print("".join(x + "\0" for x in sys.path))' || die)
+ done < <(
+ "${PYTHON}" - <<-EOF || die
+ import sys
+ print("".join(x + "\0" for x in sys.path))
+ EOF
+ )
debug-print "${FUNCNAME}: using sys.path: ${*/%/;}"
fi
@@ -605,6 +640,7 @@ python_optimize() {
local instpath=${d#${D%/}}
instpath=/${instpath##/}
+ einfo "Optimize Python modules for ${instpath}"
case "${EPYTHON}" in
python2.7|python3.[34])
"${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}"
@@ -855,22 +891,6 @@ python_doheader() {
)
}
-# @FUNCTION: python_wrapper_setup
-# @USAGE: [<path> [<impl>]]
-# @DESCRIPTION:
-# Backwards compatibility function. The relevant API is now considered
-# private, please use python_setup instead.
-python_wrapper_setup() {
- debug-print-function ${FUNCNAME} "${@}"
-
- eqawarn "python_wrapper_setup() is part of private eclass API."
- eqawarn "Please call python_setup() instead."
-
- [[ ${EAPI} == [67] ]] || die "${FUNCNAME} banned in EAPI ${EAPI}"
-
- _python_wrapper_setup "${@}"
-}
-
# @FUNCTION: _python_wrapper_setup
# @USAGE: [<path> [<impl>]]
# @INTERNAL
@@ -978,41 +998,6 @@ _python_wrapper_setup() {
export PATH PKG_CONFIG_PATH
}
-# @FUNCTION: python_is_python3
-# @USAGE: [<impl>]
-# @DESCRIPTION:
-# Check whether <impl> (or ${EPYTHON}) is a Python3k variant
-# (i.e. uses syntax and stdlib of Python 3.*).
-#
-# Returns 0 (true) if it is, 1 (false) otherwise.
-python_is_python3() {
- eqawarn "${FUNCNAME} is deprecated, as Python 2 is not supported anymore"
- [[ ${EAPI} == [67] ]] || die "${FUNCNAME} banned in EAPI ${EAPI}"
-
- local impl=${1:-${EPYTHON}}
- [[ ${impl} ]] || die "python_is_python3: no impl nor EPYTHON"
-
- [[ ${impl} == python3* || ${impl} == pypy3 ]]
-}
-
-# @FUNCTION: python_is_installed
-# @USAGE: [<impl>]
-# @DESCRIPTION:
-# Check whether the interpreter for <impl> (or ${EPYTHON}) is installed.
-# Uses has_version with a proper dependency string.
-#
-# Returns 0 (true) if it is, 1 (false) otherwise.
-python_is_installed() {
- local impl=${1:-${EPYTHON}}
- [[ ${impl} ]] || die "${FUNCNAME}: no impl nor EPYTHON"
- local hasv_args=( -b )
- [[ ${EAPI} == 6 ]] && hasv_args=( --host-root )
-
- local PYTHON_PKG_DEP
- _python_export "${impl}" PYTHON_PKG_DEP
- has_version "${hasv_args[@]}" "${PYTHON_PKG_DEP}"
-}
-
# @FUNCTION: python_fix_shebang
# @USAGE: [-f|--force] [-q|--quiet] <path>...
# @DESCRIPTION:
@@ -1193,7 +1178,7 @@ python_export_utf8_locale() {
debug-print-function ${FUNCNAME} "${@}"
# If the locale program isn't available, just return.
- type locale >/dev/null || return 0
+ type locale &>/dev/null || return 0
if [[ $(locale charmap) != UTF-8 ]]; then
# Try English first, then everything else.
@@ -1249,10 +1234,24 @@ build_sphinx() {
sed -i -e 's:^intersphinx_mapping:disabled_&:' \
"${dir}"/conf.py || die
- # not all packages include the Makefile in pypi tarball
- "${EPYTHON}" -m sphinx.cmd.build \
- -b html -d "${dir}"/_build/doctrees "${dir}" \
- "${dir}"/_build/html || die
+ # 1. not all packages include the Makefile in pypi tarball,
+ # so we call sphinx-build directly
+ # 2. if autodoc is used, we need to call sphinx via EPYTHON,
+ # to ensure that PEP 517 venv is respected
+ # 3. if autodoc is not used, then sphinx might not be installed
+ # for the current impl, so we need a fallback to sphinx-build
+ local command=( "${EPYTHON}" -m sphinx.cmd.build )
+ if ! "${EPYTHON}" -c "import sphinx.cmd.build" 2>/dev/null; then
+ command=( sphinx-build )
+ fi
+ command+=(
+ -b html
+ -d "${dir}"/_build/doctrees
+ "${dir}"
+ "${dir}"/_build/html
+ )
+ echo "${command[@]}" >&2
+ "${command[@]}" || die
HTML_DOCS+=( "${dir}/_build/html/." )
}
@@ -1368,5 +1367,77 @@ eunittest() {
return ${?}
}
+# @FUNCTION: _python_run_check_deps
+# @INTERNAL
+# @USAGE: <impl>
+# @DESCRIPTION:
+# Verify whether <impl> is an acceptable choice to run any-r1 style
+# code. Checks whether the interpreter is installed, runs
+# python_check_deps() if declared.
+_python_run_check_deps() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ local impl=${1}
+ local hasv_args=( -b )
+ [[ ${EAPI} == 6 ]] && hasv_args=( --host-root )
+
+ einfo "Checking whether ${impl} is suitable ..."
+
+ local PYTHON_PKG_DEP
+ _python_export "${impl}" PYTHON_PKG_DEP
+ ebegin " ${PYTHON_PKG_DEP}"
+ has_version "${hasv_args[@]}" "${PYTHON_PKG_DEP}"
+ eend ${?} || return 1
+ declare -f python_check_deps >/dev/null || return 0
+
+ local PYTHON_USEDEP="python_targets_${impl}(-)"
+ local PYTHON_SINGLE_USEDEP="python_single_target_${impl}(-)"
+ ebegin " python_check_deps"
+ python_check_deps
+ eend ${?}
+}
+
+# @FUNCTION: python_has_version
+# @USAGE: [-b|-d|-r] <atom>...
+# @DESCRIPTION:
+# A convenience wrapper for has_version() with verbose output and better
+# defaults for use in python_check_deps().
+#
+# The wrapper accepts EAPI 7+-style -b/-d/-r options to indicate
+# the root to perform the lookup on. Unlike has_version, the default
+# is -b. In EAPI 6, -b and -d are translated to --host-root
+# for compatibility.
+#
+# The wrapper accepts multiple package specifications. For the check
+# to succeed, *all* specified atoms must match.
+python_has_version() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ local root_arg=( -b )
+ case ${1} in
+ -b|-d|-r)
+ root_arg=( "${1}" )
+ shift
+ ;;
+ esac
+
+ if [[ ${EAPI} == 6 ]]; then
+ if [[ ${root_arg} == -r ]]; then
+ root_arg=()
+ else
+ root_arg=( --host-root )
+ fi
+ fi
+
+ local pkg
+ for pkg; do
+ ebegin " ${pkg}"
+ has_version "${root_arg[@]}" "${pkg}"
+ eend ${?} || return
+ done
+
+ return 0
+}
+
_PYTHON_UTILS_R1=1
fi