fix(lora): detect LoraManager in ComfyUI's extra custom_nodes folders
Auto-detection looked only in ComfyUI's main custom_nodes folder (#144). It now also searches every custom_nodes folder ComfyUI registers through folder_paths, main folder first, skipping folders that cannot be read.
This commit is contained in:
+34
-11
@@ -82,23 +82,46 @@ def detect_lora_manager(custom_path: str = "") -> Optional[str]:
|
||||
if p.is_dir() and _looks_like_lora_manager(p):
|
||||
return str(p.resolve())
|
||||
|
||||
# 2. Auto-detect via custom_nodes (case-insensitive scan)
|
||||
# 2. Auto-detect in every custom_nodes folder (case-insensitive scan):
|
||||
# ComfyUI's own first, then the extra ones it registered (#144).
|
||||
folders = []
|
||||
root = find_comfyui_root()
|
||||
if root:
|
||||
custom_nodes = root / "custom_nodes"
|
||||
if custom_nodes.is_dir():
|
||||
for entry in custom_nodes.iterdir():
|
||||
if (
|
||||
entry.is_dir()
|
||||
and "lora" in entry.name.lower()
|
||||
and "manager" in entry.name.lower()
|
||||
and _looks_like_lora_manager(entry)
|
||||
):
|
||||
return str(entry.resolve())
|
||||
folders.append(root / "custom_nodes")
|
||||
folders.extend(custom_nodes_directories())
|
||||
seen = set()
|
||||
for custom_nodes in folders:
|
||||
key = os.path.normcase(os.path.abspath(str(custom_nodes)))
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
found = _lora_manager_in(Path(custom_nodes))
|
||||
if found:
|
||||
return found
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _lora_manager_in(custom_nodes: Path) -> Optional[str]:
|
||||
"""The LoraManager install directly under ``custom_nodes``, or None."""
|
||||
try:
|
||||
entries = sorted(custom_nodes.iterdir()) if custom_nodes.is_dir() else []
|
||||
except OSError:
|
||||
return None
|
||||
for entry in entries:
|
||||
try:
|
||||
if (
|
||||
entry.is_dir()
|
||||
and "lora" in entry.name.lower()
|
||||
and "manager" in entry.name.lower()
|
||||
and _looks_like_lora_manager(entry)
|
||||
):
|
||||
return str(entry.resolve())
|
||||
except OSError:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def _looks_like_lora_manager(path: Path) -> bool:
|
||||
"""Heuristic: does this directory look like a LoraManager install?"""
|
||||
# Must have __init__.py (ComfyUI extension) or README.md
|
||||
|
||||
@@ -817,9 +817,66 @@ class TestDetectLoraManager(unittest.TestCase):
|
||||
self.assertTrue(lora_utils._looks_like_lora_manager(lm))
|
||||
|
||||
def test_nothing_found(self):
|
||||
with patch.object(lora_utils, "find_comfyui_root", return_value=None):
|
||||
with (
|
||||
patch.object(lora_utils, "find_comfyui_root", return_value=None),
|
||||
patch.object(lora_utils, "custom_nodes_directories", return_value=[]),
|
||||
):
|
||||
self.assertIsNone(lora_utils.detect_lora_manager())
|
||||
|
||||
def test_auto_detects_in_an_extra_custom_nodes_folder(self):
|
||||
# #144: ComfyUI's main custom_nodes has no LoraManager; an extra
|
||||
# custom_nodes path registered through folder_paths (extra model
|
||||
# paths, --base-directory) has it.
|
||||
root = _make_comfy_root(self.tmp)
|
||||
extra = self.tmp / "shared_nodes"
|
||||
extra.mkdir()
|
||||
lm = _make_lora_manager(extra, "ComfyUI-Lora-Manager")
|
||||
fake = types.SimpleNamespace(
|
||||
base_path=str(root),
|
||||
get_folder_paths=lambda name: (
|
||||
[str(root / "custom_nodes"), str(extra)]
|
||||
if name == "custom_nodes"
|
||||
else []
|
||||
),
|
||||
)
|
||||
with (
|
||||
patch.dict(sys.modules, {"folder_paths": fake}),
|
||||
patch.object(lora_utils, "find_comfyui_root", return_value=root),
|
||||
):
|
||||
self.assertEqual(lora_utils.detect_lora_manager(), str(lm.resolve()))
|
||||
|
||||
def test_main_custom_nodes_wins_over_an_extra_folder(self):
|
||||
root = _make_comfy_root(self.tmp)
|
||||
main = _make_lora_manager(root / "custom_nodes")
|
||||
extra = self.tmp / "shared_nodes"
|
||||
extra.mkdir()
|
||||
_make_lora_manager(extra)
|
||||
with (
|
||||
patch.object(lora_utils, "find_comfyui_root", return_value=root),
|
||||
patch.object(
|
||||
lora_utils,
|
||||
"custom_nodes_directories",
|
||||
return_value=[(root / "custom_nodes").resolve(), extra.resolve()],
|
||||
),
|
||||
):
|
||||
self.assertEqual(lora_utils.detect_lora_manager(), str(main.resolve()))
|
||||
|
||||
def test_an_unreadable_extra_folder_is_skipped(self):
|
||||
root = _make_comfy_root(self.tmp)
|
||||
missing = self.tmp / "gone"
|
||||
extra = self.tmp / "shared_nodes"
|
||||
extra.mkdir()
|
||||
lm = _make_lora_manager(extra)
|
||||
with (
|
||||
patch.object(lora_utils, "find_comfyui_root", return_value=root),
|
||||
patch.object(
|
||||
lora_utils,
|
||||
"custom_nodes_directories",
|
||||
return_value=[missing, extra.resolve()],
|
||||
),
|
||||
):
|
||||
self.assertEqual(lora_utils.detect_lora_manager(), str(lm.resolve()))
|
||||
|
||||
|
||||
class TestFindLoraDirectories(unittest.TestCase):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user