Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support without distutils #2146

Merged
merged 4 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
- windows-latest
- macos-latest
py:
- 3.10.0-beta.4
- 3.9
- 3.8
- 3.7
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ repos:
rev: v1.17.0
hooks:
- id: setup-cfg-fmt
args: [--min-py3-version, "3.4"]
args: [--min-py3-version, "3.5", "--max-py-version", "3.10"]
- repo: https://github.com/PyCQA/flake8
rev: "3.9.2"
hooks:
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog/1910.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Support Python interpreters without ``distutils`` (fallback to ``syconfig`` in these cases) - by :user:`gaborbernat`.

1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
Topic :: Software Development :: Libraries
Expand Down
6 changes: 3 additions & 3 deletions src/virtualenv/create/describe.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ def bin_dir(self):

@property
def script_dir(self):
return self.dest / Path(self.interpreter.distutils_install["scripts"])
return self.dest / self.interpreter.install_path("scripts")

@property
def purelib(self):
return self.dest / self.interpreter.distutils_install["purelib"]
return self.dest / self.interpreter.install_path("purelib")

@property
def platlib(self):
return self.dest / self.interpreter.distutils_install["platlib"]
return self.dest / self.interpreter.install_path("platlib")

@property
def libs(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def host_include_marker(cls, interpreter):
@property
def include(self):
# the pattern include the distribution name too at the end, remove that via the parent call
return (self.dest / self.interpreter.distutils_install["headers"]).parent
return (self.dest / self.interpreter.install_path("headers")).parent

@classmethod
def modules(cls):
Expand Down
2 changes: 1 addition & 1 deletion src/virtualenv/create/via_global_ref/builtin/pypy/pypy2.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def host_include_marker(cls, interpreter):

@property
def include(self):
return self.dest / self.interpreter.distutils_install["headers"]
return self.dest / self.interpreter.install_path("headers")

@classmethod
def modules(cls):
Expand Down
25 changes: 21 additions & 4 deletions src/virtualenv/discovery/py_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
import re
import sys
import sysconfig
import warnings
from collections import OrderedDict, namedtuple
from distutils import dist
from distutils.command.install import SCHEME_KEYS
from string import digits

VersionInfo = namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"])
Expand Down Expand Up @@ -118,10 +117,28 @@ def _fast_get_system_executable(self):
# note we must choose the original and not the pure executable as shim scripts might throw us off
return self.original_executable

def install_path(self, key):
result = self.distutils_install.get(key)
if result is None: # use sysconfig if distutils is unavailable
# set prefixes to empty => result is relative from cwd
prefixes = self.prefix, self.exec_prefix, self.base_prefix, self.base_exec_prefix
config_var = {k: "" if v in prefixes else v for k, v in self.sysconfig_vars}
result = self.sysconfig_path(key, config_var=config_var).lstrip(os.sep)
return result

@staticmethod
def _distutils_install():
# follow https://github.com/pypa/pip/blob/main/src/pip/_internal/locations.py#L95
# use distutils primarily because that's what pip does
# https://github.com/pypa/pip/blob/main/src/pip/_internal/locations.py#L95
# note here we don't import Distribution directly to allow setuptools to patch it
with warnings.catch_warnings(): # disable warning for PEP-632
warnings.simplefilter("ignore")
try:
from distutils import dist
from distutils.command.install import SCHEME_KEYS
except ImportError: # if removed or not installed ignore
return {}

d = dist.Distribution({"script_args": "--no-user-cfg"}) # conf files not parsed so they do not hijack paths
if hasattr(sys, "_framework"):
sys._framework = None # disable macOS static paths for framework
Expand Down Expand Up @@ -177,7 +194,7 @@ def system_include(self):
)
if not os.path.exists(path): # some broken packaging don't respect the sysconfig, fallback to distutils path
# the pattern include the distribution name too at the end, remove that via the parent call
fallback = os.path.join(self.prefix, os.path.dirname(self.distutils_install["headers"]))
fallback = os.path.join(self.prefix, os.path.dirname(self.install_path("headers")))
if os.path.exists(fallback):
path = fallback
return path
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/activation/test_powershell.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@


@pytest.mark.slow
def test_powershell(activation_tester_class, activation_tester):
def test_powershell(activation_tester_class, activation_tester, monkeypatch):
monkeypatch.setenv("TERM", "xterm")

class PowerShell(activation_tester_class):
def __init__(self, session):
cmd = "powershell.exe" if sys.platform == "win32" else "pwsh"
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/discovery/py_info/test_py_info_exe_based_of.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_discover_empty_folder(tmp_path, monkeypatch, session_app_data):
CURRENT.discover_exe(session_app_data, prefix=str(tmp_path))


BASE = (CURRENT.distutils_install["scripts"], ".")
BASE = (CURRENT.install_path("scripts"), ".")


@pytest.mark.skipif(not fs_supports_symlink(), reason="symlink is not supported")
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/discovery/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_discovery_via_path(monkeypatch, case, tmp_path, caplog, session_app_dat
elif case == "upper":
name = name.upper()
exe_name = "{}{}{}".format(name, current.version_info.major, ".exe" if sys.platform == "win32" else "")
target = tmp_path / current.distutils_install["scripts"]
target = tmp_path / current.install_path("scripts")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we test both execution flows paths of install_path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

target.mkdir(parents=True)
executable = target / exe_name
os.symlink(sys.executable, ensure_text(str(executable)))
Expand Down