diff --git a/docs/changelog/1663.bugfix.rst b/docs/changelog/1663.bugfix.rst new file mode 100644 index 000000000..f162936a8 --- /dev/null +++ b/docs/changelog/1663.bugfix.rst @@ -0,0 +1,2 @@ +Fix acquiring python information might be altered by distutils configuration files generating incorrect layout virtual +environments - by :user:`gaborbernat`. diff --git a/docs/changelog/1702.bugfix.rst b/docs/changelog/1702.bugfix.rst index dd1dab2ae..4e1c97c9e 100644 --- a/docs/changelog/1702.bugfix.rst +++ b/docs/changelog/1702.bugfix.rst @@ -1 +1 @@ -Upgrade embedded setuptools to ``46.0.0`` from ``45.3.0`` on Python ``3.5+``. +Upgrade embedded setuptools to ``46.0.0`` from ``45.3.0`` on Python ``3.5+`` - by :user:`gaborbernat`. diff --git a/src/virtualenv/create/via_global_ref/_virtualenv.py b/src/virtualenv/create/via_global_ref/_virtualenv.py index dd314761c..5a1f76a02 100644 --- a/src/virtualenv/create/via_global_ref/_virtualenv.py +++ b/src/virtualenv/create/via_global_ref/_virtualenv.py @@ -23,11 +23,10 @@ def parse_config_files(self, *args, **kwargs): if "prefix" in install: # the prefix governs where to install the libraries install["prefix"] = VIRTUALENV_PATCH_FILE, os.path.abspath(sys.prefix) - - if "install_scripts" in install: # the install_scripts governs where to generate console scripts - script_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "__SCRIPT_DIR__")) - install["install_scripts"] = VIRTUALENV_PATCH_FILE, script_path - + for base in ("purelib", "platlib", "headers", "scripts", "data"): + key = "install_{}".format(base) + if key in install: # do not allow global configs to hijack venv paths + install.pop(key, None) return result dist.Distribution.parse_config_files = parse_config_files diff --git a/src/virtualenv/discovery/py_info.py b/src/virtualenv/discovery/py_info.py index 894082ce0..de46875bc 100644 --- a/src/virtualenv/discovery/py_info.py +++ b/src/virtualenv/discovery/py_info.py @@ -111,8 +111,7 @@ def _fast_get_system_executable(self): @staticmethod def _distutils_install(): # follow https://github.com/pypa/pip/blob/master/src/pip/_internal/locations.py#L95 - d = Distribution({"script_args": "--no-user-cfg"}) - d.parse_config_files() + d = Distribution({"script_args": "--no-user-cfg"}) # configuration files not parsed so they do not hijack paths i = d.get_command_obj("install", create=True) i.prefix = "a" i.finalize_options() diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py index bf2de4722..70e0e6a84 100644 --- a/tests/unit/create/test_creator.py +++ b/tests/unit/create/test_creator.py @@ -369,11 +369,17 @@ def test_create_distutils_cfg(creator, tmp_path, monkeypatch): setup_cfg = dest / "setup.cfg" conf = dedent( """ - [install] - prefix={}/a - install_scripts={}/b - """ - ).format(tmp_path, tmp_path) + [install] + prefix={0}{1}prefix + install_purelib={0}{1}purelib + install_platlib={0}{1}platlib + install_headers={0}{1}headers + install_scripts={0}{1}scripts + install_data={0}{1}data + """.format( + tmp_path, os.sep + ) + ) setup_cfg.write_text(setup_cfg.read_text() + conf) monkeypatch.chdir(dest) # distutils will read the setup.cfg from the cwd, so change to that diff --git a/tests/unit/discovery/py_info/test_py_info.py b/tests/unit/discovery/py_info/test_py_info.py index 11b52c70f..ad9d399e2 100644 --- a/tests/unit/discovery/py_info/test_py_info.py +++ b/tests/unit/discovery/py_info/test_py_info.py @@ -4,8 +4,10 @@ import itertools import json import logging +import os import sys from collections import namedtuple +from textwrap import dedent import pytest @@ -237,3 +239,26 @@ def func(k, app_data, resolve_to_host, raise_on_error): warn_similar = caplog.records[-1] assert warn_similar.levelno == logging.DEBUG assert warn_similar.msg.startswith("no exact match found, chosen most similar") + + +def test_py_info_ignores_distutils_config(monkeypatch, tmp_path): + (tmp_path / "setup.cfg").write_text( + dedent( + """ + [install] + prefix={0}{1}prefix + install_purelib={0}{1}purelib + install_platlib={0}{1}platlib + install_headers={0}{1}headers + install_scripts={0}{1}scripts + install_data={0}{1}data + """.format( + tmp_path, os.sep + ) + ) + ) + monkeypatch.chdir(tmp_path) + py_info = PythonInfo.from_exe(sys.executable) + distutils = py_info.distutils_install + for key, value in distutils.items(): + assert not value.startswith(str(tmp_path)), "{}={}".format(key, value)