libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

python-utils-r1.eclass (41926B)


      1 # Copyright 1999-2022 Gentoo Authors
      2 # Distributed under the terms of the GNU General Public License v2
      3 
      4 # @ECLASS: python-utils-r1.eclass
      5 # @MAINTAINER:
      6 # Python team <python@gentoo.org>
      7 # @AUTHOR:
      8 # Author: Michał Górny <mgorny@gentoo.org>
      9 # Based on work of: Krzysztof Pawlik <nelchael@gentoo.org>
     10 # @SUPPORTED_EAPIS: 6 7 8
     11 # @BLURB: Utility functions for packages with Python parts.
     12 # @DESCRIPTION:
     13 # A utility eclass providing functions to query Python implementations,
     14 # install Python modules and scripts.
     15 #
     16 # This eclass does not set any metadata variables nor export any phase
     17 # functions. It can be inherited safely.
     18 #
     19 # For more information, please see the Python Guide:
     20 # https://projects.gentoo.org/python/guide/
     21 
     22 # NOTE: When dropping support for EAPIs here, we need to update
     23 # metadata/install-qa-check.d/60python-pyc
     24 # See bug #704286, bug #781878
     25 case "${EAPI:-0}" in
     26 	[0-5]) die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" ;;
     27 	[6-8]) ;;
     28 	*)     die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" ;;
     29 esac
     30 
     31 if [[ ${_PYTHON_ECLASS_INHERITED} ]]; then
     32 	die 'python-r1 suite eclasses can not be used with python.eclass.'
     33 fi
     34 
     35 if [[ ! ${_PYTHON_UTILS_R1} ]]; then
     36 
     37 [[ ${EAPI} == [67] ]] && inherit eapi8-dosym
     38 [[ ${EAPI} == 6 ]] && inherit eqawarn
     39 inherit multiprocessing toolchain-funcs
     40 
     41 # @ECLASS_VARIABLE: _PYTHON_ALL_IMPLS
     42 # @INTERNAL
     43 # @DESCRIPTION:
     44 # All supported Python implementations, most preferred last.
     45 _PYTHON_ALL_IMPLS=(
     46 	pypy3
     47 	python3_{8..11}
     48 )
     49 readonly _PYTHON_ALL_IMPLS
     50 
     51 # @ECLASS_VARIABLE: _PYTHON_HISTORICAL_IMPLS
     52 # @INTERNAL
     53 # @DESCRIPTION:
     54 # All historical Python implementations that are no longer supported.
     55 _PYTHON_HISTORICAL_IMPLS=(
     56 	jython2_7
     57 	pypy pypy1_{8,9} pypy2_0
     58 	python2_{5..7}
     59 	python3_{1..7}
     60 )
     61 readonly _PYTHON_HISTORICAL_IMPLS
     62 
     63 # @ECLASS_VARIABLE: PYTHON_COMPAT_NO_STRICT
     64 # @INTERNAL
     65 # @DESCRIPTION:
     66 # Set to a non-empty value in order to make eclass tolerate (ignore)
     67 # unknown implementations in PYTHON_COMPAT.
     68 #
     69 # This is intended to be set by the user when using ebuilds that may
     70 # have unknown (newer) implementations in PYTHON_COMPAT. The assumption
     71 # is that the ebuilds are intended to be used within multiple contexts
     72 # which can involve revisions of this eclass that support a different
     73 # set of Python implementations.
     74 
     75 # @FUNCTION: _python_verify_patterns
     76 # @USAGE: <pattern>...
     77 # @INTERNAL
     78 # @DESCRIPTION:
     79 # Verify whether the patterns passed to the eclass function are correct
     80 # (i.e. can match any valid implementation).  Dies on wrong pattern.
     81 _python_verify_patterns() {
     82 	debug-print-function ${FUNCNAME} "${@}"
     83 
     84 	local impl pattern
     85 	for pattern; do
     86 		case ${pattern} in
     87 			-[23]|3.[89]|3.1[01])
     88 				continue
     89 				;;
     90 		esac
     91 
     92 		for impl in "${_PYTHON_ALL_IMPLS[@]}" "${_PYTHON_HISTORICAL_IMPLS[@]}"
     93 		do
     94 			[[ ${impl} == ${pattern/./_} ]] && continue 2
     95 		done
     96 
     97 		die "Invalid implementation pattern: ${pattern}"
     98 	done
     99 }
    100 
    101 # @FUNCTION: _python_set_impls
    102 # @INTERNAL
    103 # @DESCRIPTION:
    104 # Check PYTHON_COMPAT for well-formedness and validity, then set
    105 # two global variables:
    106 #
    107 # - _PYTHON_SUPPORTED_IMPLS containing valid implementations supported
    108 #   by the ebuild (PYTHON_COMPAT - dead implementations),
    109 #
    110 # - and _PYTHON_UNSUPPORTED_IMPLS containing valid implementations that
    111 #   are not supported by the ebuild.
    112 #
    113 # Implementations in both variables are ordered using the pre-defined
    114 # eclass implementation ordering.
    115 #
    116 # This function must be called once in global scope by an eclass
    117 # utilizing PYTHON_COMPAT.
    118 _python_set_impls() {
    119 	local i
    120 
    121 	if ! declare -p PYTHON_COMPAT &>/dev/null; then
    122 		die 'PYTHON_COMPAT not declared.'
    123 	fi
    124 	if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
    125 		die 'PYTHON_COMPAT must be an array.'
    126 	fi
    127 
    128 	local obsolete=()
    129 	if [[ ! ${PYTHON_COMPAT_NO_STRICT} ]]; then
    130 		for i in "${PYTHON_COMPAT[@]}"; do
    131 			# check for incorrect implementations
    132 			# we're using pattern matching as an optimization
    133 			# please keep them in sync with _PYTHON_ALL_IMPLS
    134 			# and _PYTHON_HISTORICAL_IMPLS
    135 			case ${i} in
    136 				pypy3|python2_7|python3_[89]|python3_1[01])
    137 					;;
    138 				jython2_7|pypy|pypy1_[89]|pypy2_0|python2_[5-6]|python3_[1-7])
    139 					obsolete+=( "${i}" )
    140 					;;
    141 				*)
    142 					if has "${i}" "${_PYTHON_ALL_IMPLS[@]}" \
    143 						"${_PYTHON_HISTORICAL_IMPLS[@]}"
    144 					then
    145 						die "Mis-synced patterns in _python_set_impls: missing ${i}"
    146 					else
    147 						die "Invalid implementation in PYTHON_COMPAT: ${i}"
    148 					fi
    149 			esac
    150 		done
    151 	fi
    152 
    153 	if [[ -n ${obsolete[@]} && ${EBUILD_PHASE} == setup ]]; then
    154 		# complain if people don't clean up old impls while touching
    155 		# the ebuilds recently.  use the copyright year to infer last
    156 		# modification
    157 		# NB: this check doesn't have to work reliably
    158 		if [[ $(head -n 1 "${EBUILD}" 2>/dev/null) == *2022* ]]; then
    159 			eqawarn "Please clean PYTHON_COMPAT of obsolete implementations:"
    160 			eqawarn "  ${obsolete[*]}"
    161 		fi
    162 	fi
    163 
    164 	local supp=() unsupp=()
    165 
    166 	for i in "${_PYTHON_ALL_IMPLS[@]}"; do
    167 		if has "${i}" "${PYTHON_COMPAT[@]}"; then
    168 			supp+=( "${i}" )
    169 		else
    170 			unsupp+=( "${i}" )
    171 		fi
    172 	done
    173 
    174 	if [[ ! ${supp[@]} ]]; then
    175 		# special-case python2_7 for python-any-r1
    176 		if [[ ${_PYTHON_ALLOW_PY27} ]] && has python2_7 "${PYTHON_COMPAT[@]}"
    177 		then
    178 			supp+=( python2_7 )
    179 		else
    180 			die "No supported implementation in PYTHON_COMPAT."
    181 		fi
    182 	fi
    183 
    184 	if [[ ${_PYTHON_SUPPORTED_IMPLS[@]} ]]; then
    185 		# set once already, verify integrity
    186 		if [[ ${_PYTHON_SUPPORTED_IMPLS[@]} != ${supp[@]} ]]; then
    187 			eerror "Supported impls (PYTHON_COMPAT) changed between inherits!"
    188 			eerror "Before: ${_PYTHON_SUPPORTED_IMPLS[*]}"
    189 			eerror "Now   : ${supp[*]}"
    190 			die "_PYTHON_SUPPORTED_IMPLS integrity check failed"
    191 		fi
    192 		if [[ ${_PYTHON_UNSUPPORTED_IMPLS[@]} != ${unsupp[@]} ]]; then
    193 			eerror "Unsupported impls changed between inherits!"
    194 			eerror "Before: ${_PYTHON_UNSUPPORTED_IMPLS[*]}"
    195 			eerror "Now   : ${unsupp[*]}"
    196 			die "_PYTHON_UNSUPPORTED_IMPLS integrity check failed"
    197 		fi
    198 	else
    199 		_PYTHON_SUPPORTED_IMPLS=( "${supp[@]}" )
    200 		_PYTHON_UNSUPPORTED_IMPLS=( "${unsupp[@]}" )
    201 		readonly _PYTHON_SUPPORTED_IMPLS _PYTHON_UNSUPPORTED_IMPLS
    202 	fi
    203 }
    204 
    205 # @FUNCTION: _python_impl_matches
    206 # @USAGE: <impl> [<pattern>...]
    207 # @INTERNAL
    208 # @DESCRIPTION:
    209 # Check whether the specified <impl> matches at least one
    210 # of the patterns following it. Return 0 if it does, 1 otherwise.
    211 # Matches if no patterns are provided.
    212 #
    213 # <impl> can be in PYTHON_COMPAT or EPYTHON form. The patterns
    214 # can either be fnmatch-style or stdlib versions, e.g. "3.8", "3.9".
    215 # In the latter case, pypy3 will match if there is at least one pypy3
    216 # version matching the stdlib version.
    217 _python_impl_matches() {
    218 	[[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter"
    219 	[[ ${#} -eq 1 ]] && return 0
    220 
    221 	local impl=${1/./_} pattern
    222 	shift
    223 
    224 	for pattern; do
    225 		case ${pattern} in
    226 			-2|python2*|pypy)
    227 				if [[ ${EAPI} != [67] ]]; then
    228 					eerror
    229 					eerror "Python 2 is no longer supported in Gentoo, please remove Python 2"
    230 					eerror "${FUNCNAME[1]} calls."
    231 					die "Passing ${pattern} to ${FUNCNAME[1]} is banned in EAPI ${EAPI}"
    232 				fi
    233 				;;
    234 			-3)
    235 				# NB: "python3*" is fine, as "not pypy3"
    236 				if [[ ${EAPI} != [67] ]]; then
    237 					eerror
    238 					eerror "Python 2 is no longer supported in Gentoo, please remove Python 2"
    239 					eerror "${FUNCNAME[1]} calls."
    240 					die "Passing ${pattern} to ${FUNCNAME[1]} is banned in EAPI ${EAPI}"
    241 				fi
    242 				return 0
    243 				;;
    244 			3.9)
    245 				# the only unmasked pypy3 version is pypy3.9 atm
    246 				[[ ${impl} == python${pattern/./_} || ${impl} == pypy3 ]] &&
    247 					return 0
    248 				;;
    249 			3.8|3.1[01])
    250 				[[ ${impl} == python${pattern/./_} ]] && return 0
    251 				;;
    252 			*)
    253 				# unify value style to allow lax matching
    254 				[[ ${impl} == ${pattern/./_} ]] && return 0
    255 				;;
    256 		esac
    257 	done
    258 
    259 	return 1
    260 }
    261 
    262 # @ECLASS_VARIABLE: PYTHON
    263 # @DEFAULT_UNSET
    264 # @DESCRIPTION:
    265 # The absolute path to the current Python interpreter.
    266 #
    267 # This variable is set automatically in the following contexts:
    268 #
    269 # python-r1: Set in functions called by python_foreach_impl() or after
    270 # calling python_setup().
    271 #
    272 # python-single-r1: Set after calling python-single-r1_pkg_setup().
    273 #
    274 # distutils-r1: Set within any of the python sub-phase functions.
    275 #
    276 # Example value:
    277 # @CODE
    278 # /usr/bin/python2.7
    279 # @CODE
    280 
    281 # @ECLASS_VARIABLE: EPYTHON
    282 # @DEFAULT_UNSET
    283 # @DESCRIPTION:
    284 # The executable name of the current Python interpreter.
    285 #
    286 # This variable is set automatically in the following contexts:
    287 #
    288 # python-r1: Set in functions called by python_foreach_impl() or after
    289 # calling python_setup().
    290 #
    291 # python-single-r1: Set after calling python-single-r1_pkg_setup().
    292 #
    293 # distutils-r1: Set within any of the python sub-phase functions.
    294 #
    295 # Example value:
    296 # @CODE
    297 # python2.7
    298 # @CODE
    299 
    300 # @FUNCTION: _python_export
    301 # @USAGE: [<impl>] <variables>...
    302 # @INTERNAL
    303 # @DESCRIPTION:
    304 # Set and export the Python implementation-relevant variables passed
    305 # as parameters.
    306 #
    307 # The optional first parameter may specify the requested Python
    308 # implementation (either as PYTHON_TARGETS value, e.g. python2_7,
    309 # or an EPYTHON one, e.g. python2.7). If no implementation passed,
    310 # the current one will be obtained from ${EPYTHON}.
    311 #
    312 # The variables which can be exported are: PYTHON, EPYTHON,
    313 # PYTHON_SITEDIR. They are described more completely in the eclass
    314 # variable documentation.
    315 _python_export() {
    316 	debug-print-function ${FUNCNAME} "${@}"
    317 
    318 	local impl var
    319 
    320 	case "${1}" in
    321 		python*|jython*)
    322 			impl=${1/_/.}
    323 			shift
    324 			;;
    325 		pypy|pypy3)
    326 			impl=${1}
    327 			shift
    328 			;;
    329 		*)
    330 			impl=${EPYTHON}
    331 			if [[ -z ${impl} ]]; then
    332 				die "_python_export called without a python implementation and EPYTHON is unset"
    333 			fi
    334 			;;
    335 	esac
    336 	debug-print "${FUNCNAME}: implementation: ${impl}"
    337 
    338 	for var; do
    339 		case "${var}" in
    340 			EPYTHON)
    341 				export EPYTHON=${impl}
    342 				debug-print "${FUNCNAME}: EPYTHON = ${EPYTHON}"
    343 				;;
    344 			PYTHON)
    345 				export PYTHON=${EPREFIX}/usr/bin/${impl}
    346 				debug-print "${FUNCNAME}: PYTHON = ${PYTHON}"
    347 				;;
    348 			PYTHON_SITEDIR)
    349 				[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
    350 				PYTHON_SITEDIR=$(
    351 					"${PYTHON}" - <<-EOF || die
    352 						import sysconfig
    353 						print(sysconfig.get_path("purelib"))
    354 					EOF
    355 				)
    356 				export PYTHON_SITEDIR
    357 				debug-print "${FUNCNAME}: PYTHON_SITEDIR = ${PYTHON_SITEDIR}"
    358 				;;
    359 			PYTHON_INCLUDEDIR)
    360 				[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
    361 				PYTHON_INCLUDEDIR=$(
    362 					"${PYTHON}" - <<-EOF || die
    363 						import sysconfig
    364 						print(sysconfig.get_path("platinclude"))
    365 					EOF
    366 				)
    367 				export PYTHON_INCLUDEDIR
    368 				debug-print "${FUNCNAME}: PYTHON_INCLUDEDIR = ${PYTHON_INCLUDEDIR}"
    369 
    370 				# Jython gives a non-existing directory
    371 				if [[ ! -d ${PYTHON_INCLUDEDIR} ]]; then
    372 					die "${impl} does not install any header files!"
    373 				fi
    374 				;;
    375 			PYTHON_LIBPATH)
    376 				[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
    377 				PYTHON_LIBPATH=$(
    378 					"${PYTHON}" - <<-EOF || die
    379 						import os.path, sysconfig
    380 						print(
    381 							os.path.join(
    382 								sysconfig.get_config_var("LIBDIR"),
    383 								sysconfig.get_config_var("LDLIBRARY"))
    384 							if sysconfig.get_config_var("LDLIBRARY")
    385 							else "")
    386 					EOF
    387 				)
    388 				export PYTHON_LIBPATH
    389 				debug-print "${FUNCNAME}: PYTHON_LIBPATH = ${PYTHON_LIBPATH}"
    390 
    391 				if [[ ! ${PYTHON_LIBPATH} ]]; then
    392 					die "${impl} lacks a (usable) dynamic library"
    393 				fi
    394 				;;
    395 			PYTHON_CFLAGS)
    396 				local val
    397 
    398 				case "${impl}" in
    399 					python*)
    400 						# python-2.7, python-3.2, etc.
    401 						val=$($(tc-getPKG_CONFIG) --cflags ${impl/n/n-}) || die
    402 						;;
    403 					*)
    404 						die "${impl}: obtaining ${var} not supported"
    405 						;;
    406 				esac
    407 
    408 				export PYTHON_CFLAGS=${val}
    409 				debug-print "${FUNCNAME}: PYTHON_CFLAGS = ${PYTHON_CFLAGS}"
    410 				;;
    411 			PYTHON_LIBS)
    412 				local val
    413 
    414 				case "${impl}" in
    415 					python2*|python3.6|python3.7*)
    416 						# python* up to 3.7
    417 						val=$($(tc-getPKG_CONFIG) --libs ${impl/n/n-}) || die
    418 						;;
    419 					python*)
    420 						# python3.8+
    421 						val=$($(tc-getPKG_CONFIG) --libs ${impl/n/n-}-embed) || die
    422 						;;
    423 					*)
    424 						die "${impl}: obtaining ${var} not supported"
    425 						;;
    426 				esac
    427 
    428 				export PYTHON_LIBS=${val}
    429 				debug-print "${FUNCNAME}: PYTHON_LIBS = ${PYTHON_LIBS}"
    430 				;;
    431 			PYTHON_CONFIG)
    432 				local flags val
    433 
    434 				case "${impl}" in
    435 					python*)
    436 						[[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it"
    437 						flags=$(
    438 							"${PYTHON}" - <<-EOF || die
    439 								import sysconfig
    440 								print(sysconfig.get_config_var("ABIFLAGS")
    441 									or "")
    442 							EOF
    443 						)
    444 						val=${PYTHON}${flags}-config
    445 						;;
    446 					*)
    447 						die "${impl}: obtaining ${var} not supported"
    448 						;;
    449 				esac
    450 
    451 				export PYTHON_CONFIG=${val}
    452 				debug-print "${FUNCNAME}: PYTHON_CONFIG = ${PYTHON_CONFIG}"
    453 				;;
    454 			PYTHON_PKG_DEP)
    455 				local d
    456 				case ${impl} in
    457 					python2.7)
    458 						PYTHON_PKG_DEP='>=dev-lang/python-2.7.10_p16:2.7';;
    459 					python3.8)
    460 						PYTHON_PKG_DEP=">=dev-lang/python-3.8.15_p3:3.8";;
    461 					python3.9)
    462 						PYTHON_PKG_DEP=">=dev-lang/python-3.9.15_p3:3.9";;
    463 					python3.10)
    464 						PYTHON_PKG_DEP=">=dev-lang/python-3.10.8_p3:3.10";;
    465 					python3.11)
    466 						PYTHON_PKG_DEP=">=dev-lang/python-3.11.0_p2:3.11";;
    467 					python*)
    468 						PYTHON_PKG_DEP="dev-lang/python:${impl#python}";;
    469 					pypy)
    470 						PYTHON_PKG_DEP='>=dev-python/pypy-7.3.9-r2:0=';;
    471 					pypy3)
    472 						PYTHON_PKG_DEP='>=dev-python/pypy3-7.3.9_p9:0=';;
    473 					*)
    474 						die "Invalid implementation: ${impl}"
    475 				esac
    476 
    477 				# use-dep
    478 				if [[ ${PYTHON_REQ_USE} ]]; then
    479 					PYTHON_PKG_DEP+=[${PYTHON_REQ_USE}]
    480 				fi
    481 
    482 				export PYTHON_PKG_DEP
    483 				debug-print "${FUNCNAME}: PYTHON_PKG_DEP = ${PYTHON_PKG_DEP}"
    484 				;;
    485 			PYTHON_SCRIPTDIR)
    486 				local dir
    487 				export PYTHON_SCRIPTDIR=${EPREFIX}/usr/lib/python-exec/${impl}
    488 				debug-print "${FUNCNAME}: PYTHON_SCRIPTDIR = ${PYTHON_SCRIPTDIR}"
    489 				;;
    490 			*)
    491 				die "_python_export: unknown variable ${var}"
    492 		esac
    493 	done
    494 }
    495 
    496 # @FUNCTION: python_get_sitedir
    497 # @USAGE: [<impl>]
    498 # @DESCRIPTION:
    499 # Obtain and print the 'site-packages' path for the given
    500 # implementation. If no implementation is provided, ${EPYTHON} will
    501 # be used.
    502 python_get_sitedir() {
    503 	debug-print-function ${FUNCNAME} "${@}"
    504 
    505 	_python_export "${@}" PYTHON_SITEDIR
    506 	echo "${PYTHON_SITEDIR}"
    507 }
    508 
    509 # @FUNCTION: python_get_includedir
    510 # @USAGE: [<impl>]
    511 # @DESCRIPTION:
    512 # Obtain and print the include path for the given implementation. If no
    513 # implementation is provided, ${EPYTHON} will be used.
    514 python_get_includedir() {
    515 	debug-print-function ${FUNCNAME} "${@}"
    516 
    517 	_python_export "${@}" PYTHON_INCLUDEDIR
    518 	echo "${PYTHON_INCLUDEDIR}"
    519 }
    520 
    521 # @FUNCTION: python_get_library_path
    522 # @USAGE: [<impl>]
    523 # @DESCRIPTION:
    524 # Obtain and print the Python library path for the given implementation.
    525 # If no implementation is provided, ${EPYTHON} will be used.
    526 #
    527 # Please note that this function can be used with CPython only. Use
    528 # in another implementation will result in a fatal failure.
    529 python_get_library_path() {
    530 	debug-print-function ${FUNCNAME} "${@}"
    531 
    532 	_python_export "${@}" PYTHON_LIBPATH
    533 	echo "${PYTHON_LIBPATH}"
    534 }
    535 
    536 # @FUNCTION: python_get_CFLAGS
    537 # @USAGE: [<impl>]
    538 # @DESCRIPTION:
    539 # Obtain and print the compiler flags for building against Python,
    540 # for the given implementation. If no implementation is provided,
    541 # ${EPYTHON} will be used.
    542 #
    543 # Please note that this function can be used with CPython only.
    544 # It requires Python and pkg-config installed, and therefore proper
    545 # build-time dependencies need be added to the ebuild.
    546 python_get_CFLAGS() {
    547 	debug-print-function ${FUNCNAME} "${@}"
    548 
    549 	_python_export "${@}" PYTHON_CFLAGS
    550 	echo "${PYTHON_CFLAGS}"
    551 }
    552 
    553 # @FUNCTION: python_get_LIBS
    554 # @USAGE: [<impl>]
    555 # @DESCRIPTION:
    556 # Obtain and print the compiler flags for linking against Python,
    557 # for the given implementation. If no implementation is provided,
    558 # ${EPYTHON} will be used.
    559 #
    560 # Please note that this function can be used with CPython only.
    561 # It requires Python and pkg-config installed, and therefore proper
    562 # build-time dependencies need be added to the ebuild.
    563 python_get_LIBS() {
    564 	debug-print-function ${FUNCNAME} "${@}"
    565 
    566 	_python_export "${@}" PYTHON_LIBS
    567 	echo "${PYTHON_LIBS}"
    568 }
    569 
    570 # @FUNCTION: python_get_PYTHON_CONFIG
    571 # @USAGE: [<impl>]
    572 # @DESCRIPTION:
    573 # Obtain and print the PYTHON_CONFIG location for the given
    574 # implementation. If no implementation is provided, ${EPYTHON} will be
    575 # used.
    576 #
    577 # Please note that this function can be used with CPython only.
    578 # It requires Python installed, and therefore proper build-time
    579 # dependencies need be added to the ebuild.
    580 python_get_PYTHON_CONFIG() {
    581 	debug-print-function ${FUNCNAME} "${@}"
    582 
    583 	_python_export "${@}" PYTHON_CONFIG
    584 	echo "${PYTHON_CONFIG}"
    585 }
    586 
    587 # @FUNCTION: python_get_scriptdir
    588 # @USAGE: [<impl>]
    589 # @DESCRIPTION:
    590 # Obtain and print the script install path for the given
    591 # implementation. If no implementation is provided, ${EPYTHON} will
    592 # be used.
    593 python_get_scriptdir() {
    594 	debug-print-function ${FUNCNAME} "${@}"
    595 
    596 	_python_export "${@}" PYTHON_SCRIPTDIR
    597 	echo "${PYTHON_SCRIPTDIR}"
    598 }
    599 
    600 # @FUNCTION: python_optimize
    601 # @USAGE: [<directory>...]
    602 # @DESCRIPTION:
    603 # Compile and optimize Python modules in specified directories (absolute
    604 # paths). If no directories are provided, the default system paths
    605 # are used (prepended with ${D}).
    606 python_optimize() {
    607 	debug-print-function ${FUNCNAME} "${@}"
    608 
    609 	[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
    610 
    611 	local PYTHON=${PYTHON}
    612 	[[ ${PYTHON} ]] || _python_export PYTHON
    613 	[[ -x ${PYTHON} ]] || die "PYTHON (${PYTHON}) is not executable"
    614 
    615 	# default to sys.path
    616 	if [[ ${#} -eq 0 ]]; then
    617 		local f
    618 		while IFS= read -r -d '' f; do
    619 			# 1) accept only absolute paths
    620 			#    (i.e. skip '', '.' or anything like that)
    621 			# 2) skip paths which do not exist
    622 			#    (python2.6 complains about them verbosely)
    623 
    624 			if [[ ${f} == /* && -d ${D%/}${f} ]]; then
    625 				set -- "${D%/}${f}" "${@}"
    626 			fi
    627 		done < <(
    628 			"${PYTHON}" - <<-EOF || die
    629 				import sys
    630 				print("".join(x + "\0" for x in sys.path))
    631 			EOF
    632 		)
    633 
    634 		debug-print "${FUNCNAME}: using sys.path: ${*/%/;}"
    635 	fi
    636 
    637 	local jobs=$(makeopts_jobs)
    638 	local d
    639 	for d; do
    640 		# make sure to get a nice path without //
    641 		local instpath=${d#${D%/}}
    642 		instpath=/${instpath##/}
    643 
    644 		einfo "Optimize Python modules for ${instpath}"
    645 		case "${EPYTHON}" in
    646 			python2.7|python3.[34])
    647 				"${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}"
    648 				"${PYTHON}" -OO -m compileall -q -f -d "${instpath}" "${d}"
    649 				;;
    650 			python3.[5678]|pypy3)
    651 				# both levels of optimization are separate since 3.5
    652 				"${PYTHON}" -m compileall -j "${jobs}" -q -f -d "${instpath}" "${d}"
    653 				"${PYTHON}" -O -m compileall -j "${jobs}" -q -f -d "${instpath}" "${d}"
    654 				"${PYTHON}" -OO -m compileall -j "${jobs}" -q -f -d "${instpath}" "${d}"
    655 				;;
    656 			python*)
    657 				"${PYTHON}" -m compileall -j "${jobs}" -o 0 -o 1 -o 2 --hardlink-dupes -q -f -d "${instpath}" "${d}"
    658 				;;
    659 			*)
    660 				"${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}"
    661 				;;
    662 		esac
    663 	done
    664 }
    665 
    666 # @FUNCTION: python_scriptinto
    667 # @USAGE: <new-path>
    668 # @DESCRIPTION:
    669 # Set the directory to which files passed to python_doexe(),
    670 # python_doscript(), python_newexe() and python_newscript()
    671 # are going to be installed. The new value needs to be relative
    672 # to the installation root (${ED}).
    673 #
    674 # If not set explicitly, the directory defaults to /usr/bin.
    675 #
    676 # Example:
    677 # @CODE
    678 # src_install() {
    679 #   python_scriptinto /usr/sbin
    680 #   python_foreach_impl python_doscript foo
    681 # }
    682 # @CODE
    683 python_scriptinto() {
    684 	debug-print-function ${FUNCNAME} "${@}"
    685 
    686 	_PYTHON_SCRIPTROOT=${1}
    687 }
    688 
    689 # @FUNCTION: python_doexe
    690 # @USAGE: <files>...
    691 # @DESCRIPTION:
    692 # Install the given executables into the executable install directory,
    693 # for the current Python implementation (${EPYTHON}).
    694 #
    695 # The executable will be wrapped properly for the Python implementation,
    696 # though no shebang mangling will be performed.
    697 python_doexe() {
    698 	debug-print-function ${FUNCNAME} "${@}"
    699 
    700 	[[ ${EBUILD_PHASE} != install ]] &&
    701 		die "${FUNCNAME} can only be used in src_install"
    702 
    703 	local f
    704 	for f; do
    705 		python_newexe "${f}" "${f##*/}"
    706 	done
    707 }
    708 
    709 # @FUNCTION: python_newexe
    710 # @USAGE: <path> <new-name>
    711 # @DESCRIPTION:
    712 # Install the given executable into the executable install directory,
    713 # for the current Python implementation (${EPYTHON}).
    714 #
    715 # The executable will be wrapped properly for the Python implementation,
    716 # though no shebang mangling will be performed. It will be renamed
    717 # to <new-name>.
    718 python_newexe() {
    719 	debug-print-function ${FUNCNAME} "${@}"
    720 
    721 	[[ ${EBUILD_PHASE} != install ]] &&
    722 		die "${FUNCNAME} can only be used in src_install"
    723 	[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
    724 	[[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} <path> <new-name>"
    725 
    726 	local wrapd=${_PYTHON_SCRIPTROOT:-/usr/bin}
    727 
    728 	local f=${1}
    729 	local newfn=${2}
    730 
    731 	local scriptdir=$(python_get_scriptdir)
    732 	local d=${scriptdir#${EPREFIX}}
    733 
    734 	(
    735 		dodir "${wrapd}"
    736 		exeopts -m 0755
    737 		exeinto "${d}"
    738 		newexe "${f}" "${newfn}" || return ${?}
    739 	)
    740 
    741 	# install the wrapper
    742 	local dosym=dosym
    743 	[[ ${EAPI} == [67] ]] && dosym=dosym8
    744 	"${dosym}" -r /usr/lib/python-exec/python-exec2 "${wrapd}/${newfn}"
    745 
    746 	# don't use this at home, just call python_doscript() instead
    747 	if [[ ${_PYTHON_REWRITE_SHEBANG} ]]; then
    748 		python_fix_shebang -q "${ED%/}/${d}/${newfn}"
    749 	fi
    750 }
    751 
    752 # @FUNCTION: python_doscript
    753 # @USAGE: <files>...
    754 # @DESCRIPTION:
    755 # Install the given scripts into the executable install directory,
    756 # for the current Python implementation (${EPYTHON}).
    757 #
    758 # All specified files must start with a 'python' shebang. The shebang
    759 # will be converted, and the files will be wrapped properly
    760 # for the Python implementation.
    761 #
    762 # Example:
    763 # @CODE
    764 # src_install() {
    765 #   python_foreach_impl python_doscript ${PN}
    766 # }
    767 # @CODE
    768 python_doscript() {
    769 	debug-print-function ${FUNCNAME} "${@}"
    770 
    771 	[[ ${EBUILD_PHASE} != install ]] &&
    772 		die "${FUNCNAME} can only be used in src_install"
    773 
    774 	local _PYTHON_REWRITE_SHEBANG=1
    775 	python_doexe "${@}"
    776 }
    777 
    778 # @FUNCTION: python_newscript
    779 # @USAGE: <path> <new-name>
    780 # @DESCRIPTION:
    781 # Install the given script into the executable install directory
    782 # for the current Python implementation (${EPYTHON}), and name it
    783 # <new-name>.
    784 #
    785 # The file must start with a 'python' shebang. The shebang will be
    786 # converted, and the file will be wrapped properly for the Python
    787 # implementation. It will be renamed to <new-name>.
    788 #
    789 # Example:
    790 # @CODE
    791 # src_install() {
    792 #   python_foreach_impl python_newscript foo.py foo
    793 # }
    794 # @CODE
    795 python_newscript() {
    796 	debug-print-function ${FUNCNAME} "${@}"
    797 
    798 	[[ ${EBUILD_PHASE} != install ]] &&
    799 		die "${FUNCNAME} can only be used in src_install"
    800 
    801 	local _PYTHON_REWRITE_SHEBANG=1
    802 	python_newexe "${@}"
    803 }
    804 
    805 # @FUNCTION: python_moduleinto
    806 # @USAGE: <new-path>
    807 # @DESCRIPTION:
    808 # Set the Python module install directory for python_domodule().
    809 # The <new-path> can either be an absolute target system path (in which
    810 # case it needs to start with a slash, and ${ED} will be prepended to
    811 # it) or relative to the implementation's site-packages directory
    812 # (then it must not start with a slash). The relative path can be
    813 # specified either using the Python package notation (separated by dots)
    814 # or the directory notation (using slashes).
    815 #
    816 # When not set explicitly, the modules are installed to the top
    817 # site-packages directory.
    818 #
    819 # In the relative case, the exact path is determined directly
    820 # by each python_domodule invocation. Therefore, python_moduleinto
    821 # can be safely called before establishing the Python interpreter and/or
    822 # a single call can be used to set the path correctly for multiple
    823 # implementations, as can be seen in the following example.
    824 #
    825 # Example:
    826 # @CODE
    827 # src_install() {
    828 #   python_moduleinto bar
    829 #   # installs ${PYTHON_SITEDIR}/bar/baz.py
    830 #   python_foreach_impl python_domodule baz.py
    831 # }
    832 # @CODE
    833 python_moduleinto() {
    834 	debug-print-function ${FUNCNAME} "${@}"
    835 
    836 	_PYTHON_MODULEROOT=${1}
    837 }
    838 
    839 # @FUNCTION: python_domodule
    840 # @USAGE: <files>...
    841 # @DESCRIPTION:
    842 # Install the given modules (or packages) into the current Python module
    843 # installation directory. The list can mention both modules (files)
    844 # and packages (directories). All listed files will be installed
    845 # for all enabled implementations, and compiled afterwards.
    846 #
    847 # The files are installed into ${D} when run in src_install() phase.
    848 # Otherwise, they are installed into ${BUILD_DIR}/install location
    849 # that is suitable for picking up by distutils-r1 in PEP517 mode.
    850 #
    851 # Example:
    852 # @CODE
    853 # src_install() {
    854 #   # (${PN} being a directory)
    855 #   python_foreach_impl python_domodule ${PN}
    856 # }
    857 # @CODE
    858 python_domodule() {
    859 	debug-print-function ${FUNCNAME} "${@}"
    860 
    861 	[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
    862 
    863 	local d
    864 	if [[ ${_PYTHON_MODULEROOT} == /* ]]; then
    865 		# absolute path
    866 		d=${_PYTHON_MODULEROOT}
    867 	else
    868 		# relative to site-packages
    869 		local sitedir=$(python_get_sitedir)
    870 		d=${sitedir#${EPREFIX}}/${_PYTHON_MODULEROOT//.//}
    871 	fi
    872 
    873 	if [[ ${EBUILD_PHASE} == install ]]; then
    874 		(
    875 			insopts -m 0644
    876 			insinto "${d}"
    877 			doins -r "${@}" || return ${?}
    878 		)
    879 		python_optimize "${ED%/}/${d}"
    880 	elif [[ -n ${BUILD_DIR} ]]; then
    881 		local dest=${BUILD_DIR}/install${EPREFIX}/${d}
    882 		mkdir -p "${dest}" || die
    883 		cp -pR "${@}" "${dest}/" || die
    884 		(
    885 			cd "${dest}" &&
    886 			chmod -R a+rX "${@##*/}"
    887 		) || die
    888 	else
    889 		die "${FUNCNAME} can only be used in src_install or with BUILD_DIR set"
    890 	fi
    891 }
    892 
    893 # @FUNCTION: python_doheader
    894 # @USAGE: <files>...
    895 # @DESCRIPTION:
    896 # Install the given headers into the implementation-specific include
    897 # directory. This function is unconditionally recursive, i.e. you can
    898 # pass directories instead of files.
    899 #
    900 # Example:
    901 # @CODE
    902 # src_install() {
    903 #   python_foreach_impl python_doheader foo.h bar.h
    904 # }
    905 # @CODE
    906 python_doheader() {
    907 	debug-print-function ${FUNCNAME} "${@}"
    908 
    909 	[[ ${EBUILD_PHASE} != install ]] &&
    910 		die "${FUNCNAME} can only be used in src_install"
    911 	[[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).'
    912 
    913 	local includedir=$(python_get_includedir)
    914 	local d=${includedir#${EPREFIX}}
    915 
    916 	(
    917 		insopts -m 0644
    918 		insinto "${d}"
    919 		doins -r "${@}" || return ${?}
    920 	)
    921 }
    922 
    923 # @FUNCTION: _python_wrapper_setup
    924 # @USAGE: [<path> [<impl>]]
    925 # @INTERNAL
    926 # @DESCRIPTION:
    927 # Create proper 'python' executable and pkg-config wrappers
    928 # (if available) in the directory named by <path>. Set up PATH
    929 # and PKG_CONFIG_PATH appropriately. <path> defaults to ${T}/${EPYTHON}.
    930 #
    931 # The wrappers will be created for implementation named by <impl>,
    932 # or for one named by ${EPYTHON} if no <impl> passed.
    933 #
    934 # If the named directory contains a python symlink already, it will
    935 # be assumed to contain proper wrappers already and only environment
    936 # setup will be done. If wrapper update is requested, the directory
    937 # shall be removed first.
    938 _python_wrapper_setup() {
    939 	debug-print-function ${FUNCNAME} "${@}"
    940 
    941 	local workdir=${1:-${T}/${EPYTHON}}
    942 	local impl=${2:-${EPYTHON}}
    943 
    944 	[[ ${workdir} ]] || die "${FUNCNAME}: no workdir specified."
    945 	[[ ${impl} ]] || die "${FUNCNAME}: no impl nor EPYTHON specified."
    946 
    947 	if [[ ! -x ${workdir}/bin/python ]]; then
    948 		mkdir -p "${workdir}"/{bin,pkgconfig} || die
    949 
    950 		# Clean up, in case we were supposed to do a cheap update.
    951 		rm -f "${workdir}"/bin/python{,2,3}{,-config} || die
    952 		rm -f "${workdir}"/bin/2to3 || die
    953 		rm -f "${workdir}"/pkgconfig/python{2,3}{,-embed}.pc || die
    954 
    955 		local EPYTHON PYTHON
    956 		_python_export "${impl}" EPYTHON PYTHON
    957 
    958 		local pyver pyother
    959 		if [[ ${EPYTHON} != python2* ]]; then
    960 			pyver=3
    961 			pyother=2
    962 		else
    963 			pyver=2
    964 			pyother=3
    965 		fi
    966 
    967 		# Python interpreter
    968 		# note: we don't use symlinks because python likes to do some
    969 		# symlink reading magic that breaks stuff
    970 		# https://bugs.gentoo.org/show_bug.cgi?id=555752
    971 		cat > "${workdir}/bin/python" <<-_EOF_ || die
    972 			#!/bin/sh
    973 			exec "${PYTHON}" "\${@}"
    974 		_EOF_
    975 		cp "${workdir}/bin/python" "${workdir}/bin/python${pyver}" || die
    976 		chmod +x "${workdir}/bin/python" "${workdir}/bin/python${pyver}" || die
    977 
    978 		local nonsupp=( "python${pyother}" "python${pyother}-config" )
    979 
    980 		# CPython-specific
    981 		if [[ ${EPYTHON} == python* ]]; then
    982 			cat > "${workdir}/bin/python-config" <<-_EOF_ || die
    983 				#!/bin/sh
    984 				exec "${PYTHON}-config" "\${@}"
    985 			_EOF_
    986 			cp "${workdir}/bin/python-config" \
    987 				"${workdir}/bin/python${pyver}-config" || die
    988 			chmod +x "${workdir}/bin/python-config" \
    989 				"${workdir}/bin/python${pyver}-config" || die
    990 
    991 			# Python 2.6+.
    992 			ln -s "${PYTHON/python/2to3-}" "${workdir}"/bin/2to3 || die
    993 
    994 			# Python 2.7+.
    995 			ln -s "${EPREFIX}"/usr/$(get_libdir)/pkgconfig/${EPYTHON/n/n-}.pc \
    996 				"${workdir}"/pkgconfig/python${pyver}.pc || die
    997 
    998 			# Python 3.8+.
    999 			if [[ ${EPYTHON} != python[23].[67] ]]; then
   1000 				ln -s "${EPREFIX}"/usr/$(get_libdir)/pkgconfig/${EPYTHON/n/n-}-embed.pc \
   1001 					"${workdir}"/pkgconfig/python${pyver}-embed.pc || die
   1002 			fi
   1003 		else
   1004 			nonsupp+=( 2to3 python-config "python${pyver}-config" )
   1005 		fi
   1006 
   1007 		local x
   1008 		for x in "${nonsupp[@]}"; do
   1009 			cat >"${workdir}"/bin/${x} <<-_EOF_ || die
   1010 				#!/bin/sh
   1011 				echo "${ECLASS}: ${FUNCNAME}: ${x} is not supported by ${EPYTHON} (PYTHON_COMPAT)" >&2
   1012 				exit 127
   1013 			_EOF_
   1014 			chmod +x "${workdir}"/bin/${x} || die
   1015 		done
   1016 	fi
   1017 
   1018 	# Now, set the environment.
   1019 	# But note that ${workdir} may be shared with something else,
   1020 	# and thus already on top of PATH.
   1021 	if [[ ${PATH##:*} != ${workdir}/bin ]]; then
   1022 		PATH=${workdir}/bin${PATH:+:${PATH}}
   1023 	fi
   1024 	if [[ ${PKG_CONFIG_PATH##:*} != ${workdir}/pkgconfig ]]; then
   1025 		PKG_CONFIG_PATH=${workdir}/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}
   1026 	fi
   1027 	export PATH PKG_CONFIG_PATH
   1028 }
   1029 
   1030 # @FUNCTION: python_fix_shebang
   1031 # @USAGE: [-f|--force] [-q|--quiet] <path>...
   1032 # @DESCRIPTION:
   1033 # Replace the shebang in Python scripts with the full path
   1034 # to the current Python implementation (PYTHON, including EPREFIX).
   1035 # If a directory is passed, works recursively on all Python scripts
   1036 # found inside the directory tree.
   1037 #
   1038 # Only files having a Python shebang (a path to any known Python
   1039 # interpreter, optionally preceded by env(1) invocation) will
   1040 # be processed.  Files with any other shebang will either be skipped
   1041 # silently when a directory was passed, or an error will be reported
   1042 # for any files without Python shebangs specified explicitly.
   1043 #
   1044 # Shebangs that are compatible with the current Python version will be
   1045 # mangled unconditionally.  Incompatible shebangs will cause a fatal
   1046 # error, unless --force is specified.
   1047 #
   1048 # --force causes the function to replace shebangs with incompatible
   1049 # Python version (but not non-Python shebangs).  --quiet causes
   1050 # the function not to list modified files verbosely.
   1051 python_fix_shebang() {
   1052 	debug-print-function ${FUNCNAME} "${@}"
   1053 
   1054 	[[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)"
   1055 	local PYTHON
   1056 	_python_export "${EPYTHON}" PYTHON
   1057 
   1058 	local force quiet
   1059 	while [[ ${@} ]]; do
   1060 		case "${1}" in
   1061 			-f|--force) force=1; shift;;
   1062 			-q|--quiet) quiet=1; shift;;
   1063 			--) shift; break;;
   1064 			*) break;;
   1065 		esac
   1066 	done
   1067 
   1068 	[[ ${1} ]] || die "${FUNCNAME}: no paths given"
   1069 
   1070 	local path f
   1071 	for path; do
   1072 		local any_fixed is_recursive
   1073 
   1074 		[[ -d ${path} ]] && is_recursive=1
   1075 
   1076 		while IFS= read -r -d '' f; do
   1077 			local shebang i
   1078 			local error= match=
   1079 
   1080 			# note: we can't ||die here since read will fail if file
   1081 			# has no newline characters
   1082 			IFS= read -r shebang <"${f}"
   1083 
   1084 			# First, check if it's shebang at all...
   1085 			if [[ ${shebang} == '#!'* ]]; then
   1086 				local split_shebang=()
   1087 				read -r -a split_shebang <<<${shebang#"#!"} || die
   1088 
   1089 				local in_path=${split_shebang[0]}
   1090 				local from='^#! *[^ ]*'
   1091 				# if the first component is env(1), skip it
   1092 				if [[ ${in_path} == */env ]]; then
   1093 					in_path=${split_shebang[1]}
   1094 					from+=' *[^ ]*'
   1095 				fi
   1096 
   1097 				case ${in_path##*/} in
   1098 					"${EPYTHON}")
   1099 						match=1
   1100 						;;
   1101 					python|python[23])
   1102 						match=1
   1103 						[[ ${in_path##*/} == python2 ]] && error=1
   1104 						;;
   1105 					python[23].[0-9]|python3.[1-9][0-9]|pypy|pypy3|jython[23].[0-9])
   1106 						# Explicit mismatch.
   1107 						match=1
   1108 						error=1
   1109 						;;
   1110 				esac
   1111 			fi
   1112 
   1113 			# disregard mismatches in force mode
   1114 			[[ ${force} ]] && error=
   1115 
   1116 			if [[ ! ${match} ]]; then
   1117 				# Non-Python shebang. Allowed in recursive mode,
   1118 				# disallowed when specifying file explicitly.
   1119 				[[ ${is_recursive} ]] && continue
   1120 				error=1
   1121 			fi
   1122 
   1123 			if [[ ! ${quiet} ]]; then
   1124 				einfo "Fixing shebang in ${f#${D%/}}."
   1125 			fi
   1126 
   1127 			if [[ ! ${error} ]]; then
   1128 				debug-print "${FUNCNAME}: in file ${f#${D%/}}"
   1129 				debug-print "${FUNCNAME}: rewriting shebang: ${shebang}"
   1130 				sed -i -e "1s@${from}@#!${PYTHON}@" "${f}" || die
   1131 				any_fixed=1
   1132 			else
   1133 				eerror "The file has incompatible shebang:"
   1134 				eerror "  file: ${f#${D%/}}"
   1135 				eerror "  current shebang: ${shebang}"
   1136 				eerror "  requested impl: ${EPYTHON}"
   1137 				die "${FUNCNAME}: conversion of incompatible shebang requested"
   1138 			fi
   1139 		done < <(find -H "${path}" -type f -print0 || die)
   1140 
   1141 		if [[ ! ${any_fixed} ]]; then
   1142 			eerror "QA error: ${FUNCNAME}, ${path#${D%/}} did not match any fixable files."
   1143 			eerror "There are no Python files in specified directory."
   1144 			die "${FUNCNAME} did not match any fixable files"
   1145 		fi
   1146 	done
   1147 }
   1148 
   1149 # @FUNCTION: _python_check_locale_sanity
   1150 # @USAGE: <locale>
   1151 # @RETURN: 0 if sane, 1 otherwise
   1152 # @INTERNAL
   1153 # @DESCRIPTION:
   1154 # Check whether the specified locale sanely maps between lowercase
   1155 # and uppercase ASCII characters.
   1156 _python_check_locale_sanity() {
   1157 	local -x LC_ALL=${1}
   1158 	local IFS=
   1159 
   1160 	local lc=( {a..z} )
   1161 	local uc=( {A..Z} )
   1162 	local input="${lc[*]}${uc[*]}"
   1163 
   1164 	local output=$(tr '[:lower:][:upper:]' '[:upper:][:lower:]' <<<"${input}")
   1165 	[[ ${output} == "${uc[*]}${lc[*]}" ]]
   1166 }
   1167 
   1168 # @FUNCTION: python_export_utf8_locale
   1169 # @RETURN: 0 on success, 1 on failure.
   1170 # @DESCRIPTION:
   1171 # Attempts to export a usable UTF-8 locale in the LC_CTYPE variable. Does
   1172 # nothing if LC_ALL is defined, or if the current locale uses a UTF-8 charmap.
   1173 # This may be used to work around the quirky open() behavior of python3.
   1174 python_export_utf8_locale() {
   1175 	debug-print-function ${FUNCNAME} "${@}"
   1176 
   1177 	# If the locale program isn't available, just return.
   1178 	type locale &>/dev/null || return 0
   1179 
   1180 	if [[ $(locale charmap) != UTF-8 ]]; then
   1181 		# Try English first, then everything else.
   1182 		local lang locales="C.UTF-8 en_US.UTF-8 en_GB.UTF-8 $(locale -a)"
   1183 
   1184 		for lang in ${locales}; do
   1185 			if [[ $(LC_ALL=${lang} locale charmap 2>/dev/null) == UTF-8 ]]; then
   1186 				if _python_check_locale_sanity "${lang}"; then
   1187 					export LC_CTYPE=${lang}
   1188 					if [[ -n ${LC_ALL} ]]; then
   1189 						export LC_NUMERIC=${LC_ALL}
   1190 						export LC_TIME=${LC_ALL}
   1191 						export LC_COLLATE=${LC_ALL}
   1192 						export LC_MONETARY=${LC_ALL}
   1193 						export LC_MESSAGES=${LC_ALL}
   1194 						export LC_PAPER=${LC_ALL}
   1195 						export LC_NAME=${LC_ALL}
   1196 						export LC_ADDRESS=${LC_ALL}
   1197 						export LC_TELEPHONE=${LC_ALL}
   1198 						export LC_MEASUREMENT=${LC_ALL}
   1199 						export LC_IDENTIFICATION=${LC_ALL}
   1200 						export LC_ALL=
   1201 					fi
   1202 					return 0
   1203 				fi
   1204 			fi
   1205 		done
   1206 
   1207 		ewarn "Could not find a UTF-8 locale. This may trigger build failures in"
   1208 		ewarn "some python packages. Please ensure that a UTF-8 locale is listed in"
   1209 		ewarn "/etc/locale.gen and run locale-gen."
   1210 		return 1
   1211 	fi
   1212 
   1213 	return 0
   1214 }
   1215 
   1216 # @FUNCTION: build_sphinx
   1217 # @USAGE: <directory>
   1218 # @DESCRIPTION:
   1219 # Build HTML documentation using dev-python/sphinx in the specified
   1220 # <directory>.  Takes care of disabling Intersphinx and appending
   1221 # to HTML_DOCS.
   1222 #
   1223 # If <directory> is relative to the current directory, care needs
   1224 # to be taken to run einstalldocs from the same directory
   1225 # (usually ${S}).
   1226 build_sphinx() {
   1227 	debug-print-function ${FUNCNAME} "${@}"
   1228 	[[ ${#} -eq 1 ]] || die "${FUNCNAME} takes 1 arg: <directory>"
   1229 
   1230 	local dir=${1}
   1231 
   1232 	sed -i -e 's:^intersphinx_mapping:disabled_&:' \
   1233 		"${dir}"/conf.py || die
   1234 	# 1. not all packages include the Makefile in pypi tarball,
   1235 	# so we call sphinx-build directly
   1236 	# 2. if autodoc is used, we need to call sphinx via EPYTHON,
   1237 	# to ensure that PEP 517 venv is respected
   1238 	# 3. if autodoc is not used, then sphinx might not be installed
   1239 	# for the current impl, so we need a fallback to sphinx-build
   1240 	local command=( "${EPYTHON}" -m sphinx.cmd.build )
   1241 	if ! "${EPYTHON}" -c "import sphinx.cmd.build" 2>/dev/null; then
   1242 		command=( sphinx-build )
   1243 	fi
   1244 	command+=(
   1245 		-b html
   1246 		-d "${dir}"/_build/doctrees
   1247 		"${dir}"
   1248 		"${dir}"/_build/html
   1249 	)
   1250 	echo "${command[@]}" >&2
   1251 	"${command[@]}" || die
   1252 
   1253 	HTML_DOCS+=( "${dir}/_build/html/." )
   1254 }
   1255 
   1256 # @FUNCTION: _python_check_EPYTHON
   1257 # @INTERNAL
   1258 # @DESCRIPTION:
   1259 # Check if EPYTHON is set, die if not.
   1260 _python_check_EPYTHON() {
   1261 	if [[ -z ${EPYTHON} ]]; then
   1262 		die "EPYTHON unset, invalid call context"
   1263 	fi
   1264 }
   1265 
   1266 # @VARIABLE: EPYTEST_DESELECT
   1267 # @DEFAULT_UNSET
   1268 # @DESCRIPTION:
   1269 # Specifies an array of tests to be deselected via pytest's --deselect
   1270 # parameter, when calling epytest.  The list can include file paths,
   1271 # specific test functions or parametrized test invocations.
   1272 #
   1273 # Note that the listed files will still be subject to collection,
   1274 # i.e. modules imported in global scope will need to be available.
   1275 # If this is undesirable, EPYTEST_IGNORE can be used instead.
   1276 
   1277 # @VARIABLE: EPYTEST_IGNORE
   1278 # @DEFAULT_UNSET
   1279 # @DESCRIPTION:
   1280 # Specifies an array of paths to be ignored via pytest's --ignore
   1281 # parameter, when calling epytest.  The listed files will be entirely
   1282 # skipped from test collection.
   1283 
   1284 # @FUNCTION: epytest
   1285 # @USAGE: [<args>...]
   1286 # @DESCRIPTION:
   1287 # Run pytest, passing the standard set of pytest options, then
   1288 # --deselect and --ignore options based on EPYTEST_DESELECT
   1289 # and EPYTEST_IGNORE, then user-specified options.
   1290 #
   1291 # This command dies on failure and respects nonfatal.
   1292 epytest() {
   1293 	debug-print-function ${FUNCNAME} "${@}"
   1294 
   1295 	_python_check_EPYTHON
   1296 
   1297 	local color
   1298 	case ${NOCOLOR} in
   1299 		true|yes)
   1300 			color=no
   1301 			;;
   1302 		*)
   1303 			color=yes
   1304 			;;
   1305 	esac
   1306 
   1307 	local args=(
   1308 		# verbose progress reporting and tracebacks
   1309 		-vv
   1310 		# list all non-passed tests in the summary for convenience
   1311 		# (includes failures, skips, xfails...)
   1312 		-ra
   1313 		# print local variables in tracebacks, useful for debugging
   1314 		-l
   1315 		# override filterwarnings=error, we do not really want -Werror
   1316 		# for end users, as it tends to fail on new warnings from deps
   1317 		-Wdefault
   1318 		# override color output
   1319 		"--color=${color}"
   1320 		# count is more precise when we're dealing with a large number
   1321 		# of tests
   1322 		-o console_output_style=count
   1323 		# disable the undesirable-dependency plugins by default to
   1324 		# trigger missing argument strips.  strip options that require
   1325 		# them from config files.  enable them explicitly via "-p ..."
   1326 		# if you *really* need them.
   1327 		-p no:cov
   1328 		-p no:flake8
   1329 		-p no:flakes
   1330 		-p no:pylint
   1331 		# sterilize pytest-markdown as it runs code snippets from all
   1332 		# *.md files found without any warning
   1333 		-p no:markdown
   1334 		# pytest-sugar undoes everything that's good about pytest output
   1335 		# and makes it hard to read logs
   1336 		-p no:sugar
   1337 		# pytest-xvfb automatically spawns Xvfb for every test suite,
   1338 		# effectively forcing it even when we'd prefer the tests
   1339 		# not to have DISPLAY at all, causing crashes sometimes
   1340 		# and causing us to miss missing virtualx usage
   1341 		-p no:xvfb
   1342 		# tavern is intrusive and breaks test suites of various packages
   1343 		-p no:tavern
   1344 	)
   1345 	local x
   1346 	for x in "${EPYTEST_DESELECT[@]}"; do
   1347 		args+=( --deselect "${x}" )
   1348 	done
   1349 	for x in "${EPYTEST_IGNORE[@]}"; do
   1350 		args+=( --ignore "${x}" )
   1351 	done
   1352 	set -- "${EPYTHON}" -m pytest "${args[@]}" "${@}"
   1353 
   1354 	echo "${@}" >&2
   1355 	"${@}" || die -n "pytest failed with ${EPYTHON}"
   1356 	local ret=${?}
   1357 
   1358 	# remove common temporary directories left over by pytest plugins
   1359 	rm -rf .hypothesis .pytest_cache || die
   1360 	# pytest plugins create additional .pyc files while testing
   1361 	# see e.g. https://bugs.gentoo.org/847235
   1362 	if [[ -n ${BUILD_DIR} && -d ${BUILD_DIR} ]]; then
   1363 		find "${BUILD_DIR}" -name '*-pytest-*.pyc' -delete || die
   1364 	fi
   1365 
   1366 	return ${ret}
   1367 }
   1368 
   1369 # @FUNCTION: eunittest
   1370 # @USAGE: [<args>...]
   1371 # @DESCRIPTION:
   1372 # Run unit tests using dev-python/unittest-or-fail, passing the standard
   1373 # set of options, followed by user-specified options.
   1374 #
   1375 # This command dies on failure and respects nonfatal.
   1376 eunittest() {
   1377 	debug-print-function ${FUNCNAME} "${@}"
   1378 
   1379 	_python_check_EPYTHON
   1380 
   1381 	set -- "${EPYTHON}" -m unittest_or_fail discover -v "${@}"
   1382 
   1383 	echo "${@}" >&2
   1384 	"${@}" || die -n "Tests failed with ${EPYTHON}"
   1385 	return ${?}
   1386 }
   1387 
   1388 # @FUNCTION: _python_run_check_deps
   1389 # @INTERNAL
   1390 # @USAGE: <impl>
   1391 # @DESCRIPTION:
   1392 # Verify whether <impl> is an acceptable choice to run any-r1 style
   1393 # code.  Checks whether the interpreter is installed, runs
   1394 # python_check_deps() if declared.
   1395 _python_run_check_deps() {
   1396 	debug-print-function ${FUNCNAME} "${@}"
   1397 
   1398 	local impl=${1}
   1399 	local hasv_args=( -b )
   1400 	[[ ${EAPI} == 6 ]] && hasv_args=( --host-root )
   1401 
   1402 	einfo "Checking whether ${impl} is suitable ..."
   1403 
   1404 	local PYTHON_PKG_DEP
   1405 	_python_export "${impl}" PYTHON_PKG_DEP
   1406 	ebegin "  ${PYTHON_PKG_DEP}"
   1407 	has_version "${hasv_args[@]}" "${PYTHON_PKG_DEP}"
   1408 	eend ${?} || return 1
   1409 	declare -f python_check_deps >/dev/null || return 0
   1410 
   1411 	local PYTHON_USEDEP="python_targets_${impl}(-)"
   1412 	local PYTHON_SINGLE_USEDEP="python_single_target_${impl}(-)"
   1413 	ebegin "  python_check_deps"
   1414 	python_check_deps
   1415 	eend ${?}
   1416 }
   1417 
   1418 # @FUNCTION: python_has_version
   1419 # @USAGE: [-b|-d|-r] <atom>...
   1420 # @DESCRIPTION:
   1421 # A convenience wrapper for has_version() with verbose output and better
   1422 # defaults for use in python_check_deps().
   1423 #
   1424 # The wrapper accepts EAPI 7+-style -b/-d/-r options to indicate
   1425 # the root to perform the lookup on.  Unlike has_version, the default
   1426 # is -b.  In EAPI 6, -b and -d are translated to --host-root
   1427 # for compatibility.
   1428 #
   1429 # The wrapper accepts multiple package specifications.  For the check
   1430 # to succeed, *all* specified atoms must match.
   1431 python_has_version() {
   1432 	debug-print-function ${FUNCNAME} "${@}"
   1433 
   1434 	local root_arg=( -b )
   1435 	case ${1} in
   1436 		-b|-d|-r)
   1437 			root_arg=( "${1}" )
   1438 			shift
   1439 			;;
   1440 	esac
   1441 
   1442 	if [[ ${EAPI} == 6 ]]; then
   1443 		if [[ ${root_arg} == -r ]]; then
   1444 			root_arg=()
   1445 		else
   1446 			root_arg=( --host-root )
   1447 		fi
   1448 	fi
   1449 
   1450 	local pkg
   1451 	for pkg; do
   1452 		ebegin "    ${pkg}"
   1453 		has_version "${root_arg[@]}" "${pkg}"
   1454 		eend ${?} || return
   1455 	done
   1456 
   1457 	return 0
   1458 }
   1459 
   1460 _PYTHON_UTILS_R1=1
   1461 fi