diff --git a/core/downloader.py b/core/downloader.py index 053f3d9..056d448 100644 --- a/core/downloader.py +++ b/core/downloader.py @@ -1377,7 +1377,10 @@ def _run_huggingface_xet_transfer( """Use detailed native Xet progress when supported, with legacy fallback.""" import hf_xet from huggingface_hub.file_download import xet_get - from huggingface_hub.utils import refresh_xet_connection_info + try: + from huggingface_hub.utils import refresh_xet_connection_info + except ImportError: + refresh_xet_connection_info = None supports_session_progress = all( hasattr(hf_xet, name) @@ -1422,7 +1425,7 @@ def _run_huggingface_xet_transfer( xet_transfers.pop(progress_adapter.download_id, None) return - supports_detailed_progress = all( + supports_detailed_progress = refresh_xet_connection_info is not None and all( hasattr(hf_xet, name) for name in ( "PyItemProgressUpdate", diff --git a/tests/test_path_security.py b/tests/test_path_security.py index 1bcff2c..13d245e 100644 --- a/tests/test_path_security.py +++ b/tests/test_path_security.py @@ -477,6 +477,58 @@ class PathSecurityTests(unittest.TestCase): self.assertEqual(0.8, progress["transfer_progress"]) self.assertEqual(0.8, progress["progress"]) + def test_huggingface_xet_without_refresh_helper_uses_native_fallback(self): + legacy_hf_xet = SimpleNamespace( + PyItemProgressUpdate=object(), + PyTotalProgressUpdate=object(), + PyXetDownloadInfo=object(), + download_files=MagicMock(), + ) + real_import = __import__ + + def import_without_refresh_helper( + name, + globals=None, + locals=None, + fromlist=(), + level=0, + ): + if name == "hf_xet": + return legacy_hf_xet + if ( + name == "huggingface_hub.utils" + and "refresh_xet_connection_info" in fromlist + ): + raise ImportError("refresh_xet_connection_info is unavailable") + return real_import(name, globals, locals, fromlist, level) + + incomplete_path = Path("model.safetensors.xet-part") + xet_file_data = SimpleNamespace(file_hash="test-hash") + progress_adapter = MagicMock() + + with patch( + "builtins.__import__", + side_effect=import_without_refresh_helper, + ), patch("huggingface_hub.file_download.xet_get") as mock_xet_get: + downloader_module._run_huggingface_xet_transfer( + incomplete_path, + xet_file_data, + {"Authorization": "Bearer test"}, + 1024, + "model.safetensors", + progress_adapter, + ) + + mock_xet_get.assert_called_once_with( + incomplete_path=incomplete_path, + xet_file_data=xet_file_data, + headers={"Authorization": "Bearer test"}, + expected_size=1024, + displayed_filename="model.safetensors", + _tqdm_bar=progress_adapter, + ) + legacy_hf_xet.download_files.assert_not_called() + def test_cancel_download_calls_active_huggingface_xet_handle(self): download_id = "xet-cancel-handle-test" handle = MagicMock()