Support without distutils (#2146)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
0705f2050f
commit
c52fe3ea09
11 changed files with 36 additions and 13 deletions
1
.github/workflows/check.yml
vendored
1
.github/workflows/check.yml
vendored
|
|
@ -24,6 +24,7 @@ jobs:
|
|||
- windows-latest
|
||||
- macos-latest
|
||||
py:
|
||||
- 3.10.0-beta.4
|
||||
- 3.9
|
||||
- 3.8
|
||||
- 3.7
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
2
docs/changelog/1910.feature.rst
Normal file
2
docs/changelog/1910.feature.rst
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Support Python interpreters without ``distutils`` (fallback to ``syconfig`` in these cases) - by :user:`gaborbernat`.
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -30,15 +30,15 @@ class Describe(object):
|
|||
|
||||
@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):
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class CPython2(CPython, Python2):
|
|||
@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):
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class PyPy2(PyPy, Python2):
|
|||
|
||||
@property
|
||||
def include(self):
|
||||
return self.dest / self.interpreter.distutils_install["headers"]
|
||||
return self.dest / self.interpreter.install_path("headers")
|
||||
|
||||
@classmethod
|
||||
def modules(cls):
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ import platform
|
|||
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"])
|
||||
|
|
@ -118,10 +117,28 @@ class PythonInfo(object):
|
|||
# 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
|
||||
|
|
@ -177,7 +194,7 @@ class PythonInfo(object):
|
|||
)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ from virtualenv.activation import PowerShellActivator
|
|||
|
||||
|
||||
@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"
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
target.mkdir(parents=True)
|
||||
executable = target / exe_name
|
||||
os.symlink(sys.executable, ensure_text(str(executable)))
|
||||
|
|
|
|||
Loading…
Reference in a new issue