Distutils/Setuptools/Distribute modify shebangs of installed Python scripts, so 
that they
contain path of Python interpreter with version included (e.g. 
"#!/usr/bin/python3.2").
This behavior has both advantage and disadvantages:
  - Scripts of packages supporting only e.g. Python 2 can be executed (without 
necessity
    of using of e.g. "python2 /usr/bin/${script}") after activating of e.g. 
Python 3.
  - Scripts of packages supporting multiple Python versions ignore active 
Python version.
  - Scripts of packages supporting multiple Python versions cannot be easily 
(without
    necessity of using of e.g. "python3.1 /usr/bin/${script}") executed with a 
Python
    version different than active Python version.
The best solution, which removes these 2 disadvantages and preserves the 
advantage, seems
to be to rename Python scripts to include Python version [1] in filenames, and 
create wrapper
scripts, which call appropriate target scripts [2]. Some files sometimes try to 
execute
e.g. "/usr/bin/python /usr/bin/${script}", so wrapper scripts must be 
implemented in Python.
Wrapper scripts try to execute "${wrapper_script}-${PYTHON_ABI}" files (e.g. 
"py.test" will
execute "py.test-3.1", when Python 3.1 is set as active Python version).

distutils.eclass will automatically rename some scripts [3] in "${D}usr/bin" 
and call
the function, which generates wrapper scripts. In case somebody is interested 
in reading of
source code of python_generate_wrapper_scripts() function and potential 
suggesting of
improvements, I'm attaching this function and 2 example wrapper scripts. I'm 
planning to
commit addition of this function in next week.

[1] Actually Python ABI.
[2] Wrapper scripts can also be created for ELF target files (e.g. "mpipython").
[3] Only scripts of packages supporting installation for multiple Python 
versions will be
    renamed. Scripts, whose filenames end in [[:digit:]]+\.[[:digit:]]+, won't 
be renamed.

-- 
Arfrever Frehtes Taifersar Arahesis
# @FUNCTION: python_generate_wrapper_scripts
# @USAGE: [-E|--respect-EPYTHON] [-f|--force] [-q|--quiet] [--] <file> [files]
# @DESCRIPTION:
# Generate wrapper scripts. Existing files are overwritten only with --force 
option.
# If --respect-EPYTHON option is specified, then generated wrapper scripts will
# respect EPYTHON variable at run time.
python_generate_wrapper_scripts() {
        local eselect_python_option file force="0" quiet="0" PYTHON_ABI 
python2_enabled="0" python2_supported_versions python3_enabled="0" 
python3_supported_versions respect_EPYTHON="0"
        python2_supported_versions="2.4 2.5 2.6 2.7"
        python3_supported_versions="3.0 3.1 3.2"

        while (($#)); do
                case "$1" in
                        -E|--respect-EPYTHON)
                                respect_EPYTHON="1"
                                ;;
                        -f|--force)
                                force="1"
                                ;;
                        -q|--quiet)
                                quiet="1"
                                ;;
                        --)
                                break
                                ;;
                        -*)
                                die "${FUNCNAME}(): Unrecognized option '$1'"
                                ;;
                        *)
                                break
                                ;;
                esac
                shift
        done

        validate_PYTHON_ABIS
        for PYTHON_ABI in ${python2_supported_versions}; do
                if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
                        python2_enabled="1"
                fi
        done
        for PYTHON_ABI in ${python3_supported_versions}; do
                if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
                        python3_enabled="1"
                fi
        done

        if [[ "${python2_enabled}" == "1" && "${python3_enabled}" == "1" ]]; 
then
                eselect_python_option=
        elif [[ "${python2_enabled}" == "1" && "${python3_enabled}" == "0" ]]; 
then
                eselect_python_option="--python2"
        elif [[ "${python2_enabled}" == "0" && "${python3_enabled}" == "1" ]]; 
then
                eselect_python_option="--python3"
        else
                die "${FUNCNAME}(): Unsupported environment"
        fi

        for file in "$@"; do
                if [[ -f "${file}" && "${force}" == "0" ]]; then
                        die "${FUNCNAME}(): '$1' already exists"
                fi

                if [[ "${quiet}" == "0" ]]; then
                        einfo "Generating '${file#${D%/}}' wrapper script"
                fi

                cat << EOF > "${file}"
#!/usr/bin/env python
# Gentoo '${file##*/}' wrapper script

import os
import re
import subprocess
import sys

EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")

EOF
                if [[ "$?" != "0" ]]; then
                        die "${FUNCNAME}(): Generation of '$1' failed"
                fi
                if [[ "${respect_EPYTHON}" == "1" ]]; then
                        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:
                sys.stderr.write("EPYTHON variable has unrecognized value 
'%s'\n" % EPYTHON)
                sys.exit(1)
else:
        try:
                eselect_process = subprocess.Popen(["/usr/bin/eselect", 
"python", "show"${eselect_python_option:+, $(echo 
"\"")}${eselect_python_option}${eselect_python_option:+$(echo "\"")}], 
stdout=subprocess.PIPE)
                if eselect_process.wait() != 0:
                        raise ValueError
        except (OSError, ValueError):
                sys.stderr.write("Execution of 'eselect python 
show${eselect_python_option:+ }${eselect_python_option}' failed\n")
                sys.exit(1)

        eselect_output = eselect_process.stdout.read()
        if not isinstance(eselect_output, str):
                # Python 3
                eselect_output = eselect_output.decode()

        EPYTHON_matched = EPYTHON_re.match(eselect_output)
        if EPYTHON_matched:
                PYTHON_ABI = EPYTHON_matched.group(1)
        else:
                sys.stderr.write("'eselect python show${eselect_python_option:+ 
}${eselect_python_option}' printed unrecognized value '%s" % eselect_output)
                sys.exit(1)
EOF
                        if [[ "$?" != "0" ]]; then
                                die "${FUNCNAME}(): Generation of '$1' failed"
                        fi
                else
                        cat << EOF >> "${file}"
try:
        eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", 
"show"${eselect_python_option:+, $(echo 
"\"")}${eselect_python_option}${eselect_python_option:+$(echo "\"")}], 
stdout=subprocess.PIPE)
        if eselect_process.wait() != 0:
                raise ValueError
except (OSError, ValueError):
        sys.stderr.write("Execution of 'eselect python 
show${eselect_python_option:+ }${eselect_python_option}' failed\n")
        sys.exit(1)

eselect_output = eselect_process.stdout.read()
if not isinstance(eselect_output, str):
        # Python 3
        eselect_output = eselect_output.decode()

EPYTHON_matched = EPYTHON_re.match(eselect_output)
if EPYTHON_matched:
        PYTHON_ABI = EPYTHON_matched.group(1)
else:
        sys.stderr.write("'eselect python show${eselect_python_option:+ 
}${eselect_python_option}' printed unrecognized value '%s" % eselect_output)
        sys.exit(1)
EOF
                        if [[ "$?" != "0" ]]; then
                                die "${FUNCNAME}(): Generation of '$1' failed"
                        fi
                fi
                cat << EOF >> "${file}"

target_executable = "%s-%s" % (sys.argv[0], PYTHON_ABI)
if not os.path.exists(target_executable):
        sys.stderr.write("'%s' does not exist\n" % target_executable)
        sys.exit(1)

os.execv(target_executable, sys.argv)
EOF
                if [[ "$?" != "0" ]]; then
                        die "${FUNCNAME}(): Generation of '$1' failed"
                fi
                fperms +x "${file#${D%/}}" || die "fperms '${file}' failed"
        done
}
#!/usr/bin/env python
# Gentoo 'sphinx-build' wrapper script

import os
import re
import subprocess
import sys

EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")

try:
	eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", "show", "--python2"], stdout=subprocess.PIPE)
	if eselect_process.wait() != 0:
		raise ValueError
except (OSError, ValueError):
	sys.stderr.write("Execution of 'eselect python show --python2' failed\n")
	sys.exit(1)

eselect_output = eselect_process.stdout.read()
if not isinstance(eselect_output, str):
	# Python 3
	eselect_output = eselect_output.decode()

EPYTHON_matched = EPYTHON_re.match(eselect_output)
if EPYTHON_matched:
	PYTHON_ABI = EPYTHON_matched.group(1)
else:
	sys.stderr.write("'eselect python show --python2' printed unrecognized value '%s" % eselect_output)
	sys.exit(1)

target_executable = "%s-%s" % (sys.argv[0], PYTHON_ABI)
if not os.path.exists(target_executable):
	sys.stderr.write("'%s' does not exist\n" % target_executable)
	sys.exit(1)

os.execv(target_executable, sys.argv)
#!/usr/bin/env python
# Gentoo 'py.test' wrapper script

import os
import re
import subprocess
import sys

EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")

EPYTHON = os.environ.get("EPYTHON")
if EPYTHON:
	EPYTHON_matched = EPYTHON_re.match(EPYTHON)
	if EPYTHON_matched:
		PYTHON_ABI = EPYTHON_matched.group(1)
	else:
		sys.stderr.write("EPYTHON variable has unrecognized value '%s'\n" % EPYTHON)
		sys.exit(1)
else:
	try:
		eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", "show"], stdout=subprocess.PIPE)
		if eselect_process.wait() != 0:
			raise ValueError
	except (OSError, ValueError):
		sys.stderr.write("Execution of 'eselect python show' failed\n")
		sys.exit(1)

	eselect_output = eselect_process.stdout.read()
	if not isinstance(eselect_output, str):
		# Python 3
		eselect_output = eselect_output.decode()

	EPYTHON_matched = EPYTHON_re.match(eselect_output)
	if EPYTHON_matched:
		PYTHON_ABI = EPYTHON_matched.group(1)
	else:
		sys.stderr.write("'eselect python show' printed unrecognized value '%s" % eselect_output)
		sys.exit(1)

target_executable = "%s-%s" % (sys.argv[0], PYTHON_ABI)
if not os.path.exists(target_executable):
	sys.stderr.write("'%s' does not exist\n" % target_executable)
	sys.exit(1)

os.execv(target_executable, sys.argv)

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to