mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
fix(config): remove template default library before saving paths
This commit is contained in:
78
py/config.py
78
py/config.py
@@ -2,12 +2,12 @@ import os
|
||||
import platform
|
||||
from pathlib import Path
|
||||
import folder_paths # type: ignore
|
||||
from typing import Dict, Iterable, List, Mapping, Set
|
||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Set
|
||||
import logging
|
||||
import json
|
||||
import urllib.parse
|
||||
|
||||
from .utils.settings_paths import ensure_settings_file
|
||||
from .utils.settings_paths import ensure_settings_file, load_settings_template
|
||||
|
||||
# Use an environment variable to control standalone mode
|
||||
standalone_mode = os.environ.get("LORA_MANAGER_STANDALONE", "0") == "1" or os.environ.get("HF_HUB_DISABLE_TELEMETRY", "0") == "0"
|
||||
@@ -45,6 +45,30 @@ def _normalize_folder_paths_for_comparison(
|
||||
return normalized
|
||||
|
||||
|
||||
def _normalize_library_folder_paths(
|
||||
library_payload: Mapping[str, Any]
|
||||
) -> Dict[str, Set[str]]:
|
||||
"""Return normalized folder paths extracted from a library payload."""
|
||||
|
||||
folder_paths = library_payload.get("folder_paths")
|
||||
if isinstance(folder_paths, Mapping):
|
||||
return _normalize_folder_paths_for_comparison(folder_paths)
|
||||
return {}
|
||||
|
||||
|
||||
def _get_template_folder_paths() -> Dict[str, Set[str]]:
|
||||
"""Return normalized folder paths defined in the bundled template."""
|
||||
|
||||
template_payload = load_settings_template()
|
||||
if not template_payload:
|
||||
return {}
|
||||
|
||||
folder_paths = template_payload.get("folder_paths")
|
||||
if isinstance(folder_paths, Mapping):
|
||||
return _normalize_folder_paths_for_comparison(folder_paths)
|
||||
return {}
|
||||
|
||||
|
||||
class Config:
|
||||
"""Global configuration for LoRA Manager"""
|
||||
|
||||
@@ -81,6 +105,43 @@ class Config:
|
||||
comfy_library = libraries.get("comfyui", {})
|
||||
default_library = libraries.get("default", {})
|
||||
|
||||
template_folder_paths = _get_template_folder_paths()
|
||||
default_library_paths: Dict[str, Set[str]] = {}
|
||||
if isinstance(default_library, Mapping):
|
||||
default_library_paths = _normalize_library_folder_paths(default_library)
|
||||
|
||||
libraries_changed = False
|
||||
if (
|
||||
isinstance(default_library, Mapping)
|
||||
and template_folder_paths
|
||||
and default_library_paths == template_folder_paths
|
||||
):
|
||||
if "comfyui" in libraries:
|
||||
try:
|
||||
settings_service.delete_library("default")
|
||||
libraries_changed = True
|
||||
logger.info("Removed template 'default' library entry")
|
||||
except Exception as delete_error:
|
||||
logger.debug(
|
||||
"Failed to delete template 'default' library: %s",
|
||||
delete_error,
|
||||
)
|
||||
else:
|
||||
try:
|
||||
settings_service.rename_library("default", "comfyui")
|
||||
libraries_changed = True
|
||||
logger.info("Renamed template 'default' library to 'comfyui'")
|
||||
except Exception as rename_error:
|
||||
logger.debug(
|
||||
"Failed to rename template 'default' library: %s",
|
||||
rename_error,
|
||||
)
|
||||
|
||||
if libraries_changed:
|
||||
libraries = settings_service.get_libraries()
|
||||
comfy_library = libraries.get("comfyui", {})
|
||||
default_library = libraries.get("default", {})
|
||||
|
||||
target_folder_paths = {
|
||||
'loras': list(self.loras_roots),
|
||||
'checkpoints': list(self.checkpoints_roots or []),
|
||||
@@ -90,9 +151,16 @@ class Config:
|
||||
|
||||
normalized_target_paths = _normalize_folder_paths_for_comparison(target_folder_paths)
|
||||
|
||||
if (not comfy_library and default_library and normalized_target_paths and
|
||||
_normalize_folder_paths_for_comparison(default_library.get("folder_paths", {})) ==
|
||||
normalized_target_paths):
|
||||
normalized_default_paths: Optional[Dict[str, Set[str]]] = None
|
||||
if isinstance(default_library, Mapping):
|
||||
normalized_default_paths = _normalize_library_folder_paths(default_library)
|
||||
|
||||
if (
|
||||
not comfy_library
|
||||
and default_library
|
||||
and normalized_target_paths
|
||||
and normalized_default_paths == normalized_target_paths
|
||||
):
|
||||
try:
|
||||
settings_service.rename_library("default", "comfyui")
|
||||
logger.info("Renamed legacy 'default' library to 'comfyui'")
|
||||
|
||||
@@ -6,7 +6,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from typing import Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from platformdirs import user_config_dir
|
||||
|
||||
@@ -124,3 +124,32 @@ def _should_use_portable_settings(path: str, logger: logging.Logger) -> bool:
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def load_settings_template() -> Optional[Dict[str, Any]]:
|
||||
"""Return the parsed contents of ``settings.json.example`` when available."""
|
||||
|
||||
template_path = os.path.join(get_project_root(), "settings.json.example")
|
||||
|
||||
try:
|
||||
with open(template_path, "r", encoding="utf-8") as handle:
|
||||
payload = json.load(handle)
|
||||
except FileNotFoundError:
|
||||
_LOGGER.debug("settings.json.example not found at %s", template_path)
|
||||
return None
|
||||
except json.JSONDecodeError as exc:
|
||||
_LOGGER.warning("Failed to parse settings.json.example: %s", exc)
|
||||
return None
|
||||
except OSError as exc:
|
||||
_LOGGER.warning(
|
||||
"Could not read settings.json.example at %s: %s", template_path, exc
|
||||
)
|
||||
return None
|
||||
|
||||
if not isinstance(payload, dict):
|
||||
_LOGGER.debug(
|
||||
"settings.json.example at %s does not contain a JSON object", template_path
|
||||
)
|
||||
return None
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ def test_save_paths_renames_default_library(monkeypatch: pytest.MonkeyPatch, tmp
|
||||
def __init__(self, default_paths: Dict[str, List[str]]):
|
||||
self._default_paths = default_paths
|
||||
self.rename_calls = []
|
||||
self.delete_calls = []
|
||||
self.upsert_calls = []
|
||||
self._renamed = False
|
||||
|
||||
@@ -62,6 +63,10 @@ def test_save_paths_renames_default_library(monkeypatch: pytest.MonkeyPatch, tmp
|
||||
self.rename_calls.append((old_name, new_name))
|
||||
self._renamed = True
|
||||
|
||||
def delete_library(self, name: str): # pragma: no cover - defensive guard
|
||||
self.delete_calls.append(name)
|
||||
raise AssertionError("delete_library should not be invoked in this scenario")
|
||||
|
||||
def upsert_library(self, name: str, **payload):
|
||||
self.upsert_calls.append((name, payload))
|
||||
|
||||
@@ -124,3 +129,89 @@ def test_save_paths_logs_warning_when_upsert_fails(
|
||||
assert isinstance(config_instance, config_module.Config)
|
||||
assert fake_settings.upsert_attempts and fake_settings.upsert_attempts[0][0] == "comfyui"
|
||||
assert "Failed to save folder paths: boom" in caplog.text
|
||||
|
||||
|
||||
def test_save_paths_removes_template_default_library(monkeypatch, tmp_path):
|
||||
folder_paths = _setup_config_environment(monkeypatch, tmp_path)
|
||||
|
||||
placeholder_paths = {
|
||||
"loras": [
|
||||
"C:/path/to/your/loras_folder",
|
||||
"C:/path/to/another/loras_folder",
|
||||
],
|
||||
"checkpoints": [
|
||||
"C:/path/to/your/checkpoints_folder",
|
||||
"C:/path/to/another/checkpoints_folder",
|
||||
],
|
||||
"embeddings": [
|
||||
"C:/path/to/your/embeddings_folder",
|
||||
"C:/path/to/another/embeddings_folder",
|
||||
],
|
||||
}
|
||||
|
||||
class FakeSettingsService:
|
||||
def __init__(self):
|
||||
self.libraries = {
|
||||
"default": {
|
||||
"folder_paths": placeholder_paths,
|
||||
"default_lora_root": "",
|
||||
"default_checkpoint_root": "",
|
||||
"default_embedding_root": "",
|
||||
}
|
||||
}
|
||||
self.rename_calls = []
|
||||
self.delete_calls = []
|
||||
self.upsert_calls = []
|
||||
|
||||
def get_libraries(self):
|
||||
return self.libraries
|
||||
|
||||
def rename_library(self, old_name: str, new_name: str):
|
||||
self.rename_calls.append((old_name, new_name))
|
||||
self.libraries[new_name] = self.libraries.pop(old_name)
|
||||
|
||||
def delete_library(self, name: str):
|
||||
self.delete_calls.append(name)
|
||||
self.libraries.pop(name, None)
|
||||
|
||||
def upsert_library(self, name: str, **payload):
|
||||
self.upsert_calls.append((name, payload))
|
||||
self.libraries[name] = {**payload}
|
||||
|
||||
fake_settings = FakeSettingsService()
|
||||
monkeypatch.setattr(settings_manager_module, "settings", fake_settings)
|
||||
|
||||
monkeypatch.setattr(
|
||||
config_module,
|
||||
"load_settings_template",
|
||||
lambda: {"folder_paths": placeholder_paths},
|
||||
)
|
||||
|
||||
config_instance = config_module.Config()
|
||||
|
||||
assert isinstance(config_instance, config_module.Config)
|
||||
assert fake_settings.rename_calls == [("default", "comfyui")]
|
||||
assert not fake_settings.delete_calls
|
||||
assert len(fake_settings.upsert_calls) == 1
|
||||
assert "default" not in fake_settings.libraries
|
||||
assert set(fake_settings.libraries.keys()) == {"comfyui"}
|
||||
|
||||
name, payload = fake_settings.upsert_calls[0]
|
||||
assert name == "comfyui"
|
||||
|
||||
expected_folder_paths = {
|
||||
key: [path.replace("\\", "/") for path in paths]
|
||||
for key, paths in folder_paths.items()
|
||||
}
|
||||
assert payload["folder_paths"] == expected_folder_paths
|
||||
assert payload["default_lora_root"] == folder_paths["loras"][0].replace("\\", "/")
|
||||
assert (
|
||||
payload["default_checkpoint_root"]
|
||||
== folder_paths["checkpoints"][0].replace("\\", "/")
|
||||
)
|
||||
assert (
|
||||
payload["default_embedding_root"]
|
||||
== folder_paths["embeddings"][0].replace("\\", "/")
|
||||
)
|
||||
assert payload["metadata"] == {"display_name": "ComfyUI", "source": "comfyui"}
|
||||
assert payload["activate"] is True
|
||||
|
||||
Reference in New Issue
Block a user