Merge pull request #6 from piskunqa/main

Refactoring of last commit
This commit is contained in:
hyugogirubato
2024-07-01 22:25:14 +02:00
committed by GitHub
3 changed files with 106 additions and 105 deletions
+8 -104
View File
@@ -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:
"""
+62
View File
@@ -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))),
)
+36 -1
View File
@@ -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}