mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
Merge pull request #686 from willmiao/fix/model-extension-delete-rename
fix(model): preserve original extension on rename
This commit is contained in:
@@ -234,16 +234,19 @@ class ModelLifecycleService:
|
|||||||
raise ValueError("Invalid characters in file name")
|
raise ValueError("Invalid characters in file name")
|
||||||
|
|
||||||
target_dir = os.path.dirname(file_path)
|
target_dir = os.path.dirname(file_path)
|
||||||
old_file_name = os.path.splitext(os.path.basename(file_path))[0]
|
base_name = os.path.basename(file_path)
|
||||||
new_file_path = os.path.join(target_dir, f"{new_file_name}.safetensors").replace(
|
old_file_name, old_extension = os.path.splitext(base_name)
|
||||||
os.sep, "/"
|
if not old_extension:
|
||||||
)
|
old_extension = ".safetensors"
|
||||||
|
new_file_path = os.path.join(
|
||||||
|
target_dir, f"{new_file_name}{old_extension}"
|
||||||
|
).replace(os.sep, "/")
|
||||||
|
|
||||||
if os.path.exists(new_file_path):
|
if os.path.exists(new_file_path):
|
||||||
raise ValueError("A file with this name already exists")
|
raise ValueError("A file with this name already exists")
|
||||||
|
|
||||||
patterns = [
|
patterns = [
|
||||||
f"{old_file_name}.safetensors",
|
f"{old_file_name}{old_extension}",
|
||||||
f"{old_file_name}.metadata.json",
|
f"{old_file_name}.metadata.json",
|
||||||
f"{old_file_name}.metadata.json.bak",
|
f"{old_file_name}.metadata.json.bak",
|
||||||
]
|
]
|
||||||
@@ -336,7 +339,7 @@ class ModelLifecycleService:
|
|||||||
return suffix
|
return suffix
|
||||||
|
|
||||||
basename = os.path.basename(filename)
|
basename = os.path.basename(filename)
|
||||||
dot_index = basename.find(".")
|
dot_index = basename.rfind(".")
|
||||||
if dot_index != -1:
|
if dot_index != -1:
|
||||||
return basename[dot_index:]
|
return basename[dot_index:]
|
||||||
|
|
||||||
|
|||||||
@@ -184,6 +184,107 @@ async def test_delete_model_updates_update_service(tmp_path: Path):
|
|||||||
assert update_service.calls == [("lora", 42, [1002])]
|
assert update_service.calls == [("lora", 42, [1002])]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_rename_model_preserves_extension(tmp_path: Path):
|
||||||
|
old_name = "model"
|
||||||
|
old_extension = ".gguf"
|
||||||
|
new_name = "model-renamed"
|
||||||
|
|
||||||
|
model_path = tmp_path / f"{old_name}{old_extension}"
|
||||||
|
model_path.write_bytes(b"model")
|
||||||
|
|
||||||
|
preview_path = tmp_path / f"{old_name}.preview.png"
|
||||||
|
preview_path.write_bytes(b"preview")
|
||||||
|
|
||||||
|
metadata_path = tmp_path / f"{old_name}.metadata.json"
|
||||||
|
metadata_payload = {
|
||||||
|
"file_name": old_name,
|
||||||
|
"file_path": model_path.as_posix(),
|
||||||
|
"preview_url": preview_path.as_posix(),
|
||||||
|
}
|
||||||
|
metadata_path.write_text(json.dumps(metadata_payload))
|
||||||
|
|
||||||
|
async def metadata_loader(path: str):
|
||||||
|
with open(path, "r", encoding="utf-8") as handle:
|
||||||
|
return json.load(handle)
|
||||||
|
|
||||||
|
scanner = DummyScanner()
|
||||||
|
metadata_manager = PassthroughMetadataManager()
|
||||||
|
service = ModelLifecycleService(
|
||||||
|
scanner=scanner,
|
||||||
|
metadata_manager=metadata_manager,
|
||||||
|
metadata_loader=metadata_loader,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await service.rename_model(
|
||||||
|
file_path=model_path.as_posix(),
|
||||||
|
new_file_name=new_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_main = tmp_path / f"{new_name}{old_extension}"
|
||||||
|
expected_metadata = tmp_path / f"{new_name}.metadata.json"
|
||||||
|
expected_preview = tmp_path / f"{new_name}.preview.png"
|
||||||
|
|
||||||
|
assert expected_main.exists()
|
||||||
|
assert not model_path.exists()
|
||||||
|
assert result["new_file_path"].endswith(f"{new_name}{old_extension}")
|
||||||
|
assert expected_preview.exists()
|
||||||
|
assert not preview_path.exists()
|
||||||
|
|
||||||
|
saved_metadata = json.loads(expected_metadata.read_text())
|
||||||
|
assert saved_metadata["file_name"] == new_name
|
||||||
|
assert saved_metadata["file_path"].endswith(f"{new_name}{old_extension}")
|
||||||
|
assert saved_metadata["preview_url"].endswith(f"{new_name}.preview.png")
|
||||||
|
|
||||||
|
assert scanner.calls
|
||||||
|
old_call_path, new_call_path, payload = scanner.calls[0]
|
||||||
|
assert old_call_path.endswith(f"{old_name}{old_extension}")
|
||||||
|
assert new_call_path.endswith(f"{new_name}{old_extension}")
|
||||||
|
assert payload["file_name"] == new_name
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_rename_model_with_dotted_basename(tmp_path: Path):
|
||||||
|
old_name = "model.v1"
|
||||||
|
old_extension = ".gguf"
|
||||||
|
new_name = "renamed-model"
|
||||||
|
|
||||||
|
model_path = tmp_path / f"{old_name}{old_extension}"
|
||||||
|
model_path.write_bytes(b"content")
|
||||||
|
|
||||||
|
metadata_path = tmp_path / f"{old_name}.metadata.json"
|
||||||
|
metadata_payload = {
|
||||||
|
"file_name": old_name,
|
||||||
|
"file_path": model_path.as_posix(),
|
||||||
|
}
|
||||||
|
metadata_path.write_text(json.dumps(metadata_payload))
|
||||||
|
|
||||||
|
async def metadata_loader(path: str):
|
||||||
|
with open(path, "r", encoding="utf-8") as handle:
|
||||||
|
return json.load(handle)
|
||||||
|
|
||||||
|
scanner = DummyScanner()
|
||||||
|
metadata_manager = PassthroughMetadataManager()
|
||||||
|
service = ModelLifecycleService(
|
||||||
|
scanner=scanner,
|
||||||
|
metadata_manager=metadata_manager,
|
||||||
|
metadata_loader=metadata_loader,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await service.rename_model(
|
||||||
|
file_path=model_path.as_posix(),
|
||||||
|
new_file_name=new_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_main = tmp_path / f"{new_name}{old_extension}"
|
||||||
|
assert expected_main.exists()
|
||||||
|
assert result["new_file_path"] == expected_main.as_posix()
|
||||||
|
assert any(p.endswith(f"{new_name}{old_extension}") for p in result["renamed_files"])
|
||||||
|
|
||||||
|
saved_metadata = json.loads((tmp_path / f"{new_name}.metadata.json").read_text())
|
||||||
|
assert saved_metadata["file_name"] == new_name
|
||||||
|
assert saved_metadata["file_path"].endswith(f"{new_name}{old_extension}")
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_delete_model_removes_gguf_file(tmp_path: Path):
|
async def test_delete_model_removes_gguf_file(tmp_path: Path):
|
||||||
model_path = tmp_path / "model.gguf"
|
model_path = tmp_path / "model.gguf"
|
||||||
|
|||||||
Reference in New Issue
Block a user