Repository: python-wheel-build/fromager

Issue:
optimize dependency resolution
During bootstrap we write various requirements files as artifacts to examine different types of dependencies for packages. We could use those as a "cache" to avoid having to recompute the values, and save time when rerunning a bootstrap during override development. We already do something similar to avoid rebuilding a wheel if it already exists.

Discussion:

Patch:
diff --git a/docs/customization.md b/docs/customization.md
index c615c74..2af94fc 100644
--- a/docs/customization.md
+++ b/docs/customization.md
@@ -424,16 +424,3 @@ def post_build(
         f"{req.name}: running post build hook for {sdist_filename} and {wheel_filename}"
     )
 ```
-
-## Customizations using settings.yaml  
-
-To use predefined urls to download sources from, instead of overriding the entire `download_source` function, a mapping of package to download source url can be provided directly in settings.yaml:
-
-```yaml
-download_source:
-  torch:
-      url: "https://github.com/pytorch/pytorch/releases/download/v${version}/pytorch-v${version}.tar.gz"
-      rename_to: "torch-${version}.tar.gz"
-```
-
-User can define a predefined url for a package from which all its sources will be downloaded from. Optionally they can rename the downloaded sdist to whatever they want. The only supported template variable is `version` - it is replaced by the version returned by the resolver.
diff --git a/src/fromager/commands/bootstrap.py b/src/fromager/commands/bootstrap.py
index 4ea3f92..734b5e3 100644
--- a/src/fromager/commands/bootstrap.py
+++ b/src/fromager/commands/bootstrap.py
@@ -17,10 +17,8 @@ def _get_requirements_from_args(
     to_build = []
     to_build.extend(("toplevel", t) for t in toplevel)
     for filename in req_files:
-        to_build.extend(
-            (str(filename), req)
-            for req in requirements_file.parse_requirements_file(filename)
-        )
+        parsed_req = requirements_file.parse_requirements_file(req_files)
+        to_build.extend((filename, req) for req in parsed_req)
     return to_build
 
 
diff --git a/src/fromager/commands/list_overrides.py b/src/fromager/commands/list_overrides.py
index 1cdee5b..1d4c78b 100644
--- a/src/fromager/commands/list_overrides.py
+++ b/src/fromager/commands/list_overrides.py
@@ -9,7 +9,5 @@ def list_overrides(
     wkctx: context.WorkContext,
 ):
     """List all of the packages with overrides in the current configuration."""
-    for name in overrides.list_all(
-        wkctx.patches_dir, wkctx.envs_dir, wkctx.settings.download_source()
-    ):
+    for name in overrides.list_all(wkctx.patches_dir, wkctx.envs_dir):
         print(name)
diff --git a/src/fromager/dependencies.py b/src/fromager/dependencies.py
index 49a463a..af7c578 100644
--- a/src/fromager/dependencies.py
+++ b/src/fromager/dependencies.py
@@ -24,10 +24,23 @@ def get_build_system_dependencies(
     logger.info(
         f"{req.name}: getting build system dependencies for {req} in {sdist_root_dir}"
     )
+
+    build_system_req_file = sdist_root_dir.parent / "build-system-requirements.txt"
+    if build_system_req_file.exists():
+        logger.info(
+            f"{req.name}: loading build system dependencies from {build_system_req_file.name}"
+        )
+        return _read_requirements_file(build_system_req_file)
+
     dep_func = overrides.find_override_method(req.name, "get_build_system_dependencies")
     if not dep_func:
         dep_func = default_get_build_system_dependencies
     deps = _filter_requirements(req, dep_func(ctx, req, sdist_root_dir))
+
+    _write_requirements_file(
+        deps,
+        build_system_req_file,
+    )
     return deps
 
 
@@ -63,12 +76,25 @@ def get_build_backend_dependencies(
     logger.info(
         f"{req.name}: getting build backend dependencies for {req} in {sdist_root_dir}"
     )
+
+    build_backend_req_file = sdist_root_dir.parent / "build-backend-requirements.txt"
+    if build_backend_req_file.exists():
+        logger.info(
+            f"{req.name}: loading build backend dependencies from {build_backend_req_file.name}"
+        )
+        return _read_requirements_file(build_backend_req_file)
+
     dep_func = overrides.find_override_method(
         req.name, "get_build_backend_dependencies"
     )
     if not dep_func:
         dep_func = default_get_build_backend_dependencies
     deps = _filter_requirements(req, dep_func(ctx, req, sdist_root_dir))
+
+    _write_requirements_file(
+        deps,
+        build_backend_req_file,
+    )
     return deps
 
 
@@ -93,10 +119,23 @@ def get_build_sdist_dependencies(
     logger.info(
         f"{req.name}: getting build sdist dependencies for {req} in {sdist_root_dir}"
     )
+
+    build_sdist_req_file = sdist_root_dir.parent / "build-sdist-requirements.txt"
+    if build_sdist_req_file.exists():
+        logger.info(
+            f"{req.name}: loading build sdist dependencies from {build_sdist_req_file.name}"
+        )
+        return _read_requirements_file(build_sdist_req_file)
+
     dep_func = overrides.find_override_method(req.name, "get_build_sdist_dependencies")
     if not dep_func:
         dep_func = default_get_build_sdist_dependencies
     deps = _filter_requirements(req, dep_func(ctx, req, sdist_root_dir))
+
+    _write_requirements_file(
+        deps,
+        build_sdist_req_file,
+    )
     return deps
 
 
@@ -113,27 +152,17 @@ def default_get_build_sdist_dependencies(
     return hook_caller.get_requires_for_build_wheel()
 
 
-def get_install_dependencies(
-    ctx: context.WorkContext,
-    req: Requirement,
-    sdist_root_dir: pathlib.Path,
-) -> set[Requirement]:
-    logger.info(
-        f"{req.name}: getting installation dependencies for {req} in {sdist_root_dir}"
-    )
-    dep_func = overrides.find_override_method(req.name, "get_install_dependencies")
-    if not dep_func:
-        dep_func = default_get_install_dependencies
-    deps = _filter_requirements(req, dep_func(ctx, req, sdist_root_dir))
-    return deps
-
-
 def get_install_dependencies_of_wheel(
-    req: Requirement, wheel_filename: pathlib.Path
+    req: Requirement, wheel_filename: pathlib.Path, requirements_file_dir: pathlib.Path
 ) -> set[Requirement]:
     logger.info(f"{req.name}: getting installation dependencies from {wheel_filename}")
     wheel = pkginfo.Wheel(wheel_filename)
-    return _filter_requirements(req, wheel.requires_dist)
+    deps = _filter_requirements(req, wheel.requires_dist)
+    _write_requirements_file(
+        deps,
+        requirements_file_dir / "requirements.txt",
+    )
+    return deps
 
 
 def default_get_install_dependencies(
@@ -215,3 +244,19 @@ def get_build_backend_hook_caller(
         backend_path=backend["backend-path"],
         runner=_run_hook_with_extra_environ,
     )
+
+
+def _write_requirements_file(
+    requirements: typing.Iterable[Requirement],
+    filename: pathlib.Path,
+):
+    with open(filename, "w") as f:
+        for r in requirements:
+            f.write(f"{r}\n")
+
+
+def _read_requirements_file(
+    filename: pathlib.Path,
+) -> set[Requirement] | None:
+    lines = requirements_file.parse_requirements_file(filename)
+    return set([Requirement(line) for line in lines])
diff --git a/src/fromager/overrides.py b/src/fromager/overrides.py
index 30c0ab0..0619fa3 100644
--- a/src/fromager/overrides.py
+++ b/src/fromager/overrides.py
@@ -128,12 +128,7 @@ def find_override_method(distname: str, method: str) -> typing.Callable:
     return getattr(mod, method)
 
 
-def list_all(
-    patches_dir: pathlib.Path,
-    envs_dir: pathlib.Path,
-    download_source: dict[str, dict[str, str]],
-    test: bool = False,
-):
+def list_all(patches_dir: pathlib.Path, envs_dir: pathlib.Path, test: bool = False):
     exts = _get_extensions()
 
     def patched_projects():
@@ -167,9 +162,6 @@ def list_all(
         for item in envs_dir.glob("*/*.env"):
             yield item.stem
 
-    def projects_with_predefined_download_source():
-        yield from download_source
-
     # Use canonicalize_name() to ensure we can correctly remove duplicate
     # entries from the return list.
     return sorted(
@@ -180,7 +172,6 @@ def list_all(
                 patched_projects(),
                 patched_projects_legacy(),
                 env_projects(),
-                projects_with_predefined_download_source(),
             )
             if not test
             or n != "fromager_test"  # filter out test package except in test mode
diff --git a/src/fromager/sdist.py b/src/fromager/sdist.py
index 27d571e..3033499 100644
--- a/src/fromager/sdist.py
+++ b/src/fromager/sdist.py
@@ -213,12 +213,9 @@ def handle_requirement(
     # Process installation dependencies for all wheels.
     next_req_type = "install"
     install_dependencies = dependencies.get_install_dependencies_of_wheel(
-        req, wheel_filename
-    )
-    _write_requirements_file(
-        install_dependencies,
-        unpack_dir / "requirements.txt",
+        req, wheel_filename, unpack_dir
     )
+
     for dep in _sort_requirements(install_dependencies):
         try:
             handle_requirement(ctx, dep, next_req_type, why)
@@ -310,10 +307,7 @@ def _handle_build_system_requirements(
     build_system_dependencies = dependencies.get_build_system_dependencies(
         ctx, req, sdist_root_dir
     )
-    _write_requirements_file(
-        build_system_dependencies,
-        sdist_root_dir.parent / "build-system-requirements.txt",
-    )
+
     for dep in _sort_requirements(build_system_dependencies):
         try:
             resolved = handle_requirement(ctx, dep, "build-system", why)
@@ -337,10 +331,7 @@ def _handle_build_backend_requirements(
     build_backend_dependencies = dependencies.get_build_backend_dependencies(
         ctx, req, sdist_root_dir
     )
-    _write_requirements_file(
-        build_backend_dependencies,
-        sdist_root_dir.parent / "build-backend-requirements.txt",
-    )
+
     for dep in _sort_requirements(build_backend_dependencies):
         try:
             resolved = handle_requirement(ctx, dep, "build-backend", why)
@@ -364,10 +355,7 @@ def _handle_build_sdist_requirements(
     build_sdist_dependencies = dependencies.get_build_sdist_dependencies(
         ctx, req, sdist_root_dir
     )
-    _write_requirements_file(
-        build_sdist_dependencies,
-        sdist_root_dir.parent / "build-sdist-requirements.txt",
-    )
+
     for dep in _sort_requirements(build_sdist_dependencies):
         try:
             resolved = handle_requirement(ctx, dep, "build-sdist", why)
@@ -390,10 +378,7 @@ def prepare_build_environment(
     build_system_dependencies = dependencies.get_build_system_dependencies(
         ctx, req, sdist_root_dir
     )
-    _write_requirements_file(
-        build_system_dependencies,
-        sdist_root_dir.parent / "build-system-requirements.txt",
-    )
+
     for dep in build_system_dependencies:
         # We may need these dependencies installed in order to run build hooks
         # Example: frozenlist build-system.requires includes expandvars because
@@ -415,10 +400,7 @@ def prepare_build_environment(
     build_backend_dependencies = dependencies.get_build_backend_dependencies(
         ctx, req, sdist_root_dir
     )
-    _write_requirements_file(
-        build_backend_dependencies,
-        sdist_root_dir.parent / "build-backend-requirements.txt",
-    )
+
     for dep in build_backend_dependencies:
         # Build backends are often used to package themselves, so in
         # order to determine their dependencies they may need to be
@@ -440,10 +422,7 @@ def prepare_build_environment(
     build_sdist_dependencies = dependencies.get_build_sdist_dependencies(
         ctx, req, sdist_root_dir
     )
-    _write_requirements_file(
-        build_sdist_dependencies,
-        sdist_root_dir.parent / "build-sdist-requirements.txt",
-    )
+
     for dep in build_sdist_dependencies:
         try:
             _maybe_install(ctx, dep, next_req_type, None)
@@ -483,15 +462,6 @@ def prepare_build_environment(
     return build_env.path
 
 
-def _write_requirements_file(
-    requirements: typing.Iterable[Requirement],
-    filename: pathlib.Path,
-):
-    with open(filename, "w") as f:
-        for r in requirements:
-            f.write(f"{r}\n")
-
-
 def _maybe_install(
     ctx: context.WorkContext,
     req: Requirement,
diff --git a/src/fromager/settings.py b/src/fromager/settings.py
index 20d0ed6..8efc9c4 100644
--- a/src/fromager/settings.py
+++ b/src/fromager/settings.py
@@ -17,19 +17,6 @@ class Settings:
         names = p.get(variant) or []
         return set(overrides.pkgname_to_override_module(n) for n in names)
 
-    def download_source(self) -> dict[str, dict[str, str]]:
-        return self._data.get("download_source") or {}
-
-    def sdist_download_url(self, pkg: str) -> str | None:
-        p = self.download_source()
-        download_source = p.get(pkg) or {}
-        return download_source.get("url")
-
-    def sdist_local_filename(self, pkg: str) -> str | None:
-        p = self.download_source()
-        download_source = p.get(pkg) or {}
-        return download_source.get("rename_to")
-
 
 def _parse(content: str) -> Settings:
     data = yaml.safe_load(content)
diff --git a/src/fromager/sources.py b/src/fromager/sources.py
index 06ac1b7..4fca4b7 100644
--- a/src/fromager/sources.py
+++ b/src/fromager/sources.py
@@ -4,7 +4,6 @@ import logging
 import os.path
 import pathlib
 import shutil
-import string
 import subprocess
 import tarfile
 import typing
@@ -21,7 +20,6 @@ from . import context, dependencies, overrides, resolver, tarballs, vendor_rust
 logger = logging.getLogger(__name__)
 
 PYPI_SERVER_URL = "https://pypi.org/simple"
-GITHUB_URL = "https://github.com"
 DEFAULT_SDIST_SERVER_URLS = [
     PYPI_SERVER_URL,
 ]
@@ -128,23 +126,10 @@ def default_download_source(
     sdist_server_url: str,
 ) -> tuple[pathlib.Path, str, str]:
     "Download the requirement and return the name of the output path."
-    url_template = ctx.settings.sdist_download_url(req.name)
-    rename_to_template = ctx.settings.sdist_local_filename(req.name)
-
-    # don't include sdists if the user wants to download source from a predefined url
-    include_sdists = url_template is None
-    include_wheels = not include_sdists
-
-    org_url, version = resolve_dist(
-        ctx, req, sdist_server_url, include_sdists, include_wheels
+    url, version = resolve_dist(
+        ctx, req, sdist_server_url, include_sdists=True, include_wheels=False
     )
-
-    url = _resolve_template(url_template, req, version) or org_url
-    logger.debug(f"{req.name}: using {url} instead of {org_url}")
-
-    rename_to = _resolve_template(rename_to_template, req, version)
-
-    source_filename = _download_source_check(ctx.sdists_downloads, url, rename_to)
+    source_filename = _download_source_check(ctx.sdists_downloads, url)
     logger.debug(
         f"{req.name}: have source for {req} version {version} in {source_filename}"
     )
@@ -153,10 +138,8 @@ def default_download_source(
 
 # Helper method to check whether .zip /.tar / .tgz is able to extract and check its content.
 # It will throw exception if any other file is encountered. Eg: index.html
-def _download_source_check(
-    destination_dir: pathlib.Path, url: str, rename_to: str | None = None
-) -> str:
-    source_filename = download_url(destination_dir, url, rename_to)
+def _download_source_check(destination_dir, url):
+    source_filename = download_url(destination_dir, url)
     if source_filename.suffix == ".zip":
         source_file_contents = zipfile.ZipFile(source_filename).namelist()
         if not source_file_contents:
@@ -173,11 +156,8 @@ def _download_source_check(
     return source_filename
 
 
-def download_url(
-    destination_dir: pathlib.Path, url: str, rename_to: str | None = None
-) -> pathlib.Path:
-    basename = rename_to if rename_to else os.path.basename(urlparse(url).path)
-    outfile = pathlib.Path(destination_dir) / basename
+def download_url(destination_dir: pathlib.Path, url: str) -> pathlib.Path:
+    outfile = pathlib.Path(destination_dir) / os.path.basename(urlparse(url).path)
     logger.debug(
         "looking for %s %s", outfile, "(exists)" if outfile.exists() else "(not there)"
     )
@@ -196,19 +176,6 @@ def download_url(
     return outfile
 
 
-def _resolve_template(template: str | None, req: Requirement, version: str):
-    if not template:
-        return None
-    template_env = {"version": version}
-    try:
-        return string.Template(template).substitute(template_env)
-    except KeyError:
-        logger.warning(
-            f"{req.name}: Couldn't resolve url or name for {req} using the template: {template_env}"
-        )
-        raise
-
-
 def _sdist_root_name(source_filename: pathlib.Path) -> str:
     base_name = pathlib.Path(source_filename).name
     if base_name.endswith(".tar.gz"):
@@ -257,7 +224,7 @@ def unpack_source(
     return (next(iter(unpack_dir.glob("*"))), True)
 
 
-def patch_source(ctx: context.WorkContext, source_root_dir: pathlib.Path):
+def _patch_source(ctx: context.WorkContext, source_root_dir: pathlib.Path):
     for p in overrides.patches_for_source_dir(ctx.patches_dir, source_root_dir.name):
         logger.info("applying patch file %s to %s", p, source_root_dir)
         with open(p, "r") as f:
@@ -319,7 +286,7 @@ def _default_prepare_source(
 ) -> pathlib.Path:
     source_root_dir, is_new = unpack_source(ctx, source_filename)
     if is_new:
-        patch_source(ctx, source_root_dir)
+        _patch_source(ctx, source_root_dir)
         vendor_rust.vendor_rust(req, source_root_dir)
     return source_root_dir
 


Test patch:
diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py
index 59a74f3..5e2b24a 100644
--- a/tests/test_bootstrap.py
+++ b/tests/test_bootstrap.py
@@ -1,4 +1,5 @@
-import pathlib
+import typing
+from unittest.mock import patch
 
 from fromager.commands import bootstrap
 
@@ -13,9 +14,10 @@ def test_get_requirements_multiple_args():
     assert [("toplevel", "a"), ("toplevel", "b")] == requirements
 
 
-def test_get_requirements_args_and_file(tmp_path: pathlib.Path):
-    requirements_file = tmp_path / "requirements.txt"
-    requirements_file.write_text("c\n")
+@patch("fromager.requirements_file.parse_requirements_file")
+def test_get_requirements_args_and_file(parse_requirements_file: typing.Callable):
+    requirements_file = "requirements.txt"
+    parse_requirements_file.return_value = ["c"]
     requirements = bootstrap._get_requirements_from_args(
         ["a", "b"], [requirements_file]
     )
diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py
index 17cddbf..7b615bc 100644
--- a/tests/test_dependencies.py
+++ b/tests/test_dependencies.py
@@ -74,6 +74,20 @@ def test_get_build_system_dependencies(tmp_context: context.WorkContext):
     assert names == set(["setuptools", "setuptools_scm"])
 
 
+def test_get_build_system_dependencies_cached(
+    tmp_context: context.WorkContext, tmp_path: pathlib.Path
+):
+    sdist_root_dir = tmp_path / "sdist"
+    sdist_root_dir.mkdir()
+
+    req_file = tmp_path / "build-system-requirements.txt"
+    req_file.write_text("foo==1.0")
+    results = dependencies.get_build_system_dependencies(
+        tmp_context, Requirement("fromager"), sdist_root_dir
+    )
+    assert results == set([Requirement("foo==1.0")])
+
+
 @_clean_build_artifacts
 def test_get_build_backend_dependencies(tmp_context: context.WorkContext):
     results = dependencies.get_build_backend_dependencies(
@@ -85,6 +99,20 @@ def test_get_build_backend_dependencies(tmp_context: context.WorkContext):
     assert names == set()
 
 
+def test_get_build_backend_dependencies_cached(
+    tmp_context: context.WorkContext, tmp_path: pathlib.Path
+):
+    sdist_root_dir = tmp_path / "sdist"
+    sdist_root_dir.mkdir()
+
+    req_file = tmp_path / "build-backend-requirements.txt"
+    req_file.write_text("foo==1.0")
+    results = dependencies.get_build_backend_dependencies(
+        tmp_context, Requirement("fromager"), sdist_root_dir
+    )
+    assert results == set([Requirement("foo==1.0")])
+
+
 @_clean_build_artifacts
 def test_get_build_sdist_dependencies(tmp_context: context.WorkContext):
     results = dependencies.get_build_sdist_dependencies(
@@ -96,15 +124,15 @@ def test_get_build_sdist_dependencies(tmp_context: context.WorkContext):
     assert names == set()
 
 
-@_clean_build_artifacts
-def test_get_install_dependencies(tmp_context: context.WorkContext):
-    pyproject_contents = dependencies.get_pyproject_contents(_fromager_root)
-    expected = set(
-        Requirement(d) for d in pyproject_contents["project"]["dependencies"]
-    )
-    actual = dependencies.get_install_dependencies(
-        tmp_context,
-        Requirement("fromager"),
-        _fromager_root,
+def test_get_build_sdist_dependencies_cached(
+    tmp_context: context.WorkContext, tmp_path: pathlib.Path
+):
+    sdist_root_dir = tmp_path / "sdist"
+    sdist_root_dir.mkdir()
+
+    req_file = tmp_path / "build-sdist-requirements.txt"
+    req_file.write_text("foo==1.0")
+    results = dependencies.get_build_sdist_dependencies(
+        tmp_context, Requirement("fromager"), sdist_root_dir
     )
-    assert actual == expected
+    assert results == set([Requirement("foo==1.0")])
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
index 7030cd3..4ce41b2 100644
--- a/tests/test_overrides.py
+++ b/tests/test_overrides.py
@@ -92,7 +92,7 @@ def test_extra_environ_for_pkg_expansion(tmp_path: pathlib.Path):
         extra_environ = overrides.extra_environ_for_pkg(tmp_path, pkg_name, variant)
 
 
-def test_list_all(tmp_path: pathlib.Path):
+def test_list_all(tmp_path):
     patches_dir = tmp_path / "patches"
     patches_dir.mkdir()
 
@@ -124,25 +124,17 @@ def test_list_all(tmp_path: pathlib.Path):
     project_env2 = variant_dir / "fromager_test.env"
     project_env2.write_text("VAR1=VALUE1\nVAR2=VALUE2")  # duplicate
 
-    download_source = {
-        "project-with-download-source": {"url": "url"},
-        "another-project-with-download-source": {"url": "url"},
-    }
-
     expected = [
         "project-with-patch",
         "legacy-project",
         "project-with-env",
         "fromager-test",
-        "project-with-download-source",
-        "another-project-with-download-source",
     ]
     expected.sort()
 
     packages = overrides.list_all(
         patches_dir=patches_dir,
         envs_dir=env_dir,
-        download_source=download_source,
         test=True,
     )
 
diff --git a/tests/test_settings.py b/tests/test_settings.py
index 03ca013..4a3e386 100644
--- a/tests/test_settings.py
+++ b/tests/test_settings.py
@@ -27,28 +27,3 @@ def test_with_pre_built():
     """)
     )
     assert s.pre_built("cuda") == set(["a", "b"])
-
-
-def test_with_download_source():
-    s = settings._parse(
-        textwrap.dedent("""
-    download_source:
-      foo:
-        url: url
-        rename_to: rename
-    """)
-    )
-    assert s.sdist_local_filename("foo") == "rename"
-    assert s.sdist_local_filename("bar") is None
-    assert s.sdist_download_url("foo") == "url"
-    assert s.sdist_download_url("bar") is None
-
-
-def test_no_download_source():
-    s = settings._parse(
-        textwrap.dedent("""
-    pre_built:
-    """)
-    )
-    assert s.sdist_local_filename("foo") is None
-    assert s.sdist_download_url("foo") is None
diff --git a/tests/test_sources.py b/tests/test_sources.py
index be2683c..de57b8e 100644
--- a/tests/test_sources.py
+++ b/tests/test_sources.py
@@ -1,11 +1,9 @@
 import pathlib
-import typing
 from unittest.mock import patch
 
 import pytest
-from packaging.requirements import Requirement
 
-from fromager import context, settings, sources
+from fromager import sources
 
 
 @patch("fromager.sources.download_url")
@@ -18,69 +16,3 @@ def test_invalid_tarfile(mock_download_url, tmp_path: pathlib.Path):
     text_file.write_text("This is a test file")
     with pytest.raises(TypeError):
         sources._download_source_check(fake_dir, fake_url)
-
-
-def test_resolve_template_with_no_template():
-    req = Requirement("foo==1.0")
-    assert sources._resolve_template(None, req, "1.0") is None
-
-
-def test_resolve_template_with_version():
-    req = Requirement("foo==1.0")
-    assert sources._resolve_template("url-${version}", req, "1.0") == "url-1.0"
-
-
-def test_resolve_template_with_no_matching_template():
-    req = Requirement("foo==1.0")
-    with pytest.raises(KeyError):
-        sources._resolve_template("url-${flag}", req, "1.0")
-
-
-@patch("fromager.sources.resolve_dist")
-@patch("fromager.sources._download_source_check")
-@patch.object(settings.Settings, "sdist_download_url")
-@patch.object(settings.Settings, "sdist_local_filename")
-def test_default_download_source_no_predefined_url(
-    sdist_local_filename: typing.Callable,
-    sdist_download_url: typing.Callable,
-    download_source_check: typing.Callable,
-    resolve_dist: typing.Callable,
-    tmp_context: context.WorkContext,
-):
-    resolve_dist.return_value = ("url", "1.0")
-    download_source_check.return_value = pathlib.Path("filename.zip")
-    sdist_download_url.return_value = None
-    sdist_local_filename.return_value = None
-    req = Requirement("foo==1.0")
-    sdist_server_url = sources.PYPI_SERVER_URL
-
-    sources.default_download_source(tmp_context, req, sdist_server_url)
-
-    resolve_dist.assert_called_with(tmp_context, req, sdist_server_url, True, False)
-    download_source_check.assert_called_with(tmp_context.sdists_downloads, "url", None)
-
-
-@patch("fromager.sources.resolve_dist")
-@patch("fromager.sources._download_source_check")
-@patch.object(settings.Settings, "sdist_download_url")
-@patch.object(settings.Settings, "sdist_local_filename")
-def test_default_download_source_with_predefined_url(
-    sdist_local_filename: typing.Callable,
-    sdist_download_url: typing.Callable,
-    download_source_check: typing.Callable,
-    resolve_dist: typing.Callable,
-    tmp_context: context.WorkContext,
-):
-    resolve_dist.return_value = ("url", "1.0")
-    download_source_check.return_value = pathlib.Path("filename")
-    sdist_download_url.return_value = "predefined_url-${version}"
-    sdist_local_filename.return_value = "foo-${version}"
-    req = Requirement("foo==1.0")
-    sdist_server_url = sources.PYPI_SERVER_URL
-
-    sources.default_download_source(tmp_context, req, sdist_server_url)
-
-    resolve_dist.assert_called_with(tmp_context, req, sdist_server_url, False, True)
-    download_source_check.assert_called_with(
-        tmp_context.sdists_downloads, "predefined_url-1.0", "foo-1.0"
-    )