app-emacs/ebuild-mode: ppc stable wrt bug #706066
[gentoo.git] / eclass / distutils-r1.eclass
index b249985a2a1c4a3dbe8c2fe3f8aeb06296a9e418..a840769cdecf1382f0c63539ccb238073d3aa6df 100644 (file)
@@ -1,6 +1,5 @@
-# Copyright 1999-2015 Gentoo Foundation
+# Copyright 1999-2019 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
-# $Id$
 
 # @ECLASS: distutils-r1.eclass
 # @MAINTAINER:
@@ -8,6 +7,7 @@
 # @AUTHOR:
 # Author: Michał Górny <mgorny@gentoo.org>
 # Based on the work of: Krzysztof Pawlik <nelchael@gentoo.org>
+# @SUPPORTED_EAPIS: 5 6 7
 # @BLURB: A simple eclass to build Python packages using distutils.
 # @DESCRIPTION:
 # A simple eclass providing functions to build Python packages using
 # https://wiki.gentoo.org/wiki/Project:Python/distutils-r1
 
 case "${EAPI:-0}" in
-       0|1|2|3)
+       0|1|2|3|4)
                die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
                ;;
-       4|5)
+       5|6|7)
                ;;
        *)
                die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
@@ -77,12 +77,30 @@ esac
 # to be exported. It must be run in order for the eclass functions
 # to function properly.
 
+# @ECLASS-VARIABLE: DISTUTILS_USE_SETUPTOOLS
+# @PRE_INHERIT
+# @DESCRIPTION:
+# Controls adding dev-python/setuptools dependency.  The allowed values
+# are:
+#
+# - no -- do not add the dependency (pure distutils package)
+# - bdepend -- add it to BDEPEND (the default)
+# - rdepend -- add it to BDEPEND+RDEPEND (when using entry_points)
+# - manual -- do not add the depedency and suppress the checks
+#             (assumes you will take care of doing it correctly)
+#
+# This variable is effective only if DISTUTILS_OPTIONAL is disabled.
+# It needs to be set before the inherit line.
+: ${DISTUTILS_USE_SETUPTOOLS:=bdepend}
+
 if [[ ! ${_DISTUTILS_R1} ]]; then
 
-inherit eutils toolchain-funcs
+[[ ${EAPI} == [456] ]] && inherit eutils
+[[ ${EAPI} == [56] ]] && inherit xdg-utils
+inherit multiprocessing toolchain-funcs
 
 if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
-       inherit multiprocessing python-r1
+       inherit python-r1
 else
        inherit python-single-r1
 fi
@@ -95,11 +113,35 @@ fi
 
 if [[ ! ${_DISTUTILS_R1} ]]; then
 
-if [[ ! ${DISTUTILS_OPTIONAL} ]]; then
-       RDEPEND=${PYTHON_DEPS}
-       DEPEND=${PYTHON_DEPS}
+_distutils_set_globals() {
+       local rdep=${PYTHON_DEPS}
+       local bdep=${rdep}
+
+       case ${DISTUTILS_USE_SETUPTOOLS} in
+               no|manual)
+                       ;;
+               bdepend)
+                       bdep+=" dev-python/setuptools[${PYTHON_USEDEP}]"
+                       ;;
+               rdepend)
+                       bdep+=" dev-python/setuptools[${PYTHON_USEDEP}]"
+                       rdep+=" dev-python/setuptools[${PYTHON_USEDEP}]"
+                       ;;
+               *)
+                       die "Invalid DISTUTILS_USE_SETUPTOOLS=${DISTUTILS_USE_SETUPTOOLS}"
+                       ;;
+       esac
+
+       RDEPEND=${rdep}
+       if [[ ${EAPI} != [56] ]]; then
+               BDEPEND=${bdep}
+       else
+               DEPEND=${bdep}
+       fi
        REQUIRED_USE=${PYTHON_REQUIRED_USE}
-fi
+}
+[[ ! ${DISTUTILS_OPTIONAL} ]] && _distutils_set_globals
+unset -f _distutils_set_globals
 
 # @ECLASS-VARIABLE: PATCHES
 # @DEFAULT_UNSET
@@ -191,6 +233,12 @@ fi
 # (allowing any implementation). If multiple values are specified,
 # implementations matching any of the patterns will be accepted.
 #
+# The patterns can be either fnmatch-style patterns (matched via bash
+# == operator against PYTHON_COMPAT values) or '-2' / '-3' to indicate
+# appropriately all enabled Python 2/3 implementations (alike
+# python_is_python3). Remember to escape or quote the fnmatch patterns
+# to prevent accidental shell filename expansion.
+#
 # If the restriction needs to apply conditionally to a USE flag,
 # the variable should be set conditionally as well (e.g. in an early
 # phase function or other convenient location).
@@ -220,17 +268,218 @@ fi
 # }
 # @CODE
 
+# @FUNCTION: distutils_enable_sphinx
+# @USAGE: <subdir> [--no-autodoc | <plugin-pkgs>...]
+# @DESCRIPTION:
+# Set up IUSE, BDEPEND, python_check_deps() and python_compile_all() for
+# building HTML docs via dev-python/sphinx.  python_compile_all() will
+# append to HTML_DOCS if docs are enabled.
+#
+# This helper is meant for the most common case, that is a single Sphinx
+# subdirectory with standard layout, building and installing HTML docs
+# behind USE=doc.  It assumes it's the only consumer of the three
+# aforementioned functions.  If you need to use a custom implemention,
+# you can't use it.
+#
+# If your package uses additional Sphinx plugins, they should be passed
+# (without PYTHON_USEDEP) as <plugin-pkgs>.  The function will take care
+# of setting appropriate any-of dep and python_check_deps().
+#
+# If no plugin packages are specified, the eclass will still utilize
+# any-r1 API to support autodoc (documenting source code).
+# If the package uses neither autodoc nor additional plugins, you should
+# pass --no-autodoc to disable this API and simplify the resulting code.
+#
+# This function must be called in global scope.  Take care not to
+# overwrite the variables set by it.  If you need to extend
+# python_compile_all(), you can call the original implementation
+# as sphinx_compile_all.
+distutils_enable_sphinx() {
+       debug-print-function ${FUNCNAME} "${@}"
+       [[ ${#} -ge 1 ]] || die "${FUNCNAME} takes at least one arg: <subdir>"
+
+       _DISTUTILS_SPHINX_SUBDIR=${1}
+       shift
+       _DISTUTILS_SPHINX_PLUGINS=( "${@}" )
+
+       local deps autodoc=1 d
+       for d; do
+               if [[ ${d} == --no-autodoc ]]; then
+                       autodoc=
+               else
+                       deps+="
+                               ${d}[\${PYTHON_USEDEP}]"
+               fi
+       done
+
+       if [[ ! ${autodoc} && -n ${deps} ]]; then
+               die "${FUNCNAME}: do not pass --no-autodoc if external plugins are used"
+       fi
+       if [[ ${autodoc} ]]; then
+               deps="$(python_gen_any_dep "
+                       dev-python/sphinx[\${PYTHON_USEDEP}]
+                       ${deps}")"
+
+               python_check_deps() {
+                       use doc || return 0
+                       local p
+                       for p in dev-python/sphinx "${_DISTUTILS_SPHINX_PLUGINS[@]}"; do
+                               has_version "${p}[${PYTHON_USEDEP}]" || return 1
+                       done
+               }
+       else
+               deps="dev-python/sphinx"
+       fi
+
+       sphinx_compile_all() {
+               use doc || return
+
+               local confpy=${_DISTUTILS_SPHINX_SUBDIR}/conf.py
+               [[ -f ${confpy} ]] ||
+                       die "${confpy} not found, distutils_enable_sphinx call wrong"
+
+               if [[ ${_DISTUTILS_SPHINX_PLUGINS[0]} == --no-autodoc ]]; then
+                       if grep -F -q 'sphinx.ext.autodoc' "${confpy}"; then
+                               die "distutils_enable_sphinx: --no-autodoc passed but sphinx.ext.autodoc found in ${confpy}"
+                       fi
+               else
+                       if ! grep -F -q 'sphinx.ext.autodoc' "${confpy}"; then
+                               die "distutils_enable_sphinx: sphinx.ext.autodoc not found in ${confpy}, pass --no-autodoc"
+                       fi
+               fi
+
+               build_sphinx "${_DISTUTILS_SPHINX_SUBDIR}"
+       }
+       python_compile_all() { sphinx_compile_all; }
+
+       IUSE+=" doc"
+       if [[ ${EAPI} == [56] ]]; then
+               DEPEND+=" doc? ( ${deps} )"
+       else
+               BDEPEND+=" doc? ( ${deps} )"
+       fi
+
+       # we need to ensure successful return in case we're called last,
+       # otherwise Portage may wrongly assume sourcing failed
+       return 0
+}
+
+# @FUNCTION: distutils_enable_tests
+# @USAGE: <test-runner>
+# @DESCRIPTION:
+# Set up IUSE, RESTRICT, BDEPEND and python_test() for running tests
+# with the specified test runner.  Also copies the current value
+# of RDEPEND to test?-BDEPEND.  The test-runner argument must be one of:
+#
+# - nose: nosetests (dev-python/nose)
+# - pytest: dev-python/pytest
+# - setup.py: setup.py test (no deps included)
+# - unittest: for built-in Python unittest module
+#
+# This function is meant as a helper for common use cases, and it only
+# takes care of basic setup.  You still need to list additional test
+# dependencies manually.  If you have uncommon use case, you should
+# not use it and instead enable tests manually.
+#
+# This function must be called in global scope, after RDEPEND has been
+# declared.  Take care not to overwrite the variables set by it.
+distutils_enable_tests() {
+       debug-print-function ${FUNCNAME} "${@}"
+       [[ ${#} -eq 1 ]] || die "${FUNCNAME} takes exactly one argument: test-runner"
+
+       local test_deps
+       case ${1} in
+               nose)
+                       test_deps="dev-python/nose[${PYTHON_USEDEP}]"
+                       python_test() {
+                               nosetests -v || die "Tests fail with ${EPYTHON}"
+                       }
+                       ;;
+               pytest)
+                       test_deps="dev-python/pytest[${PYTHON_USEDEP}]"
+                       python_test() {
+                               pytest -vv || die "Tests fail with ${EPYTHON}"
+                       }
+                       ;;
+               setup.py)
+                       python_test() {
+                               esetup.py test --verbose
+                       }
+                       ;;
+               unittest)
+                       python_test() {
+                               "${EPYTHON}" -m unittest discover -v ||
+                                       die "Tests fail with ${EPYTHON}"
+                       }
+                       ;;
+               *)
+                       die "${FUNCNAME}: unsupported argument: ${1}"
+       esac
+
+       if [[ -n ${test_deps} || -n ${RDEPEND} ]]; then
+               IUSE+=" test"
+               RESTRICT+=" !test? ( test )"
+               if [[ ${EAPI} == [56] ]]; then
+                       DEPEND+=" test? ( ${test_deps} ${RDEPEND} )"
+               else
+                       BDEPEND+=" test? ( ${test_deps} ${RDEPEND} )"
+               fi
+       fi
+
+       # we need to ensure successful return in case we're called last,
+       # otherwise Portage may wrongly assume sourcing failed
+       return 0
+}
+
+# @FUNCTION: _distutils-r1_verify_use_setuptools
+# @INTERNAL
+# @DESCRIPTION:
+# Check setup.py for signs that DISTUTILS_USE_SETUPTOOLS have been set
+# incorrectly.
+_distutils_verify_use_setuptools() {
+       [[ ${DISTUTILS_OPTIONAL} ]] && return
+       [[ ${DISTUTILS_USE_SETUPTOOLS} == manual ]] && return
+
+       # ok, those are cheap greps.  we can try toimprove them if we hit
+       # false positives.
+       local expected=no
+       if [[ ${CATEGORY}/${PN} == dev-python/setuptools ]]; then
+               # as a special case, setuptools provides itself ;-)
+               :
+       elif grep -E -q -s '(from|import)\s+setuptools' setup.py; then
+               if grep -E -q -s 'entry_points\s*=' setup.py; then
+                       expected=rdepend
+               elif grep -F -q -s '[options.entry_points]' setup.cfg; then
+                       expected=rdepend
+               else
+                       expected=bdepend
+               fi
+       fi
+
+       if [[ ${DISTUTILS_USE_SETUPTOOLS} != ${expected} ]]; then
+               if [[ ! ${_DISTUTILS_SETUPTOOLS_WARNED} ]]; then
+                       _DISTUTILS_SETUPTOOLS_WARNED=1
+                       local def=
+                       [[ ${DISTUTILS_USE_SETUPTOOLS} == bdepend ]] && def=' (default?)'
+
+                       eqawarn "DISTUTILS_USE_SETUPTOOLS value is probably incorrect"
+                       eqawarn "  value:    DISTUTILS_USE_SETUPTOOLS=${DISTUTILS_USE_SETUPTOOLS}${def}"
+                       eqawarn "  expected: DISTUTILS_USE_SETUPTOOLS=${expected}"
+               fi
+       fi
+}
+
 # @FUNCTION: esetup.py
 # @USAGE: [<args>...]
 # @DESCRIPTION:
 # Run setup.py using currently selected Python interpreter
-# (if ${PYTHON} is set; fallback 'python' otherwise).
+# (if ${EPYTHON} is set; fallback 'python' otherwise).
 #
 # setup.py will be passed the following, in order:
 # 1. ${mydistutilsargs[@]}
 # 2. additional arguments passed to the esetup.py function.
 #
-# Please note that setup.py will respect defaults (unless overriden
+# Please note that setup.py will respect defaults (unless overridden
 # via command-line options) from setup.cfg that is created
 # in distutils-r1_python_compile and in distutils-r1_python_install.
 #
@@ -241,10 +490,20 @@ esetup.py() {
        local die_args=()
        [[ ${EAPI} != [45] ]] && die_args+=( -n )
 
-       set -- "${PYTHON:-python}" setup.py "${mydistutilsargs[@]}" "${@}"
+       [[ ${BUILD_DIR} ]] && _distutils-r1_create_setup_cfg
+       _distutils_verify_use_setuptools
+
+       set -- "${EPYTHON:-python}" setup.py "${mydistutilsargs[@]}" "${@}"
 
        echo "${@}" >&2
-       "${@}" || die "${die_args[@]}" || return ${?}
+       "${@}" || die "${die_args[@]}"
+       local ret=${?}
+
+       if [[ ${BUILD_DIR} ]]; then
+               rm "${HOME}"/.pydistutils.cfg || die "${die_args[@]}"
+       fi
+
+       return ${ret}
 }
 
 # @FUNCTION: distutils_install_for_testing
@@ -314,11 +573,13 @@ _distutils-r1_disable_ez_setup() {
 distutils-r1_python_prepare_all() {
        debug-print-function ${FUNCNAME} "${@}"
 
-       if [[ ${EAPI} != [45] ]]; then
-               default
-       else
-               [[ ${PATCHES} ]] && epatch "${PATCHES[@]}"
-               epatch_user
+       if [[ ! ${DISTUTILS_OPTIONAL} ]]; then
+               if [[ ${EAPI} != [45] ]]; then
+                       default
+               else
+                       [[ ${PATCHES} ]] && epatch "${PATCHES[@]}"
+                       epatch_user
+               fi
        fi
 
        # by default, use in-source build if python_prepare() is used
@@ -373,16 +634,13 @@ _distutils-r1_create_setup_cfg() {
                #
                # note: due to some packages (wxpython) relying on separate
                # platlib & purelib dirs, we do not set --build-lib (which
-               # can not be overriden with --build-*lib)
+               # can not be overridden with --build-*lib)
                build-platlib = %(build-base)s/lib
                build-purelib = %(build-base)s/lib
 
                # make the ebuild writer lives easier
                build-scripts = %(build-base)s/scripts
 
-               [egg_info]
-               egg-base = ${BUILD_DIR}
-
                # this is needed by distutils_install_for_testing since
                # setuptools like to create .egg files for install --home.
                [bdist_egg]
@@ -398,7 +656,7 @@ _distutils-r1_create_setup_cfg() {
                        [install]
                        compile = True
                        optimize = 2
-                       root = ${D}
+                       root = ${D%/}
                _EOF_
 
                if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
@@ -418,7 +676,7 @@ _distutils-r1_create_setup_cfg() {
 _distutils-r1_copy_egg_info() {
        mkdir -p "${BUILD_DIR}" || die
        # stupid freebsd can't do 'cp -t ${BUILD_DIR} {} +'
-       find -name '*.egg-info' -type d -exec cp -pr {} "${BUILD_DIR}"/ ';' || die
+       find -name '*.egg-info' -type d -exec cp -R -p {} "${BUILD_DIR}"/ ';' || die
 }
 
 # @FUNCTION: distutils-r1_python_compile
@@ -433,10 +691,25 @@ _distutils-r1_copy_egg_info() {
 distutils-r1_python_compile() {
        debug-print-function ${FUNCNAME} "${@}"
 
-       _distutils-r1_create_setup_cfg
        _distutils-r1_copy_egg_info
 
-       esetup.py build "${@}"
+       local build_args=()
+       # distutils is parallel-capable since py3.5
+       # to avoid breaking stable ebuilds, enable it only if either:
+       # a. we're dealing with EAPI 7
+       # b. we're dealing with Python 3.7 or PyPy3
+       if python_is_python3 && [[ ${EPYTHON} != python3.4 ]]; then
+               if [[ ${EAPI} != [56] || ${EPYTHON} != python3.[56] ]]; then
+                       local jobs=$(makeopts_jobs "${MAKEOPTS}" INF)
+                       if [[ ${jobs} == INF ]]; then
+                               local nproc=$(get_nproc)
+                               jobs=$(( nproc + 1 ))
+                       fi
+                       build_args+=( -j "${jobs}" )
+               fi
+       fi
+
+       esetup.py build "${build_args[@]}" "${@}"
 }
 
 # @FUNCTION: _distutils-r1_wrap_scripts
@@ -508,12 +781,12 @@ distutils-r1_python_install() {
        # enable compilation for the install phase.
        local -x PYTHONDONTWRITEBYTECODE=
 
-       # re-create setup.cfg with install paths
-       _distutils-r1_create_setup_cfg
-
        # python likes to compile any module it sees, which triggers sandbox
        # failures if some packages haven't compiled their modules yet.
+       addpredict "${EPREFIX}/usr/lib/${EPYTHON}"
        addpredict "${EPREFIX}/usr/$(get_libdir)/${EPYTHON}"
+       addpredict /usr/lib/pypy2.7
+       addpredict /usr/lib/pypy3.6
        addpredict /usr/lib/portage/pym
        addpredict /usr/local # bug 498232
 
@@ -552,19 +825,28 @@ distutils-r1_python_install() {
                done
        fi
 
-       local root=${D}/_${EPYTHON}
-       [[ ${DISTUTILS_SINGLE_IMPL} ]] && root=${D}
+       local root=${D%/}/_${EPYTHON}
+       [[ ${DISTUTILS_SINGLE_IMPL} ]] && root=${D%/}
 
        esetup.py install --root="${root}" "${args[@]}"
 
-       local forbidden_package_names=( examples test tests )
+       local forbidden_package_names=( examples test tests .pytest_cache )
        local p
        for p in "${forbidden_package_names[@]}"; do
                if [[ -d ${root}$(python_get_sitedir)/${p} ]]; then
                        die "Package installs '${p}' package which is forbidden and likely a bug in the build system."
                fi
        done
-       if [[ -d ${root}/usr/$(get_libdir)/pypy/share ]]; then
+
+       local shopt_save=$(shopt -p nullglob)
+       shopt -s nullglob
+       local pypy_dirs=(
+               "${root}/usr/$(get_libdir)"/pypy*/share
+               "${root}/usr/lib"/pypy*/share
+       )
+       ${shopt_save}
+
+       if [[ -n ${pypy_dirs} ]]; then
                local cmd=die
                [[ ${EAPI} == [45] ]] && cmd=eqawarn
                "${cmd}" "Package installs 'share' in PyPy prefix, see bug #465546."
@@ -572,7 +854,7 @@ distutils-r1_python_install() {
 
        if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
                _distutils-r1_wrap_scripts "${root}" "${scriptdir}"
-               multibuild_merge_root "${root}" "${D}"
+               multibuild_merge_root "${root}" "${D%/}"
        fi
 }
 
@@ -587,9 +869,11 @@ distutils-r1_python_install_all() {
        if declare -p EXAMPLES &>/dev/null; then
                [[ ${EAPI} != [45] ]] && die "EXAMPLES are banned in EAPI ${EAPI}"
 
-               local INSDESTTREE=/usr/share/doc/${PF}/examples
-               doins -r "${EXAMPLES[@]}"
-               docompress -x "${INSDESTTREE}"
+               (
+                       docinto examples
+                       dodoc -r "${EXAMPLES[@]}"
+               )
+               docompress -x "/usr/share/doc/${PF}/examples"
        fi
 
        _DISTUTILS_DEFAULT_CALLED=1
@@ -612,7 +896,11 @@ distutils-r1_run_phase() {
        debug-print-function ${FUNCNAME} "${@}"
 
        if [[ ${DISTUTILS_IN_SOURCE_BUILD} ]]; then
-               if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
+               # only force BUILD_DIR if implementation is explicitly enabled
+               # for building; any-r1 API may select one that is not
+               # https://bugs.gentoo.org/701506
+               if [[ ! ${DISTUTILS_SINGLE_IMPL} ]] &&
+                               has "${EPYTHON/./_}" ${PYTHON_TARGETS}; then
                        cd "${BUILD_DIR}" || die
                fi
                local BUILD_DIR=${BUILD_DIR}/build
@@ -627,12 +915,6 @@ distutils-r1_run_phase() {
        # in the sys.path_importer_cache)
        mkdir -p "${BUILD_DIR}/lib" || die
 
-       # We need separate home for each implementation, for .pydistutils.cfg.
-       if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
-               local -x HOME=${HOME}/${EPYTHON}
-               mkdir -p "${HOME}" || die
-       fi
-
        # Set up build environment, bug #513664.
        local -x AR=${AR} CC=${CC} CPP=${CPP} CXX=${CXX}
        tc-export AR CC CPP CXX
@@ -666,22 +948,20 @@ distutils-r1_run_phase() {
 _distutils-r1_run_common_phase() {
        local DISTUTILS_ORIG_BUILD_DIR=${BUILD_DIR}
 
-       if [[ ${DISTUTILS_SINGLE_IMPL} ]]; then
-               local best_impl patterns=( "${DISTUTILS_ALL_SUBPHASE_IMPLS[@]-*}" )
-               _distutils_try_impl() {
-                       local pattern
-                       for pattern in "${patterns[@]}"; do
-                               if [[ ${EPYTHON} == ${pattern} ]]; then
-                                       best_impl=${MULTIBUILD_VARIANT}
-                               fi
-                       done
-               }
-               python_foreach_impl _distutils_try_impl
-
-               local PYTHON_COMPAT=( "${best_impl}" )
+       if [[ ${DISTUTILS_SINGLE_IMPL} ]]; then
+               # reuse the dedicated code branch
+               _distutils-r1_run_foreach_impl "${@}"
+       else
+               local -x EPYTHON PYTHON
+               local -x PATH=${PATH} PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
+               python_setup "${DISTUTILS_ALL_SUBPHASE_IMPLS[@]}"
+
+               local MULTIBUILD_VARIANTS=( "${EPYTHON/./_}" )
+               # store for restoring after distutils-r1_run_phase.
+               local _DISTUTILS_INITIAL_CWD=${PWD}
+               multibuild_foreach_variant \
+                       distutils-r1_run_phase "${@}"
        fi
-
-       _distutils-r1_run_foreach_impl "${@}"
 }
 
 # @FUNCTION: _distutils-r1_run_foreach_impl
@@ -692,15 +972,6 @@ _distutils-r1_run_common_phase() {
 _distutils-r1_run_foreach_impl() {
        debug-print-function ${FUNCNAME} "${@}"
 
-       if [[ ${DISTUTILS_NO_PARALLEL_BUILD} ]]; then
-               [[ ${EAPI} == [45] ]] || die "DISTUTILS_NO_PARALLEL_BUILD is banned in EAPI ${EAPI}"
-
-               eqawarn "DISTUTILS_NO_PARALLEL_BUILD is no longer meaningful. Now all builds"
-               eqawarn "are non-parallel. Please remove it from the ebuild."
-
-               unset DISTUTILS_NO_PARALLEL_BUILD # avoid repeated warnings
-       fi
-
        # store for restoring after distutils-r1_run_phase.
        local _DISTUTILS_INITIAL_CWD=${PWD}
        set -- distutils-r1_run_phase "${@}"
@@ -744,6 +1015,7 @@ distutils-r1_src_prepare() {
 
 distutils-r1_src_configure() {
        python_export_utf8_locale
+       [[ ${EAPI} == [56] ]] && xdg_environment_reset # Bug 577704
 
        if declare -f python_configure >/dev/null; then
                _distutils-r1_run_foreach_impl python_configure
@@ -768,10 +1040,14 @@ distutils-r1_src_compile() {
        fi
 }
 
-_clean_egg_info() {
-       # Work around for setuptools test behavior (bug 534058).
-       # https://bitbucket.org/pypa/setuptools/issue/292
-       rm -rf "${BUILD_DIR}"/lib/*.egg-info
+# @FUNCTION: _distutils-r1_clean_egg_info
+# @INTERNAL
+# @DESCRIPTION:
+# Clean up potential stray egg-info files left by setuptools test phase.
+# Those files ended up being unversioned, and caused issues:
+# https://bugs.gentoo.org/534058
+_distutils-r1_clean_egg_info() {
+       rm -rf "${BUILD_DIR}"/lib/*.egg-info || die
 }
 
 distutils-r1_src_test() {
@@ -779,7 +1055,7 @@ distutils-r1_src_test() {
 
        if declare -f python_test >/dev/null; then
                _distutils-r1_run_foreach_impl python_test
-               _distutils-r1_run_foreach_impl _clean_egg_info
+               _distutils-r1_run_foreach_impl _distutils-r1_clean_egg_info
        fi
 
        if declare -f python_test_all >/dev/null; then
@@ -787,6 +1063,33 @@ distutils-r1_src_test() {
        fi
 }
 
+# @FUNCTION: _distutils-r1_check_namespace_pth
+# @INTERNAL
+# @DESCRIPTION:
+# Check if any *-nspkg.pth files were installed (by setuptools)
+# and warn about the policy non-conformance if they were.
+_distutils-r1_check_namespace_pth() {
+       local f pth=()
+
+       while IFS= read -r -d '' f; do
+               pth+=( "${f}" )
+       done < <(find "${ED%/}" -name '*-nspkg.pth' -print0)
+
+       if [[ ${pth[@]} ]]; then
+               ewarn "The following *-nspkg.pth files were found installed:"
+               ewarn
+               for f in "${pth[@]}"; do
+                       ewarn "  ${f#${ED%/}}"
+               done
+               ewarn
+               ewarn "The presence of those files may break namespaces in Python 3.5+. Please"
+               ewarn "read our documentation on reliable handling of namespaces and update"
+               ewarn "the ebuild accordingly:"
+               ewarn
+               ewarn "  https://wiki.gentoo.org/wiki/Project:Python/Namespace_packages"
+       fi
+}
+
 distutils-r1_src_install() {
        debug-print-function ${FUNCNAME} "${@}"
 
@@ -810,6 +1113,8 @@ distutils-r1_src_install() {
 
                "${cmd}" "QA: python_install_all() didn't call distutils-r1_python_install_all"
        fi
+
+       _distutils-r1_check_namespace_pth
 }
 
 # -- distutils.eclass functions --