Skip to content

Commit

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

Resolves #1663.

Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
  • Loading branch information
gaborbernat committed Mar 10, 2020
1 parent d852194 commit b55072e
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 b55072e

Please sign in to comment.