Skip to content

Commit 7af704e

Browse files
authored
Merge pull request #7310 from chrahunt/refactor/scheme
Add Scheme model and use for wheel installation
2 parents e9cd20c + 6fa64a6 commit 7af704e

File tree

5 files changed

+101
-31
lines changed

5 files changed

+101
-31
lines changed

src/pip/_internal/locations.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from distutils.command.install import SCHEME_KEYS # type: ignore
1717
from distutils.command.install import install as distutils_install_command
1818

19+
from pip._internal.models.scheme import Scheme
1920
from pip._internal.utils import appdirs
2021
from pip._internal.utils.compat import WINDOWS
2122
from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast
@@ -153,3 +154,41 @@ def distutils_scheme(
153154
)
154155

155156
return scheme
157+
158+
159+
def get_scheme(
160+
dist_name, # type: str
161+
user=False, # type: bool
162+
home=None, # type: Optional[str]
163+
root=None, # type: Optional[str]
164+
isolated=False, # type: bool
165+
prefix=None, # type: Optional[str]
166+
):
167+
# type: (...) -> Scheme
168+
"""
169+
Get the "scheme" corresponding to the input parameters. The distutils
170+
documentation provides the context for the available schemes:
171+
https://docs.python.org/3/install/index.html#alternate-installation
172+
173+
:param dist_name: the name of the package to retrieve the scheme for, used
174+
in the headers scheme path
175+
:param user: indicates to use the "user" scheme
176+
:param home: indicates to use the "home" scheme and provides the base
177+
directory for the same
178+
:param root: root under which other directories are re-based
179+
:param isolated: equivalent to --no-user-cfg, i.e. do not consider
180+
~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for
181+
scheme paths
182+
:param prefix: indicates to use the "prefix" scheme and provides the
183+
base directory for the same
184+
"""
185+
scheme = distutils_scheme(
186+
dist_name, user, home, root, isolated, prefix
187+
)
188+
return Scheme(
189+
platlib=scheme["platlib"],
190+
purelib=scheme["purelib"],
191+
headers=scheme["headers"],
192+
scripts=scheme["scripts"],
193+
data=scheme["data"],
194+
)

src/pip/_internal/models/scheme.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
For types associated with installation schemes.
3+
4+
For a general overview of available schemes and their context, see
5+
https://docs.python.org/3/install/index.html#alternate-installation.
6+
"""
7+
8+
9+
class Scheme(object):
10+
"""A Scheme holds paths which are used as the base directories for
11+
artifacts associated with a Python package.
12+
"""
13+
def __init__(
14+
self,
15+
platlib, # type: str
16+
purelib, # type: str
17+
headers, # type: str
18+
scripts, # type: str
19+
data, # type: str
20+
):
21+
self.platlib = platlib
22+
self.purelib = purelib
23+
self.headers = headers
24+
self.scripts = scripts
25+
self.data = data

src/pip/_internal/req/req_install.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import os
99
import shutil
1010
import sys
11-
import sysconfig
1211
import zipfile
1312
from distutils.util import change_root
1413

@@ -22,7 +21,7 @@
2221
from pip._internal import pep425tags, wheel
2322
from pip._internal.build_env import NoOpBuildEnvironment
2423
from pip._internal.exceptions import InstallationError
25-
from pip._internal.locations import distutils_scheme
24+
from pip._internal.locations import get_scheme
2625
from pip._internal.models.link import Link
2726
from pip._internal.operations.build.metadata import generate_metadata
2827
from pip._internal.operations.build.metadata_legacy import \
@@ -65,11 +64,12 @@
6564

6665
if MYPY_CHECK_RUNNING:
6766
from typing import (
68-
Any, Dict, Iterable, List, Mapping, Optional, Sequence, Union,
67+
Any, Dict, Iterable, List, Optional, Sequence, Union,
6968
)
7069
from pip._internal.build_env import BuildEnvironment
7170
from pip._internal.cache import WheelCache
7271
from pip._internal.index.package_finder import PackageFinder
72+
from pip._internal.models.scheme import Scheme
7373
from pip._vendor.pkg_resources import Distribution
7474
from pip._vendor.packaging.specifiers import SpecifierSet
7575
from pip._vendor.packaging.markers import Marker
@@ -540,7 +540,7 @@ def is_wheel(self):
540540
def move_wheel_files(
541541
self,
542542
wheeldir, # type: str
543-
scheme, # type: Mapping[str, str]
543+
scheme, # type: Scheme
544544
warn_script_location=True, # type: bool
545545
pycompile=True # type: bool
546546
):
@@ -852,6 +852,15 @@ def install(
852852
pycompile=True # type: bool
853853
):
854854
# type: (...) -> None
855+
scheme = get_scheme(
856+
self.name,
857+
user=use_user_site,
858+
home=home,
859+
root=root,
860+
isolated=self.isolated,
861+
prefix=prefix,
862+
)
863+
855864
global_options = global_options if global_options is not None else []
856865
if self.editable:
857866
self.install_editable(
@@ -862,14 +871,11 @@ def install(
862871
use_user_site=use_user_site,
863872
)
864873
return
874+
865875
if self.is_wheel:
866876
version = wheel.wheel_version(self.source_dir)
867877
wheel.check_compatibility(version, self.name)
868878

869-
scheme = distutils_scheme(
870-
self.name, user=use_user_site, home=home, root=root,
871-
isolated=self.isolated, prefix=prefix,
872-
)
873879
self.move_wheel_files(
874880
self.source_dir,
875881
scheme=scheme,
@@ -889,12 +895,7 @@ def install(
889895
install_options = list(install_options) + \
890896
self.options.get('install_options', [])
891897

892-
header_dir = None # type: Optional[str]
893-
if running_under_virtualenv():
894-
py_ver_str = 'python' + sysconfig.get_python_version()
895-
header_dir = os.path.join(
896-
sys.prefix, 'include', 'site', py_ver_str, self.name
897-
)
898+
header_dir = scheme.headers
898899

899900
with TempDirectory(kind="record") as temp_dir:
900901
record_filename = os.path.join(temp_dir.path, 'install-record.txt')

src/pip/_internal/wheel.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636

3737
if MYPY_CHECK_RUNNING:
3838
from typing import (
39-
Dict, List, Optional, Sequence, Mapping, Tuple, IO, Text, Any,
39+
Dict, List, Optional, Sequence, Tuple, IO, Text, Any,
4040
Iterable, Callable, Set,
4141
)
42+
43+
from pip._internal.models.scheme import Scheme
4244
from pip._internal.pep425tags import Pep425Tag
4345

4446
InstalledCSVRow = Tuple[str, ...]
@@ -289,7 +291,7 @@ def make(self, specification, options=None):
289291
def install_unpacked_wheel(
290292
name, # type: str
291293
wheeldir, # type: str
292-
scheme, # type: Mapping[str, str]
294+
scheme, # type: Scheme
293295
req_description, # type: str
294296
pycompile=True, # type: bool
295297
warn_script_location=True # type: bool
@@ -311,9 +313,9 @@ def install_unpacked_wheel(
311313
# installation.
312314

313315
if root_is_purelib(name, wheeldir):
314-
lib_dir = scheme['purelib']
316+
lib_dir = scheme.purelib
315317
else:
316-
lib_dir = scheme['platlib']
318+
lib_dir = scheme.platlib
317319

318320
info_dir = [] # type: List[str]
319321
data_dirs = []
@@ -458,10 +460,10 @@ def is_entrypoint_wrapper(name):
458460
fixer = fix_script
459461
filter = is_entrypoint_wrapper
460462
source = os.path.join(wheeldir, datadir, subdir)
461-
dest = scheme[subdir]
463+
dest = getattr(scheme, subdir)
462464
clobber(source, dest, False, fixer=fixer, filter=filter)
463465

464-
maker = PipScriptMaker(None, scheme['scripts'])
466+
maker = PipScriptMaker(None, scheme.scripts)
465467

466468
# Ensure old scripts are overwritten.
467469
# See https://github.com/pypa/pip/issues/1800

tests/unit/test_wheel.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
from pip._internal import pep425tags, wheel
1212
from pip._internal.commands.wheel import WheelCommand
1313
from pip._internal.exceptions import InvalidWheelFilename, UnsupportedWheel
14-
from pip._internal.locations import distutils_scheme
14+
from pip._internal.locations import get_scheme
1515
from pip._internal.models.link import Link
16+
from pip._internal.models.scheme import Scheme
1617
from pip._internal.req.req_install import InstallRequirement
1718
from pip._internal.utils.compat import WINDOWS
1819
from pip._internal.utils.misc import hash_file
@@ -482,29 +483,31 @@ def prep(self, data, tmpdir):
482483
self.src = os.path.join(tmpdir, 'src')
483484
self.dest = os.path.join(tmpdir, 'dest')
484485
unpack_file(self.wheelpath, self.src)
485-
self.scheme = {
486-
'scripts': os.path.join(self.dest, 'bin'),
487-
'purelib': os.path.join(self.dest, 'lib'),
488-
'data': os.path.join(self.dest, 'data'),
489-
}
486+
self.scheme = Scheme(
487+
purelib=os.path.join(self.dest, 'lib'),
488+
platlib=os.path.join(self.dest, 'lib'),
489+
headers=os.path.join(self.dest, 'headers'),
490+
scripts=os.path.join(self.dest, 'bin'),
491+
data=os.path.join(self.dest, 'data'),
492+
)
490493
self.src_dist_info = os.path.join(
491494
self.src, 'sample-1.2.0.dist-info')
492495
self.dest_dist_info = os.path.join(
493-
self.scheme['purelib'], 'sample-1.2.0.dist-info')
496+
self.scheme.purelib, 'sample-1.2.0.dist-info')
494497

495498
def assert_installed(self):
496499
# lib
497500
assert os.path.isdir(
498-
os.path.join(self.scheme['purelib'], 'sample'))
501+
os.path.join(self.scheme.purelib, 'sample'))
499502
# dist-info
500503
metadata = os.path.join(self.dest_dist_info, 'METADATA')
501504
assert os.path.isfile(metadata)
502505
# data files
503-
data_file = os.path.join(self.scheme['data'], 'my_data', 'data_file')
506+
data_file = os.path.join(self.scheme.data, 'my_data', 'data_file')
504507
assert os.path.isfile(data_file)
505508
# package data
506509
pkg_data = os.path.join(
507-
self.scheme['purelib'], 'sample', 'package_data.dat')
510+
self.scheme.purelib, 'sample', 'package_data.dat')
508511
assert os.path.isfile(pkg_data)
509512

510513
def test_std_install(self, data, tmpdir):
@@ -520,7 +523,7 @@ def test_std_install(self, data, tmpdir):
520523
def test_install_prefix(self, data, tmpdir):
521524
prefix = os.path.join(os.path.sep, 'some', 'path')
522525
self.prep(data, tmpdir)
523-
scheme = distutils_scheme(
526+
scheme = get_scheme(
524527
self.name,
525528
user=False,
526529
home=None,

0 commit comments

Comments
 (0)