refactor shared remote file size resolution

This commit is contained in:
Dariusz L
2026-08-06 22:25:42 +02:00
parent 83c7943f8a
commit 76d0a3aa7c
5 changed files with 115 additions and 21 deletions
+7 -10
View File
@@ -51,6 +51,7 @@ from .common import (
build_custom_result_fields,
collect_download_urls,
is_remote_link_marked_dead,
resolve_file_size,
)
log = create_module_logger(__name__)
@@ -671,20 +672,16 @@ def _resolve_file_size_bytes(
file_info: Dict[str, Any],
download_urls: Optional[List[str]] = None,
) -> Optional[int]:
size = extract_file_size(file_info)
if size:
return size
urls = download_urls if download_urls is not None else _collect_archive_download_urls(
file_info,
**_NORMALIZED_DOWNLOAD_URL_OPTIONS,
)
for url in sorted(urls, key=_remote_size_probe_priority):
size = _fetch_remote_file_size_bytes(url)
if size:
return size
return None
ordered_urls = sorted(urls, key=_remote_size_probe_priority)
return resolve_file_size(
file_info,
ordered_urls,
probe=_fetch_remote_file_size_bytes,
)
def _mirror_from_top_file(file_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
+21 -2
View File
@@ -2,9 +2,28 @@
Common utilities for external model metadata sources.
"""
from typing import Any, Callable, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
from ..type_utils import extract_file_sha256
from ..type_utils import extract_file_sha256, extract_file_size
def resolve_file_size(
file_info: Dict[str, Any],
candidate_urls: Iterable[str],
*,
probe: Callable[[str], Optional[int]],
) -> Optional[int]:
"""Resolve a model file size from metadata and ordered remote candidates."""
size = extract_file_size(file_info)
if size:
return size
for url in candidate_urls:
size = probe(url)
if size:
return size
return None
def build_custom_result_fields(
+13 -8
View File
@@ -31,6 +31,7 @@ from ..type_utils import (
normalize_sha256,
prepare_remote_size_probe_url,
)
from .common import resolve_file_size
HF_API_URL = "https://huggingface.co/api"
HF_AUTHOR_FALLBACKS = ["Comfy-Org", "Kijai"]
@@ -721,9 +722,11 @@ def _build_huggingface_result(
) -> Dict[str, Any]:
sha256 = _extract_huggingface_file_sha256(file_info)
download_url = get_huggingface_download_url(repo_id, file_path)
size = extract_file_size(file_info)
if not size:
size = _fetch_remote_file_size_bytes(download_url, headers=headers)
size = resolve_file_size(
file_info,
[download_url],
probe=lambda url: _fetch_remote_file_size_bytes(url, headers=headers),
)
return build_model_result(
"huggingface",
model_id=repo_id,
@@ -1552,13 +1555,15 @@ def build_huggingface_custom_result(
file_info = candidate
break
size = extract_file_size(file_info)
if not size:
size = fetch_remote_file_size_cached(
download_url,
size = resolve_file_size(
file_info,
[download_url],
probe=lambda url: fetch_remote_file_size_cached(
url,
headers=headers,
timeout=10,
)
),
)
sha256 = _extract_huggingface_file_sha256(file_info)
def quote_url_path(val):
+18
View File
@@ -11,6 +11,7 @@ from core.sources.huggingface import (
HF_AUTHOR_FALLBACKS,
_build_author_index_from_models,
_fetch_author_index,
_fetch_remote_file_size_bytes,
_find_matching_file_in_author_index,
_get_author_index,
_is_author_index_fresh,
@@ -589,6 +590,23 @@ class HuggingFaceSourceTests(unittest.TestCase):
normalized = _normalize_huggingface_size_probe_url(url)
self.assertEqual(normalized, "https://huggingface.co/user/repo/resolve/main/model.safetensors")
@patch(
"core.sources.huggingface.fetch_remote_file_size_cached",
return_value=789,
)
def test_remote_size_probe_preserves_headers_and_timeout(self, mock_fetch):
url = "https://huggingface.co/user/repo/blob/main/model.safetensors"
headers = {"Authorization": "Bearer test"}
size = _fetch_remote_file_size_bytes(url, headers=headers, timeout=7)
self.assertEqual(size, 789)
mock_fetch.assert_called_once_with(
"https://huggingface.co/user/repo/resolve/main/model.safetensors",
headers=headers,
timeout=7,
)
def test_custom_result_uses_sha256_from_exact_huggingface_file(self):
sha256 = "a" * 64
url = (
+56 -1
View File
@@ -62,7 +62,11 @@ from core.sources.civitai import (
search_civitai,
search_civitai_for_file,
)
from core.sources.common import build_custom_result_fields, is_remote_link_marked_dead
from core.sources.common import (
build_custom_result_fields,
is_remote_link_marked_dead,
resolve_file_size,
)
from core.type_utils import prepare_remote_size_probe_url
# ---------------------------------------------------------------------------
@@ -1152,6 +1156,57 @@ class PrepareSizeProbeUrlTests(unittest.TestCase):
class CivArchiveMirrorSizeProbeTests(unittest.TestCase):
def test_shared_file_size_resolver_prefers_metadata(self):
probe = MagicMock(return_value=654321)
size = resolve_file_size(
{"size": 123456},
["https://example.com/model.safetensors"],
probe=probe,
)
self.assertEqual(size, 123456)
probe.assert_not_called()
def test_shared_file_size_resolver_uses_ordered_probe_until_success(self):
probe = MagicMock(side_effect=[None, 654321])
urls = [
"https://example.com/first.safetensors",
"https://example.com/second.safetensors",
"https://example.com/third.safetensors",
]
size = resolve_file_size({}, urls, probe=probe)
self.assertEqual(size, 654321)
probe.assert_has_calls([
((urls[0],), {}),
((urls[1],), {}),
])
self.assertEqual(probe.call_count, 2)
def test_metadata_size_is_preferred_over_remote_probe(self):
with patch("core.sources.civarchive._fetch_remote_file_size_bytes") as mock_fetch:
size = _resolve_file_size_bytes(
{"size": 123456},
["https://huggingface.co/org/repo/resolve/main/model.safetensors"],
)
self.assertEqual(size, 123456)
mock_fetch.assert_not_called()
@patch(
"core.sources.civarchive._fetch_remote_file_size_bytes",
return_value=654321,
)
def test_zero_metadata_size_falls_back_to_remote_probe(self, mock_fetch):
url = "https://huggingface.co/org/repo/resolve/main/model.safetensors"
size = _resolve_file_size_bytes({"size": 0}, [url])
self.assertEqual(size, 654321)
mock_fetch.assert_called_once_with(url)
@patch(
"core.sources.civarchive.fetch_remote_file_size_cached",
return_value=364853140,