comictagger/comicapi/merge.py

73 lines
1.7 KiB
Python
Raw Normal View History

2024-05-10 15:51:13 -07:00
from __future__ import annotations
import dataclasses
from collections.abc import Collection
from enum import auto
2024-05-10 15:51:13 -07:00
from typing import Any
from comicapi.utils import DefaultDict, StrEnum, norm_fold
2024-05-10 15:51:13 -07:00
@dataclasses.dataclass
class Credit:
person: str = ""
role: str = ""
primary: bool = False
2024-12-05 18:43:35 -08:00
language: str = "" # Should be ISO 639 language code
2024-05-10 15:51:13 -07:00
def __str__(self) -> str:
2024-12-05 18:43:35 -08:00
lang = ""
if self.language:
lang = f" [{self.language}]"
return f"{self.role}: {self.person}{lang}"
2024-05-10 15:51:13 -07:00
class Mode(StrEnum):
OVERLAY = auto()
ADD_MISSING = auto()
def merge_lists(old: Collection[Any], new: Collection[Any]) -> list[Any] | set[Any]:
"""Dedupes normalised (NFKD), casefolded values using 'new' values on collisions"""
if len(new) == 0:
return old if isinstance(old, set) else list(old)
if len(old) == 0:
return new if isinstance(new, set) else list(new)
# Create dict to preserve case
new_dict = {norm_fold(str(n)): n for n in new}
old_dict = {norm_fold(str(c)): c for c in old}
old_dict.update(new_dict)
if isinstance(old, set):
return set(old_dict.values())
return list(old_dict.values())
def overlay(old: Any, new: Any) -> Any:
"""overlay - When the `new` object is not empty, replace `old` with `new`."""
if new is None or (isinstance(new, Collection) and len(new) == 0):
2024-05-10 15:51:13 -07:00
return old
return new
attribute = DefaultDict(
{
Mode.OVERLAY: overlay,
Mode.ADD_MISSING: lambda old, new: overlay(new, old),
},
default=lambda x: overlay,
)
2024-05-10 15:51:13 -07:00
lists = DefaultDict(
2024-05-10 15:51:13 -07:00
{
Mode.OVERLAY: merge_lists,
Mode.ADD_MISSING: lambda old, new: merge_lists(new, old),
2024-05-10 15:51:13 -07:00
},
default=lambda x: overlay,
2024-05-10 15:51:13 -07:00
)