refactor(model_scanner): normalize path comparisons for model roots

fix(example_images_download_manager): re-raise specific exception on download error

refactor(usage_stats): define constants locally to avoid conditional imports

test(example_images_download_manager): update exception handling in download tests

test(example_images_file_manager): differentiate between os.startfile and subprocess.Popen in tests

test(example_images_paths): ensure valid example images root with single-library mode

test(usage_stats): use string literals for metadata payload to avoid conditional imports
This commit is contained in:
Will Miao
2025-10-05 15:48:50 +08:00
parent e21d5835ec
commit 413444500e
7 changed files with 48 additions and 9 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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__)

View File

@@ -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})

View File

@@ -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:

View File

@@ -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

View File

@@ -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"}]},
},
}