public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-dev] Patches for python.eclass and distutils.eclass
@ 2010-12-15 14:31 Arfrever Frehtes Taifersar Arahesis
  2010-12-15 14:56 ` Ulrich Mueller
  0 siblings, 1 reply; 2+ messages in thread
From: Arfrever Frehtes Taifersar Arahesis @ 2010-12-15 14:31 UTC (permalink / raw
  To: Gentoo Development; +Cc: qa


[-- Attachment #1.1: Type: Text/Plain, Size: 2274 bytes --]

Patch for python.eclass is divided into 3 subpatches.
Subpatch #1 adds/improves/updates support for Jython in many functions and fixes some minor
bugs in python_generate_wrapper_scripts().
Subpatch #2 adds python_merge_intermediate_installation_images() function. This function will
provide improved and more generic version of a functionality of distutils_src_install().
This function automatically performs the following actions:
- Renaming of versioned Python scripts.
- Conversion of shebangs in Python scripts.
- Merging of intermediate installation images into installation image.
- Generation of Python wrapper scripts.
Example usage:
src_install() {
	installation() {
		emake DESTDIR="${T}/images/${PYTHON_ABI}" install
	}
	python_execute_function installation
	python_merge_intermediate_installation_images "${T}/images"
}
Python scripts in /usr/bin and /usr/sbin are versioned by default.
PYTHON_VERSIONED_SCRIPTS, PYTHON_VERSIONED_EXECUTABLES and PYTHON_NONVERSIONED_EXECUTABLES
are used to control, which files should be versioned.
PYTHON_VERSIONED_EXECUTABLES is useful e.g. for dev-util/eric, which installs shell scripts.
Subpatch #3 renames some private arrays for consistency with other arrays.
E.g. _PYTHON_GLOBALLY_SUPPORTED_ABIS will contain Python ABIs generally supported by
python.eclass, while _PYTHON_LOCALLY_SUPPORTED_ABIS will contain Python ABIs supported by
current package.

Patch for distutils.eclass is divided into 2 subpatches.
Subpatch #1 ports distutils_src_install() to use python_merge_intermediate_installation_images()
and deprecates DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS variable, which is used only in
2 packages in the tree.
Subpatch #2 adds optional deprecation warnings for some cases. Deprecation warnings are
printed only when PYTHON_DEPRECATION_WARNINGS variable is set (e.g. in /etc/make.conf).
It might be useful for Gentoo developers to set this variable to avoid committing ebuilds
using deprecated functionality. This subpatch does NOT introduce any deprecation, because
the corresponding functionality has been already deprecated since 2010-08-03 (without
deprecation warnings).

I'm planning to commit these patches in 1 week.

-- 
Arfrever Frehtes Taifersar Arahesis

[-- Attachment #1.2: python.eclass.patch --]
[-- Type: text/x-patch, Size: 28540 bytes --]

--- python.eclass
+++ python.eclass
@@ -15,15 +15,35 @@
 	die "API of python.eclass in EAPI=\"${EAPI}\" not established"
 fi
 
-_CPYTHON2_SUPPORTED_ABIS=(2.4 2.5 2.6 2.7)
-_CPYTHON3_SUPPORTED_ABIS=(3.0 3.1 3.2)
-_JYTHON_SUPPORTED_ABIS=(2.5-jython)
-_PYTHON_SUPPORTED_ABIS=(${_CPYTHON2_SUPPORTED_ABIS[@]} ${_CPYTHON3_SUPPORTED_ABIS[@]} ${_JYTHON_SUPPORTED_ABIS[@]})
+_CPYTHON2_GLOBALLY_SUPPORTED_ABIS=(2.4 2.5 2.6 2.7)
+_CPYTHON3_GLOBALLY_SUPPORTED_ABIS=(3.0 3.1 3.2)
+_JYTHON_GLOBALLY_SUPPORTED_ABIS=(2.5-jython)
+_PYTHON_GLOBALLY_SUPPORTED_ABIS=(${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]} ${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]} ${_JYTHON_GLOBALLY_SUPPORTED_ABIS[@]})
 
 # ================================================================================================
 # ===================================== HANDLING OF METADATA =====================================
 # ================================================================================================
 
+_python_check_python_abi_matching() {
+	if [[ "$#" -ne 2 ]]; then
+		die "${FUNCNAME}() requires 2 arguments"
+	fi
+
+	if [[ "$2" == *"-cpython" ]]; then
+		[[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ && "$1" == ${2%-cpython} ]]
+	elif [[ "$2" == *"-jython" ]]; then
+		[[ "$1" == $2 ]]
+	else
+		if [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ ]]; then
+			[[ "$1" == $2 ]]
+		elif [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+-jython$ ]]; then
+			[[ "${1%-jython}" == $2 ]]
+		else
+			die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+		fi
+	fi
+}
+
 # @ECLASS-VARIABLE: PYTHON_DEPEND
 # @DESCRIPTION:
 # Specification of dependency on dev-lang/python.
@@ -67,17 +87,17 @@
 
 			if [[ "${major_version}" == "2" ]]; then
 				python2="1"
-				python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python2_minimal_version="${minimal_version}"
 				python2_maximal_version="${maximal_version}"
 			elif [[ "${major_version}" == "3" ]]; then
 				python3="1"
-				python_versions=("${_CPYTHON3_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python3_minimal_version="${minimal_version}"
 				python3_maximal_version="${maximal_version}"
 			else
 				python_all="1"
-				python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python_minimal_version="${minimal_version}"
 				python_maximal_version="${maximal_version}"
 			fi
@@ -115,7 +135,7 @@
 			if [[ -z "${python_minimal_version}" && -z "${python_maximal_version}" ]]; then
 				_PYTHON_ATOMS+=("dev-lang/python")
 			else
-				python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python_minimal_version="${python_minimal_version:-${python_versions[0]}}"
 				python_maximal_version="${python_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
 				_append_accepted_versions_range
@@ -125,7 +145,7 @@
 				if [[ -z "${python3_minimal_version}" && -z "${python3_maximal_version}" ]]; then
 					_PYTHON_ATOMS+=("=dev-lang/python-3*")
 				else
-					python_versions=("${_CPYTHON3_SUPPORTED_ABIS[@]}")
+					python_versions=("${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 					python_minimal_version="${python3_minimal_version:-${python_versions[0]}}"
 					python_maximal_version="${python3_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
 					_append_accepted_versions_range
@@ -135,7 +155,7 @@
 				if [[ -z "${python2_minimal_version}" && -z "${python2_maximal_version}" ]]; then
 					_PYTHON_ATOMS+=("=dev-lang/python-2*")
 				else
-					python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}")
+					python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}")
 					python_minimal_version="${python2_minimal_version:-${python_versions[0]}}"
 					python_maximal_version="${python2_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
 					_append_accepted_versions_range
@@ -350,6 +370,9 @@
 		die "${FUNCNAME}() does not accept arguments"
 	fi
 
+	export JYTHON_SYSTEM_CACHEDIR="1"
+	addwrite "${EPREFIX}/var/cache/jython"
+
 	if _python_package_supporting_installation_for_multiple_python_abis; then
 		_python_calculate_PYTHON_ABIS
 		export EPYTHON="$(PYTHON -f)"
@@ -405,14 +428,16 @@
 	EXPORT_FUNCTIONS pkg_setup
 fi
 
+_PYTHON_SHEBANG_BASE_PART_REGEX='^#![[:space:]]*([^[:space:]]*/usr/bin/env[[:space:]]+)?([^[:space:]]*/)?(jython|python)'
+
 # @FUNCTION: python_convert_shebangs
-# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
+# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_ABI|Python_version> <file|directory> [files|directories]
 # @DESCRIPTION:
 # Convert shebangs in specified files. Directories can be specified only with --recursive option.
 python_convert_shebangs() {
 	_python_check_python_pkg_setup_execution
 
-	local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
+	local argument file files=() only_executables="0" python_interpreter quiet="0" recursive="0"
 
 	while (($#)); do
 		case "$1" in
@@ -445,7 +470,11 @@
 		die "${FUNCNAME}(): Missing files or directories"
 	fi
 
-	python_version="$1"
+	if [[ -n "$(_python_get_implementation --ignore-invalid "$1")" ]]; then
+		python_interpreter="$(PYTHON "$1")"
+	else
+		python_interpreter="python$1"
+	fi
 	shift
 
 	for argument in "$@"; do
@@ -470,17 +499,14 @@
 		file="${file#./}"
 		[[ "${only_executables}" == "1" && ! -x "${file}" ]] && continue
 
-		if [[ "$(head -n1 "${file}")" =~ ^'#!'.*python ]]; then
+		if [[ "$(head -n1 "${file}")" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX} ]]; then
 			[[ "$(sed -ne "2p" "${file}")" =~ ^"# Gentoo '".*"' wrapper script generated by python_generate_wrapper_scripts()"$ ]] && continue
 
 			if [[ "${quiet}" == "0" ]]; then
 				einfo "Converting shebang in '${file}'"
 			fi
 
-			sed -e "1s/python\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?/python${python_version}/" -i "${file}" || die "Conversion of shebang in '${file}' failed"
-
-			# Delete potential whitespace after "#!".
-			sed -e '1s/\(^#!\)[[:space:]]*/\1/' -i "${file}" || die "sed '${file}' failed"
+			sed -e "1s:^#![[:space:]]*\([^[:space:]]*/usr/bin/env[[:space:]]\)\?[[:space:]]*\([^[:space:]]*/\)\?\(jython\|python\)\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?\(\$\|[[:space:]].*\):#!\1\2${python_interpreter}\6:" -i "${file}" || die "Conversion of shebang in '${file}' failed"
 		fi
 	done
 }
@@ -618,17 +644,17 @@
 			fi
 
 			for PYTHON_ABI in ${USE_PYTHON}; do
-				if ! has "${PYTHON_ABI}" ${_PYTHON_SUPPORTED_ABIS[@]}; then
+				if ! has "${PYTHON_ABI}" "${_PYTHON_GLOBALLY_SUPPORTED_ABIS[@]}"; then
 					die "USE_PYTHON variable contains invalid value '${PYTHON_ABI}'"
 				fi
 
-				if has "${PYTHON_ABI}" "${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}"; then
+				if has "${PYTHON_ABI}" "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; then
 					cpython_enabled="1"
 				fi
 
 				support_ABI="1"
 				while read restricted_ABI; do
-					if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+					if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
 						support_ABI="0"
 						break
 					fi
@@ -659,10 +685,10 @@
 
 				python2_version="$("${EPREFIX}/usr/bin/python2" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
 
-				for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
+				for PYTHON_ABI in "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 					support_python_major_version="1"
 					while read restricted_ABI; do
-						if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+						if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
 							support_python_major_version="0"
 						fi
 					done <<< "${restricted_ABIs}"
@@ -670,8 +696,8 @@
 				done
 				if [[ "${support_python_major_version}" == "1" ]]; then
 					while read restricted_ABI; do
-						if [[ "${python2_version}" == ${restricted_ABI} ]]; then
-							die "Active version of Python 2 is not supported by ${CATEGORY}/${PF}"
+						if _python_check_python_abi_matching "${python2_version}" "${restricted_ABI}"; then
+							die "Active version of CPython 2 is not supported by ${CATEGORY}/${PF}"
 						fi
 					done <<< "${restricted_ABIs}"
 				else
@@ -686,10 +712,10 @@
 
 				python3_version="$("${EPREFIX}/usr/bin/python3" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
 
-				for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
+				for PYTHON_ABI in "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 					support_python_major_version="1"
 					while read restricted_ABI; do
-						if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+						if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
 							support_python_major_version="0"
 						fi
 					done <<< "${restricted_ABIs}"
@@ -697,8 +723,8 @@
 				done
 				if [[ "${support_python_major_version}" == "1" ]]; then
 					while read restricted_ABI; do
-						if [[ "${python3_version}" == ${restricted_ABI} ]]; then
-							die "Active version of Python 3 is not supported by ${CATEGORY}/${PF}"
+						if _python_check_python_abi_matching "${python3_version}" "${restricted_ABI}"; then
+							die "Active version of CPython 3 is not supported by ${CATEGORY}/${PF}"
 						fi
 					done <<< "${restricted_ABIs}"
 				else
@@ -740,7 +766,7 @@
 						element="${element#* }"
 						operator="${element%% *}"
 						flags="${element#* }"
-						if [[ "${PYTHON_ABI}" == ${pattern} ]]; then
+						if _python_check_python_abi_matching "${PYTHON_ABI}" "${pattern}"; then
 							if [[ "${operator}" == "+" ]]; then
 								eval "export ${variable}+=\"\${variable:+ }${flags}\""
 							elif [[ "${operator}" == "-" ]]; then
@@ -1057,7 +1083,7 @@
 
 	_python_initialize_prefix_variables
 
-	local eselect_python_option file force="0" quiet="0" PYTHON_ABI python2_enabled="0" python3_enabled="0" respect_EPYTHON="0"
+	local eselect_python_option file force="0" quiet="0" PYTHON_ABI PYTHON_ABIS_list python2_enabled="0" python3_enabled="0" respect_EPYTHON="0"
 
 	while (($#)); do
 		case "$1" in
@@ -1089,12 +1115,12 @@
 	fi
 
 	_python_calculate_PYTHON_ABIS
-	for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
+	for PYTHON_ABI in "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 		if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
 			python2_enabled="1"
 		fi
 	done
-	for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
+	for PYTHON_ABI in "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 		if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
 			python3_enabled="1"
 		fi
@@ -1110,9 +1136,11 @@
 		die "${FUNCNAME}(): Unsupported environment"
 	fi
 
+	PYTHON_ABIS_list="$("$(PYTHON -f)" -c "print(', '.join('\"%s\"' % x for x in reversed('${PYTHON_ABIS}'.split())))")"
+
 	for file in "$@"; do
 		if [[ -f "${file}" && "${force}" == "0" ]]; then
-			die "${FUNCNAME}(): '$1' already exists"
+			die "${FUNCNAME}(): '${file}' already exists"
 		fi
 
 		if [[ "${quiet}" == "0" ]]; then
@@ -1128,10 +1156,22 @@
 import subprocess
 import sys
 
-EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")
+cpython_re = re.compile(r"^python(\d+\.\d+)$")
+jython_re = re.compile(r"^jython(\d+\.\d+)$")
 python_shebang_re = re.compile(r"^#! *(${EPREFIX}/usr/bin/python|(${EPREFIX})?/usr/bin/env +(${EPREFIX}/usr/bin/)?python)")
 python_verification_output_re = re.compile("^GENTOO_PYTHON_TARGET_SCRIPT_PATH supported\n$")
 
+def get_PYTHON_ABI(EPYTHON):
+	cpython_matched = cpython_re.match(EPYTHON)
+	jython_matched = jython_re.match(EPYTHON)
+	if cpython_matched is not None:
+		PYTHON_ABI = cpython_matched.group(1)
+	elif jython_matched is not None:
+		PYTHON_ABI = jython_matched.group(1) + "-jython"
+	else:
+		PYTHON_ABI = None
+	return PYTHON_ABI
+
 EOF
 		if [[ "$?" != "0" ]]; then
 			die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1140,10 +1180,8 @@
 			cat << EOF >> "${file}"
 EPYTHON = os.environ.get("EPYTHON")
 if EPYTHON:
-	EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-	if EPYTHON_matched:
-		PYTHON_ABI = EPYTHON_matched.group(1)
-	else:
+	PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+	if PYTHON_ABI is None:
 		sys.stderr.write("EPYTHON variable has unrecognized value '%s'\n" % EPYTHON)
 		sys.exit(1)
 else:
@@ -1161,12 +1199,16 @@
 		EPYTHON = EPYTHON.decode()
 	EPYTHON = EPYTHON.rstrip("\n")
 
-	EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-	if EPYTHON_matched:
-		PYTHON_ABI = EPYTHON_matched.group(1)
-	else:
+	PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+	if PYTHON_ABI is None:
 		sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s'\n" % EPYTHON)
 		sys.exit(1)
+
+wrapper_script_path = os.path.realpath(sys.argv[0])
+target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+if not os.path.exists(target_executable_path):
+	sys.stderr.write("'%s' does not exist\n" % target_executable_path)
+	sys.exit(1)
 EOF
 			if [[ "$?" != "0" ]]; then
 				die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1187,12 +1229,19 @@
 	EPYTHON = EPYTHON.decode()
 EPYTHON = EPYTHON.rstrip("\n")
 
-EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-if EPYTHON_matched:
-	PYTHON_ABI = EPYTHON_matched.group(1)
-else:
+PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+if PYTHON_ABI is None:
 	sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s'\n" % EPYTHON)
 	sys.exit(1)
+
+wrapper_script_path = os.path.realpath(sys.argv[0])
+for PYTHON_ABI in [PYTHON_ABI, ${PYTHON_ABIS_list}]:
+	target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+	if os.path.exists(target_executable_path):
+		break
+else:
+	sys.stderr.write("No target script exists for '%s'\n" % wrapper_script_path)
+	sys.exit(1)
 EOF
 			if [[ "$?" != "0" ]]; then
 				die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1200,15 +1249,6 @@
 		fi
 		cat << EOF >> "${file}"
 
-wrapper_script_path = os.path.realpath(sys.argv[0])
-target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
-os.environ["GENTOO_PYTHON_PROCESS_NAME"] = os.path.basename(sys.argv[0])
-os.environ["GENTOO_PYTHON_WRAPPER_SCRIPT_PATH"] = sys.argv[0]
-os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH"] = target_executable_path
-if not os.path.exists(target_executable_path):
-	sys.stderr.write("'%s' does not exist\n" % target_executable_path)
-	sys.exit(1)
-
 target_executable = open(target_executable_path, "rb")
 target_executable_first_line = target_executable.readline()
 if not isinstance(target_executable_first_line, str):
@@ -1218,7 +1258,7 @@
 python_shebang_matched = python_shebang_re.match(target_executable_first_line)
 target_executable.close()
 
-if python_shebang_matched:
+if python_shebang_matched is not None:
 	try:
 		python_interpreter_path = "${EPREFIX}/usr/bin/%s" % EPYTHON
 		os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"] = "1"
@@ -1235,13 +1275,27 @@
 		if not python_verification_output_re.match(python_verification_output):
 			raise ValueError
 
-		os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+		if cpython_re.match(EPYTHON) is not None:
+			os.environ["GENTOO_PYTHON_PROCESS_NAME"] = os.path.basename(sys.argv[0])
+			os.environ["GENTOO_PYTHON_WRAPPER_SCRIPT_PATH"] = sys.argv[0]
+			os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH"] = target_executable_path
+
+		if hasattr(os, "execv"):
+			os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+		else:
+			sys.exit(subprocess.Popen([python_interpreter_path] + sys.argv).wait())
+	except (KeyboardInterrupt, SystemExit):
+		raise
 	except:
 		pass
-	if "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION" in os.environ:
-		del os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"]
+	for variable in ("GENTOO_PYTHON_PROCESS_NAME", "GENTOO_PYTHON_WRAPPER_SCRIPT_PATH", "GENTOO_PYTHON_TARGET_SCRIPT_PATH", "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"):
+		if variable in os.environ:
+			del os.environ[variable]
 
-os.execv(target_executable_path, sys.argv)
+if hasattr(os, "execv"):
+	os.execv(target_executable_path, sys.argv)
+else:
+	sys.exit(subprocess.Popen([target_executable_path] + sys.argv[1:]).wait())
 EOF
 		if [[ "$?" != "0" ]]; then
 			die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1250,6 +1304,184 @@
 	done
 }
 
+# @ECLASS-VARIABLE: PYTHON_VERSIONED_SCRIPTS
+# @DESCRIPTION:
+# Array of regular expressions of paths to versioned Python scripts.
+# Python scripts in /usr/bin and /usr/sbin are versioned by default.
+
+# @ECLASS-VARIABLE: PYTHON_VERSIONED_EXECUTABLES
+# @DESCRIPTION:
+# Array of regular expressions of paths to versioned executables (including Python scripts).
+
+# @ECLASS-VARIABLE: PYTHON_NONVERSIONED_EXECUTABLES
+# @DESCRIPTION:
+# Array of regular expressions of paths to nonversioned executables (including Python scripts).
+
+# @FUNCTION: python_merge_intermediate_installation_images
+# @USAGE: [-q|--quiet] [--] <intermediate_installation_images_directory>
+# @DESCRIPTION:
+# Merge intermediate installation images into installation image.
+python_merge_intermediate_installation_images() {
+	_python_check_python_pkg_setup_execution
+	_python_initialize_prefix_variables
+
+	local b file files=() intermediate_installation_images_directory PYTHON_ABI quiet="0" regex shebang version_executable wrapper_scripts=() wrapper_scripts_set=()
+
+	# Check if phase is src_install().
+	[[ "${EBUILD_PHASE}" != "install" ]] && die "${FUNCNAME}() can be used only in src_install() phase"
+
+	while (($#)); do
+		case "$1" in
+			-q|--quiet)
+				quiet="1"
+				;;
+			--)
+				shift
+				break
+				;;
+			-*)
+				die "${FUNCNAME}(): Unrecognized option '$1'"
+				;;
+			*)
+				break
+				;;
+		esac
+		shift
+	done
+
+	if [[ "$#" -ne 1 ]]; then
+		die "${FUNCNAME}() requires 1 argument"
+	fi
+
+	intermediate_installation_images_directory="$1"
+
+	if [[ ! -d "${intermediate_installation_images_directory}" ]]; then
+		die "${FUNCNAME}(): Intermediate installation images directory '${intermediate_installation_images_directory}' does not exist"
+	fi
+
+	_python_calculate_PYTHON_ABIS
+	if [[ "$(PYTHON -f --ABI)" == 3.* ]]; then
+		b="b"
+	fi
+
+	while read -d $'\0' -r file; do
+		files+=("${file}")
+	done < <("$(PYTHON -f)" -c \
+"import os
+import sys
+
+if hasattr(sys.stdout, 'buffer'):
+	# Python 3
+	stdout = sys.stdout.buffer
+else:
+	# Python 2
+	stdout = sys.stdout
+
+files_set = set()
+
+os.chdir(${b}'${intermediate_installation_images_directory}')
+
+for PYTHON_ABI in ${b}'${PYTHON_ABIS}'.split():
+	for root, dirs, files in os.walk(PYTHON_ABI + ${b}'${EPREFIX}'):
+		root = root[len(PYTHON_ABI + ${b}'${EPREFIX}')+1:]
+		files_set.update(root + ${b}'/' + file for file in files)
+
+for file in sorted(files_set):
+	stdout.write(file)
+	stdout.write(${b}'\x00')" || die "${FUNCNAME}(): Failure of extraction of files in intermediate installation images")
+
+	for PYTHON_ABI in ${PYTHON_ABIS}; do
+		if [[ ! -d "${intermediate_installation_images_directory}/${PYTHON_ABI}" ]]; then
+			die "${FUNCNAME}(): Intermediate installation image for Python ABI '${PYTHON_ABI}' does not exist"
+		fi
+
+		pushd "${intermediate_installation_images_directory}/${PYTHON_ABI}${EPREFIX}" > /dev/null || die "pushd failed"
+
+		for file in "${files[@]}"; do
+			version_executable="0"
+			for regex in "/usr/bin/.*" "/usr/sbin/.*" "${PYTHON_VERSIONED_SCRIPTS[@]}"; do
+				if [[ "/${file}" =~ ^${regex}$ ]]; then
+					version_executable="1"
+					break
+				fi
+			done
+			for regex in "${PYTHON_VERSIONED_EXECUTABLES[@]}"; do
+				if [[ "/${file}" =~ ^${regex}$ ]]; then
+					version_executable="2"
+					break
+				fi
+			done
+			if [[ "${version_executable}" != "0" ]]; then
+				for regex in "${PYTHON_NONVERSIONED_EXECUTABLES[@]}"; do
+					if [[ "/${file}" =~ ^${regex}$ ]]; then
+						version_executable="0"
+						break
+					fi
+				done
+			fi
+
+			[[ "${version_executable}" == "0" || ! -x "${file}" ]] && continue
+
+			shebang="$(head -n1 "${file}")" || die "Extraction of shebang from '${file}' failed"
+
+			if [[ "${version_executable}" == "2" ]]; then
+				wrapper_scripts+=("${ED}${file}")
+			elif [[ "${version_executable}" == "1" ]]; then
+				if [[ "${shebang}" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX}([[:digit:]]+(\.[[:digit:]]+)?)?($|[[:space:]]+) ]]; then
+					wrapper_scripts+=("${ED}${file}")
+				else
+					version_executable="0"
+				fi
+			fi
+
+			[[ "${version_executable}" == "0" ]] && continue
+
+			if [[ -e "${file}-${PYTHON_ABI}" ]]; then
+				die "${FUNCNAME}(): '${EPREFIX}/${file}-${PYTHON_ABI}' already exists"
+			fi
+
+			mv "${file}" "${file}-${PYTHON_ABI}" || die "Renaming of '${file}' failed"
+
+			if [[ "${shebang}" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX}[[:digit:]]*($|[[:space:]]+) ]]; then
+				python_convert_shebangs $([[ "${quiet}" == "1" ]] && echo --quiet) "${PYTHON_ABI}" "${file}-${PYTHON_ABI}"
+			fi
+		done
+
+		popd > /dev/null || die "popd failed"
+
+		cp -fr --preserve=all "${intermediate_installation_images_directory}/${PYTHON_ABI}/"* "${ED}" || die "Merging of intermediate installation image for Python ABI '${PYTHON_ABI} to installation image failed"
+	done
+
+	if [[ "${#wrapper_scripts[@]}" -ge 1 ]]; then
+		rm -f "${T}/python_wrapper_scripts"
+
+		for file in "${wrapper_scripts[@]}"; do
+			echo -n "${file}" >> "${T}/python_wrapper_scripts"
+			echo -en "\x00" >> "${T}/python_wrapper_scripts"
+		done
+
+		while read -d $'\0' -r file; do
+			wrapper_scripts_set+=("${file}")
+		done < <("$(PYTHON -f)" -c \
+"import sys
+
+if hasattr(sys.stdout, 'buffer'):
+	# Python 3
+	stdout = sys.stdout.buffer
+else:
+	# Python 2
+	stdout = sys.stdout
+
+files = set(open('${T}/python_wrapper_scripts', 'rb').read().rstrip(${b}'\x00').split(${b}'\x00'))
+
+for file in sorted(files):
+	stdout.write(file)
+	stdout.write(${b}'\x00')" || die "${FUNCNAME}(): Failure of extraction of set of wrapper scripts")
+
+		python_generate_wrapper_scripts $([[ "${quiet}" == "1" ]] && echo --quiet) "${wrapper_scripts_set[@]}"
+	fi
+}
+
 # ================================================================================================
 # ========= FUNCTIONS FOR PACKAGES NOT SUPPORTING INSTALLATION FOR MULTIPLE PYTHON ABIS ==========
 # ================================================================================================
@@ -1257,9 +1489,12 @@
 unset EPYTHON PYTHON_ABI
 
 # @FUNCTION: python_set_active_version
-# @USAGE: <CPython_ABI|2|3>
+# @USAGE: <Python_ABI|2|3>
 # @DESCRIPTION:
-# Set specified version of CPython as active version of Python.
+# Set locally active version of Python.
+# If Python_ABI argument is specified, then version of Python corresponding to Python_ABI is used.
+# If 2 argument is specified, then active version of CPython 2 is used.
+# If 3 argument is specified, then active version of CPython 3 is used.
 #
 # This function can be used only in pkg_setup() phase.
 python_set_active_version() {
@@ -1277,9 +1512,12 @@
 	_python_initial_sanity_checks
 
 	if [[ -z "${PYTHON_ABI}" ]]; then
-		if [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ ]]; then
-			if ! _python_implementation && ! has_version "dev-lang/python:$1"; then
-				die "${FUNCNAME}(): 'dev-lang/python:$1' is not installed"
+		if [[ -n "$(_python_get_implementation --ignore-invalid "$1")" ]]; then
+			# PYTHON_ABI variable is intended to be used only in ebuilds/eclasses,
+			# so it does not need to be exported to subprocesses.
+			PYTHON_ABI="$1"
+			if ! _python_implementation && ! has_version "$(python_get_implementational_package)"; then
+				die "${FUNCNAME}(): '$(python_get_implementational_package)' is not installed"
 			fi
 			export EPYTHON="$(PYTHON "$1")"
 		elif [[ "$1" == "2" ]]; then
@@ -1287,19 +1525,18 @@
 				die "${FUNCNAME}(): '=dev-lang/python-2*' is not installed"
 			fi
 			export EPYTHON="$(PYTHON -2)"
+			PYTHON_ABI="${EPYTHON#python}"
+			PYTHON_ABI="${PYTHON_ABI%%-*}"
 		elif [[ "$1" == "3" ]]; then
 			if ! _python_implementation && ! has_version "=dev-lang/python-3*"; then
 				die "${FUNCNAME}(): '=dev-lang/python-3*' is not installed"
 			fi
 			export EPYTHON="$(PYTHON -3)"
+			PYTHON_ABI="${EPYTHON#python}"
+			PYTHON_ABI="${PYTHON_ABI%%-*}"
 		else
 			die "${FUNCNAME}(): Unrecognized argument '$1'"
 		fi
-
-		# PYTHON_ABI variable is intended to be used only in ebuilds/eclasses,
-		# so it does not need to be exported to subprocesses.
-		PYTHON_ABI="${EPYTHON#python}"
-		PYTHON_ABI="${PYTHON_ABI%%-*}"
 	fi
 
 	_python_final_sanity_checks
@@ -1336,6 +1573,27 @@
 	sys.stdout.write("-jython")'
 
 _python_get_implementation() {
+	local ignore_invalid="0"
+
+	while (($#)); do
+		case "$1" in
+			--ignore-invalid)
+				ignore_invalid="1"
+				;;
+			--)
+				shift
+				break
+				;;
+			-*)
+				die "${FUNCNAME}(): Unrecognized option '$1'"
+				;;
+			*)
+				break
+				;;
+		esac
+		shift
+	done
+
 	if [[ "$#" -ne 1 ]]; then
 		die "${FUNCNAME}() requires 1 argument"
 	fi
@@ -1345,7 +1603,9 @@
 	elif [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+-jython$ ]]; then
 		echo "Jython"
 	else
-		die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+		if [[ "${ignore_invalid}" == "0" ]]; then
+			die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+		fi
 	fi
 }
 
@@ -1354,8 +1614,8 @@
 # @DESCRIPTION:
 # Print filename of Python interpreter for specified Python ABI. If Python_ABI argument
 # is ommitted, then PYTHON_ABI environment variable must be set and is used.
-# If -2 option is specified, then active version of Python 2 is used.
-# If -3 option is specified, then active version of Python 3 is used.
+# If -2 option is specified, then active version of CPython 2 is used.
+# If -3 option is specified, then active version of CPython 3 is used.
 # If --final-ABI option is specified, then final ABI from the list of enabled ABIs is used.
 # -2, -3 and --final-ABI options and Python_ABI argument cannot be specified simultaneously.
 # If --ABI option is specified, then only specified Python ABI is printed instead of
@@ -1416,14 +1676,14 @@
 		elif [[ "${python2}" == "1" ]]; then
 			PYTHON_ABI="$(eselect python show --python2 --ABI)"
 			if [[ -z "${PYTHON_ABI}" ]]; then
-				die "${FUNCNAME}(): Active version of Python 2 not set"
+				die "${FUNCNAME}(): Active version of CPython 2 not set"
 			elif [[ "${PYTHON_ABI}" != "2."* ]]; then
 				die "${FUNCNAME}(): Internal error in \`eselect python show --python2\`"
 			fi
 		elif [[ "${python3}" == "1" ]]; then
 			PYTHON_ABI="$(eselect python show --python3 --ABI)"
 			if [[ -z "${PYTHON_ABI}" ]]; then
-				die "${FUNCNAME}(): Active version of Python 3 not set"
+				die "${FUNCNAME}(): Active version of CPython 3 not set"
 			elif [[ "${PYTHON_ABI}" != "3."* ]]; then
 				die "${FUNCNAME}(): Internal error in \`eselect python show --python3\`"
 			fi
@@ -1459,7 +1719,7 @@
 		if [[ "$(_python_get_implementation "${PYTHON_ABI}")" == "CPython" ]]; then
 			python_interpreter="python${PYTHON_ABI}"
 		elif [[ "$(_python_get_implementation "${PYTHON_ABI}")" == "Jython" ]]; then
-			python_interpreter="jython-${PYTHON_ABI%-jython}"
+			python_interpreter="jython${PYTHON_ABI%-jython}"
 		fi
 
 		if [[ "${absolute_path_output}" == "1" ]]; then
@@ -2176,7 +2436,7 @@
 					base_module_name="${base_module_name%\$py.class}"
 					py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
 				else
-					py_file="${compiled_file%\$py.class}"
+					py_file="${compiled_file%\$py.class}.py"
 				fi
 				if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
 					[[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue

[-- Attachment #1.3: python.eclass.patch.1 --]
[-- Type: text/x-patch, Size: 17576 bytes --]

--- python.eclass
+++ python.eclass
@@ -24,6 +24,26 @@
 # ===================================== HANDLING OF METADATA =====================================
 # ================================================================================================
 
+_python_check_python_abi_matching() {
+	if [[ "$#" -ne 2 ]]; then
+		die "${FUNCNAME}() requires 2 arguments"
+	fi
+
+	if [[ "$2" == *"-cpython" ]]; then
+		[[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ && "$1" == ${2%-cpython} ]]
+	elif [[ "$2" == *"-jython" ]]; then
+		[[ "$1" == $2 ]]
+	else
+		if [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ ]]; then
+			[[ "$1" == $2 ]]
+		elif [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+-jython$ ]]; then
+			[[ "${1%-jython}" == $2 ]]
+		else
+			die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+		fi
+	fi
+}
+
 # @ECLASS-VARIABLE: PYTHON_DEPEND
 # @DESCRIPTION:
 # Specification of dependency on dev-lang/python.
@@ -350,6 +370,9 @@
 		die "${FUNCNAME}() does not accept arguments"
 	fi
 
+	export JYTHON_SYSTEM_CACHEDIR="1"
+	addwrite "${EPREFIX}/var/cache/jython"
+
 	if _python_package_supporting_installation_for_multiple_python_abis; then
 		_python_calculate_PYTHON_ABIS
 		export EPYTHON="$(PYTHON -f)"
@@ -405,14 +428,16 @@
 	EXPORT_FUNCTIONS pkg_setup
 fi
 
+_PYTHON_SHEBANG_BASE_PART_REGEX='^#![[:space:]]*([^[:space:]]*/usr/bin/env[[:space:]]+)?([^[:space:]]*/)?(jython|python)'
+
 # @FUNCTION: python_convert_shebangs
-# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
+# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_ABI|Python_version> <file|directory> [files|directories]
 # @DESCRIPTION:
 # Convert shebangs in specified files. Directories can be specified only with --recursive option.
 python_convert_shebangs() {
 	_python_check_python_pkg_setup_execution
 
-	local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
+	local argument file files=() only_executables="0" python_interpreter quiet="0" recursive="0"
 
 	while (($#)); do
 		case "$1" in
@@ -445,7 +470,11 @@
 		die "${FUNCNAME}(): Missing files or directories"
 	fi
 
-	python_version="$1"
+	if [[ -n "$(_python_get_implementation --ignore-invalid "$1")" ]]; then
+		python_interpreter="$(PYTHON "$1")"
+	else
+		python_interpreter="python$1"
+	fi
 	shift
 
 	for argument in "$@"; do
@@ -470,17 +499,14 @@
 		file="${file#./}"
 		[[ "${only_executables}" == "1" && ! -x "${file}" ]] && continue
 
-		if [[ "$(head -n1 "${file}")" =~ ^'#!'.*python ]]; then
+		if [[ "$(head -n1 "${file}")" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX} ]]; then
 			[[ "$(sed -ne "2p" "${file}")" =~ ^"# Gentoo '".*"' wrapper script generated by python_generate_wrapper_scripts()"$ ]] && continue
 
 			if [[ "${quiet}" == "0" ]]; then
 				einfo "Converting shebang in '${file}'"
 			fi
 
-			sed -e "1s/python\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?/python${python_version}/" -i "${file}" || die "Conversion of shebang in '${file}' failed"
-
-			# Delete potential whitespace after "#!".
-			sed -e '1s/\(^#!\)[[:space:]]*/\1/' -i "${file}" || die "sed '${file}' failed"
+			sed -e "1s:^#![[:space:]]*\([^[:space:]]*/usr/bin/env[[:space:]]\)\?[[:space:]]*\([^[:space:]]*/\)\?\(jython\|python\)\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?\(\$\|[[:space:]].*\):#!\1\2${python_interpreter}\6:" -i "${file}" || die "Conversion of shebang in '${file}' failed"
 		fi
 	done
 }
@@ -628,7 +654,7 @@
 
 				support_ABI="1"
 				while read restricted_ABI; do
-					if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+					if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
 						support_ABI="0"
 						break
 					fi
@@ -662,7 +688,7 @@
 				for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
 					support_python_major_version="1"
 					while read restricted_ABI; do
-						if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+						if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
 							support_python_major_version="0"
 						fi
 					done <<< "${restricted_ABIs}"
@@ -670,8 +696,8 @@
 				done
 				if [[ "${support_python_major_version}" == "1" ]]; then
 					while read restricted_ABI; do
-						if [[ "${python2_version}" == ${restricted_ABI} ]]; then
-							die "Active version of Python 2 is not supported by ${CATEGORY}/${PF}"
+						if _python_check_python_abi_matching "${python2_version}" "${restricted_ABI}"; then
+							die "Active version of CPython 2 is not supported by ${CATEGORY}/${PF}"
 						fi
 					done <<< "${restricted_ABIs}"
 				else
@@ -689,7 +715,7 @@
 				for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
 					support_python_major_version="1"
 					while read restricted_ABI; do
-						if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+						if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
 							support_python_major_version="0"
 						fi
 					done <<< "${restricted_ABIs}"
@@ -697,8 +723,8 @@
 				done
 				if [[ "${support_python_major_version}" == "1" ]]; then
 					while read restricted_ABI; do
-						if [[ "${python3_version}" == ${restricted_ABI} ]]; then
-							die "Active version of Python 3 is not supported by ${CATEGORY}/${PF}"
+						if _python_check_python_abi_matching "${python3_version}" "${restricted_ABI}"; then
+							die "Active version of CPython 3 is not supported by ${CATEGORY}/${PF}"
 						fi
 					done <<< "${restricted_ABIs}"
 				else
@@ -740,7 +766,7 @@
 						element="${element#* }"
 						operator="${element%% *}"
 						flags="${element#* }"
-						if [[ "${PYTHON_ABI}" == ${pattern} ]]; then
+						if _python_check_python_abi_matching "${PYTHON_ABI}" "${pattern}"; then
 							if [[ "${operator}" == "+" ]]; then
 								eval "export ${variable}+=\"\${variable:+ }${flags}\""
 							elif [[ "${operator}" == "-" ]]; then
@@ -1057,7 +1083,7 @@
 
 	_python_initialize_prefix_variables
 
-	local eselect_python_option file force="0" quiet="0" PYTHON_ABI python2_enabled="0" python3_enabled="0" respect_EPYTHON="0"
+	local eselect_python_option file force="0" quiet="0" PYTHON_ABI PYTHON_ABIS_list python2_enabled="0" python3_enabled="0" respect_EPYTHON="0"
 
 	while (($#)); do
 		case "$1" in
@@ -1110,9 +1136,11 @@
 		die "${FUNCNAME}(): Unsupported environment"
 	fi
 
+	PYTHON_ABIS_list="$("$(PYTHON -f)" -c "print(', '.join('\"%s\"' % x for x in reversed('${PYTHON_ABIS}'.split())))")"
+
 	for file in "$@"; do
 		if [[ -f "${file}" && "${force}" == "0" ]]; then
-			die "${FUNCNAME}(): '$1' already exists"
+			die "${FUNCNAME}(): '${file}' already exists"
 		fi
 
 		if [[ "${quiet}" == "0" ]]; then
@@ -1128,10 +1156,22 @@
 import subprocess
 import sys
 
-EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")
+cpython_re = re.compile(r"^python(\d+\.\d+)$")
+jython_re = re.compile(r"^jython(\d+\.\d+)$")
 python_shebang_re = re.compile(r"^#! *(${EPREFIX}/usr/bin/python|(${EPREFIX})?/usr/bin/env +(${EPREFIX}/usr/bin/)?python)")
 python_verification_output_re = re.compile("^GENTOO_PYTHON_TARGET_SCRIPT_PATH supported\n$")
 
+def get_PYTHON_ABI(EPYTHON):
+	cpython_matched = cpython_re.match(EPYTHON)
+	jython_matched = jython_re.match(EPYTHON)
+	if cpython_matched is not None:
+		PYTHON_ABI = cpython_matched.group(1)
+	elif jython_matched is not None:
+		PYTHON_ABI = jython_matched.group(1) + "-jython"
+	else:
+		PYTHON_ABI = None
+	return PYTHON_ABI
+
 EOF
 		if [[ "$?" != "0" ]]; then
 			die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1140,10 +1180,8 @@
 			cat << EOF >> "${file}"
 EPYTHON = os.environ.get("EPYTHON")
 if EPYTHON:
-	EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-	if EPYTHON_matched:
-		PYTHON_ABI = EPYTHON_matched.group(1)
-	else:
+	PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+	if PYTHON_ABI is None:
 		sys.stderr.write("EPYTHON variable has unrecognized value '%s'\n" % EPYTHON)
 		sys.exit(1)
 else:
@@ -1161,12 +1199,16 @@
 		EPYTHON = EPYTHON.decode()
 	EPYTHON = EPYTHON.rstrip("\n")
 
-	EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-	if EPYTHON_matched:
-		PYTHON_ABI = EPYTHON_matched.group(1)
-	else:
+	PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+	if PYTHON_ABI is None:
 		sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s'\n" % EPYTHON)
 		sys.exit(1)
+
+wrapper_script_path = os.path.realpath(sys.argv[0])
+target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+if not os.path.exists(target_executable_path):
+	sys.stderr.write("'%s' does not exist\n" % target_executable_path)
+	sys.exit(1)
 EOF
 			if [[ "$?" != "0" ]]; then
 				die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1187,12 +1229,19 @@
 	EPYTHON = EPYTHON.decode()
 EPYTHON = EPYTHON.rstrip("\n")
 
-EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-if EPYTHON_matched:
-	PYTHON_ABI = EPYTHON_matched.group(1)
-else:
+PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+if PYTHON_ABI is None:
 	sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s'\n" % EPYTHON)
 	sys.exit(1)
+
+wrapper_script_path = os.path.realpath(sys.argv[0])
+for PYTHON_ABI in [PYTHON_ABI, ${PYTHON_ABIS_list}]:
+	target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+	if os.path.exists(target_executable_path):
+		break
+else:
+	sys.stderr.write("No target script exists for '%s'\n" % wrapper_script_path)
+	sys.exit(1)
 EOF
 			if [[ "$?" != "0" ]]; then
 				die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1200,15 +1249,6 @@
 		fi
 		cat << EOF >> "${file}"
 
-wrapper_script_path = os.path.realpath(sys.argv[0])
-target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
-os.environ["GENTOO_PYTHON_PROCESS_NAME"] = os.path.basename(sys.argv[0])
-os.environ["GENTOO_PYTHON_WRAPPER_SCRIPT_PATH"] = sys.argv[0]
-os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH"] = target_executable_path
-if not os.path.exists(target_executable_path):
-	sys.stderr.write("'%s' does not exist\n" % target_executable_path)
-	sys.exit(1)
-
 target_executable = open(target_executable_path, "rb")
 target_executable_first_line = target_executable.readline()
 if not isinstance(target_executable_first_line, str):
@@ -1218,7 +1258,7 @@
 python_shebang_matched = python_shebang_re.match(target_executable_first_line)
 target_executable.close()
 
-if python_shebang_matched:
+if python_shebang_matched is not None:
 	try:
 		python_interpreter_path = "${EPREFIX}/usr/bin/%s" % EPYTHON
 		os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"] = "1"
@@ -1235,13 +1275,27 @@
 		if not python_verification_output_re.match(python_verification_output):
 			raise ValueError
 
-		os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+		if cpython_re.match(EPYTHON) is not None:
+			os.environ["GENTOO_PYTHON_PROCESS_NAME"] = os.path.basename(sys.argv[0])
+			os.environ["GENTOO_PYTHON_WRAPPER_SCRIPT_PATH"] = sys.argv[0]
+			os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH"] = target_executable_path
+
+		if hasattr(os, "execv"):
+			os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+		else:
+			sys.exit(subprocess.Popen([python_interpreter_path] + sys.argv).wait())
+	except (KeyboardInterrupt, SystemExit):
+		raise
 	except:
 		pass
-	if "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION" in os.environ:
-		del os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"]
+	for variable in ("GENTOO_PYTHON_PROCESS_NAME", "GENTOO_PYTHON_WRAPPER_SCRIPT_PATH", "GENTOO_PYTHON_TARGET_SCRIPT_PATH", "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"):
+		if variable in os.environ:
+			del os.environ[variable]
 
-os.execv(target_executable_path, sys.argv)
+if hasattr(os, "execv"):
+	os.execv(target_executable_path, sys.argv)
+else:
+	sys.exit(subprocess.Popen([target_executable_path] + sys.argv[1:]).wait())
 EOF
 		if [[ "$?" != "0" ]]; then
 			die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1257,9 +1311,12 @@
 unset EPYTHON PYTHON_ABI
 
 # @FUNCTION: python_set_active_version
-# @USAGE: <CPython_ABI|2|3>
+# @USAGE: <Python_ABI|2|3>
 # @DESCRIPTION:
-# Set specified version of CPython as active version of Python.
+# Set locally active version of Python.
+# If Python_ABI argument is specified, then version of Python corresponding to Python_ABI is used.
+# If 2 argument is specified, then active version of CPython 2 is used.
+# If 3 argument is specified, then active version of CPython 3 is used.
 #
 # This function can be used only in pkg_setup() phase.
 python_set_active_version() {
@@ -1277,9 +1334,12 @@
 	_python_initial_sanity_checks
 
 	if [[ -z "${PYTHON_ABI}" ]]; then
-		if [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ ]]; then
-			if ! _python_implementation && ! has_version "dev-lang/python:$1"; then
-				die "${FUNCNAME}(): 'dev-lang/python:$1' is not installed"
+		if [[ -n "$(_python_get_implementation --ignore-invalid "$1")" ]]; then
+			# PYTHON_ABI variable is intended to be used only in ebuilds/eclasses,
+			# so it does not need to be exported to subprocesses.
+			PYTHON_ABI="$1"
+			if ! _python_implementation && ! has_version "$(python_get_implementational_package)"; then
+				die "${FUNCNAME}(): '$(python_get_implementational_package)' is not installed"
 			fi
 			export EPYTHON="$(PYTHON "$1")"
 		elif [[ "$1" == "2" ]]; then
@@ -1287,19 +1347,18 @@
 				die "${FUNCNAME}(): '=dev-lang/python-2*' is not installed"
 			fi
 			export EPYTHON="$(PYTHON -2)"
+			PYTHON_ABI="${EPYTHON#python}"
+			PYTHON_ABI="${PYTHON_ABI%%-*}"
 		elif [[ "$1" == "3" ]]; then
 			if ! _python_implementation && ! has_version "=dev-lang/python-3*"; then
 				die "${FUNCNAME}(): '=dev-lang/python-3*' is not installed"
 			fi
 			export EPYTHON="$(PYTHON -3)"
+			PYTHON_ABI="${EPYTHON#python}"
+			PYTHON_ABI="${PYTHON_ABI%%-*}"
 		else
 			die "${FUNCNAME}(): Unrecognized argument '$1'"
 		fi
-
-		# PYTHON_ABI variable is intended to be used only in ebuilds/eclasses,
-		# so it does not need to be exported to subprocesses.
-		PYTHON_ABI="${EPYTHON#python}"
-		PYTHON_ABI="${PYTHON_ABI%%-*}"
 	fi
 
 	_python_final_sanity_checks
@@ -1336,6 +1395,27 @@
 	sys.stdout.write("-jython")'
 
 _python_get_implementation() {
+	local ignore_invalid="0"
+
+	while (($#)); do
+		case "$1" in
+			--ignore-invalid)
+				ignore_invalid="1"
+				;;
+			--)
+				shift
+				break
+				;;
+			-*)
+				die "${FUNCNAME}(): Unrecognized option '$1'"
+				;;
+			*)
+				break
+				;;
+		esac
+		shift
+	done
+
 	if [[ "$#" -ne 1 ]]; then
 		die "${FUNCNAME}() requires 1 argument"
 	fi
@@ -1345,7 +1425,9 @@
 	elif [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+-jython$ ]]; then
 		echo "Jython"
 	else
-		die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+		if [[ "${ignore_invalid}" == "0" ]]; then
+			die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+		fi
 	fi
 }
 
@@ -1354,8 +1436,8 @@
 # @DESCRIPTION:
 # Print filename of Python interpreter for specified Python ABI. If Python_ABI argument
 # is ommitted, then PYTHON_ABI environment variable must be set and is used.
-# If -2 option is specified, then active version of Python 2 is used.
-# If -3 option is specified, then active version of Python 3 is used.
+# If -2 option is specified, then active version of CPython 2 is used.
+# If -3 option is specified, then active version of CPython 3 is used.
 # If --final-ABI option is specified, then final ABI from the list of enabled ABIs is used.
 # -2, -3 and --final-ABI options and Python_ABI argument cannot be specified simultaneously.
 # If --ABI option is specified, then only specified Python ABI is printed instead of
@@ -1416,14 +1498,14 @@
 		elif [[ "${python2}" == "1" ]]; then
 			PYTHON_ABI="$(eselect python show --python2 --ABI)"
 			if [[ -z "${PYTHON_ABI}" ]]; then
-				die "${FUNCNAME}(): Active version of Python 2 not set"
+				die "${FUNCNAME}(): Active version of CPython 2 not set"
 			elif [[ "${PYTHON_ABI}" != "2."* ]]; then
 				die "${FUNCNAME}(): Internal error in \`eselect python show --python2\`"
 			fi
 		elif [[ "${python3}" == "1" ]]; then
 			PYTHON_ABI="$(eselect python show --python3 --ABI)"
 			if [[ -z "${PYTHON_ABI}" ]]; then
-				die "${FUNCNAME}(): Active version of Python 3 not set"
+				die "${FUNCNAME}(): Active version of CPython 3 not set"
 			elif [[ "${PYTHON_ABI}" != "3."* ]]; then
 				die "${FUNCNAME}(): Internal error in \`eselect python show --python3\`"
 			fi
@@ -1459,7 +1541,7 @@
 		if [[ "$(_python_get_implementation "${PYTHON_ABI}")" == "CPython" ]]; then
 			python_interpreter="python${PYTHON_ABI}"
 		elif [[ "$(_python_get_implementation "${PYTHON_ABI}")" == "Jython" ]]; then
-			python_interpreter="jython-${PYTHON_ABI%-jython}"
+			python_interpreter="jython${PYTHON_ABI%-jython}"
 		fi
 
 		if [[ "${absolute_path_output}" == "1" ]]; then
@@ -2176,7 +2258,7 @@
 					base_module_name="${base_module_name%\$py.class}"
 					py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
 				else
-					py_file="${compiled_file%\$py.class}"
+					py_file="${compiled_file%\$py.class}.py"
 				fi
 				if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
 					[[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue

[-- Attachment #1.4: python.eclass.patch.2 --]
[-- Type: text/x-patch, Size: 6265 bytes --]

--- python.eclass
+++ python.eclass
@@ -1304,6 +1304,184 @@
 	done
 }
 
+# @ECLASS-VARIABLE: PYTHON_VERSIONED_SCRIPTS
+# @DESCRIPTION:
+# Array of regular expressions of paths to versioned Python scripts.
+# Python scripts in /usr/bin and /usr/sbin are versioned by default.
+
+# @ECLASS-VARIABLE: PYTHON_VERSIONED_EXECUTABLES
+# @DESCRIPTION:
+# Array of regular expressions of paths to versioned executables (including Python scripts).
+
+# @ECLASS-VARIABLE: PYTHON_NONVERSIONED_EXECUTABLES
+# @DESCRIPTION:
+# Array of regular expressions of paths to nonversioned executables (including Python scripts).
+
+# @FUNCTION: python_merge_intermediate_installation_images
+# @USAGE: [-q|--quiet] [--] <intermediate_installation_images_directory>
+# @DESCRIPTION:
+# Merge intermediate installation images into installation image.
+python_merge_intermediate_installation_images() {
+	_python_check_python_pkg_setup_execution
+	_python_initialize_prefix_variables
+
+	local b file files=() intermediate_installation_images_directory PYTHON_ABI quiet="0" regex shebang version_executable wrapper_scripts=() wrapper_scripts_set=()
+
+	# Check if phase is src_install().
+	[[ "${EBUILD_PHASE}" != "install" ]] && die "${FUNCNAME}() can be used only in src_install() phase"
+
+	while (($#)); do
+		case "$1" in
+			-q|--quiet)
+				quiet="1"
+				;;
+			--)
+				shift
+				break
+				;;
+			-*)
+				die "${FUNCNAME}(): Unrecognized option '$1'"
+				;;
+			*)
+				break
+				;;
+		esac
+		shift
+	done
+
+	if [[ "$#" -ne 1 ]]; then
+		die "${FUNCNAME}() requires 1 argument"
+	fi
+
+	intermediate_installation_images_directory="$1"
+
+	if [[ ! -d "${intermediate_installation_images_directory}" ]]; then
+		die "${FUNCNAME}(): Intermediate installation images directory '${intermediate_installation_images_directory}' does not exist"
+	fi
+
+	_python_calculate_PYTHON_ABIS
+	if [[ "$(PYTHON -f --ABI)" == 3.* ]]; then
+		b="b"
+	fi
+
+	while read -d $'\0' -r file; do
+		files+=("${file}")
+	done < <("$(PYTHON -f)" -c \
+"import os
+import sys
+
+if hasattr(sys.stdout, 'buffer'):
+	# Python 3
+	stdout = sys.stdout.buffer
+else:
+	# Python 2
+	stdout = sys.stdout
+
+files_set = set()
+
+os.chdir(${b}'${intermediate_installation_images_directory}')
+
+for PYTHON_ABI in ${b}'${PYTHON_ABIS}'.split():
+	for root, dirs, files in os.walk(PYTHON_ABI + ${b}'${EPREFIX}'):
+		root = root[len(PYTHON_ABI + ${b}'${EPREFIX}')+1:]
+		files_set.update(root + ${b}'/' + file for file in files)
+
+for file in sorted(files_set):
+	stdout.write(file)
+	stdout.write(${b}'\x00')" || die "${FUNCNAME}(): Failure of extraction of files in intermediate installation images")
+
+	for PYTHON_ABI in ${PYTHON_ABIS}; do
+		if [[ ! -d "${intermediate_installation_images_directory}/${PYTHON_ABI}" ]]; then
+			die "${FUNCNAME}(): Intermediate installation image for Python ABI '${PYTHON_ABI}' does not exist"
+		fi
+
+		pushd "${intermediate_installation_images_directory}/${PYTHON_ABI}${EPREFIX}" > /dev/null || die "pushd failed"
+
+		for file in "${files[@]}"; do
+			version_executable="0"
+			for regex in "/usr/bin/.*" "/usr/sbin/.*" "${PYTHON_VERSIONED_SCRIPTS[@]}"; do
+				if [[ "/${file}" =~ ^${regex}$ ]]; then
+					version_executable="1"
+					break
+				fi
+			done
+			for regex in "${PYTHON_VERSIONED_EXECUTABLES[@]}"; do
+				if [[ "/${file}" =~ ^${regex}$ ]]; then
+					version_executable="2"
+					break
+				fi
+			done
+			if [[ "${version_executable}" != "0" ]]; then
+				for regex in "${PYTHON_NONVERSIONED_EXECUTABLES[@]}"; do
+					if [[ "/${file}" =~ ^${regex}$ ]]; then
+						version_executable="0"
+						break
+					fi
+				done
+			fi
+
+			[[ "${version_executable}" == "0" || ! -x "${file}" ]] && continue
+
+			shebang="$(head -n1 "${file}")" || die "Extraction of shebang from '${file}' failed"
+
+			if [[ "${version_executable}" == "2" ]]; then
+				wrapper_scripts+=("${ED}${file}")
+			elif [[ "${version_executable}" == "1" ]]; then
+				if [[ "${shebang}" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX}([[:digit:]]+(\.[[:digit:]]+)?)?($|[[:space:]]+) ]]; then
+					wrapper_scripts+=("${ED}${file}")
+				else
+					version_executable="0"
+				fi
+			fi
+
+			[[ "${version_executable}" == "0" ]] && continue
+
+			if [[ -e "${file}-${PYTHON_ABI}" ]]; then
+				die "${FUNCNAME}(): '${EPREFIX}/${file}-${PYTHON_ABI}' already exists"
+			fi
+
+			mv "${file}" "${file}-${PYTHON_ABI}" || die "Renaming of '${file}' failed"
+
+			if [[ "${shebang}" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX}[[:digit:]]*($|[[:space:]]+) ]]; then
+				python_convert_shebangs $([[ "${quiet}" == "1" ]] && echo --quiet) "${PYTHON_ABI}" "${file}-${PYTHON_ABI}"
+			fi
+		done
+
+		popd > /dev/null || die "popd failed"
+
+		cp -fr --preserve=all "${intermediate_installation_images_directory}/${PYTHON_ABI}/"* "${ED}" || die "Merging of intermediate installation image for Python ABI '${PYTHON_ABI} to installation image failed"
+	done
+
+	if [[ "${#wrapper_scripts[@]}" -ge 1 ]]; then
+		rm -f "${T}/python_wrapper_scripts"
+
+		for file in "${wrapper_scripts[@]}"; do
+			echo -n "${file}" >> "${T}/python_wrapper_scripts"
+			echo -en "\x00" >> "${T}/python_wrapper_scripts"
+		done
+
+		while read -d $'\0' -r file; do
+			wrapper_scripts_set+=("${file}")
+		done < <("$(PYTHON -f)" -c \
+"import sys
+
+if hasattr(sys.stdout, 'buffer'):
+	# Python 3
+	stdout = sys.stdout.buffer
+else:
+	# Python 2
+	stdout = sys.stdout
+
+files = set(open('${T}/python_wrapper_scripts', 'rb').read().rstrip(${b}'\x00').split(${b}'\x00'))
+
+for file in sorted(files):
+	stdout.write(file)
+	stdout.write(${b}'\x00')" || die "${FUNCNAME}(): Failure of extraction of set of wrapper scripts")
+
+		python_generate_wrapper_scripts $([[ "${quiet}" == "1" ]] && echo --quiet) "${wrapper_scripts_set[@]}"
+	fi
+}
+
 # ================================================================================================
 # ========= FUNCTIONS FOR PACKAGES NOT SUPPORTING INSTALLATION FOR MULTIPLE PYTHON ABIS ==========
 # ================================================================================================

[-- Attachment #1.5: python.eclass.patch.3 --]
[-- Type: text/x-patch, Size: 5408 bytes --]

--- python.eclass
+++ python.eclass
@@ -15,10 +15,10 @@
 	die "API of python.eclass in EAPI=\"${EAPI}\" not established"
 fi
 
-_CPYTHON2_SUPPORTED_ABIS=(2.4 2.5 2.6 2.7)
-_CPYTHON3_SUPPORTED_ABIS=(3.0 3.1 3.2)
-_JYTHON_SUPPORTED_ABIS=(2.5-jython)
-_PYTHON_SUPPORTED_ABIS=(${_CPYTHON2_SUPPORTED_ABIS[@]} ${_CPYTHON3_SUPPORTED_ABIS[@]} ${_JYTHON_SUPPORTED_ABIS[@]})
+_CPYTHON2_GLOBALLY_SUPPORTED_ABIS=(2.4 2.5 2.6 2.7)
+_CPYTHON3_GLOBALLY_SUPPORTED_ABIS=(3.0 3.1 3.2)
+_JYTHON_GLOBALLY_SUPPORTED_ABIS=(2.5-jython)
+_PYTHON_GLOBALLY_SUPPORTED_ABIS=(${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]} ${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]} ${_JYTHON_GLOBALLY_SUPPORTED_ABIS[@]})
 
 # ================================================================================================
 # ===================================== HANDLING OF METADATA =====================================
@@ -87,17 +87,17 @@
 
 			if [[ "${major_version}" == "2" ]]; then
 				python2="1"
-				python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python2_minimal_version="${minimal_version}"
 				python2_maximal_version="${maximal_version}"
 			elif [[ "${major_version}" == "3" ]]; then
 				python3="1"
-				python_versions=("${_CPYTHON3_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python3_minimal_version="${minimal_version}"
 				python3_maximal_version="${maximal_version}"
 			else
 				python_all="1"
-				python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python_minimal_version="${minimal_version}"
 				python_maximal_version="${maximal_version}"
 			fi
@@ -135,7 +135,7 @@
 			if [[ -z "${python_minimal_version}" && -z "${python_maximal_version}" ]]; then
 				_PYTHON_ATOMS+=("dev-lang/python")
 			else
-				python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}")
+				python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 				python_minimal_version="${python_minimal_version:-${python_versions[0]}}"
 				python_maximal_version="${python_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
 				_append_accepted_versions_range
@@ -145,7 +145,7 @@
 				if [[ -z "${python3_minimal_version}" && -z "${python3_maximal_version}" ]]; then
 					_PYTHON_ATOMS+=("=dev-lang/python-3*")
 				else
-					python_versions=("${_CPYTHON3_SUPPORTED_ABIS[@]}")
+					python_versions=("${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
 					python_minimal_version="${python3_minimal_version:-${python_versions[0]}}"
 					python_maximal_version="${python3_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
 					_append_accepted_versions_range
@@ -155,7 +155,7 @@
 				if [[ -z "${python2_minimal_version}" && -z "${python2_maximal_version}" ]]; then
 					_PYTHON_ATOMS+=("=dev-lang/python-2*")
 				else
-					python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}")
+					python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}")
 					python_minimal_version="${python2_minimal_version:-${python_versions[0]}}"
 					python_maximal_version="${python2_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
 					_append_accepted_versions_range
@@ -644,11 +644,11 @@
 			fi
 
 			for PYTHON_ABI in ${USE_PYTHON}; do
-				if ! has "${PYTHON_ABI}" ${_PYTHON_SUPPORTED_ABIS[@]}; then
+				if ! has "${PYTHON_ABI}" "${_PYTHON_GLOBALLY_SUPPORTED_ABIS[@]}"; then
 					die "USE_PYTHON variable contains invalid value '${PYTHON_ABI}'"
 				fi
 
-				if has "${PYTHON_ABI}" "${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}"; then
+				if has "${PYTHON_ABI}" "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; then
 					cpython_enabled="1"
 				fi
 
@@ -685,7 +685,7 @@
 
 				python2_version="$("${EPREFIX}/usr/bin/python2" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
 
-				for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
+				for PYTHON_ABI in "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 					support_python_major_version="1"
 					while read restricted_ABI; do
 						if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
@@ -712,7 +712,7 @@
 
 				python3_version="$("${EPREFIX}/usr/bin/python3" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
 
-				for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
+				for PYTHON_ABI in "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 					support_python_major_version="1"
 					while read restricted_ABI; do
 						if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
@@ -1115,12 +1115,12 @@
 	fi
 
 	_python_calculate_PYTHON_ABIS
-	for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
+	for PYTHON_ABI in "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 		if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
 			python2_enabled="1"
 		fi
 	done
-	for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
+	for PYTHON_ABI in "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; do
 		if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
 			python3_enabled="1"
 		fi

[-- Attachment #1.6: distutils.eclass.patch --]
[-- Type: text/x-patch, Size: 4808 bytes --]

--- distutils.eclass
+++ distutils.eclass
@@ -27,6 +27,24 @@
 	RDEPEND="${DEPEND}"
 fi
 
+if [[ -n "${PYTHON_DEPRECATION_WARNINGS}" ]]; then
+	if has "${EAPI:-0}" 0 1 && [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
+		ewarn
+		ewarn "\"${EBUILD}\":"
+		ewarn "Deprecation Warning: Usage of distutils.eclass in packages supporting installation"
+		ewarn "for multiple Python ABIs in EAPI <=1 is deprecated and will be banned on 2011-06-01."
+		ewarn "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
+		ewarn
+	elif has "${EAPI:-0}" 0 1 2 && [[ -z "${SUPPORT_PYTHON_ABIS}" ]]; then
+		ewarn
+		ewarn "\"${EBUILD}\":"
+		ewarn "Deprecation Warning: Usage of distutils.eclass in packages not supporting installation"
+		ewarn "for multiple Python ABIs in EAPI <=2 is deprecated and will be banned on 2011-06-01."
+		ewarn "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
+		ewarn
+	fi
+fi
+
 # 'python' variable is deprecated. Use PYTHON() instead.
 if has "${EAPI:-0}" 0 1 2 && [[ -z "${SUPPORT_PYTHON_ABIS}" ]]; then
 	python="python"
@@ -86,11 +104,16 @@
 # @DESCRIPTION:
 # Set this to disable renaming of Python scripts containing versioned shebangs
 # and generation of wrapper scripts.
+if [[ -n "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" ]]; then
+	ewarn
+	ewarn "\"${EBUILD}\":"
+	ewarn "Deprecation Warning: DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS is deprecated"
+	ewarn "and will be banned on 2011-02-01. Use PYTHON_NONVERSIONED_EXECUTABLES=(\".*\")."
+	ewarn "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
+	ewarn
 
-# @ECLASS-VARIABLE: DISTUTILS_NONVERSIONED_PYTHON_SCRIPTS
-# @DESCRIPTION:
-# List of paths to Python scripts, relative to ${ED}, which are excluded from
-# renaming and generation of wrapper scripts.
+	PYTHON_NONVERSIONED_EXECUTABLES=(".*")
+fi
 
 # @ECLASS-VARIABLE: DOCS
 # @DESCRIPTION:
@@ -298,48 +321,20 @@
 	_python_set_color_variables
 
 	if _python_package_supporting_installation_for_multiple_python_abis; then
-		if [[ -z "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-			declare -A wrapper_scripts=()
-
-			rename_scripts_with_versioned_shebangs() {
-				if [[ -d "${ED}usr/bin" ]]; then
-					cd "${ED}usr/bin"
-
-					local nonversioned_file file
-					for file in *; do
-						if [[ -f "${file}" && ! "${file}" =~ [[:digit:]]+\.[[:digit:]]+(-jython)?$ && "$(head -n1 "${file}")" =~ ^'#!'.*(python|jython-)[[:digit:]]+\.[[:digit:]]+ ]]; then
-							for nonversioned_file in "${DISTUTILS_NONVERSIONED_PYTHON_SCRIPTS[@]}"; do
-								[[ "${nonversioned_file}" == "/usr/bin/${file}" ]] && continue 2
-							done
-							mv "${file}" "${file}-${PYTHON_ABI}" || die "Renaming of '${file}' failed"
-							wrapper_scripts+=(["${ED}usr/bin/${file}"]=)
-						fi
-					done
-				fi
-			}
-		fi
-
 		distutils_installation() {
 			_distutils_hook pre
 
 			local setup_file
 			for setup_file in "${DISTUTILS_SETUP_FILES[@]-setup.py}"; do
-				echo ${_BOLD}"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --root="${D}" --no-compile "$@"${_NORMAL}
-				"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --root="${D}" --no-compile "$@" || return "$?"
+				echo ${_BOLD}"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --no-compile --root="${T}/images/${PYTHON_ABI}" "$@"${_NORMAL}
+				"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --no-compile --root="${T}/images/${PYTHON_ABI}" "$@" || return "$?"
 			done
 
-			if [[ -z "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-				rename_scripts_with_versioned_shebangs
-			fi
-
 			_distutils_hook post
 		}
 		python_execute_function ${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES:+-s} distutils_installation "$@"
 
-		if [[ -z "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" && "${#wrapper_scripts[@]}" -ne 0 && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-			python_generate_wrapper_scripts "${!wrapper_scripts[@]}"
-		fi
-		unset wrapper_scripts
+		python_merge_intermediate_installation_images "${T}/images"
 	else
 		# Mark the package to be rebuilt after a Python upgrade.
 		python_need_rebuild

[-- Attachment #1.7: distutils.eclass.patch.1 --]
[-- Type: text/x-patch, Size: 3714 bytes --]

--- distutils.eclass
+++ distutils.eclass
@@ -86,11 +86,16 @@
 # @DESCRIPTION:
 # Set this to disable renaming of Python scripts containing versioned shebangs
 # and generation of wrapper scripts.
+if [[ -n "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" ]]; then
+	ewarn
+	ewarn "\"${EBUILD}\":"
+	ewarn "Deprecation Warning: DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS is deprecated"
+	ewarn "and will be banned on 2011-02-01. Use PYTHON_NONVERSIONED_EXECUTABLES=(\".*\")."
+	ewarn "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
+	ewarn
 
-# @ECLASS-VARIABLE: DISTUTILS_NONVERSIONED_PYTHON_SCRIPTS
-# @DESCRIPTION:
-# List of paths to Python scripts, relative to ${ED}, which are excluded from
-# renaming and generation of wrapper scripts.
+	PYTHON_NONVERSIONED_EXECUTABLES=(".*")
+fi
 
 # @ECLASS-VARIABLE: DOCS
 # @DESCRIPTION:
@@ -298,48 +303,20 @@
 	_python_set_color_variables
 
 	if _python_package_supporting_installation_for_multiple_python_abis; then
-		if [[ -z "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-			declare -A wrapper_scripts=()
-
-			rename_scripts_with_versioned_shebangs() {
-				if [[ -d "${ED}usr/bin" ]]; then
-					cd "${ED}usr/bin"
-
-					local nonversioned_file file
-					for file in *; do
-						if [[ -f "${file}" && ! "${file}" =~ [[:digit:]]+\.[[:digit:]]+(-jython)?$ && "$(head -n1 "${file}")" =~ ^'#!'.*(python|jython-)[[:digit:]]+\.[[:digit:]]+ ]]; then
-							for nonversioned_file in "${DISTUTILS_NONVERSIONED_PYTHON_SCRIPTS[@]}"; do
-								[[ "${nonversioned_file}" == "/usr/bin/${file}" ]] && continue 2
-							done
-							mv "${file}" "${file}-${PYTHON_ABI}" || die "Renaming of '${file}' failed"
-							wrapper_scripts+=(["${ED}usr/bin/${file}"]=)
-						fi
-					done
-				fi
-			}
-		fi
-
 		distutils_installation() {
 			_distutils_hook pre
 
 			local setup_file
 			for setup_file in "${DISTUTILS_SETUP_FILES[@]-setup.py}"; do
-				echo ${_BOLD}"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --root="${D}" --no-compile "$@"${_NORMAL}
-				"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --root="${D}" --no-compile "$@" || return "$?"
+				echo ${_BOLD}"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --no-compile --root="${T}/images/${PYTHON_ABI}" "$@"${_NORMAL}
+				"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --no-compile --root="${T}/images/${PYTHON_ABI}" "$@" || return "$?"
 			done
 
-			if [[ -z "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-				rename_scripts_with_versioned_shebangs
-			fi
-
 			_distutils_hook post
 		}
 		python_execute_function ${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES:+-s} distutils_installation "$@"
 
-		if [[ -z "${DISTUTILS_DISABLE_VERSIONING_OF_PYTHON_SCRIPTS}" && "${#wrapper_scripts[@]}" -ne 0 && "${BASH_VERSINFO[0]}" -ge 4 ]]; then
-			python_generate_wrapper_scripts "${!wrapper_scripts[@]}"
-		fi
-		unset wrapper_scripts
+		python_merge_intermediate_installation_images "${T}/images"
 	else
 		# Mark the package to be rebuilt after a Python upgrade.
 		python_need_rebuild

[-- Attachment #1.8: distutils.eclass.patch.2 --]
[-- Type: text/x-patch, Size: 1137 bytes --]

--- distutils.eclass
+++ distutils.eclass
@@ -27,6 +27,24 @@
 	RDEPEND="${DEPEND}"
 fi
 
+if [[ -n "${PYTHON_DEPRECATION_WARNINGS}" ]]; then
+	if has "${EAPI:-0}" 0 1 && [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
+		ewarn
+		ewarn "\"${EBUILD}\":"
+		ewarn "Deprecation Warning: Usage of distutils.eclass in packages supporting installation"
+		ewarn "for multiple Python ABIs in EAPI <=1 is deprecated and will be banned on 2011-06-01."
+		ewarn "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
+		ewarn
+	elif has "${EAPI:-0}" 0 1 2 && [[ -z "${SUPPORT_PYTHON_ABIS}" ]]; then
+		ewarn
+		ewarn "\"${EBUILD}\":"
+		ewarn "Deprecation Warning: Usage of distutils.eclass in packages not supporting installation"
+		ewarn "for multiple Python ABIs in EAPI <=2 is deprecated and will be banned on 2011-06-01."
+		ewarn "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
+		ewarn
+	fi
+fi
+
 # 'python' variable is deprecated. Use PYTHON() instead.
 if has "${EAPI:-0}" 0 1 2 && [[ -z "${SUPPORT_PYTHON_ABIS}" ]]; then
 	python="python"

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [gentoo-dev] Patches for python.eclass and distutils.eclass
  2010-12-15 14:31 [gentoo-dev] Patches for python.eclass and distutils.eclass Arfrever Frehtes Taifersar Arahesis
@ 2010-12-15 14:56 ` Ulrich Mueller
  0 siblings, 0 replies; 2+ messages in thread
From: Ulrich Mueller @ 2010-12-15 14:56 UTC (permalink / raw
  To: gentoo-dev

>>>>> On Wed, 15 Dec 2010, Arfrever Frehtes Taifersar Arahesis wrote:

>+			sed -e "1s:^#![[:space:]]*\([^[:space:]]*/usr/bin/env[[:space:]]\)\?[[:space:]]*\([^[:space:]]*/\)\?\(jython\|python\)\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?\(\$\|[[:space:]].*\):#!\1\2${python_interpreter}\6:" -i "${file}" || die "Conversion of shebang in '${file}' failed"
>+				echo ${_BOLD}"$(PYTHON)" "${setup_file}" "${DISTUTILS_GLOBAL_OPTIONS[@]}" $([[ -z "${DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES}" ]] && echo build -b "$(_distutils_get_build_dir)") install --no-compile --root="${T}/images/${PYTHON_ABI}" "$@"${_NORMAL}

This is unreadable. Could you please use a reasonable line length
below 80 characters? In your mail message and (more important) in the
eclasses.

Thanks
Ulrich



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-12-15 14:56 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-15 14:31 [gentoo-dev] Patches for python.eclass and distutils.eclass Arfrever Frehtes Taifersar Arahesis
2010-12-15 14:56 ` Ulrich Mueller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox