mirror of
https://github.com/flatcar/scripts.git
synced 2025-09-30 18:12:08 +02:00
eclass/python-utils-r1: Sync with Gentoo
It's from Gentoo commit 607b95b7a1245b02224486e6871b783c5e858500.
This commit is contained in:
parent
e33bbd547f
commit
2f4804d78c
@ -1,4 +1,4 @@
|
|||||||
# Copyright 1999-2021 Gentoo Authors
|
# Copyright 1999-2022 Gentoo Authors
|
||||||
# Distributed under the terms of the GNU General Public License v2
|
# Distributed under the terms of the GNU General Public License v2
|
||||||
|
|
||||||
# @ECLASS: python-utils-r1.eclass
|
# @ECLASS: python-utils-r1.eclass
|
||||||
@ -17,7 +17,7 @@
|
|||||||
# functions. It can be inherited safely.
|
# functions. It can be inherited safely.
|
||||||
#
|
#
|
||||||
# For more information, please see the Python Guide:
|
# For more information, please see the Python Guide:
|
||||||
# https://dev.gentoo.org/~mgorny/python-guide/
|
# https://projects.gentoo.org/python/guide/
|
||||||
|
|
||||||
# NOTE: When dropping support for EAPIs here, we need to update
|
# NOTE: When dropping support for EAPIs here, we need to update
|
||||||
# metadata/install-qa-check.d/60python-pyc
|
# metadata/install-qa-check.d/60python-pyc
|
||||||
@ -37,17 +37,17 @@ if [[ ! ${_PYTHON_UTILS_R1} ]]; then
|
|||||||
[[ ${EAPI} == [67] ]] && inherit eapi8-dosym
|
[[ ${EAPI} == [67] ]] && inherit eapi8-dosym
|
||||||
inherit multiprocessing toolchain-funcs
|
inherit multiprocessing toolchain-funcs
|
||||||
|
|
||||||
# @ECLASS-VARIABLE: _PYTHON_ALL_IMPLS
|
# @ECLASS_VARIABLE: _PYTHON_ALL_IMPLS
|
||||||
# @INTERNAL
|
# @INTERNAL
|
||||||
# @DESCRIPTION:
|
# @DESCRIPTION:
|
||||||
# All supported Python implementations, most preferred last.
|
# All supported Python implementations, most preferred last.
|
||||||
_PYTHON_ALL_IMPLS=(
|
_PYTHON_ALL_IMPLS=(
|
||||||
pypy3
|
pypy3
|
||||||
python3_{8..10}
|
python3_{8..11}
|
||||||
)
|
)
|
||||||
readonly _PYTHON_ALL_IMPLS
|
readonly _PYTHON_ALL_IMPLS
|
||||||
|
|
||||||
# @ECLASS-VARIABLE: _PYTHON_HISTORICAL_IMPLS
|
# @ECLASS_VARIABLE: _PYTHON_HISTORICAL_IMPLS
|
||||||
# @INTERNAL
|
# @INTERNAL
|
||||||
# @DESCRIPTION:
|
# @DESCRIPTION:
|
||||||
# All historical Python implementations that are no longer supported.
|
# All historical Python implementations that are no longer supported.
|
||||||
@ -59,7 +59,7 @@ _PYTHON_HISTORICAL_IMPLS=(
|
|||||||
)
|
)
|
||||||
readonly _PYTHON_HISTORICAL_IMPLS
|
readonly _PYTHON_HISTORICAL_IMPLS
|
||||||
|
|
||||||
# @ECLASS-VARIABLE: PYTHON_COMPAT_NO_STRICT
|
# @ECLASS_VARIABLE: PYTHON_COMPAT_NO_STRICT
|
||||||
# @INTERNAL
|
# @INTERNAL
|
||||||
# @DESCRIPTION:
|
# @DESCRIPTION:
|
||||||
# Set to a non-empty value in order to make eclass tolerate (ignore)
|
# Set to a non-empty value in order to make eclass tolerate (ignore)
|
||||||
@ -82,7 +82,11 @@ _python_verify_patterns() {
|
|||||||
|
|
||||||
local impl pattern
|
local impl pattern
|
||||||
for pattern; do
|
for pattern; do
|
||||||
[[ ${pattern} == -[23] ]] && continue
|
case ${pattern} in
|
||||||
|
-[23]|3.[89]|3.1[01])
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
for impl in "${_PYTHON_ALL_IMPLS[@]}" "${_PYTHON_HISTORICAL_IMPLS[@]}"
|
for impl in "${_PYTHON_ALL_IMPLS[@]}" "${_PYTHON_HISTORICAL_IMPLS[@]}"
|
||||||
do
|
do
|
||||||
@ -119,6 +123,8 @@ _python_set_impls() {
|
|||||||
if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
|
if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
|
||||||
die 'PYTHON_COMPAT must be an array.'
|
die 'PYTHON_COMPAT must be an array.'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local obsolete=()
|
||||||
if [[ ! ${PYTHON_COMPAT_NO_STRICT} ]]; then
|
if [[ ! ${PYTHON_COMPAT_NO_STRICT} ]]; then
|
||||||
for i in "${PYTHON_COMPAT[@]}"; do
|
for i in "${PYTHON_COMPAT[@]}"; do
|
||||||
# check for incorrect implementations
|
# check for incorrect implementations
|
||||||
@ -126,7 +132,10 @@ _python_set_impls() {
|
|||||||
# please keep them in sync with _PYTHON_ALL_IMPLS
|
# please keep them in sync with _PYTHON_ALL_IMPLS
|
||||||
# and _PYTHON_HISTORICAL_IMPLS
|
# and _PYTHON_HISTORICAL_IMPLS
|
||||||
case ${i} in
|
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_1[01])
|
||||||
|
;;
|
||||||
|
jython2_7|pypy|pypy1_[89]|pypy2_0|python2_[5-6]|python3_[1-7])
|
||||||
|
obsolete+=( "${i}" )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if has "${i}" "${_PYTHON_ALL_IMPLS[@]}" \
|
if has "${i}" "${_PYTHON_ALL_IMPLS[@]}" \
|
||||||
@ -140,6 +149,17 @@ _python_set_impls() {
|
|||||||
done
|
done
|
||||||
fi
|
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=()
|
local supp=() unsupp=()
|
||||||
|
|
||||||
for i in "${_PYTHON_ALL_IMPLS[@]}"; do
|
for i in "${_PYTHON_ALL_IMPLS[@]}"; do
|
||||||
@ -190,12 +210,14 @@ _python_set_impls() {
|
|||||||
# Matches if no patterns are provided.
|
# Matches if no patterns are provided.
|
||||||
#
|
#
|
||||||
# <impl> can be in PYTHON_COMPAT or EPYTHON form. The patterns
|
# <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() {
|
_python_impl_matches() {
|
||||||
[[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter"
|
[[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter"
|
||||||
[[ ${#} -eq 1 ]] && return 0
|
[[ ${#} -eq 1 ]] && return 0
|
||||||
|
|
||||||
local impl=${1} pattern
|
local impl=${1/./_} pattern
|
||||||
shift
|
shift
|
||||||
|
|
||||||
for pattern; do
|
for pattern; do
|
||||||
@ -218,9 +240,17 @@ _python_impl_matches() {
|
|||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
3.9)
|
||||||
|
# the only unmasked pypy3 version is pypy3.9 atm
|
||||||
|
[[ ${impl} == python${pattern/./_} || ${impl} == pypy3 ]] &&
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
3.8|3.1[01])
|
||||||
|
[[ ${impl} == python${pattern/./_} ]] && return 0
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
# unify value style to allow lax matching
|
# unify value style to allow lax matching
|
||||||
[[ ${impl/./_} == ${pattern/./_} ]] && return 0
|
[[ ${impl} == ${pattern/./_} ]] && return 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@ -228,7 +258,7 @@ _python_impl_matches() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# @ECLASS-VARIABLE: PYTHON
|
# @ECLASS_VARIABLE: PYTHON
|
||||||
# @DEFAULT_UNSET
|
# @DEFAULT_UNSET
|
||||||
# @DESCRIPTION:
|
# @DESCRIPTION:
|
||||||
# The absolute path to the current Python interpreter.
|
# The absolute path to the current Python interpreter.
|
||||||
@ -247,7 +277,7 @@ _python_impl_matches() {
|
|||||||
# /usr/bin/python2.7
|
# /usr/bin/python2.7
|
||||||
# @CODE
|
# @CODE
|
||||||
|
|
||||||
# @ECLASS-VARIABLE: EPYTHON
|
# @ECLASS_VARIABLE: EPYTHON
|
||||||
# @DEFAULT_UNSET
|
# @DEFAULT_UNSET
|
||||||
# @DESCRIPTION:
|
# @DESCRIPTION:
|
||||||
# The executable name of the current Python interpreter.
|
# The executable name of the current Python interpreter.
|
||||||
@ -266,23 +296,6 @@ _python_impl_matches() {
|
|||||||
# python2.7
|
# python2.7
|
||||||
# @CODE
|
# @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
|
# @FUNCTION: _python_export
|
||||||
# @USAGE: [<impl>] <variables>...
|
# @USAGE: [<impl>] <variables>...
|
||||||
# @INTERNAL
|
# @INTERNAL
|
||||||
@ -333,13 +346,23 @@ _python_export() {
|
|||||||
;;
|
;;
|
||||||
PYTHON_SITEDIR)
|
PYTHON_SITEDIR)
|
||||||
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
|
[[ -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
|
export PYTHON_SITEDIR
|
||||||
debug-print "${FUNCNAME}: PYTHON_SITEDIR = ${PYTHON_SITEDIR}"
|
debug-print "${FUNCNAME}: PYTHON_SITEDIR = ${PYTHON_SITEDIR}"
|
||||||
;;
|
;;
|
||||||
PYTHON_INCLUDEDIR)
|
PYTHON_INCLUDEDIR)
|
||||||
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
|
[[ -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
|
export PYTHON_INCLUDEDIR
|
||||||
debug-print "${FUNCNAME}: PYTHON_INCLUDEDIR = ${PYTHON_INCLUDEDIR}"
|
debug-print "${FUNCNAME}: PYTHON_INCLUDEDIR = ${PYTHON_INCLUDEDIR}"
|
||||||
|
|
||||||
@ -350,7 +373,17 @@ _python_export() {
|
|||||||
;;
|
;;
|
||||||
PYTHON_LIBPATH)
|
PYTHON_LIBPATH)
|
||||||
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
|
[[ -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
|
export PYTHON_LIBPATH
|
||||||
debug-print "${FUNCNAME}: PYTHON_LIBPATH = ${PYTHON_LIBPATH}"
|
debug-print "${FUNCNAME}: PYTHON_LIBPATH = ${PYTHON_LIBPATH}"
|
||||||
|
|
||||||
@ -400,7 +433,13 @@ _python_export() {
|
|||||||
case "${impl}" in
|
case "${impl}" in
|
||||||
python*)
|
python*)
|
||||||
[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
|
[[ -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
|
val=${PYTHON}${flags}-config
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@ -416,12 +455,20 @@ _python_export() {
|
|||||||
case ${impl} in
|
case ${impl} in
|
||||||
python2.7)
|
python2.7)
|
||||||
PYTHON_PKG_DEP='>=dev-lang/python-2.7.5-r2:2.7';;
|
PYTHON_PKG_DEP='>=dev-lang/python-2.7.5-r2:2.7';;
|
||||||
|
python3.8)
|
||||||
|
PYTHON_PKG_DEP=">=dev-lang/python-3.8.12_p1-r1:3.8";;
|
||||||
|
python3.9)
|
||||||
|
PYTHON_PKG_DEP=">=dev-lang/python-3.9.9-r1:3.9";;
|
||||||
|
python3.10)
|
||||||
|
PYTHON_PKG_DEP=">=dev-lang/python-3.10.0_p1-r1:3.10";;
|
||||||
|
python3.11)
|
||||||
|
PYTHON_PKG_DEP=">=dev-lang/python-3.11.0_beta1-r1:3.11";;
|
||||||
python*)
|
python*)
|
||||||
PYTHON_PKG_DEP="dev-lang/python:${impl#python}";;
|
PYTHON_PKG_DEP="dev-lang/python:${impl#python}";;
|
||||||
pypy)
|
pypy)
|
||||||
PYTHON_PKG_DEP='>=dev-python/pypy-7.3.0:0=';;
|
PYTHON_PKG_DEP='>=dev-python/pypy-7.3.0:0=';;
|
||||||
pypy3)
|
pypy3)
|
||||||
PYTHON_PKG_DEP='>=dev-python/pypy3-7.3.7:0=';;
|
PYTHON_PKG_DEP='>=dev-python/pypy3-7.3.7-r1:0=';;
|
||||||
*)
|
*)
|
||||||
die "Invalid implementation: ${impl}"
|
die "Invalid implementation: ${impl}"
|
||||||
esac
|
esac
|
||||||
@ -558,15 +605,6 @@ python_get_scriptdir() {
|
|||||||
python_optimize() {
|
python_optimize() {
|
||||||
debug-print-function ${FUNCNAME} "${@}"
|
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).'
|
[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
|
||||||
|
|
||||||
local PYTHON=${PYTHON}
|
local PYTHON=${PYTHON}
|
||||||
@ -585,20 +623,24 @@ python_optimize() {
|
|||||||
if [[ ${f} == /* && -d ${D%/}${f} ]]; then
|
if [[ ${f} == /* && -d ${D%/}${f} ]]; then
|
||||||
set -- "${D%/}${f}" "${@}"
|
set -- "${D%/}${f}" "${@}"
|
||||||
fi
|
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: ${*/%/;}"
|
debug-print "${FUNCNAME}: using sys.path: ${*/%/;}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local jobs=$(makeopts_jobs "${MAKEOPTS}" INF)
|
local jobs=$(makeopts_jobs)
|
||||||
[[ ${jobs} == INF ]] && jobs=$(get_nproc)
|
|
||||||
|
|
||||||
local d
|
local d
|
||||||
for d; do
|
for d; do
|
||||||
# make sure to get a nice path without //
|
# make sure to get a nice path without //
|
||||||
local instpath=${d#${D%/}}
|
local instpath=${d#${D%/}}
|
||||||
instpath=/${instpath##/}
|
instpath=/${instpath##/}
|
||||||
|
|
||||||
|
einfo "Optimize Python modules for ${instpath}"
|
||||||
case "${EPYTHON}" in
|
case "${EPYTHON}" in
|
||||||
python2.7|python3.[34])
|
python2.7|python3.[34])
|
||||||
"${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}"
|
"${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}"
|
||||||
@ -849,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
|
# @FUNCTION: _python_wrapper_setup
|
||||||
# @USAGE: [<path> [<impl>]]
|
# @USAGE: [<path> [<impl>]]
|
||||||
# @INTERNAL
|
# @INTERNAL
|
||||||
@ -972,63 +998,33 @@ _python_wrapper_setup() {
|
|||||||
export PATH PKG_CONFIG_PATH
|
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
|
# @FUNCTION: python_fix_shebang
|
||||||
# @USAGE: [-f|--force] [-q|--quiet] <path>...
|
# @USAGE: [-f|--force] [-q|--quiet] <path>...
|
||||||
# @DESCRIPTION:
|
# @DESCRIPTION:
|
||||||
# Replace the shebang in Python scripts with the current Python
|
# Replace the shebang in Python scripts with the full path
|
||||||
# implementation (EPYTHON). If a directory is passed, works recursively
|
# to the current Python implementation (PYTHON, including EPREFIX).
|
||||||
# on all Python scripts.
|
# If a directory is passed, works recursively on all Python scripts
|
||||||
|
# found inside the directory tree.
|
||||||
#
|
#
|
||||||
# Only files having a 'python*' shebang will be modified. Files with
|
# Only files having a Python shebang (a path to any known Python
|
||||||
# other shebang will either be skipped when working recursively
|
# interpreter, optionally preceded by env(1) invocation) will
|
||||||
# on a directory or treated as error when specified explicitly.
|
# be processed. Files with any other shebang will either be skipped
|
||||||
|
# silently when a directory was passed, or an error will be reported
|
||||||
|
# for any files without Python shebangs specified explicitly.
|
||||||
#
|
#
|
||||||
# Shebangs matching explicitly current Python version will be left
|
# Shebangs that are compatible with the current Python version will be
|
||||||
# unmodified. Shebangs requesting another Python version will be treated
|
# mangled unconditionally. Incompatible shebangs will cause a fatal
|
||||||
# as fatal error, unless --force is given.
|
# error, unless --force is specified.
|
||||||
#
|
#
|
||||||
# --force causes the function to replace even shebangs that require
|
# --force causes the function to replace shebangs with incompatible
|
||||||
# incompatible Python version. --quiet causes the function not to list
|
# Python version (but not non-Python shebangs). --quiet causes
|
||||||
# modified files verbosely.
|
# the function not to list modified files verbosely.
|
||||||
python_fix_shebang() {
|
python_fix_shebang() {
|
||||||
debug-print-function ${FUNCNAME} "${@}"
|
debug-print-function ${FUNCNAME} "${@}"
|
||||||
|
|
||||||
[[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)"
|
[[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)"
|
||||||
|
local PYTHON
|
||||||
|
_python_export "${EPYTHON}" PYTHON
|
||||||
|
|
||||||
local force quiet
|
local force quiet
|
||||||
while [[ ${@} ]]; do
|
while [[ ${@} ]]; do
|
||||||
@ -1044,13 +1040,13 @@ python_fix_shebang() {
|
|||||||
|
|
||||||
local path f
|
local path f
|
||||||
for path; do
|
for path; do
|
||||||
local any_correct any_fixed is_recursive
|
local any_fixed is_recursive
|
||||||
|
|
||||||
[[ -d ${path} ]] && is_recursive=1
|
[[ -d ${path} ]] && is_recursive=1
|
||||||
|
|
||||||
while IFS= read -r -d '' f; do
|
while IFS= read -r -d '' f; do
|
||||||
local shebang i
|
local shebang i
|
||||||
local error= from=
|
local error= match=
|
||||||
|
|
||||||
# note: we can't ||die here since read will fail if file
|
# note: we can't ||die here since read will fail if file
|
||||||
# has no newline characters
|
# has no newline characters
|
||||||
@ -1059,64 +1055,36 @@ python_fix_shebang() {
|
|||||||
# First, check if it's shebang at all...
|
# First, check if it's shebang at all...
|
||||||
if [[ ${shebang} == '#!'* ]]; then
|
if [[ ${shebang} == '#!'* ]]; then
|
||||||
local split_shebang=()
|
local split_shebang=()
|
||||||
read -r -a split_shebang <<<${shebang} || die
|
read -r -a split_shebang <<<${shebang#"#!"} || die
|
||||||
|
|
||||||
# Match left-to-right in a loop, to avoid matching random
|
local in_path=${split_shebang[0]}
|
||||||
# repetitions like 'python2.7 python2'.
|
local from='^#! *[^ ]*'
|
||||||
for i in "${split_shebang[@]}"; do
|
# if the first component is env(1), skip it
|
||||||
case "${i}" in
|
if [[ ${in_path} == */env ]]; then
|
||||||
*"${EPYTHON}")
|
in_path=${split_shebang[1]}
|
||||||
debug-print "${FUNCNAME}: in file ${f#${D%/}}"
|
from+=' *[^ ]*'
|
||||||
debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}"
|
fi
|
||||||
|
|
||||||
# Nothing to do, move along.
|
case ${in_path##*/} in
|
||||||
any_correct=1
|
"${EPYTHON}")
|
||||||
from=${EPYTHON}
|
match=1
|
||||||
break
|
;;
|
||||||
;;
|
python|python[23])
|
||||||
*python|*python[23])
|
match=1
|
||||||
debug-print "${FUNCNAME}: in file ${f#${D%/}}"
|
[[ ${in_path##*/} == python2 ]] && error=1
|
||||||
debug-print "${FUNCNAME}: rewriting shebang: ${shebang}"
|
;;
|
||||||
|
python[23].[0-9]|python3.[1-9][0-9]|pypy|pypy3|jython[23].[0-9])
|
||||||
if [[ ${i} == *python2 ]]; then
|
# Explicit mismatch.
|
||||||
from=python2
|
match=1
|
||||||
if [[ ! ${force} ]]; then
|
error=1
|
||||||
error=1
|
;;
|
||||||
fi
|
esac
|
||||||
elif [[ ${i} == *python3 ]]; then
|
|
||||||
from=python3
|
|
||||||
else
|
|
||||||
from=python
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*python[23].[0-9]|*python3.[1-9][0-9]|*pypy|*pypy3|*jython[23].[0-9])
|
|
||||||
# Explicit mismatch.
|
|
||||||
if [[ ! ${force} ]]; then
|
|
||||||
error=1
|
|
||||||
else
|
|
||||||
case "${i}" in
|
|
||||||
*python[23].[0-9])
|
|
||||||
from="python[23].[0-9]";;
|
|
||||||
*python3.[1-9][0-9])
|
|
||||||
from="python3.[1-9][0-9]";;
|
|
||||||
*pypy)
|
|
||||||
from="pypy";;
|
|
||||||
*pypy3)
|
|
||||||
from="pypy3";;
|
|
||||||
*jython[23].[0-9])
|
|
||||||
from="jython[23].[0-9]";;
|
|
||||||
*)
|
|
||||||
die "${FUNCNAME}: internal error in 2nd pattern match";;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! ${error} && ! ${from} ]]; then
|
# disregard mismatches in force mode
|
||||||
|
[[ ${force} ]] && error=
|
||||||
|
|
||||||
|
if [[ ! ${match} ]]; then
|
||||||
# Non-Python shebang. Allowed in recursive mode,
|
# Non-Python shebang. Allowed in recursive mode,
|
||||||
# disallowed when specifying file explicitly.
|
# disallowed when specifying file explicitly.
|
||||||
[[ ${is_recursive} ]] && continue
|
[[ ${is_recursive} ]] && continue
|
||||||
@ -1128,13 +1096,9 @@ python_fix_shebang() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! ${error} ]]; then
|
if [[ ! ${error} ]]; then
|
||||||
# We either want to match ${from} followed by space
|
debug-print "${FUNCNAME}: in file ${f#${D%/}}"
|
||||||
# or at end-of-string.
|
debug-print "${FUNCNAME}: rewriting shebang: ${shebang}"
|
||||||
if [[ ${shebang} == *${from}" "* ]]; then
|
sed -i -e "1s@${from}@#!${PYTHON}@" "${f}" || die
|
||||||
sed -i -e "1s:${from} :${EPYTHON} :" "${f}" || die
|
|
||||||
else
|
|
||||||
sed -i -e "1s:${from}$:${EPYTHON}:" "${f}" || die
|
|
||||||
fi
|
|
||||||
any_fixed=1
|
any_fixed=1
|
||||||
else
|
else
|
||||||
eerror "The file has incompatible shebang:"
|
eerror "The file has incompatible shebang:"
|
||||||
@ -1147,12 +1111,7 @@ python_fix_shebang() {
|
|||||||
|
|
||||||
if [[ ! ${any_fixed} ]]; then
|
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."
|
||||||
if [[ ${any_correct} ]]; then
|
eerror "There are no Python files in specified directory."
|
||||||
eerror "All files have ${EPYTHON} shebang already."
|
|
||||||
else
|
|
||||||
eerror "There are no Python files in specified directory."
|
|
||||||
fi
|
|
||||||
|
|
||||||
die "${FUNCNAME} did not match any fixable files"
|
die "${FUNCNAME} did not match any fixable files"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -1187,7 +1146,7 @@ python_export_utf8_locale() {
|
|||||||
debug-print-function ${FUNCNAME} "${@}"
|
debug-print-function ${FUNCNAME} "${@}"
|
||||||
|
|
||||||
# If the locale program isn't available, just return.
|
# 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
|
if [[ $(locale charmap) != UTF-8 ]]; then
|
||||||
# Try English first, then everything else.
|
# Try English first, then everything else.
|
||||||
@ -1243,9 +1202,24 @@ build_sphinx() {
|
|||||||
|
|
||||||
sed -i -e 's:^intersphinx_mapping:disabled_&:' \
|
sed -i -e 's:^intersphinx_mapping:disabled_&:' \
|
||||||
"${dir}"/conf.py || die
|
"${dir}"/conf.py || die
|
||||||
# not all packages include the Makefile in pypi tarball
|
# 1. not all packages include the Makefile in pypi tarball,
|
||||||
sphinx-build -b html -d "${dir}"/_build/doctrees "${dir}" \
|
# so we call sphinx-build directly
|
||||||
"${dir}"/_build/html || die
|
# 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/." )
|
HTML_DOCS+=( "${dir}/_build/html/." )
|
||||||
}
|
}
|
||||||
@ -1291,6 +1265,16 @@ epytest() {
|
|||||||
|
|
||||||
_python_check_EPYTHON
|
_python_check_EPYTHON
|
||||||
|
|
||||||
|
local color
|
||||||
|
case ${NOCOLOR} in
|
||||||
|
true|yes)
|
||||||
|
color=no
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
color=yes
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
local args=(
|
local args=(
|
||||||
# verbose progress reporting and tracebacks
|
# verbose progress reporting and tracebacks
|
||||||
-vv
|
-vv
|
||||||
@ -1302,6 +1286,22 @@ epytest() {
|
|||||||
# override filterwarnings=error, we do not really want -Werror
|
# override filterwarnings=error, we do not really want -Werror
|
||||||
# for end users, as it tends to fail on new warnings from deps
|
# for end users, as it tends to fail on new warnings from deps
|
||||||
-Wdefault
|
-Wdefault
|
||||||
|
# override color output
|
||||||
|
"--color=${color}"
|
||||||
|
# count is more precise when we're dealing with a large number
|
||||||
|
# of tests
|
||||||
|
-o console_output_style=count
|
||||||
|
# disable the undesirable-dependency plugins by default to
|
||||||
|
# trigger missing argument strips. strip options that require
|
||||||
|
# them from config files. enable them explicitly via "-p ..."
|
||||||
|
# if you *really* need them.
|
||||||
|
-p no:cov
|
||||||
|
-p no:flake8
|
||||||
|
-p no:flakes
|
||||||
|
-p no:pylint
|
||||||
|
# sterilize pytest-markdown as it runs code snippets from all
|
||||||
|
# *.md files found without any warning
|
||||||
|
-p no:markdown
|
||||||
)
|
)
|
||||||
local x
|
local x
|
||||||
for x in "${EPYTEST_DESELECT[@]}"; do
|
for x in "${EPYTEST_DESELECT[@]}"; do
|
||||||
@ -1341,5 +1341,77 @@ eunittest() {
|
|||||||
return ${?}
|
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
|
_PYTHON_UTILS_R1=1
|
||||||
fi
|
fi
|
||||||
|
Loading…
x
Reference in New Issue
Block a user