Convert GenericMetadata to a dataclass

dataclasses allow for simple comparison and object creation

Add more tests
This commit is contained in:
Timmy Welch 2022-07-01 16:12:29 -07:00
parent cb5b321539
commit 3d84af3746
5 changed files with 173 additions and 54 deletions

View File

@ -21,6 +21,7 @@ possible, however lossy it might be
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from typing import Any, TypedDict
from comicapi import utils
@ -64,6 +65,7 @@ class CreditMetadata(TypedDict):
primary: bool
@dataclass
class GenericMetadata:
writer_synonyms = ["writer", "plotter", "scripter"]
penciller_synonyms = ["artist", "penciller", "penciler", "breakdowns"]
@ -73,59 +75,63 @@ class GenericMetadata:
cover_synonyms = ["cover", "covers", "coverartist", "cover artist"]
editor_synonyms = ["editor"]
def __init__(self) -> None:
is_empty: bool = True
tag_origin: str | None = None
self.is_empty: bool = True
self.tag_origin: str | None = None
series: str | None = None
issue: str | None = None
title: str | None = None
publisher: str | None = None
month: int | None = None
year: int | None = None
day: int | None = None
issue_count: int | None = None
volume: int | None = None
genre: str | None = None
language: str | None = None # 2 letter iso code
comments: str | None = None # use same way as Summary in CIX
self.series: str | None = None
self.issue: str | None = None
self.title: str | None = None
self.publisher: str | None = None
self.month: int | None = None
self.year: int | None = None
self.day: int | None = None
self.issue_count: int | None = None
self.volume: int | None = None
self.genre: str | None = None
self.language: str | None = None # 2 letter iso code
self.comments: str | None = None # use same way as Summary in CIX
volume_count: int | None = None
critical_rating: float | None = None # rating in cbl; CommunityRating in CIX
country: str | None = None
self.volume_count: int | None = None
self.critical_rating: float | None = None # rating in cbl; CommunityRating in CIX
self.country: str | None = None
alternate_series: str | None = None
alternate_number: str | None = None
alternate_count: int | None = None
imprint: str | None = None
notes: str | None = None
web_link: str | None = None
format: str | None = None
manga: str | None = None
black_and_white: bool | None = None
page_count: int | None = None
maturity_rating: str | None = None
self.alternate_series: str | None = None
self.alternate_number: str | None = None
self.alternate_count: int | None = None
self.imprint: str | None = None
self.notes: str | None = None
self.web_link: str | None = None
self.format: str | None = None
self.manga: str | None = None
self.black_and_white: bool | None = None
self.page_count: int | None = None
self.maturity_rating: str | None = None
story_arc: str | None = None
series_group: str | None = None
scan_info: str | None = None
self.story_arc: str | None = None
self.series_group: str | None = None
self.scan_info: str | None = None
characters: str | None = None
teams: str | None = None
locations: str | None = None
self.characters: str | None = None
self.teams: str | None = None
self.locations: str | None = None
credits: list[CreditMetadata] = field(default_factory=list)
tags: list[str] = field(default_factory=list)
pages: list[ImageMetadata] = field(default_factory=list)
self.credits: list[CreditMetadata] = []
self.tags: list[str] = []
self.pages: list[ImageMetadata] = []
# Some CoMet-only items
price: str | None = None
is_version_of: str | None = None
rights: str | None = None
identifier: str | None = None
last_mark: str | None = None
cover_image: str | None = None
# Some CoMet-only items
self.price: str | None = None
self.is_version_of: str | None = None
self.rights: str | None = None
self.identifier: str | None = None
self.last_mark: str | None = None
self.cover_image: str | None = None
def __post_init__(self):
for key, value in self.__dict__.items():
if value and key != "is_empty":
self.is_empty = False
break
def overlay(self, new_md: GenericMetadata) -> None:
"""Overlay a metadata object on this one

View File

@ -48,9 +48,7 @@ def test_metadata_read():
thisdir / "data" / "Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz"
)
md = c.read_cix()
md_dict = md.__dict__
md_test_dict = comicapi.genericmetadata.md_test.__dict__
assert md_dict == md_test_dict
assert md == comicapi.genericmetadata.md_test
def test_save_cix(tmp_path):
@ -118,9 +116,7 @@ def test_copy_to_archive(archiver, tmp_path):
assert set(cbz.archiver.get_filename_list()) == set(comic_archive.archiver.get_filename_list())
md = comic_archive.read_cix()
md_dict = md.__dict__
md_test_dict = comicapi.genericmetadata.md_test.__dict__
assert md_dict == md_test_dict
assert md == comicapi.genericmetadata.md_test
md = comicapi.genericmetadata.GenericMetadata()
md.overlay(comicapi.genericmetadata.md_test)
@ -129,6 +125,4 @@ def test_copy_to_archive(archiver, tmp_path):
assert comic_archive.write_cix(md)
test_md = comic_archive.read_cix()
md_dict = md.__dict__
test_md_dict = test_md.__dict__
assert md_dict == test_md_dict
assert md == test_md

View File

@ -0,0 +1,62 @@
from __future__ import annotations
import dataclasses
import pytest
import comicapi.genericmetadata
@pytest.fixture
def md():
yield dataclasses.replace(comicapi.genericmetadata.md_test)
stuff = [
(
{"series": "test", "issue": "2", "title": "never"},
dataclasses.replace(comicapi.genericmetadata.md_test, series="test", issue="2", title="never"),
),
(
{"series": "", "issue": "2", "title": "never"},
dataclasses.replace(comicapi.genericmetadata.md_test, series=None, issue="2", title="never"),
),
(
{},
dataclasses.replace(comicapi.genericmetadata.md_test),
),
]
@pytest.mark.parametrize("replaced, expected", stuff)
def test_metadata_overlay(md: comicapi.genericmetadata.GenericMetadata, replaced, expected):
md_overlay = comicapi.genericmetadata.GenericMetadata(**replaced)
md.overlay(md_overlay)
assert md == expected
def test_add_credit():
md = comicapi.genericmetadata.GenericMetadata()
md.add_credit(person="test", role="writer", primary=False)
md.credits == [{"person": "test", "role": "writer", "primary": False}]
def test_add_credit_primary():
md = comicapi.genericmetadata.GenericMetadata()
md.add_credit(person="test", role="writer", primary=False)
md.add_credit(person="test", role="writer", primary=True)
md.credits == [{"person": "test", "role": "writer", "primary": True}]
credits = [
("writer", "Dara Naraghi"),
("writeR", "Dara Naraghi"),
]
@pytest.mark.parametrize("role, expected", credits)
def test_get_primary_credit(md, role, expected):
assert md.get_primary_credit(role) == expected

View File

@ -13,6 +13,7 @@ issues = [
("22.BEY", 22.0, "022.BEY"),
("22A", 22.0, "022A"),
("22-A", 22.0, "022-A"),
("", None, ""),
]

56
tests/utils_test.py Normal file
View File

@ -0,0 +1,56 @@
from __future__ import annotations
import pytest
import comicapi.utils
def test_recursive_list_with_file(tmp_path) -> None:
foo_png = tmp_path / "foo.png"
foo_png.write_text("not a png")
temp_folder = tmp_path / "bar"
temp_folder.mkdir()
temp_file = temp_folder / "test.cbz"
temp_file.write_text("not a zip")
temp_folder2 = tmp_path / "bar" / "baz" / "something else"
temp_folder2.mkdir(parents=True)
temp_cbr = temp_folder2 / "bar.cbr"
temp_cbr.write_text("not a rar")
temp_txt = tmp_path / "info.txt"
temp_txt.write_text("this is here")
expected_result = {str(foo_png), str(temp_cbr), str(temp_file), str(temp_txt)}
result = set(comicapi.utils.get_recursive_filelist([tmp_path]))
assert result == expected_result
values = [
({"data": "", "is_int": False, "is_float": False}, None),
({"data": None, "is_int": False, "is_float": False}, None),
({"data": None, "is_int": True, "is_float": False}, None),
({"data": " ", "is_int": True, "is_float": False}, None),
({"data": "", "is_int": True, "is_float": False}, None),
({"data": "9", "is_int": False, "is_float": False}, "9"),
({"data": 9, "is_int": False, "is_float": False}, "9"),
({"data": 9, "is_int": True, "is_float": False}, 9),
({"data": "9", "is_int": True, "is_float": False}, 9),
({"data": 9.3, "is_int": True, "is_float": False}, 9),
({"data": "9.3", "is_int": True, "is_float": False}, 9),
({"data": "9.", "is_int": True, "is_float": False}, 9),
({"data": " 9 . 3 l", "is_int": True, "is_float": False}, 9),
({"data": 9, "is_int": False, "is_float": True}, 9.0),
({"data": "9", "is_int": False, "is_float": True}, 9.0),
({"data": 9.3, "is_int": False, "is_float": True}, 9.3),
({"data": "9.3", "is_int": False, "is_float": True}, 9.3),
({"data": "9.", "is_int": False, "is_float": True}, 9.0),
({"data": " 9 . 3 l", "is_int": False, "is_float": True}, 9.3),
]
@pytest.mark.parametrize("value, result", values)
def test_xlate(value, result):
assert comicapi.utils.xlate(**value) == result