From c9540e868f57237f7306000591c8b44e2eb88bb5 Mon Sep 17 00:00:00 2001 From: Oleskii Pyskun Date: Mon, 1 Jul 2024 16:47:09 +0300 Subject: [PATCH] Refactoring of last commit --- cbz/comic.py | 112 ++++------------------------------------------- cbz/constants.py | 62 ++++++++++++++++++++++++++ cbz/models.py | 37 +++++++++++++++- 3 files changed, 106 insertions(+), 105 deletions(-) diff --git a/cbz/comic.py b/cbz/comic.py index 6fa830c..d81a95c 100644 --- a/cbz/comic.py +++ b/cbz/comic.py @@ -3,123 +3,26 @@ from __future__ import annotations import json import zipfile from io import BytesIO +from pathlib import Path from typing import Union import xmltodict -from langcodes import Language -from pathlib import Path from cbz import utils -from cbz.constants import YesNo, Manga, AgeRating, Format, xml_name +from cbz.constants import xml_name from cbz.models import ComicModel from cbz.page import PageInfo -def rating(value: int) -> int: - assert -1 <= value <= 5, 'Rating must be between 0 and 5' - return value - - -def language(value: str) -> str: - if value and not Language.get(value).is_valid(): - raise ValueError('Invalid language') - return value - - class ComicInfo(ComicModel): def __init__(self, pages: [PageInfo], **kwargs): self.__pages = pages - # TODO: need change to loop with setattr - self.title = str(kwargs.get('title', kwargs.get('Title', ''))) - self.series = str(kwargs.get('series', kwargs.get('Series', ''))) - self.number = str(kwargs.get('number', kwargs.get('Number', ''))) - self.count = int(kwargs.get('count', kwargs.get('Count', -1))) - self.volume = int(kwargs.get('volume', kwargs.get('Volume', -1))) - self.alternate_series = str(kwargs.get('alternate_series', kwargs.get('AlternateSeries', ''))) - self.alternate_number = str(kwargs.get('alternate_number', kwargs.get('AlternateNumber', ''))) - self.alternate_count = int(kwargs.get('alternate_count', kwargs.get('AlternateCount', -1))) - self.summary = str(kwargs.get('summary', kwargs.get('Summary', ''))) - self.notes = str(kwargs.get('notes', kwargs.get('Notes', ''))) - self.year = int(kwargs.get('year', kwargs.get('Year', -1))) - self.month = int(kwargs.get('month', kwargs.get('Month', -1))) - self.day = int(kwargs.get('day', kwargs.get('Day', -1))) - self.writer = str(kwargs.get('writer', kwargs.get('Writer', ''))) - self.penciller = str(kwargs.get('penciller', kwargs.get('Penciller', ''))) - self.inker = str(kwargs.get('inker', kwargs.get('Inker', ''))) - self.colorist = str(kwargs.get('colorist', kwargs.get('Colorist', ''))) - self.letterer = str(kwargs.get('letterer', kwargs.get('Letterer', ''))) - self.cover_artist = str(kwargs.get('cover_artist', kwargs.get('CoverArtist', ''))) - self.editor = str(kwargs.get('editor', kwargs.get('Editor', ''))) - self.translator = str(kwargs.get('translator', kwargs.get('Translator', ''))) - self.publisher = str(kwargs.get('publisher', kwargs.get('Publisher', ''))) - self.imprint = str(kwargs.get('imprint', kwargs.get('imprint', 'Imprint'))) - self.genre = str(kwargs.get('genre', kwargs.get('Genre', ''))) - self.tags = str(kwargs.get('tags', kwargs.get('Tags', ''))) - self.web = str(kwargs.get('web', kwargs.get('Web', ''))) - self.language_iso = language(kwargs.get('language_iso', kwargs.get('LanguageISO', ''))) - self.format = Format(kwargs.get('format', kwargs.get('Format', Format.UNKNOWN))) - self.ean = str(kwargs.get('ean', kwargs.get('EAN', ''))) - self.black_white = YesNo(kwargs.get('black_white', kwargs.get('BlackAndWhite', YesNo.UNKNOWN))) - self.manga = Manga(kwargs.get('manga', kwargs.get('Manga', Manga.UNKNOWN))) - self.characters = str(kwargs.get('characters', kwargs.get('Characters', ''))) - self.teams = str(kwargs.get('teams', kwargs.get('Teams', ''))) - self.locations = str(kwargs.get('locations', kwargs.get('Locations', ''))) - self.scan_information = str(kwargs.get('scan_information', kwargs.get('ScanInformation', ''))) - self.story_arc = str(kwargs.get('story_arc', kwargs.get('StoryArc', ''))) - self.story_arc_number = str(kwargs.get('story_arc_number', kwargs.get('StoryArcNumber', ''))) - self.series_group = str(kwargs.get('series_group', kwargs.get('series_group', ''))) - self.age_rating = AgeRating(kwargs.get('age_rating', kwargs.get('AgeRating', AgeRating.UNKNOWN))) - self.community_rating = rating(kwargs.get('community_rating', kwargs.get('CommunityRating', -1))) - self.main_character_or_team = str(kwargs.get('main_character_or_team', kwargs.get('MainCharacterOrTeam', ''))) - self.review = str(kwargs.get('review', kwargs.get('Review', ''))) + super(ComicInfo, self).__init__(kwargs) def dumps(self) -> dict: - # TODO: need change to loop with getattr - return utils.dumps({ - 'Title': str(self.title), - 'Series': str(self.series), - 'Number': str(self.number), - 'Count': int(self.count), - 'Volume': int(self.volume), - 'AlternateSeries': str(self.alternate_series), - 'AlternateNumber': str(self.alternate_number), - 'AlternateCount': int(self.alternate_count), - 'Summary': str(self.summary), - 'Notes': str(self.notes), - 'Year': int(self.year), - 'Month': int(self.month), - 'Day': int(self.day), - 'Writer': str(self.writer), - 'Penciller': str(self.penciller), - 'Inker': str(self.inker), - 'Colorist': str(self.colorist), - 'Letterer': str(self.letterer), - 'CoverArtist': str(self.cover_artist), - 'Editor': str(self.editor), - 'Translator': str(self.translator), - 'Publisher': str(self.publisher), - 'Imprint': str(self.imprint), - 'Genre': str(self.genre), - 'Tags': str(self.tags), - 'Web': str(self.web), - 'PageCount': len(self.__pages), - 'LanguageISO': language(self.language_iso), - 'Format': self.format, - 'EAN': str(self.ean), - 'BlackAndWhite': self.black_white, - 'Manga': self.manga, - 'Characters': str(self.characters), - 'Teams': str(self.teams), - 'Locations': str(self.locations), - 'ScanInformation': str(self.scan_information), - 'StoryArc': str(self.story_arc), - 'StoryArcNumber': str(self.story_arc_number), - 'SeriesGroup': str(self.series_group), - 'AgeRating': self.age_rating, - 'Pages': [{'Image': i, **page.dumps()} for i, page in enumerate(self.__pages)], - 'CommunityRating': rating(self.community_rating), - 'MainCharacterOrTeam': str(self.main_character_or_team), - 'Review': str(self.review) + return utils.dumps(self._get() | { + "Pages": [{'Image': i, **page.dumps()} for i, page in enumerate(self.__pages)], + 'PageCount': len(self.__pages) }) def __repr__(self) -> str: @@ -166,8 +69,9 @@ class ComicInfo(ComicModel): if not isinstance(path, (Path, str)): raise ValueError(f'Expecting Path object or path string, got {path!r}') self._filepath = path + new_file = self.pack() with Path(path).open(mode='wb') as f: - f.write(self.pack()) + f.write(new_file) def save(self) -> None: """ diff --git a/cbz/constants.py b/cbz/constants.py index 91b0991..622a170 100644 --- a/cbz/constants.py +++ b/cbz/constants.py @@ -1,4 +1,5 @@ from enum import Enum +from langcodes import Language xml_name = "ComicInfo.xml" @@ -100,3 +101,64 @@ class Format(Enum): WEB_COMIC = 'Web Comic' # YEAR_ONE = 'Year 1' YEAR_ONE = 'Year One' + + +class ValidRating(float): + def __init__(self, val): + assert -1 <= float(val) <= 5, f'Rating must be between 0 and 5, input {val}' + super(ValidRating, self).__init__() + + +class ValidLanguage(str): + def __init__(self, val): + if val and not Language.get(str(val)).is_valid(): + raise ValueError(f'Invalid {val} language') + super(ValidLanguage, self).__init__() + + +FIELDS = ( + # model: (key, xml key): (variable name, (expected type, second expected type,...)) + # in case of multiple expected formats, value cast to first type in tuple + (("title", "Title"), ("title", (str,))), + (("series", "Series"), ("series", (str,))), + (("number", "Number"), ("number", (str, int, float))), + (("count", "Count"), ("count", (int,))), + (("volume", "Volume"), ("volume", (int,))), + (("alternate_series", "AlternateSeries"), ("alternate_series", (str,))), + (("alternate_number", "AlternateNumber"), ("alternate_number", (str, int, float))), + (("alternate_count", "AlternateCount"), ("alternate_count", (int,))), + (("summary", "Summary"), ("summary", (str,))), + (("notes", "Notes"), ("notes", (str,))), + (("year", "Year"), ("year", (int,))), + (("month", "Month"), ("month", (int,))), + (("day", "Day"), ("day", (int,))), + (("writer", "Writer"), ("writer", (str,))), + (("penciller", "Penciller"), ("penciller", (str,))), + (("inker", "Inker"), ("inker", (str,))), + (("colorist", "Colorist"), ("colorist", (str,))), + (("letterer", "Letterer"), ("letterer", (str,))), + (("cover_artist", "CoverArtist"), ("cover_artist", (str,))), + (("editor", "Editor"), ("editor", (str,))), + (("translator", "Translator"), ("translator", (str,))), + (("publisher", "Publisher"), ("publisher", (str,))), + (("imprint", "Imprint"), ("imprint", (str,))), + (("genre", "Genre"), ("genre", (str,))), + (("tags", "Tags"), ("tags", (str,))), + (("web", "Web"), ("web", (str,))), + (("format", "Format"), ("format", (Format, str))), + (("ean", "EAN"), ("ean", (str,))), + (("black_white", "BlackAndWhite"), ("black_white", (YesNo, str))), + (("manga", "Manga"), ("manga", (Manga, str))), + (("characters", "Characters"), ("characters", (str,))), + (("teams", "Teams"), ("teams", (str,))), + (("locations", "Locations"), ("locations", (str,))), + (("scan_information", "ScanInformation"), ("scan_information", (str,))), + (("story_arc", "StoryArc"), ("story_arc", (str,))), + (("story_arc_number", "StoryArcNumber"), ("story_arc_number", (str,))), + (("series_group", "SeriesGroup"), ("series_group", (str,))), + (("age_rating", "AgeRating"), ("age_rating", (AgeRating, str))), + (("main_character_or_team", "MainCharacterOrTeam"), ("main_character_or_team", (str,))), + (("review", "Review"), ("review", (str,))), + (("language_iso", "LanguageISO"), ("language_iso", (ValidLanguage, str))), + (("community_rating", "CommunityRating"), ("community_rating", (ValidRating, float, int, str))), +) diff --git a/cbz/models.py b/cbz/models.py index d1b67d0..e602d12 100644 --- a/cbz/models.py +++ b/cbz/models.py @@ -1,4 +1,5 @@ -from cbz.constants import YesNo, Manga, AgeRating, Format +from cbz.constants import YesNo, Manga, AgeRating, Format, FIELDS +from typing import Any class ComicModel: @@ -45,3 +46,37 @@ class ComicModel: main_character_or_team: str = "" review: str = "" _filepath: str = "" + + def __init__(self, kwargs: dict): + """ + Set class variables from input dictionary, check types of input and cast values to correct type + :param kwargs: dictionary of input data + """ + for kwarg_key, kwarg_value in kwargs.items(): + for keys, values in FIELDS: + if kwarg_key in keys: + variable, types = values + if hasattr(self, variable): + setattr(self, variable, self._check_type(kwarg_key, kwarg_value, types)) + break + + @staticmethod + def _check_type(key: str, value: Any, types: tuple) -> Any: + """ + Check type of value, and cast this value to first type of the types + :param key: name of key of variable (using only for best error information) + :param value: value for a check + :param types: list of the allowed types + :return: value with new type + """ + if not isinstance(value, types): + raise ValueError( + f"Unexpected type of {key}, got: {type(value).__name__}, expected: {[i.__name__ for i in types]}") + return types[0](value) + + def _get(self) -> dict: + """ + Create dictionary from variables by FIELDS + :return: dictionary with variables value + """ + return {key[1]: self._check_type(value[0], getattr(self, value[0]), value[1]) for key, value in FIELDS}