Skip to content

Commit 3089e87

Browse files
authored
Merge pull request #7262 from sbidoul/refactor-should_use_ephem_cache-sbi
Refactor should_use_ephemeral_cache
2 parents be13cf9 + e638e24 commit 3089e87

File tree

2 files changed

+148
-26
lines changed

2 files changed

+148
-26
lines changed

src/pip/_internal/wheel.py

+64-26
Original file line numberDiff line numberDiff line change
@@ -772,61 +772,99 @@ def _contains_egg_info(
772772
return bool(_egg_info_re.search(s))
773773

774774

775-
def should_use_ephemeral_cache(
775+
def should_build(
776776
req, # type: InstallRequirement
777-
should_unpack, # type: bool
778-
cache_available, # type: bool
777+
need_wheel, # type: bool
779778
check_binary_allowed, # type: BinaryAllowedPredicate
780779
):
781780
# type: (...) -> Optional[bool]
782-
"""Return whether to build an InstallRequirement object using the
783-
ephemeral cache.
784-
785-
:param cache_available: whether a cache directory is available for the
786-
should_unpack=True case.
787-
788-
:return: True or False to build the requirement with ephem_cache=True
789-
or False, respectively; or None not to build the requirement.
790-
"""
781+
"""Return whether an InstallRequirement should be built into a wheel."""
791782
if req.constraint:
792783
# never build requirements that are merely constraints
793-
return None
784+
return False
794785
if req.is_wheel:
795-
if not should_unpack:
786+
if need_wheel:
796787
logger.info(
797788
'Skipping %s, due to already being wheel.', req.name,
798789
)
799-
return None
800-
if not should_unpack:
801-
# i.e. pip wheel, not pip install;
802-
# return False, knowing that the caller will never cache
803-
# in this case anyway, so this return merely means "build it".
804-
# TODO improve this behavior
805790
return False
806791

792+
if need_wheel:
793+
# i.e. pip wheel, not pip install
794+
return True
795+
807796
if req.editable or not req.source_dir:
808-
return None
797+
return False
809798

810799
if not check_binary_allowed(req):
811800
logger.info(
812801
"Skipping wheel build for %s, due to binaries "
813802
"being disabled for it.", req.name,
814803
)
815-
return None
804+
return False
805+
806+
return True
807+
808+
809+
def should_cache(
810+
req, # type: InstallRequirement
811+
check_binary_allowed, # type: BinaryAllowedPredicate
812+
):
813+
# type: (...) -> Optional[bool]
814+
"""
815+
Return whether a built InstallRequirement can be stored in the persistent
816+
wheel cache, assuming the wheel cache is available, and should_build()
817+
has determined a wheel needs to be built.
818+
"""
819+
if not should_build(
820+
req, need_wheel=False, check_binary_allowed=check_binary_allowed
821+
):
822+
# never cache if pip install (need_wheel=False) would not have built
823+
# (editable mode, etc)
824+
return False
816825

817826
if req.link and req.link.is_vcs:
818827
# VCS checkout. Build wheel just for this run.
819-
return True
828+
return False
820829

821830
link = req.link
822831
base, ext = link.splitext()
823-
if cache_available and _contains_egg_info(base):
824-
return False
832+
if _contains_egg_info(base):
833+
return True
825834

826835
# Otherwise, build the wheel just for this run using the ephemeral
827836
# cache since we are either in the case of e.g. a local directory, or
828837
# no cache directory is available to use.
829-
return True
838+
return False
839+
840+
841+
def should_use_ephemeral_cache(
842+
req, # type: InstallRequirement
843+
should_unpack, # type: bool
844+
cache_available, # type: bool
845+
check_binary_allowed, # type: BinaryAllowedPredicate
846+
):
847+
# type: (...) -> Optional[bool]
848+
"""Return whether to build an InstallRequirement object using the
849+
ephemeral cache.
850+
851+
:param cache_available: whether a cache directory is available for the
852+
should_unpack=True case.
853+
854+
:return: True or False to build the requirement with ephem_cache=True
855+
or False, respectively; or None not to build the requirement.
856+
"""
857+
if not should_build(req, not should_unpack, check_binary_allowed):
858+
return None
859+
if not should_unpack:
860+
# i.e. pip wheel, not pip install;
861+
# return False, knowing that the caller will never cache
862+
# in this case anyway, so this return merely means "build it".
863+
# TODO improve this behavior
864+
return False
865+
if not cache_available:
866+
return True
867+
return not should_cache(req, check_binary_allowed)
830868

831869

832870
def format_command_result(

tests/unit/test_wheel.py

+84
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@
2323
from tests.lib import DATA_DIR, assert_paths_equal
2424

2525

26+
class ReqMock:
27+
28+
def __init__(
29+
self,
30+
name="pendulum",
31+
is_wheel=False,
32+
editable=False,
33+
link=None,
34+
constraint=False,
35+
source_dir="/tmp/pip-install-123/pendulum",
36+
):
37+
self.name = name
38+
self.is_wheel = is_wheel
39+
self.editable = editable
40+
self.link = link
41+
self.constraint = constraint
42+
self.source_dir = source_dir
43+
44+
2645
@pytest.mark.parametrize(
2746
"s, expected",
2847
[
@@ -82,6 +101,71 @@ def test_format_tag(file_tag, expected):
82101
assert actual == expected
83102

84103

104+
@pytest.mark.parametrize(
105+
"req, need_wheel, disallow_binaries, expected",
106+
[
107+
# pip wheel (need_wheel=True)
108+
(ReqMock(), True, False, True),
109+
(ReqMock(), True, True, True),
110+
(ReqMock(constraint=True), True, False, False),
111+
(ReqMock(is_wheel=True), True, False, False),
112+
(ReqMock(editable=True), True, False, True),
113+
(ReqMock(source_dir=None), True, False, True),
114+
(ReqMock(link=Link("git+https://g.c/org/repo")), True, False, True),
115+
(ReqMock(link=Link("git+https://g.c/org/repo")), True, True, True),
116+
# pip install (need_wheel=False)
117+
(ReqMock(), False, False, True),
118+
(ReqMock(), False, True, False),
119+
(ReqMock(constraint=True), False, False, False),
120+
(ReqMock(is_wheel=True), False, False, False),
121+
(ReqMock(editable=True), False, False, False),
122+
(ReqMock(source_dir=None), False, False, False),
123+
# By default (i.e. when binaries are allowed), VCS requirements
124+
# should be built in install mode.
125+
(ReqMock(link=Link("git+https://g.c/org/repo")), False, False, True),
126+
# Disallowing binaries, however, should cause them not to be built.
127+
(ReqMock(link=Link("git+https://g.c/org/repo")), False, True, False),
128+
],
129+
)
130+
def test_should_build(req, need_wheel, disallow_binaries, expected):
131+
should_build = wheel.should_build(
132+
req,
133+
need_wheel,
134+
check_binary_allowed=lambda req: not disallow_binaries,
135+
)
136+
assert should_build is expected
137+
138+
139+
@pytest.mark.parametrize(
140+
"req, disallow_binaries, expected",
141+
[
142+
(ReqMock(editable=True), False, False),
143+
(ReqMock(source_dir=None), False, False),
144+
(ReqMock(link=Link("git+https://g.c/org/repo")), False, False),
145+
(ReqMock(link=Link("https://g.c/dist.tgz")), False, False),
146+
(ReqMock(link=Link("https://g.c/dist-2.0.4.tgz")), False, True),
147+
(ReqMock(editable=True), True, False),
148+
(ReqMock(source_dir=None), True, False),
149+
(ReqMock(link=Link("git+https://g.c/org/repo")), True, False),
150+
(ReqMock(link=Link("https://g.c/dist.tgz")), True, False),
151+
(ReqMock(link=Link("https://g.c/dist-2.0.4.tgz")), True, False),
152+
],
153+
)
154+
def test_should_cache(
155+
req, disallow_binaries, expected
156+
):
157+
def check_binary_allowed(req):
158+
return not disallow_binaries
159+
160+
should_cache = wheel.should_cache(req, check_binary_allowed)
161+
if not wheel.should_build(
162+
req, need_wheel=False, check_binary_allowed=check_binary_allowed
163+
):
164+
# never cache if pip install (need_wheel=False) would not have built)
165+
assert not should_cache
166+
assert should_cache is expected
167+
168+
85169
@pytest.mark.parametrize(
86170
"base_name, should_unpack, cache_available, expected",
87171
[

0 commit comments

Comments
 (0)