feat: improve civitai data handling and type safety, fixes #565

- Replace setdefault with get and explicit dict initialization in MetadataUpdater
- Change civitai field type from Optional[Dict] to Dict[str, Any] with default_factory
- Add None check and dict initialization in BaseModelMetadata.__post_init__
- Ensures civitai data is always a dictionary, preventing type errors and improving code reliability
This commit is contained in:
Will Miao
2025-10-14 16:03:33 +08:00
parent c48095d9c6
commit 3d98572a62
3 changed files with 48 additions and 3 deletions

View File

@@ -270,7 +270,12 @@ class MetadataUpdater:
"""
try:
await MetadataManager.hydrate_model_data(model_data)
civitai_data = model_data.setdefault('civitai', {})
civitai_data = model_data.get('civitai')
if not isinstance(civitai_data, dict):
civitai_data = {}
model_data['civitai'] = civitai_data
custom_images = civitai_data.get('customImages')
if not isinstance(custom_images, list):
@@ -446,4 +451,4 @@ class MetadataUpdater:
except Exception as e:
logger.error(f"Error parsing image metadata: {e}", exc_info=True)
return None
return None

View File

@@ -18,7 +18,7 @@ class BaseModelMetadata:
preview_nsfw_level: int = 0 # NSFW level of the preview image
notes: str = "" # Additional notes
from_civitai: bool = True # Whether from Civitai
civitai: Optional[Dict] = None # Civitai API data if available
civitai: Dict[str, Any] = field(default_factory=dict) # Civitai API data if available
tags: List[str] = None # Model tags
modelDescription: str = "" # Full model description
civitai_deleted: bool = False # Whether deleted from Civitai
@@ -31,6 +31,9 @@ class BaseModelMetadata:
def __post_init__(self):
# Initialize empty lists to avoid mutable default parameter issue
if self.civitai is None:
self.civitai = {}
if self.tags is None:
self.tags = []

View File

@@ -0,0 +1,37 @@
import json
import pytest
from py.utils.metadata_manager import MetadataManager
from py.utils.models import BaseModelMetadata
@pytest.mark.asyncio
async def test_base_model_metadata_sets_empty_civitai_dict():
metadata = BaseModelMetadata(
file_name="model",
model_name="Model",
file_path="/tmp/model.safetensors",
size=0,
modified=0.0,
sha256="deadbeef",
base_model="Unknown",
preview_url="",
)
assert metadata.civitai == {}
@pytest.mark.asyncio
async def test_create_default_metadata_uses_empty_civitai(tmp_path):
model_path = tmp_path / "example.safetensors"
model_path.write_bytes(b"stub")
metadata = await MetadataManager.create_default_metadata(str(model_path))
assert metadata is not None
assert metadata.civitai == {}
metadata_path = model_path.with_suffix(".metadata.json")
payload = json.loads(metadata_path.read_text(encoding="utf-8"))
assert payload.get("civitai") == {}