Skip to content

Commit 03f1e5b

Browse files
committed
Allow to decide whether to use distutils or sysconfig with sysconfig._PIP_USE_SYSCONFIG
Fixes #10647
1 parent 4cdb516 commit 03f1e5b

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

news/10647.feature.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Allow Python distributors to opt-out from or opt-in to the ``sysconfig``
2+
installation scheme backend. By default, the installation scheme backend is
3+
``sysconfig`` on Python 3.10 or later, but by setting the ``sysconfig._PIP_USE_SYSCONFIG``
4+
the distributors can override this default: The boolean value of this private ``sysconfig``
5+
attribute will take precedence over the default if set.
6+
This can be used for compatibility considerations as well as for opting in for more leading-edge
7+
technology if so desired.
8+
Distributors who set ``sysconfig._PIP_USE_SYSCONFIG = False`` are strongly encouraged to ensure ``distutils`` is present,
9+
e.g. it is not recommended to set this when ``distutils`` was removed from the standard library, as it will result in failures.

src/pip/_internal/locations/__init__.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,20 @@
4545

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

48-
_USE_SYSCONFIG = sys.version_info >= (3, 10)
48+
49+
def _should_use_sysconfig() -> bool:
50+
"""
51+
This function determines the value of _USE_SYSCONFIG.
52+
By default, pip uses sysconfig on Python 3.10+.
53+
But Python distributors can override this decision by setting:
54+
sysconfig._PIP_USE_SYSCONFIG = True / False
55+
Rationale in https://github.com/pypa/pip/issues/10647
56+
"""
57+
return bool(getattr(sysconfig, "_PIP_USE_SYSCONFIG", sys.version_info >= (3, 10)))
58+
59+
60+
# This is a function for testability, but should be constant during any one run.
61+
_USE_SYSCONFIG = _should_use_sysconfig()
4962

5063

5164
def _looks_like_bpo_44860() -> bool:

tests/unit/test_locations.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
import os
77
import shutil
88
import sys
9+
import sysconfig
910
import tempfile
1011
from typing import Any, Dict
1112
from unittest.mock import Mock
1213

1314
import pytest
1415

15-
from pip._internal.locations import SCHEME_KEYS, get_scheme
16+
from pip._internal.locations import SCHEME_KEYS, _should_use_sysconfig, get_scheme
1617
from tests.lib.path import Path
1718

1819
if sys.platform == "win32":
@@ -82,6 +83,24 @@ def get_mock_getpwuid(self, uid: int) -> pwd.struct_passwd:
8283
result.pw_name = self.username
8384
return result
8485

86+
def test_default_should_use_sysconfig(
87+
self, monkeypatch: pytest.MonkeyPatch
88+
) -> None:
89+
monkeypatch.delattr(sysconfig, "_PIP_USE_SYSCONFIG", raising=False)
90+
if sys.version_info[:2] >= (3, 10):
91+
assert _should_use_sysconfig() is True
92+
else:
93+
assert _should_use_sysconfig() is False
94+
95+
@pytest.mark.parametrize("vendor_value", [True, False, None, "", 0, 1])
96+
def test_vendor_overriden_should_use_sysconfig(
97+
self, monkeypatch: pytest.MonkeyPatch, vendor_value: Any
98+
) -> None:
99+
monkeypatch.setattr(
100+
sysconfig, "_PIP_USE_SYSCONFIG", vendor_value, raising=False
101+
)
102+
assert _should_use_sysconfig() is bool(vendor_value)
103+
85104

86105
class TestDistutilsScheme:
87106
def test_root_modifies_appropriately(self) -> None:

0 commit comments

Comments
 (0)