Skip to content

Commit cb411c2

Browse files
committed
Switch install scheme backend to sysconfig
1 parent b9f8295 commit cb411c2

File tree

6 files changed

+44
-18
lines changed

6 files changed

+44
-18
lines changed

news/10358.removal.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
On Python 3.10 or later, the installation scheme backend has been changed to use
2+
``sysconfig``. This is to anticipate the deprecation of ``distutils`` in Python
3+
3.10, and its scheduled removal in 3.12. For compatibility considerations, pip
4+
installations running on Python 3.9 or lower will continue to use ``distutils``.

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ follow_imports = skip
5757
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache -r aR --color=yes
5858
markers =
5959
network: tests that need network
60+
incompatible_with_sysconfig
6061
incompatible_with_test_venv
6162
incompatible_with_venv
6263
no_auto_tempdir_manager

src/pip/_internal/locations/__init__.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545

4646
_PLATLIBDIR: str = getattr(sys, "platlibdir", "lib")
4747

48+
_USE_SYSCONFIG = sys.version_info >= (3, 10)
49+
4850

4951
def _looks_like_bpo_44860() -> bool:
5052
"""The resolution to bpo-44860 will change this incorrect platlib.
@@ -190,15 +192,18 @@ def get_scheme(
190192
isolated: bool = False,
191193
prefix: Optional[str] = None,
192194
) -> Scheme:
193-
old = _distutils.get_scheme(
195+
new = _sysconfig.get_scheme(
194196
dist_name,
195197
user=user,
196198
home=home,
197199
root=root,
198200
isolated=isolated,
199201
prefix=prefix,
200202
)
201-
new = _sysconfig.get_scheme(
203+
if _USE_SYSCONFIG:
204+
return new
205+
206+
old = _distutils.get_scheme(
202207
dist_name,
203208
user=user,
204209
home=home,
@@ -333,8 +338,11 @@ def get_scheme(
333338

334339

335340
def get_bin_prefix() -> str:
336-
old = _distutils.get_bin_prefix()
337341
new = _sysconfig.get_bin_prefix()
342+
if _USE_SYSCONFIG:
343+
return new
344+
345+
old = _distutils.get_bin_prefix()
338346
if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="bin_prefix"):
339347
_log_context()
340348
return old
@@ -363,8 +371,11 @@ def _looks_like_deb_system_dist_packages(value: str) -> bool:
363371

364372
def get_purelib() -> str:
365373
"""Return the default pure-Python lib location."""
366-
old = _distutils.get_purelib()
367374
new = _sysconfig.get_purelib()
375+
if _USE_SYSCONFIG:
376+
return new
377+
378+
old = _distutils.get_purelib()
368379
if _looks_like_deb_system_dist_packages(old):
369380
return old
370381
if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="purelib"):
@@ -374,19 +385,32 @@ def get_purelib() -> str:
374385

375386
def get_platlib() -> str:
376387
"""Return the default platform-shared lib location."""
377-
old = _distutils.get_platlib()
378388
new = _sysconfig.get_platlib()
389+
if _USE_SYSCONFIG:
390+
return new
391+
392+
old = _distutils.get_platlib()
379393
if _looks_like_deb_system_dist_packages(old):
380394
return old
381395
if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="platlib"):
382396
_log_context()
383397
return old
384398

385399

400+
def _deduplicated(v1: str, v2: str) -> List[str]:
401+
"""Deduplicate values from a list."""
402+
if v1 == v2:
403+
return [v1]
404+
return [v1, v2]
405+
406+
386407
def get_prefixed_libs(prefix: str) -> List[str]:
387408
"""Return the lib locations under ``prefix``."""
388-
old_pure, old_plat = _distutils.get_prefixed_libs(prefix)
389409
new_pure, new_plat = _sysconfig.get_prefixed_libs(prefix)
410+
if _USE_SYSCONFIG:
411+
return _deduplicated(new_pure, new_plat)
412+
413+
old_pure, old_plat = _distutils.get_prefixed_libs(prefix)
390414

391415
warned = [
392416
_warn_if_mismatch(
@@ -403,6 +427,4 @@ def get_prefixed_libs(prefix: str) -> List[str]:
403427
if any(warned):
404428
_log_context(prefix=prefix)
405429

406-
if old_pure == old_plat:
407-
return [old_pure]
408-
return [old_pure, old_plat]
430+
return _deduplicated(old_pure, old_plat)

src/pip/_internal/operations/install/wheel.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -641,14 +641,7 @@ def pyc_output_path(path: str) -> str:
641641
with warnings.catch_warnings():
642642
warnings.filterwarnings('ignore')
643643
for path in pyc_source_file_paths():
644-
# Python 2's `compileall.compile_file` requires a str in
645-
# error cases, so we must convert to the native type.
646-
path_arg = ensure_str(
647-
path, encoding=sys.getfilesystemencoding()
648-
)
649-
success = compileall.compile_file(
650-
path_arg, force=True, quiet=True
651-
)
644+
success = compileall.compile_file(path, force=True, quiet=True)
652645
if success:
653646
pyc_path = pyc_output_path(path)
654647
assert os.path.exists(pyc_path)

tests/conftest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from setuptools.wheel import Wheel
1616

1717
from pip._internal.cli.main import main as pip_entry_point
18+
from pip._internal.locations import _USE_SYSCONFIG
1819
from pip._internal.utils.temp_dir import global_tempdir_manager
1920
from tests.lib import DATA_DIR, SRC_DIR, PipTestEnvironment, TestData
2021
from tests.lib.certs import make_tls_cert, serialize_cert, serialize_key
@@ -77,6 +78,9 @@ def pytest_collection_modifyitems(config, items):
7778
):
7879
item.add_marker(pytest.mark.skip("Incompatible with venv"))
7980

81+
if item.get_closest_marker("incompatible_with_sysconfig") and _USE_SYSCONFIG:
82+
item.add_marker(pytest.mark.skip("Incompatible with sysconfig"))
83+
8084
module_path = os.path.relpath(
8185
item.module.__file__,
8286
os.path.commonprefix([__file__, item.module.__file__]),

tests/unit/test_locations.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def test_root_modifies_appropriately(self, monkeypatch):
9696
expected = os.path.join(root, path[1:])
9797
assert os.path.abspath(root_scheme[key]) == expected
9898

99+
@pytest.mark.incompatible_with_sysconfig
99100
@pytest.mark.incompatible_with_venv
100101
def test_distutils_config_file_read(self, tmpdir, monkeypatch):
101102
# This deals with nt/posix path differences
@@ -115,10 +116,11 @@ def test_distutils_config_file_read(self, tmpdir, monkeypatch):
115116
scheme = _get_scheme_dict('example')
116117
assert scheme['scripts'] == install_scripts
117118

119+
@pytest.mark.incompatible_with_sysconfig
118120
@pytest.mark.incompatible_with_venv
119121
# when we request install-lib, we should install everything (.py &
120122
# .so) into that path; i.e. ensure platlib & purelib are set to
121-
# this path
123+
# this path. sysconfig does not support this.
122124
def test_install_lib_takes_precedence(self, tmpdir, monkeypatch):
123125
# This deals with nt/posix path differences
124126
install_lib = os.path.normcase(os.path.abspath(

0 commit comments

Comments
 (0)