diff --git a/py/services/model_scanner.py b/py/services/model_scanner.py index 4e1c0eac..5822b223 100644 --- a/py/services/model_scanner.py +++ b/py/services/model_scanner.py @@ -620,8 +620,12 @@ class ModelScanner: try: # Find the appropriate root path for this file root_path = None - for potential_root in self.get_model_roots(): - if path.startswith(potential_root): + model_roots = self.get_model_roots() + for potential_root in model_roots: + # Normalize both paths for comparison + normalized_path = os.path.normpath(path) + normalized_root = os.path.normpath(potential_root) + if normalized_path.startswith(normalized_root): root_path = potential_root break diff --git a/py/utils/example_images_download_manager.py b/py/utils/example_images_download_manager.py index ed6ca69a..f6b13930 100644 --- a/py/utils/example_images_download_manager.py +++ b/py/utils/example_images_download_manager.py @@ -202,6 +202,11 @@ class DownloadManager: ) snapshot = self._progress.snapshot() + except ExampleImagesDownloadError: + # Re-raise our own exception types without wrapping + self._is_downloading = False + self._download_task = None + raise except Exception as e: self._is_downloading = False self._download_task = None diff --git a/py/utils/usage_stats.py b/py/utils/usage_stats.py index 3268ea04..d886ab9f 100644 --- a/py/utils/usage_stats.py +++ b/py/utils/usage_stats.py @@ -13,9 +13,19 @@ from ..services.service_registry import ServiceRegistry # Check if running in standalone mode standalone_mode = os.environ.get("LORA_MANAGER_STANDALONE", "0") == "1" or os.environ.get("HF_HUB_DISABLE_TELEMETRY", "0") == "0" +# Define constants locally to avoid dependency on conditional imports +MODELS = "models" +LORAS = "loras" + if not standalone_mode: from ..metadata_collector.metadata_registry import MetadataRegistry - from ..metadata_collector.constants import MODELS, LORAS + # Import constants from metadata_collector to ensure consistency, but we have fallbacks defined above + try: + from ..metadata_collector.constants import MODELS as _MODELS, LORAS as _LORAS + MODELS = _MODELS + LORAS = _LORAS + except ImportError: + pass # Use the local definitions logger = logging.getLogger(__name__) diff --git a/tests/utils/test_example_images_download_manager_unit.py b/tests/utils/test_example_images_download_manager_unit.py index d0083c7e..754e5278 100644 --- a/tests/utils/test_example_images_download_manager_unit.py +++ b/tests/utils/test_example_images_download_manager_unit.py @@ -30,10 +30,12 @@ def restore_settings() -> None: async def test_start_download_requires_configured_path(monkeypatch: pytest.MonkeyPatch) -> None: manager = download_module.DownloadManager(ws_manager=RecordingWebSocketManager()) - with pytest.raises(download_module.ExampleImagesDownloadError) as exc_info: + # Ensure example_images_path is not configured + settings.settings.pop('example_images_path', None) + + with pytest.raises(download_module.DownloadConfigurationError) as exc_info: await manager.start_download({}) - assert isinstance(exc_info.value.__cause__, download_module.DownloadConfigurationError) assert "not configured" in str(exc_info.value) result = await manager.start_download({"auto_mode": True}) diff --git a/tests/utils/test_example_images_file_manager.py b/tests/utils/test_example_images_file_manager.py index 38b1896b..e360b587 100644 --- a/tests/utils/test_example_images_file_manager.py +++ b/tests/utils/test_example_images_file_manager.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import os import subprocess from typing import Any, Dict @@ -37,20 +38,30 @@ async def test_open_folder_requires_existing_model_directory(monkeypatch: pytest (model_folder / "image.png").write_text("data", encoding="utf-8") popen_calls: list[list[str]] = [] + startfile_calls: list[str] = [] class DummyPopen: def __init__(self, cmd, *_args, **_kwargs): popen_calls.append(cmd) + def dummy_startfile(path): + startfile_calls.append(path) + monkeypatch.setattr("subprocess.Popen", DummyPopen) + monkeypatch.setattr("os.startfile", dummy_startfile) request = JsonRequest({"model_hash": model_hash}) response = await ExampleImagesFileManager.open_folder(request) body = json.loads(response.text) assert body["success"] is True - assert popen_calls - assert model_hash in popen_calls[0][-1] + # On Windows, os.startfile is used; on other platforms, subprocess.Popen + if os.name == 'nt': + assert startfile_calls + assert model_hash in startfile_calls[0] + else: + assert popen_calls + assert model_hash in popen_calls[0][-1] async def test_open_folder_rejects_invalid_paths(monkeypatch: pytest.MonkeyPatch, tmp_path) -> None: diff --git a/tests/utils/test_example_images_paths.py b/tests/utils/test_example_images_paths.py index d52e0545..2e47242d 100644 --- a/tests/utils/test_example_images_paths.py +++ b/tests/utils/test_example_images_paths.py @@ -104,6 +104,10 @@ def test_iter_library_roots_returns_all_configured(tmp_path): def test_is_valid_example_images_root_accepts_hash_directories(tmp_path): settings.settings['example_images_path'] = str(tmp_path) + # Ensure single-library mode (not multi-library mode) + settings.settings['libraries'] = {'default': {}} + settings.settings['active_library'] = 'default' + hash_folder = tmp_path / ('d' * 64) hash_folder.mkdir() (hash_folder / 'image.png').write_text('data', encoding='utf-8') @@ -112,4 +116,6 @@ def test_is_valid_example_images_root_accepts_hash_directories(tmp_path): invalid_folder = tmp_path / 'not_hash' invalid_folder.mkdir() + # Add a non-hash file to make it clearly invalid + (invalid_folder / 'invalid.txt').write_text('invalid', encoding='utf-8') assert is_valid_example_images_root(str(tmp_path)) is False diff --git a/tests/utils/test_usage_stats.py b/tests/utils/test_usage_stats.py index e5657ee5..6102f690 100644 --- a/tests/utils/test_usage_stats.py +++ b/tests/utils/test_usage_stats.py @@ -113,11 +113,12 @@ async def test_usage_stats_background_processor_handles_pending_prompts(tmp_path stats, tasks, _ = _prepare_usage_stats(tmp_path, monkeypatch, sleep_override=fast_sleep) metadata_calls = [] + # Use string literals directly to avoid dependency on conditional imports metadata_payload = { - MODELS: { + "models": { "1": {"type": "checkpoint", "name": "model.ckpt"}, }, - LORAS: { + "loras": { "2": {"lora_list": [{"name": "awesome_lora.safetensors"}]}, }, }