Skip to content

Commit

Permalink
Fix py info might be misslead by distutils config
Browse files Browse the repository at this point in the history
Ignore configuration file parsing when getting distutils data.

Resolves pypa#1663.

Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
  • Loading branch information
gaborbernat committed Mar 10, 2020
1 parent 53f8aba commit 8cde327
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 14 deletions.
2 changes: 2 additions & 0 deletions docs/changelog/1663.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix acquiring python information might be altered by distutils configuration files generating incorrect layout virtual
environments - by :user:`gaborbernat`.
2 changes: 1 addition & 1 deletion docs/changelog/1702.bugfix.rst
Original file line number Diff line number Diff line change
@@ -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`.
9 changes: 4 additions & 5 deletions src/virtualenv/create/via_global_ref/_virtualenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions src/virtualenv/discovery/py_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,9 @@ 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.prefix = os.sep # paths generated are relative to prefix that contains the path sep, this makes it relative
i.finalize_options()
result = {key: (getattr(i, "install_{}".format(key))[1:]).lstrip(os.sep) for key in SCHEME_KEYS}
return result
Expand Down
16 changes: 11 additions & 5 deletions tests/unit/create/test_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/discovery/py_info/test_py_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import itertools
import json
import logging
import os
import sys
from collections import namedtuple
from textwrap import dedent

import pytest

Expand Down Expand Up @@ -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)

0 comments on commit 8cde327

Please sign in to comment.