Fix handling of PYTHON_USE_WITH with more than 2 USE flags.
authorArfrever Frehtes Taifersar Arahesis <arfrever@gentoo.org>
Mon, 17 May 2010 18:01:59 +0000 (18:01 +0000)
committerArfrever Frehtes Taifersar Arahesis <arfrever@gentoo.org>
Mon, 17 May 2010 18:01:59 +0000 (18:01 +0000)
Improve python_pkg_setup().
Rename python_clean_sitedirs() to python_clean_installation_image().
Improve python_clean_installation_image().
Improve handling of -- option in phase functions.
Add check for dev-lang/python in validate_PYTHON_ABIS() (bug #319651).
Improve error message in python_copy_sources().
Improve python_set_active_version().
Improve error messages in PYTHON().
Support PEP 3147 in python_mod_optimize(), python_mod_cleanup() and python_mod_compile().

eclass/python.eclass

index a4315519f081286f63b5ceaedd22d552d0c1dd59..9e5afa762d7906940e82a2bed2d22ca60497a183 100644 (file)
@@ -1,6 +1,6 @@
 # Copyright 1999-2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.96 2010/03/26 15:23:17 arfrever Exp $
+# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.97 2010/05/17 18:01:59 arfrever Exp $
 
 # @ECLASS: python.eclass
 # @MAINTAINER:
@@ -184,20 +184,158 @@ fi
 # Set this to a name of a USE flag if you need to make either PYTHON_USE_WITH or
 # PYTHON_USE_WITH_OR atoms conditional under a USE flag.
 
+if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR} ]]; then
+       _PYTHON_USE_WITH_ATOMS_ARRAY=()
+       if [[ -n "${PYTHON_USE_WITH}" ]]; then
+               for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
+                       _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${PYTHON_USE_WITH// /,}]")
+               done
+       elif [[ -n "${PYTHON_USE_WITH_OR}" ]]; then
+               for _USE_flag in ${PYTHON_USE_WITH_OR}; do
+                       for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
+                               _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${_USE_flag}]")
+                       done
+               done
+               unset _USE_flag
+       fi
+       if [[ "${#_PYTHON_USE_WITH_ATOMS_ARRAY[@]}" -gt 1 ]]; then
+               _PYTHON_USE_WITH_ATOMS="|| ( ${_PYTHON_USE_WITH_ATOMS_ARRAY[@]} )"
+       else
+               _PYTHON_USE_WITH_ATOMS="${_PYTHON_USE_WITH_ATOMS_ARRAY[@]}"
+       fi
+       if [[ -n "${PYTHON_USE_WITH_OPT}" ]]; then
+               _PYTHON_USE_WITH_ATOMS="${PYTHON_USE_WITH_OPT}? ( ${_PYTHON_USE_WITH_ATOMS} )"
+       fi
+       DEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
+       RDEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
+       unset _PYTHON_ATOM _PYTHON_USE_WITH_ATOMS _PYTHON_USE_WITH_ATOMS_ARRAY
+fi
+
+unset _PYTHON_ATOMS
+
+# ================================================================================================
+# =================================== MISCELLANEOUS FUNCTIONS ====================================
+# ================================================================================================
+
+_python_implementation() {
+       if [[ "${CATEGORY}/${PN}" == "dev-lang/python" ]]; then
+               return 0
+       elif [[ "${CATEGORY}/${PN}" == "dev-java/jython" ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+_python_package_supporting_installation_for_multiple_python_abis() {
+       if [[ "${EBUILD_PHASE}" == "depend" ]]; then
+               die "${FUNCNAME}() cannot be used in global scope"
+       fi
+
+       if has "${EAPI:-0}" 0 1 2 3 4; then
+               if [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
+                       return 0
+               else
+                       return 1
+               fi
+       else
+               die "${FUNCNAME}(): Support for EAPI=\"${EAPI}\" not implemented"
+       fi
+}
+
+_python_initialize_prefix_variables() {
+       if has "${EAPI:-0}" 0 1 2; then
+               if [[ -n "${ROOT}" && -z "${EROOT}" ]]; then
+                       EROOT="${ROOT%/}${EPREFIX}/"
+               fi
+               if [[ -n "${D}" && -z "${ED}" ]]; then
+                       ED="${D%/}${EPREFIX}/"
+               fi
+       fi
+}
+
+unset PYTHON_SANITY_CHECKS
+
+_python_initial_sanity_checks() {
+       if [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
+               # Ensure that /usr/bin/python and /usr/bin/python-config are valid.
+               if [[ "$(readlink "${EPREFIX}/usr/bin/python")" != "python-wrapper" ]]; then
+                       eerror "'${EPREFIX}/usr/bin/python' is not valid symlink."
+                       eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
+                       die "'${EPREFIX}/usr/bin/python' is not valid symlink"
+               fi
+               if [[ "$(<"${EPREFIX}/usr/bin/python-config")" != *"Gentoo python-config wrapper script"* ]]; then
+                       eerror "'${EPREFIX}/usr/bin/python-config' is not valid script"
+                       eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
+                       die "'${EPREFIX}/usr/bin/python-config' is not valid script"
+               fi
+       fi
+}
+
+_python_final_sanity_checks() {
+       if ! _python_implementation && [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
+               local PYTHON_ABI="${PYTHON_ABI}"
+               for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI}}; do
+                       # Ensure that appropriate version of Python is installed.
+                       if ! has_version "$(python_get_implementational_package)"; then
+                               die "$(python_get_implementational_package) is not installed"
+                       fi
+
+                       # Ensure that EPYTHON variable is respected.
+                       if [[ "$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")" != "${PYTHON_ABI}" ]]; then
+                               eerror "Path to 'python':                 '$(type -p python)'"
+                               eerror "ABI:                              '${ABI}'"
+                               eerror "DEFAULT_ABI:                      '${DEFAULT_ABI}'"
+                               eerror "EPYTHON:                          '$(PYTHON)'"
+                               eerror "PYTHON_ABI:                       '${PYTHON_ABI}'"
+                               eerror "Locally active version of Python: '$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")'"
+                               die "'python' does not respect EPYTHON variable"
+                       fi
+               done
+       fi
+       PYTHON_SANITY_CHECKS="1"
+}
+
+_python_set_color_variables() {
+       if [[ "${NOCOLOR:-false}" =~ ^(false|no)$ ]]; then
+               _BOLD=$'\e[1m'
+               _RED=$'\e[1;31m'
+               _GREEN=$'\e[1;32m'
+               _BLUE=$'\e[1;34m'
+               _CYAN=$'\e[1;36m'
+               _NORMAL=$'\e[0m'
+       else
+               _BOLD=
+               _RED=
+               _GREEN=
+               _BLUE=
+               _CYAN=
+               _NORMAL=
+       fi
+}
+
+unset PYTHON_PKG_SETUP_EXECUTED
+
 # @FUNCTION: python_pkg_setup
 # @DESCRIPTION:
-# Makes sure PYTHON_USE_WITH or PYTHON_USE_WITH_OR listed use flags
-# are respected. Only exported if one of those variables is set.
-if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR} ]]; then
-       python_pkg_setup() {
-               # Check if phase is pkg_setup().
-               [[ "${EBUILD_PHASE}" != "setup" ]] && die "${FUNCNAME}() can be used only in pkg_setup() phase"
+# Perform sanity checks and initialize environment.
+#
+# This function is exported in EAPI 2 and 3 when PYTHON_USE_WITH or PYTHON_USE_WITH_OR variable
+# is set and always in EAPI >=4. Calling of this function is mandatory in EAPI >=4.
+#
+# This function can be used only in pkg_setup() phase.
+python_pkg_setup() {
+       # Check if phase is pkg_setup().
+       [[ "${EBUILD_PHASE}" != "setup" ]] && die "${FUNCNAME}() can be used only in pkg_setup() phase"
 
-               python_pkg_setup_fail() {
-                       eerror "${1}"
-                       die "${1}"
-               }
+       if _python_package_supporting_installation_for_multiple_python_abis; then
+               validate_PYTHON_ABIS
+               export EPYTHON="$(PYTHON -f)"
+       else
+               PYTHON_ABI="$(PYTHON --ABI)"
+       fi
 
+       if ! has "${EAPI:-0}" 0 1 && [[ -n "${PYTHON_USE_WITH}" || -n "${PYTHON_USE_WITH_OR}" ]]; then
                if [[ "${PYTHON_USE_WITH_OPT}" ]]; then
                        if [[ "${PYTHON_USE_WITH_OPT}" == !* ]]; then
                                use ${PYTHON_USE_WITH_OPT#!} && return
@@ -207,23 +345,25 @@ if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR
                fi
 
                python_pkg_setup_check_USE_flags() {
-                       local pyatom use
-                       pyatom="$(python_get_implementational_package)"
+                       local python_atom USE_flag
+                       python_atom="$(python_get_implementational_package)"
 
-                       for use in ${PYTHON_USE_WITH}; do
-                               if ! has_version "${pyatom}[${use}]"; then
-                                       python_pkg_setup_fail "Please rebuild ${pyatom} with the following USE flags enabled: ${PYTHON_USE_WITH}"
+                       for USE_flag in ${PYTHON_USE_WITH}; do
+                               if ! has_version "${python_atom}[${USE_flag}]"; then
+                                       eerror "Please rebuild ${python_atom} with the following USE flags enabled: ${PYTHON_USE_WITH}"
+                                       die "Please rebuild ${python_atom} with the following USE flags enabled: ${PYTHON_USE_WITH}"
                                fi
                        done
 
-                       for use in ${PYTHON_USE_WITH_OR}; do
-                               if has_version "${pyatom}[${use}]"; then
+                       for USE_flag in ${PYTHON_USE_WITH_OR}; do
+                               if has_version "${python_atom}[${USE_flag}]"; then
                                        return
                                fi
                        done
 
                        if [[ ${PYTHON_USE_WITH_OR} ]]; then
-                               python_pkg_setup_fail "Please rebuild ${pyatom} with at least one of the following USE flags enabled: ${PYTHON_USE_WITH_OR}"
+                               eerror "Please rebuild ${python_atom} with at least one of the following USE flags enabled: ${PYTHON_USE_WITH_OR}"
+                               die "Please rebuild ${python_atom} with at least one of the following USE flags enabled: ${PYTHON_USE_WITH_OR}"
                        fi
                }
 
@@ -233,38 +373,148 @@ if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR
                        python_pkg_setup_check_USE_flags
                fi
 
-               unset -f python_pkg_setup_check_USE_flags python_pkg_setup_fail
-       }
+               unset -f python_pkg_setup_check_USE_flags
+       fi
+
+       PYTHON_PKG_SETUP_EXECUTED="1"
+}
 
+if ! has "${EAPI:-0}" 0 1 2 3 || has "${EAPI:-0}" 2 3 && [[ -n "${PYTHON_USE_WITH}" || -n "${PYTHON_USE_WITH_OR}" ]]; then
        EXPORT_FUNCTIONS pkg_setup
+fi
 
-       _PYTHON_USE_WITH_ATOMS_ARRAY=()
-       if [[ -n "${PYTHON_USE_WITH}" ]]; then
-               for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
-                       _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${PYTHON_USE_WITH/ /,}]")
-               done
-       elif [[ -n "${PYTHON_USE_WITH_OR}" ]]; then
-               for _USE_flag in ${PYTHON_USE_WITH_OR}; do
-                       for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
-                               _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${_USE_flag}]")
-                       done
+# @FUNCTION: python_convert_shebangs
+# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
+# @DESCRIPTION:
+# Convert shebangs in specified files. Directories can be specified only with --recursive option.
+python_convert_shebangs() {
+       local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
+
+       while (($#)); do
+               case "$1" in
+                       -r|--recursive)
+                               recursive="1"
+                               ;;
+                       -q|--quiet)
+                               quiet="1"
+                               ;;
+                       -x|--only-executables)
+                               only_executables="1"
+                               ;;
+                       --)
+                               shift
+                               break
+                               ;;
+                       -*)
+                               die "${FUNCNAME}(): Unrecognized option '$1'"
+                               ;;
+                       *)
+                               break
+                               ;;
+               esac
+               shift
+       done
+
+       if [[ "$#" -eq 0 ]]; then
+               die "${FUNCNAME}(): Missing Python version and files or directories"
+       elif [[ "$#" -eq 1 ]]; then
+               die "${FUNCNAME}(): Missing files or directories"
+       fi
+
+       python_version="$1"
+       shift
+
+       for argument in "$@"; do
+               if [[ ! -e "${argument}" ]]; then
+                       die "${FUNCNAME}(): '${argument}' does not exist"
+               elif [[ -f "${argument}" ]]; then
+                       files+=("${argument}")
+               elif [[ -d "${argument}" ]]; then
+                       if [[ "${recursive}" == "1" ]]; then
+                               while read -d $'\0' -r file; do
+                                       files+=("${file}")
+                               done < <(find "${argument}" $([[ "${only_executables}" == "1" ]] && echo -perm /111) -type f -print0)
+                       else
+                               die "${FUNCNAME}(): '${argument}' is not a regular file"
+                       fi
+               else
+                       die "${FUNCNAME}(): '${argument}' is not a regular file or a directory"
+               fi
+       done
+
+       for file in "${files[@]}"; do
+               file="${file#./}"
+               [[ "${only_executables}" == "1" && ! -x "${file}" ]] && continue
+
+               if [[ "$(head -n1 "${file}")" =~ ^'#!'.*python ]]; 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"
+               fi
+       done
+}
+
+# @FUNCTION: python_clean_installation_image
+# @USAGE: [-q|--quiet]
+# @DESCRIPTION:
+# Delete needless files in installation image.
+python_clean_installation_image() {
+       _python_initialize_prefix_variables
+
+       local file files=() quiet="0"
+
+       # 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"
+                               ;;
+                       -*)
+                               die "${FUNCNAME}(): Unrecognized option '$1'"
+                               ;;
+                       *)
+                               die "${FUNCNAME}(): Invalid usage"
+                               ;;
+               esac
+               shift
+       done
+
+       while read -d $'\0' -r file; do
+               files+=("${file}")
+       done < <(find "${ED}" "(" -name "*.py[co]" -o -name "*\$py.class" ")" -type f -print0)
+
+       if [[ "${#files[@]}" -gt 0 ]]; then
+               if [[ "${quiet}" == "0" ]]; then
+                       ewarn "Deleting byte-compiled Python modules needlessly generated by build system:"
+               fi
+               for file in "${files[@]}"; do
+                       if [[ "${quiet}" == "0" ]]; then
+                               ewarn " ${file}"
+                       fi
+                       rm -f "${file}"
                done
-               unset _USE_flag
        fi
-       if [[ "${#_PYTHON_USE_WITH_ATOMS_ARRAY[@]}" -gt 1 ]]; then
-               _PYTHON_USE_WITH_ATOMS="|| ( ${_PYTHON_USE_WITH_ATOMS_ARRAY[@]} )"
+
+       python_clean_sitedirs() {
+               find "${ED}$(python_get_sitedir)" "(" -name "*.c" -o -name "*.h" -o -name "*.la" ")" -type f -print0 | xargs -0 rm -f
+       }
+       if _python_package_supporting_installation_for_multiple_python_abis; then
+               python_execute_function -q python_clean_sitedirs
        else
-               _PYTHON_USE_WITH_ATOMS="${_PYTHON_USE_WITH_ATOMS_ARRAY[@]}"
+               python_clean_sitedirs
        fi
-       if [[ -n "${PYTHON_USE_WITH_OPT}" ]]; then
-               _PYTHON_USE_WITH_ATOMS="${PYTHON_USE_WITH_OPT}? ( ${_PYTHON_USE_WITH_ATOMS} )"
-       fi
-       DEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
-       RDEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
-       unset _PYTHON_ATOM _PYTHON_USE_WITH_ATOMS _PYTHON_USE_WITH_ATOMS_ARRAY
-fi
 
-unset _PYTHON_ATOMS
+       unset -f python_clean_sitedirs
+}
 
 # ================================================================================================
 # =========== FUNCTIONS FOR PACKAGES SUPPORTING INSTALLATION FOR MULTIPLE PYTHON ABIS ============
@@ -294,7 +544,7 @@ if ! has "${EAPI:-0}" 0 1; then
                                die \"\${FUNCNAME}() cannot be used in ebuilds of packages not supporting installation for multiple Python ABIs\"
                        fi
 
-                       python_execute_function -d -s \"\$@\"
+                       python_execute_function -d -s -- \"\$@\"
                }"
        done
        unset python_default_function
@@ -358,6 +608,10 @@ validate_PYTHON_ABIS() {
                else
                        local python_version python2_version= python3_version= support_python_major_version
 
+                       if ! has_version "dev-lang/python"; then
+                               die "${FUNCNAME}(): 'dev-lang/python' is not installed"
+                       fi
+
                        python_version="$("${EPREFIX}/usr/bin/python" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
 
                        if has_version "=dev-lang/python-2*"; then
@@ -675,7 +929,7 @@ python_copy_sources() {
 
        if [[ "$#" -eq 0 ]]; then
                if [[ "${WORKDIR}" == "${S}" ]]; then
-                       die "${FUNCNAME}() cannot be used"
+                       die "${FUNCNAME}() cannot be used with current value of S variable"
                fi
                dirs=("${S%/}")
        else
@@ -909,6 +1163,10 @@ python_set_active_version() {
                die "${FUNCNAME}() cannot be used in ebuilds of packages supporting installation for multiple Python ABIs"
        fi
 
+       if [[ -n "${PYTHON_PKG_SETUP_EXECUTED}" ]]; then
+               die "${FUNCNAME}() should be called before python_pkg_setup()"
+       fi
+
        if [[ "$#" -ne 1 ]]; then
                die "${FUNCNAME}() requires 1 argument"
        fi
@@ -1045,19 +1303,22 @@ PYTHON() {
                elif [[ "${python2}" == "1" ]]; then
                        PYTHON_ABI="$(eselect python show --python2 --ABI)"
                        if [[ -z "${PYTHON_ABI}" ]]; then
-                               die "${FUNCNAME}(): Active Python 2 interpreter not set"
+                               die "${FUNCNAME}(): Active version of Python 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 Python 3 interpreter not set"
+                               die "${FUNCNAME}(): Active version of Python 3 not set"
                        elif [[ "${PYTHON_ABI}" != "3."* ]]; then
                                die "${FUNCNAME}(): Internal error in \`eselect python show --python3\`"
                        fi
                elif ! _python_package_supporting_installation_for_multiple_python_abis; then
                        PYTHON_ABI="$("${EPREFIX}/usr/bin/python" -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")"
+                       if [[ -z "${PYTHON_ABI}" ]]; then
+                               die "${FUNCNAME}(): Main active version of Python not set"
+                       fi
                elif [[ -z "${PYTHON_ABI}" ]]; then
                        die "${FUNCNAME}(): Invalid usage: ${FUNCNAME}() should be used in ABI-specific local scope"
                fi
@@ -1397,194 +1658,6 @@ python_get_version() {
        fi
 }
 
-# ================================================================================================
-# =================================== MISCELLANEOUS FUNCTIONS ====================================
-# ================================================================================================
-
-_python_implementation() {
-       if [[ "${CATEGORY}/${PN}" == "dev-lang/python" ]]; then
-               return 0
-       elif [[ "${CATEGORY}/${PN}" == "dev-java/jython" ]]; then
-               return 0
-       else
-               return 1
-       fi
-}
-
-_python_package_supporting_installation_for_multiple_python_abis() {
-       if [[ "${EBUILD_PHASE}" == "depend" ]]; then
-               die "${FUNCNAME}() cannot be used in global scope"
-       fi
-
-       if has "${EAPI:-0}" 0 1 2 3 4; then
-               if [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
-                       return 0
-               else
-                       return 1
-               fi
-       else
-               die "${FUNCNAME}(): Support for EAPI=\"${EAPI}\" not implemented"
-       fi
-}
-
-_python_initialize_prefix_variables() {
-       if has "${EAPI:-0}" 0 1 2; then
-               if [[ -n "${ROOT}" && -z "${EROOT}" ]]; then
-                       EROOT="${ROOT%/}${EPREFIX}/"
-               fi
-               if [[ -n "${D}" && -z "${ED}" ]]; then
-                       ED="${D%/}${EPREFIX}/"
-               fi
-       fi
-}
-
-unset PYTHON_SANITY_CHECKS
-
-_python_initial_sanity_checks() {
-       if [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
-               # Ensure that /usr/bin/python and /usr/bin/python-config are valid.
-               if [[ "$(readlink "${EPREFIX}/usr/bin/python")" != "python-wrapper" ]]; then
-                       eerror "'${EPREFIX}/usr/bin/python' is not valid symlink."
-                       eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
-                       die "'${EPREFIX}/usr/bin/python' is not valid symlink"
-               fi
-               if [[ "$(<"${EPREFIX}/usr/bin/python-config")" != *"Gentoo python-config wrapper script"* ]]; then
-                       eerror "'${EPREFIX}/usr/bin/python-config' is not valid script"
-                       eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
-                       die "'${EPREFIX}/usr/bin/python-config' is not valid script"
-               fi
-       fi
-}
-
-_python_final_sanity_checks() {
-       if ! _python_implementation && [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
-               local PYTHON_ABI="${PYTHON_ABI}"
-               for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI}}; do
-                       # Ensure that appropriate version of Python is installed.
-                       if ! has_version "$(python_get_implementational_package)"; then
-                               die "$(python_get_implementational_package) is not installed"
-                       fi
-
-                       # Ensure that EPYTHON variable is respected.
-                       if [[ "$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")" != "${PYTHON_ABI}" ]]; then
-                               eerror "python:                    '$(type -p python)'"
-                               eerror "ABI:                       '${ABI}'"
-                               eerror "DEFAULT_ABI:               '${DEFAULT_ABI}'"
-                               eerror "EPYTHON:                   '$(PYTHON)'"
-                               eerror "PYTHON_ABI:                '${PYTHON_ABI}'"
-                               eerror "Version of enabled Python: '$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")'"
-                               die "'python' does not respect EPYTHON variable"
-                       fi
-               done
-       fi
-       PYTHON_SANITY_CHECKS="1"
-}
-
-_python_set_color_variables() {
-       if [[ "${NOCOLOR:-false}" =~ ^(false|no)$ ]]; then
-               _BOLD=$'\e[1m'
-               _RED=$'\e[1;31m'
-               _GREEN=$'\e[1;32m'
-               _BLUE=$'\e[1;34m'
-               _CYAN=$'\e[1;36m'
-               _NORMAL=$'\e[0m'
-       else
-               _BOLD=
-               _RED=
-               _GREEN=
-               _BLUE=
-               _CYAN=
-               _NORMAL=
-       fi
-}
-
-# @FUNCTION: python_convert_shebangs
-# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
-# @DESCRIPTION:
-# Convert shebangs in specified files. Directories can be specified only with --recursive option.
-python_convert_shebangs() {
-       local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
-
-       while (($#)); do
-               case "$1" in
-                       -r|--recursive)
-                               recursive="1"
-                               ;;
-                       -q|--quiet)
-                               quiet="1"
-                               ;;
-                       -x|--only-executables)
-                               only_executables="1"
-                               ;;
-                       --)
-                               shift
-                               break
-                               ;;
-                       -*)
-                               die "${FUNCNAME}(): Unrecognized option '$1'"
-                               ;;
-                       *)
-                               break
-                               ;;
-               esac
-               shift
-       done
-
-       if [[ "$#" -eq 0 ]]; then
-               die "${FUNCNAME}(): Missing Python version and files or directories"
-       elif [[ "$#" -eq 1 ]]; then
-               die "${FUNCNAME}(): Missing files or directories"
-       fi
-
-       python_version="$1"
-       shift
-
-       for argument in "$@"; do
-               if [[ ! -e "${argument}" ]]; then
-                       die "${FUNCNAME}(): '${argument}' does not exist"
-               elif [[ -f "${argument}" ]]; then
-                       files+=("${argument}")
-               elif [[ -d "${argument}" ]]; then
-                       if [[ "${recursive}" == "1" ]]; then
-                               while read -d $'\0' -r file; do
-                                       files+=("${file}")
-                               done < <(find "${argument}" $([[ "${only_executables}" == "1" ]] && echo -perm /111) -type f -print0)
-                       else
-                               die "${FUNCNAME}(): '${argument}' is not a regular file"
-                       fi
-               else
-                       die "${FUNCNAME}(): '${argument}' is not a regular file or a directory"
-               fi
-       done
-
-       for file in "${files[@]}"; do
-               file="${file#./}"
-               [[ "${only_executables}" == "1" && ! -x "${file}" ]] && continue
-
-               if [[ "$(head -n1 "${file}")" =~ ^'#!'.*python ]]; 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"
-               fi
-       done
-}
-
-# @FUNCTION: python_clean_sitedirs
-# @DESCRIPTION:
-# Delete needless files in site-packages directories in ${ED}.
-python_clean_sitedirs() {
-       _python_initialize_prefix_variables
-
-       find "${ED}"usr/$(get_libdir)/python*/site-packages "(" -name "*.c" -o -name "*.h" -o -name "*.la" ")" -type f -print0 | xargs -0 rm -f
-}
-
 # ================================================================================================
 # ================================ FUNCTIONS FOR RUNNING OF TESTS ================================
 # ================================================================================================
@@ -1830,6 +1903,93 @@ python_disable_pyc() {
        export PYTHONDONTWRITEBYTECODE="1"
 }
 
+_python_clean_compiled_modules() {
+       _python_initialize_prefix_variables
+       _python_set_color_variables
+
+       [[ "${FUNCNAME[1]}" =~ ^(python_mod_optimize|python_mod_compile|python_mod_cleanup)$ ]] || die "${FUNCNAME}(): Invalid usage"
+
+       local base_module_name compiled_file compiled_files=() dir path py_file root
+
+       # Strip trailing slash from EROOT.
+       root="${EROOT%/}"
+
+       for path in "$@"; do
+               compiled_files=()
+               if [[ -d "${path}" ]]; then
+                       while read -d $'\0' -r compiled_file; do
+                               compiled_files+=("${compiled_file}")
+                       done < <(find "${path}" "(" -name "*.py[co]" -o -name "*\$py.class" ")" -print0)
+
+                       if [[ "${EBUILD_PHASE}" == "postrm" ]]; then
+                               # Delete empty child directories.
+                               find "${path}" -type d | sort -r | while read -r dir; do
+                                       rmdir "${dir}" 2> /dev/null && echo "${_CYAN}<<< ${dir}${_NORMAL}"
+                               done
+                       fi
+               elif [[ "${path}" == *.py ]]; then
+                       base_module_name="${path##*/}"
+                       base_module_name="${base_module_name%.py}"
+                       if [[ -d "${path%/*}/__pycache__" ]]; then
+                               while read -d $'\0' -r compiled_file; do
+                                       compiled_files+=("${compiled_file}")
+                               done < <(find "${path%/*}/__pycache__" "(" -name "${base_module_name}.*.py[co]" -o -name "${base_module_name}\$py.class" ")" -print0)
+                       fi
+                       compiled_files+=("${path}c" "${path}o" "${path%.py}\$py.class")
+               fi
+
+               for compiled_file in "${compiled_files[@]}"; do
+                       [[ ! -f "${compiled_file}" ]] && continue
+                       dir="${compiled_file%/*}"
+                       dir="${dir##*/}"
+                       if [[ "${compiled_file}" == *.py[co] ]]; then
+                               if [[ "${dir}" == "__pycache__" ]]; then
+                                       base_module_name="${compiled_file##*/}"
+                                       base_module_name="${base_module_name%%.*py[co]}"
+                                       py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
+                               else
+                                       py_file="${compiled_file%[co]}"
+                               fi
+                               if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
+                                       [[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue
+                               else
+                                       [[ -f "${py_file}" ]] && continue
+                               fi
+                               echo "${_BLUE}<<< ${compiled_file%[co]}[co]${_NORMAL}"
+                               rm -f "${compiled_file%[co]}"[co]
+                       elif [[ "${compiled_file}" == *\$py.class ]]; then
+                               if [[ "${dir}" == "__pycache__" ]]; then
+                                       base_module_name="${compiled_file##*/}"
+                                       base_module_name="${base_module_name%\$py.class}"
+                                       py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
+                               else
+                                       py_file="${compiled_file%\$py.class}"
+                               fi
+                               if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
+                                       [[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue
+                               else
+                                       [[ -f "${py_file}" ]] && continue
+                               fi
+                               echo "${_BLUE}<<< ${compiled_file}${_NORMAL}"
+                               rm -f "${compiled_file}"
+                       else
+                               die "${FUNCNAME}(): Unrecognized file type: '${compiled_file}'"
+                       fi
+
+                       # Delete empty parent directories.
+                       dir="${compiled_file%/*}"
+                       while [[ "${dir}" != "${root}" ]]; do
+                               if rmdir "${compiled_file%/*}" 2> /dev/null; then
+                                       echo "${_CYAN}<<< ${compiled_file%/*}${_NORMAL}"
+                               else
+                                       break
+                               fi
+                               dir="${dir%/*}"
+                       done
+               done
+       done
+}
+
 # @FUNCTION: python_mod_optimize
 # @USAGE: [options] [directory|file]
 # @DESCRIPTION:
@@ -1849,12 +2009,22 @@ python_mod_optimize() {
        [[ "${EBUILD_PHASE}" != "postinst" ]] && die "${FUNCNAME}() can be used only in pkg_postinst() phase"
 
        if ! has "${EAPI:-0}" 0 1 2 || _python_package_supporting_installation_for_multiple_python_abis; then
-               local dir file options=() other_dirs=() other_files=() previous_PYTHON_ABI="${PYTHON_ABI}" PYTHON_ABI="${PYTHON_ABI}" return_code root site_packages_absolute_dirs=() site_packages_dirs=() site_packages_absolute_files=() site_packages_files=()
+               # PYTHON_ABI variable cannot be local in packages not supporting installation for multiple Python ABIs.
+               local dir file iterated_PYTHON_ABIS options=() other_dirs=() other_files=() previous_PYTHON_ABI="${PYTHON_ABI}" return_code root site_packages_absolute_dirs=() site_packages_dirs=() site_packages_absolute_files=() site_packages_files=()
+
+               if _python_package_supporting_installation_for_multiple_python_abis; then
+                       if [[ -z "${PYTHON_ABIS}" ]]; then
+                               die "${FUNCNAME}(): Environment not initialized"
+                       fi
+                       iterated_PYTHON_ABIS="${PYTHON_ABIS}"
+               else
+                       iterated_PYTHON_ABIS="${PYTHON_ABI:=$(PYTHON --ABI)}"
+               fi
 
-               # Strip trailing slash from ROOT.
+               # Strip trailing slash from EROOT.
                root="${EROOT%/}"
 
-               # Respect ROOT and options passed to compileall.py.
+               # Respect EROOT and options passed to compileall.py.
                while (($#)); do
                        case "$1" in
                                -l|-f|-q)
@@ -1868,20 +2038,23 @@ python_mod_optimize() {
                                        ewarn "${FUNCNAME}(): Ignoring option '$1'"
                                        ;;
                                *)
-                                       if ! _python_implementation && [[ "$1" =~ ^"${EPREFIX}"/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
-                                               die "${FUNCNAME}() does not support absolute paths of directories/files in site-packages directories"
+                                       if ! _python_implementation && [[ "$1" =~ ^/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
+                                               die "${FUNCNAME}(): Paths of directories / files in site-packages directories must be relative to site-packages directories"
                                        elif [[ "$1" =~ ^/ ]]; then
-                                               if [[ -d "${root}/$1" ]]; then
-                                                       other_dirs+=("${root}/$1")
-                                               elif [[ -f "${root}/$1" ]]; then
-                                                       other_files+=("${root}/$1")
-                                               elif [[ -e "${root}/$1" ]]; then
-                                                       ewarn "'${root}/$1' is not a file or a directory!"
+                                               if _python_package_supporting_installation_for_multiple_python_abis; then
+                                                       die "${FUNCNAME}(): Absolute paths cannot be used in ebuilds of packages supporting installation for multiple Python ABIs"
+                                               fi
+                                               if [[ -d "${root}$1" ]]; then
+                                                       other_dirs+=("${root}$1")
+                                               elif [[ -f "${root}$1" ]]; then
+                                                       other_files+=("${root}$1")
+                                               elif [[ -e "${root}$1" ]]; then
+                                                       ewarn "'${root}$1' is not a file or a directory!"
                                                else
-                                                       ewarn "'${root}/$1' does not exist!"
+                                                       ewarn "'${root}$1' does not exist!"
                                                fi
                                        else
-                                               for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI:-$(PYTHON --ABI)}}; do
+                                               for PYTHON_ABI in ${iterated_PYTHON_ABIS}; do
                                                        if [[ -d "${root}$(python_get_sitedir)/$1" ]]; then
                                                                site_packages_dirs+=("$1")
                                                                break
@@ -1903,7 +2076,7 @@ python_mod_optimize() {
                # Set additional options.
                options+=("-q")
 
-               for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI:-$(PYTHON --ABI)}}; do
+               for PYTHON_ABI in ${iterated_PYTHON_ABIS}; do
                        if ((${#site_packages_dirs[@]})) || ((${#site_packages_files[@]})); then
                                return_code="0"
                                ebegin "Compilation and optimization of Python modules for $(python_get_implementation) $(python_get_version)"
@@ -1915,6 +2088,7 @@ python_mod_optimize() {
                                        if [[ "$(_python_get_implementation "${PYTHON_ABI}")" != "Jython" ]]; then
                                                "$(PYTHON)" -O "${root}$(python_get_libdir)/compileall.py" "${options[@]}" "${site_packages_absolute_dirs[@]}" &> /dev/null || return_code="1"
                                        fi
+                                       _python_clean_compiled_modules "${site_packages_absolute_dirs[@]}"
                                fi
                                if ((${#site_packages_files[@]})); then
                                        for file in "${site_packages_files[@]}"; do
@@ -1924,17 +2098,20 @@ python_mod_optimize() {
                                        if [[ "$(_python_get_implementation "${PYTHON_ABI}")" != "Jython" ]]; then
                                                "$(PYTHON)" -O "${root}$(python_get_libdir)/py_compile.py" "${site_packages_absolute_files[@]}" &> /dev/null || return_code="1"
                                        fi
+                                       _python_clean_compiled_modules "${site_packages_absolute_files[@]}"
                                fi
                                eend "${return_code}"
                        fi
                        unset site_packages_absolute_dirs site_packages_absolute_files
                done
 
-               # Restore previous value of PYTHON_ABI.
-               if [[ -n "${previous_PYTHON_ABI}" ]]; then
-                       PYTHON_ABI="${previous_PYTHON_ABI}"
-               else
-                       unset PYTHON_ABI
+               if _python_package_supporting_installation_for_multiple_python_abis; then
+                       # Restore previous value of PYTHON_ABI.
+                       if [[ -n "${previous_PYTHON_ABI}" ]]; then
+                               PYTHON_ABI="${previous_PYTHON_ABI}"
+                       else
+                               unset PYTHON_ABI
+                       fi
                fi
 
                if ((${#other_dirs[@]})) || ((${#other_files[@]})); then
@@ -1945,12 +2122,14 @@ python_mod_optimize() {
                                if [[ "$(_python_get_implementation "${PYTHON_ABI-$(PYTHON --ABI)}")" != "Jython" ]]; then
                                        "$(PYTHON ${PYTHON_ABI})" -O "${root}$(python_get_libdir)/compileall.py" "${options[@]}" "${other_dirs[@]}" &> /dev/null || return_code="1"
                                fi
+                               _python_clean_compiled_modules "${other_dirs[@]}"
                        fi
                        if ((${#other_files[@]})); then
                                "$(PYTHON ${PYTHON_ABI})" "${root}$(python_get_libdir)/py_compile.py" "${other_files[@]}" || return_code="1"
                                if [[ "$(_python_get_implementation "${PYTHON_ABI-$(PYTHON --ABI)}")" != "Jython" ]]; then
                                        "$(PYTHON ${PYTHON_ABI})" -O "${root}$(python_get_libdir)/py_compile.py" "${other_files[@]}" &> /dev/null || return_code="1"
                                fi
+                               _python_clean_compiled_modules "${other_dirs[@]}"
                        fi
                        eend "${return_code}"
                fi
@@ -1960,7 +2139,7 @@ python_mod_optimize() {
                # strip trailing slash
                myroot="${EROOT%/}"
 
-               # respect ROOT and options passed to compileall.py
+               # respect EROOT and options passed to compileall.py
                while (($#)); do
                        case "$1" in
                                -l|-f|-q)
@@ -1974,15 +2153,15 @@ python_mod_optimize() {
                                        ewarn "${FUNCNAME}(): Ignoring option '$1'"
                                        ;;
                                *)
-                                       if [[ -d "${myroot}"/$1 ]]; then
-                                               mydirs+=("${myroot}/$1")
-                                       elif [[ -f "${myroot}"/$1 ]]; then
-                                               # Files are passed to python_mod_compile which is ROOT-aware
+                                       if [[ -d "${myroot}/${1#/}" ]]; then
+                                               mydirs+=("${myroot}/${1#/}")
+                                       elif [[ -f "${myroot}/${1#/}" ]]; then
+                                               # Files are passed to python_mod_compile which is EROOT-aware
                                                myfiles+=("$1")
-                                       elif [[ -e "${myroot}/$1" ]]; then
-                                               ewarn "${myroot}/$1 is not a file or directory!"
+                                       elif [[ -e "${myroot}/${1#/}" ]]; then
+                                               ewarn "${myroot}/${1#/} is not a file or directory!"
                                        else
-                                               ewarn "${myroot}/$1 does not exist!"
+                                               ewarn "${myroot}/${1#/} does not exist!"
                                        fi
                                        ;;
                        esac
@@ -1992,10 +2171,13 @@ python_mod_optimize() {
                # set additional opts
                myopts+=(-q)
 
+               PYTHON_ABI="$(PYTHON --ABI)"
+
                ebegin "Compilation and optimization of Python modules for $(python_get_implementation) $(python_get_version)"
                if ((${#mydirs[@]})); then
                        "$(PYTHON ${PYTHON_ABI})" "${myroot}$(python_get_libdir)/compileall.py" "${myopts[@]}" "${mydirs[@]}" || return_code="1"
                        "$(PYTHON ${PYTHON_ABI})" -O "${myroot}$(python_get_libdir)/compileall.py" "${myopts[@]}" "${mydirs[@]}" &> /dev/null || return_code="1"
+                       _python_clean_compiled_modules "${mydirs[@]}"
                fi
 
                if ((${#myfiles[@]})); then
@@ -2019,83 +2201,63 @@ python_mod_optimize() {
 # This function can be used only in pkg_postrm() phase.
 python_mod_cleanup() {
        _python_initialize_prefix_variables
-       _python_set_color_variables
 
-       local path py_file PYTHON_ABI="${PYTHON_ABI}" SEARCH_PATH=() root
+       local dir iterated_PYTHON_ABIS PYTHON_ABI="${PYTHON_ABI}" root search_paths=() sitedir
 
        # Check if phase is pkg_postrm().
        [[ "${EBUILD_PHASE}" != "postrm" ]] && die "${FUNCNAME}() can be used only in pkg_postrm() phase"
 
-       # Strip trailing slash from ROOT.
+       if _python_package_supporting_installation_for_multiple_python_abis; then
+               if [[ -z "${PYTHON_ABIS}" ]]; then
+                       die "${FUNCNAME}(): Environment not initialized"
+               fi
+               iterated_PYTHON_ABIS="${PYTHON_ABIS}"
+       else
+               iterated_PYTHON_ABIS="${PYTHON_ABI:-$(PYTHON --ABI)}"
+       fi
+
+       # Strip trailing slash from EROOT.
        root="${EROOT%/}"
 
        if (($#)); then
                if ! has "${EAPI:-0}" 0 1 2 || _python_package_supporting_installation_for_multiple_python_abis; then
                        while (($#)); do
-                               if ! _python_implementation && [[ "$1" =~ ^"${EPREFIX}"/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
-                                       die "${FUNCNAME}() does not support absolute paths of directories/files in site-packages directories"
+                               if ! _python_implementation && [[ "$1" =~ ^/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
+                                       die "${FUNCNAME}(): Paths of directories / files in site-packages directories must be relative to site-packages directories"
                                elif [[ "$1" =~ ^/ ]]; then
-                                       SEARCH_PATH+=("${root}/${1#/}")
+                                       if _python_package_supporting_installation_for_multiple_python_abis; then
+                                               die "${FUNCNAME}(): Absolute paths cannot be used in ebuilds of packages supporting installation for multiple Python ABIs"
+                                       fi
+                                       search_paths+=("${root}$1")
                                else
-                                       for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI:-$(PYTHON --ABI)}}; do
-                                               SEARCH_PATH+=("${root}$(python_get_sitedir)/$1")
+                                       for PYTHON_ABI in ${iterated_PYTHON_ABIS}; do
+                                               search_paths+=("${root}$(python_get_sitedir)/$1")
                                        done
                                fi
                                shift
                        done
                else
-                       SEARCH_PATH=("${@#/}")
-                       SEARCH_PATH=("${SEARCH_PATH[@]/#/${root}/}")
+                       search_paths=("${@#/}")
+                       search_paths=("${search_paths[@]/#/${root}/}")
                fi
        else
-               local dir sitedir
                for dir in "${root}"/usr/lib*; do
                        if [[ -d "${dir}" && ! -L "${dir}" ]]; then
                                for sitedir in "${dir}"/python*/site-packages; do
                                        if [[ -d "${sitedir}" ]]; then
-                                               SEARCH_PATH+=("${sitedir}")
+                                               search_paths+=("${sitedir}")
                                        fi
                                done
                        fi
                done
                for sitedir in "${root}"/usr/share/jython-*/Lib/site-packages; do
                        if [[ -d "${sitedir}" ]]; then
-                               SEARCH_PATH+=("${sitedir}")
+                               search_paths+=("${sitedir}")
                        fi
                done
        fi
 
-       for path in "${SEARCH_PATH[@]}"; do
-               if [[ -d "${path}" ]]; then
-                       find "${path}" "(" -name "*.py[co]" -o -name "*\$py.class" ")" -print0 | while read -rd ''; do
-                               if [[ "${REPLY}" == *[co] ]]; then
-                                       py_file="${REPLY%[co]}"
-                                       [[ -f "${py_file}" || (! -f "${py_file}c" && ! -f "${py_file}o") ]] && continue
-                                       echo "${_BLUE}<<< ${py_file}[co]${_NORMAL}"
-                                       rm -f "${py_file}"[co]
-                               elif [[ "${REPLY}" == *\$py.class ]]; then
-                                       py_file="${REPLY%\$py.class}.py"
-                                       [[ -f "${py_file}" || ! -f "${py_file%.py}\$py.class" ]] && continue
-                                       echo "${_BLUE}<<< ${py_file%.py}\$py.class${_NORMAL}"
-                                       rm -f "${py_file%.py}\$py.class"
-                               fi
-                       done
-
-                       # Attempt to delete directories, which may be empty.
-                       find "${path}" -type d | sort -r | while read -r dir; do
-                               rmdir "${dir}" 2>/dev/null && echo "${_CYAN}<<< ${dir}${_NORMAL}"
-                       done
-               elif [[ "${path}" == *.py && ! -f "${path}" ]]; then
-                       if [[ (-f "${path}c" || -f "${path}o") ]]; then
-                               echo "${_BLUE}<<< ${path}[co]${_NORMAL}"
-                               rm -f "${path}"[co]
-                       fi
-                       if [[ -f "${path%.py}\$py.class" ]]; then
-                               echo "${_BLUE}<<< ${path%.py}\$py.class${_NORMAL}"
-                               rm -f "${path%.py}\$py.class"
-                       fi
-               fi
-       done
+       _python_clean_compiled_modules "${search_paths[@]}"
 }
 
 # ================================================================================================
@@ -2159,6 +2321,8 @@ python_mod_exists() {
                die "${FUNCNAME}() cannot be used in this EAPI"
        fi
 
+       _python_set_color_variables
+
        echo
        echo " ${_RED}*${_NORMAL} ${_RED}Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01.${_NORMAL}"
        echo " ${_RED}*${_NORMAL} ${_RED}Use USE dependencies and/or has_version() instead of ${FUNCNAME}().${_NORMAL}"
@@ -2187,6 +2351,8 @@ python_tkinter_exists() {
                die "${FUNCNAME}() cannot be used in this EAPI"
        fi
 
+       _python_set_color_variables
+
        if [[ "${FUNCNAME[1]}" != "distutils_python_tkinter" ]]; then
                echo
                echo " ${_RED}*${_NORMAL} ${_RED}Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01.${_NORMAL}"
@@ -2238,14 +2404,17 @@ python_mod_compile() {
        # strip trailing slash
        myroot="${EROOT%/}"
 
-       # respect ROOT
+       # respect EROOT
        for f in "$@"; do
                [[ -f "${myroot}/${f}" ]] && myfiles+=("${myroot}/${f}")
        done
 
+       PYTHON_ABI="$(PYTHON --ABI)"
+
        if ((${#myfiles[@]})); then
                "$(PYTHON ${PYTHON_ABI})" "${myroot}$(python_get_libdir)/py_compile.py" "${myfiles[@]}"
                "$(PYTHON ${PYTHON_ABI})" -O "${myroot}$(python_get_libdir)/py_compile.py" "${myfiles[@]}" &> /dev/null
+               _python_clean_compiled_modules "${myfiles[@]}"
        else
                ewarn "No files to compile!"
        fi