diff --git a/src/fromager/bootstrapper.py b/src/fromager/bootstrapper.py index 1dff6de0..e03d6091 100644 --- a/src/fromager/bootstrapper.py +++ b/src/fromager/bootstrapper.py @@ -1100,13 +1100,17 @@ def _download_wheel_from_cache( f"checking if wheel was already uploaded to {self.cache_wheel_server_url}" ) try: - wheel_url, _ = resolver.resolve( - ctx=self.ctx, - req=Requirement(f"{req.name}=={resolved_version}"), + # Use PyPIProvider directly for cache lookups, bypassing resolver + # hooks. Cache servers are always simple PyPI index servers. + pinned_req = Requirement(f"{req.name}=={resolved_version}") + provider = resolver.PyPIProvider( sdist_server_url=self.cache_wheel_server_url, include_sdists=False, include_wheels=True, + constraints=self.ctx.constraints, ) + results = resolver.find_all_matching_from_provider(provider, pinned_req) + wheel_url, _ = results[0] wheelfile_name = pathlib.Path(urlparse(wheel_url).path) pbi = self.ctx.package_build_info(req) expected_build_tag = pbi.build_tag(resolved_version) diff --git a/tests/test_bootstrapper.py b/tests/test_bootstrapper.py index 726125c3..62886dca 100644 --- a/tests/test_bootstrapper.py +++ b/tests/test_bootstrapper.py @@ -370,3 +370,41 @@ def mock_bootstrap_impl( success_key_10 = f"{canonicalize_name('testpkg')}==1.0" assert success_key_20 in tmp_context.dependency_graph.nodes assert success_key_10 in tmp_context.dependency_graph.nodes + + +@patch("fromager.resolver.find_all_matching_from_provider") +@patch("fromager.resolver.PyPIProvider") +def test_download_wheel_from_cache_bypasses_hooks( + mock_pypi_provider: Mock, + mock_find_all: Mock, + tmp_context: WorkContext, +) -> None: + """Verify _download_wheel_from_cache uses PyPIProvider directly, not hooks.""" + bt = bootstrapper.Bootstrapper(tmp_context) + bt.cache_wheel_server_url = "https://cache.example.com/simple/" + + mock_provider = Mock() + mock_pypi_provider.return_value = mock_provider + # Raise so the except clause returns (None, None) before hitting + # network calls later in the function. + mock_find_all.side_effect = RuntimeError("no match") + + with patch("fromager.overrides.find_and_invoke") as mock_override: + result = bt._download_wheel_from_cache( + req=Requirement("test-pkg"), + resolved_version=Version("1.0.0"), + ) + + assert result == (None, None) + + # Hook system must NOT be called for cache lookups + mock_override.assert_not_called() + + # PyPIProvider must be instantiated directly + mock_pypi_provider.assert_called_once_with( + sdist_server_url="https://cache.example.com/simple/", + include_sdists=False, + include_wheels=True, + constraints=tmp_context.constraints, + ) + mock_find_all.assert_called_once_with(mock_provider, Requirement("test-pkg==1.0.0"))