From 51b5261f4010423335ad2491721fb8fc034602cf Mon Sep 17 00:00:00 2001 From: Will Miao Date: Wed, 19 Nov 2025 11:20:09 +0800 Subject: [PATCH] fix(model): align rename extension detection --- py/services/model_lifecycle_service.py | 2 +- .../services/test_model_lifecycle_service.py | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/py/services/model_lifecycle_service.py b/py/services/model_lifecycle_service.py index 594c5f4b..0e0a2def 100644 --- a/py/services/model_lifecycle_service.py +++ b/py/services/model_lifecycle_service.py @@ -339,7 +339,7 @@ class ModelLifecycleService: return suffix basename = os.path.basename(filename) - dot_index = basename.find(".") + dot_index = basename.rfind(".") if dot_index != -1: return basename[dot_index:] diff --git a/tests/services/test_model_lifecycle_service.py b/tests/services/test_model_lifecycle_service.py index 65c63cf3..4817745c 100644 --- a/tests/services/test_model_lifecycle_service.py +++ b/tests/services/test_model_lifecycle_service.py @@ -243,6 +243,48 @@ async def test_rename_model_preserves_extension(tmp_path: Path): 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 async def test_delete_model_removes_gguf_file(tmp_path: Path): model_path = tmp_path / "model.gguf"