Skip to content

Commit 82e1250

Browse files
authored
Merge pull request #1333 from ryanpetrello/warn-missing-sdist
fix(resolver): warn when a version is skipped due to missing sdist
2 parents 0883ce2 + a70ff9c commit 82e1250

2 files changed

Lines changed: 101 additions & 1 deletion

File tree

src/fromager/resolver.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,25 @@ def find_matches(
10191019
requirements: RequirementsMap,
10201020
incompatibilities: CandidatesMap,
10211021
) -> Candidates:
1022-
return super().find_matches(identifier, requirements, incompatibilities)
1022+
candidates = super().find_matches(identifier, requirements, incompatibilities)
1023+
if not self.include_wheels:
1024+
accepted_versions = {c.version for c in candidates}
1025+
all_candidates = self._find_cached_candidates(identifier)
1026+
sdist_versions = {c.version for c in all_candidates if c.is_sdist}
1027+
reqs = requirements.get(identifier, [])
1028+
for c in all_candidates:
1029+
if (
1030+
not c.is_sdist
1031+
and c.version not in accepted_versions
1032+
and c.version not in sdist_versions
1033+
and all(c.version in r.specifier for r in reqs)
1034+
):
1035+
logger.warning(
1036+
"%s==%s: no sdist available, only a wheel (skipped)",
1037+
c.name,
1038+
c.version,
1039+
)
1040+
return candidates
10231041

10241042

10251043
class MatchFunction(typing.Protocol):

tests/test_resolver.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,33 @@
3939
<!--SERIAL 22812307-->
4040
"""
4141

42+
_wheel_only_simple_response = """
43+
<!DOCTYPE html>
44+
<html>
45+
<head>
46+
<meta name="pypi:repository-version" content="1.1">
47+
<title>Links for testpkg</title>
48+
</head>
49+
<body>
50+
<h1>Links for testpkg</h1>
51+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.0.tar.gz">testpkg-1.0.0.tar.gz</a>
52+
<br/>
53+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.0-py3-none-any.whl">testpkg-1.0.0-py3-none-any.whl</a>
54+
<br/>
55+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.1.tar.gz">testpkg-1.0.1.tar.gz</a>
56+
<br/>
57+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.1-py3-none-any.whl">testpkg-1.0.1-py3-none-any.whl</a>
58+
<br/>
59+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.2-py3-none-any.whl">testpkg-1.0.2-py3-none-any.whl</a>
60+
<br/>
61+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.3.tar.gz">testpkg-1.0.3.tar.gz</a>
62+
<br/>
63+
<a href="https://files.pythonhosted.org/packages/testpkg-1.0.3-py3-none-any.whl">testpkg-1.0.3-py3-none-any.whl</a>
64+
</body>
65+
</html>
66+
"""
67+
68+
4269
_numpy_simple_response = """
4370
<!DOCTYPE html>
4471
<html>
@@ -1278,3 +1305,58 @@ def test_cli_package_resolver(
12781305
assert "- PyPI versions: 1.2.2, 1.3.1+local, 1.3.2, 2.0.0a1" in result.stdout
12791306
assert "- only wheels on PyPI: 1.3.1+local, 2.0.0a1" in result.stdout
12801307
assert "- missing from Fromager: 1.3.1+local, 2.0.0a1" in result.stdout
1308+
1309+
1310+
def test_warn_wheel_only_version(caplog: pytest.LogCaptureFixture) -> None:
1311+
"""Warn when a version matching the specifier has no sdist."""
1312+
with requests_mock.Mocker() as r:
1313+
r.get(
1314+
"https://pypi.org/simple/testpkg/",
1315+
text=_wheel_only_simple_response,
1316+
)
1317+
1318+
provider = resolver.PyPIProvider(include_wheels=False)
1319+
reporter: resolvelib.BaseReporter = resolvelib.BaseReporter()
1320+
rslvr = resolvelib.Resolver(provider, reporter)
1321+
1322+
result = rslvr.resolve([Requirement("testpkg>=1.0.0")])
1323+
candidate = result.mapping["testpkg"]
1324+
assert str(candidate.version) == "1.0.3"
1325+
1326+
assert "testpkg==1.0.2: no sdist available, only a wheel (skipped)" in caplog.text
1327+
1328+
1329+
def test_no_warn_when_sdist_exists(caplog: pytest.LogCaptureFixture) -> None:
1330+
"""No warning for versions that have both sdist and wheel."""
1331+
with requests_mock.Mocker() as r:
1332+
r.get(
1333+
"https://pypi.org/simple/testpkg/",
1334+
text=_wheel_only_simple_response,
1335+
)
1336+
1337+
provider = resolver.PyPIProvider(include_wheels=False)
1338+
reporter: resolvelib.BaseReporter = resolvelib.BaseReporter()
1339+
rslvr = resolvelib.Resolver(provider, reporter)
1340+
1341+
rslvr.resolve([Requirement("testpkg>=1.0.0")])
1342+
1343+
assert "testpkg==1.0.0" not in caplog.text
1344+
assert "testpkg==1.0.1" not in caplog.text
1345+
assert "testpkg==1.0.3" not in caplog.text
1346+
1347+
1348+
def test_no_warn_outside_specifier(caplog: pytest.LogCaptureFixture) -> None:
1349+
"""No warning for wheel-only versions outside the requirement specifier."""
1350+
with requests_mock.Mocker() as r:
1351+
r.get(
1352+
"https://pypi.org/simple/testpkg/",
1353+
text=_wheel_only_simple_response,
1354+
)
1355+
1356+
provider = resolver.PyPIProvider(include_wheels=False)
1357+
reporter: resolvelib.BaseReporter = resolvelib.BaseReporter()
1358+
rslvr = resolvelib.Resolver(provider, reporter)
1359+
1360+
rslvr.resolve([Requirement("testpkg>=1.0.3")])
1361+
1362+
assert "testpkg==1.0.2" not in caplog.text

0 commit comments

Comments
 (0)