"""A dataclass representing book data from the library system and catalogue.""" from __future__ import annotations import json from dataclasses import dataclass, field from typing import Any import regex @dataclass class BookData: """A dataclass representing the book object. Returns ------- self : BookData The book data object with attributes like title, author, year, etc. """ ppn: str | None = None title: str | None = None signature: str | None = None edition: str | None = None link: str | None = None isbn: str | list[str] | None = field(default_factory=list[str]) author: str | None = None language: str | list[str] | None = field(default_factory=list[str]) publisher: str | None = None place: str | None = None year: int | None = None pages: str | None = None library_location: str | None = None in_apparat: bool | None = False adis_idn: str | None = None old_book: Any | None = None media_type: str | None = None in_library: bool | None = None # whether the book is in the library or not libraries: list[str] | None = field(default_factory=list[str]) medianr: int | None = None # media number def __post_init__(self) -> None: """Run Post-initialization processing.""" self.library_location = ( str(self.library_location) if self.library_location else None ) if isinstance(self.language, list) and self.language: self.language = [lang.strip() for lang in self.language if lang.strip()] self.language = ",".join(self.language) self.year = regex.sub(r"[^\d]", "", str(self.year)) if self.year else None self.in_library = True if self.signature else False def from_dict(self, data: dict[str, Any]) -> BookData: for key, value in data.items(): setattr(self, key, value) return self def merge(self, other: BookData) -> BookData: for key, value in other.__dict__.items(): # merge lists, if the attribute is a list, extend it if isinstance(value, list): current_value = getattr(self, key) if current_value is None: current_value = [] elif not isinstance(current_value, list): current_value = [current_value] # extend the list with the new values, but only if they are not already in the list for v in value: if v not in current_value: current_value.append(v) setattr(self, key, current_value) if value is not None and ( getattr(self, key) is None or getattr(self, key) == "" ): setattr(self, key, value) # in language, drop all entries that are longer than 3 characters if isinstance(self.language, list): self.language = [lang for lang in self.language if len(lang) <= 4] return self @property def to_dict(self) -> str: """Convert the dataclass to a dictionary.""" data_dict = { key: value for key, value in self.__dict__.items() if value is not None } # remove old_book from data_dict data_dict.pop("old_book", None) return json.dumps(data_dict, ensure_ascii=False) def from_dataclass(self, dataclass: Any | None) -> None: if dataclass is None: return for key, value in dataclass.__dict__.items(): setattr(self, key, value) def get_book_type(self) -> str: if isinstance(self.media_type, str): if "Online" in self.pages: return "eBook" return "Druckausgabe" return None def from_string(self, data: str) -> BookData: ndata = json.loads(data) return BookData(**ndata) def from_LehmannsSearchResult(self, result: Any) -> BookData: self.title = result.title self.author = "; ".join(result.authors) if result.authors else None self.edition = str(result.edition) if result.edition else None self.link = result.url self.isbn = ( result.isbn13 if isinstance(result.isbn13, list) else [result.isbn13] if result.isbn13 else [] ) self.pages = str(result.pages) if result.pages else None self.publisher = result.publisher self.year = str(result.year) if result.year else None # self.pages = str(result.pages) if result.pages else None return self @property def edition_number(self) -> int | None: if self.edition is None: return 0 match = regex.search(r"(\d+)", self.edition) if match: return int(match.group(1)) return 0