Skip to content

Commit

Permalink
fix building python3.10 virtualenvs on debian derivatives (#2415)
Browse files Browse the repository at this point in the history
  • Loading branch information
asottile authored Sep 12, 2022
1 parent 56003ce commit 445a68d
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/changelog/2350.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix selected scheme on debian derivatives for python 3.10 when ``python3-distutils`` is not installed or the ``venv`` scheme is not avaiable - by :user:`asottile`.
17 changes: 15 additions & 2 deletions src/virtualenv/discovery/py_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,23 @@ def abs_path(v):
self.file_system_encoding = u(sys.getfilesystemencoding())
self.stdout_encoding = u(getattr(sys.stdout, "encoding", None))

if "venv" in sysconfig.get_scheme_names():
scheme_names = sysconfig.get_scheme_names()

if "venv" in scheme_names:
self.sysconfig_scheme = "venv"
self.sysconfig_paths = {
u(i): u(sysconfig.get_path(i, expand=False, scheme="venv")) for i in sysconfig.get_path_names()
u(i): u(sysconfig.get_path(i, expand=False, scheme=self.sysconfig_scheme))
for i in sysconfig.get_path_names()
}
# we cannot use distutils at all if "venv" exists, distutils don't know it
self.distutils_install = {}
# debian / ubuntu python 3.10 without `python3-distutils` will report
# mangled `local/bin` / etc. names for the default prefix
# intentionally select `posix_prefix` which is the unaltered posix-like paths
elif sys.version_info[:2] == (3, 10) and "deb_system" in scheme_names:
self.sysconfig_scheme = "posix_prefix"
self.sysconfig_paths = {
i: sysconfig.get_path(i, expand=False, scheme=self.sysconfig_scheme) for i in sysconfig.get_path_names()
}
# we cannot use distutils at all if "venv" exists, distutils don't know it
self.distutils_install = {}
Expand Down
71 changes: 71 additions & 0 deletions tests/unit/discovery/py_info/test_py_info.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import functools
import itertools
import json
import logging
Expand Down Expand Up @@ -375,3 +376,73 @@ def test_custom_venv_install_scheme_is_prefered(mocker):
pyver = f"{pyinfo.version_info.major}.{pyinfo.version_info.minor}"
assert pyinfo.install_path("scripts") == "bin"
assert pyinfo.install_path("purelib").replace(os.sep, "/") == f"lib/python{pyver}/site-packages"


@pytest.mark.skipif(sys.version_info[:2] != (3, 10), reason="3.10 specific")
def test_uses_posix_prefix_on_debian_3_10_without_venv(mocker):
# this is taken from ubuntu 22.04 /usr/lib/python3.10/sysconfig.py
sysconfig_install_schemes = {
"posix_prefix": {
"stdlib": "{installed_base}/{platlibdir}/python{py_version_short}",
"platstdlib": "{platbase}/{platlibdir}/python{py_version_short}",
"purelib": "{base}/lib/python{py_version_short}/site-packages",
"platlib": "{platbase}/{platlibdir}/python{py_version_short}/site-packages",
"include": "{installed_base}/include/python{py_version_short}{abiflags}",
"platinclude": "{installed_platbase}/include/python{py_version_short}{abiflags}",
"scripts": "{base}/bin",
"data": "{base}",
},
"posix_home": {
"stdlib": "{installed_base}/lib/python",
"platstdlib": "{base}/lib/python",
"purelib": "{base}/lib/python",
"platlib": "{base}/lib/python",
"include": "{installed_base}/include/python",
"platinclude": "{installed_base}/include/python",
"scripts": "{base}/bin",
"data": "{base}",
},
"nt": {
"stdlib": "{installed_base}/Lib",
"platstdlib": "{base}/Lib",
"purelib": "{base}/Lib/site-packages",
"platlib": "{base}/Lib/site-packages",
"include": "{installed_base}/Include",
"platinclude": "{installed_base}/Include",
"scripts": "{base}/Scripts",
"data": "{base}",
},
"deb_system": {
"stdlib": "{installed_base}/{platlibdir}/python{py_version_short}",
"platstdlib": "{platbase}/{platlibdir}/python{py_version_short}",
"purelib": "{base}/lib/python3/dist-packages",
"platlib": "{platbase}/{platlibdir}/python3/dist-packages",
"include": "{installed_base}/include/python{py_version_short}{abiflags}",
"platinclude": "{installed_platbase}/include/python{py_version_short}{abiflags}",
"scripts": "{base}/bin",
"data": "{base}",
},
"posix_local": {
"stdlib": "{installed_base}/{platlibdir}/python{py_version_short}",
"platstdlib": "{platbase}/{platlibdir}/python{py_version_short}",
"purelib": "{base}/local/lib/python{py_version_short}/dist-packages",
"platlib": "{platbase}/local/lib/python{py_version_short}/dist-packages",
"include": "{installed_base}/local/include/python{py_version_short}{abiflags}",
"platinclude": "{installed_platbase}/local/include/python{py_version_short}{abiflags}",
"scripts": "{base}/local/bin",
"data": "{base}",
},
}
# reset the default in case we're on a system which doesn't have this problem
sysconfig_get_path = functools.partial(sysconfig.get_path, scheme="posix_local")

# make it look like python3-distutils is not available
mocker.patch.dict(sys.modules, {"distutils.command": None})
mocker.patch("sysconfig._INSTALL_SCHEMES", sysconfig_install_schemes)
mocker.patch("sysconfig.get_path", sysconfig_get_path)
mocker.patch("sysconfig.get_default_scheme", return_value="posix_local")

pyinfo = PythonInfo()
pyver = f"{pyinfo.version_info.major}.{pyinfo.version_info.minor}"
assert pyinfo.install_path("scripts") == "bin"
assert pyinfo.install_path("purelib").replace(os.sep, "/") == f"lib/python{pyver}/site-packages"

0 comments on commit 445a68d

Please sign in to comment.