Add tests for IssueIdentifier
Change tags to a set from a string
Add copy and replace convenience functions on GenericMetadata
Update deprecated resampling code for Pillow
Change comicvine test data to be the same as the test comic
Cleanup tests
This commit is contained in:
Timmy Welch 2022-07-18 09:00:56 -07:00
parent 99030fae6b
commit 6e7660c3d9
12 changed files with 327 additions and 136 deletions

View File

@ -98,13 +98,11 @@ class ComicBookInfo:
metadata.critical_rating = utils.xlate(cbi["rating"], True)
metadata.credits = cbi["credits"]
metadata.tags = cbi["tags"]
metadata.tags = set(cbi["tags"]) if cbi["tags"] is not None else set()
# make sure credits and tags are at least empty lists and not None
if metadata.credits is None:
metadata.credits = []
if metadata.tags is None:
metadata.tags = []
# need the language string to be ISO
if metadata.language is not None:

View File

@ -20,8 +20,9 @@ possible, however lossy it might be
# limitations under the License.
from __future__ import annotations
import copy
import dataclasses
import logging
from dataclasses import dataclass, field
from typing import Any, TypedDict
from comicapi import utils
@ -65,7 +66,7 @@ class CreditMetadata(TypedDict):
primary: bool
@dataclass
@dataclasses.dataclass
class GenericMetadata:
writer_synonyms = ["writer", "plotter", "scripter"]
penciller_synonyms = ["artist", "penciller", "penciler", "breakdowns"]
@ -115,9 +116,9 @@ class GenericMetadata:
teams: str | None = None
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)
credits: list[CreditMetadata] = dataclasses.field(default_factory=list)
tags: set[str] = dataclasses.field(default_factory=set)
pages: list[ImageMetadata] = dataclasses.field(default_factory=list)
# Some CoMet-only items
price: str | None = None
@ -133,6 +134,14 @@ class GenericMetadata:
self.is_empty = False
break
def copy(self) -> GenericMetadata:
return copy.deepcopy(self)
def replace(self, /, **kwargs) -> GenericMetadata:
tmp = self.copy()
tmp.__dict__.update(kwargs)
return tmp
def overlay(self, new_md: GenericMetadata) -> None:
"""Overlay a metadata object on this one
@ -408,7 +417,7 @@ md_test.credits = [
CreditMetadata({"primary": False, "person": "Sam Kieth", "role": "Cover"}),
CreditMetadata({"primary": False, "person": "Ted Adams", "role": "Editor"}),
]
md_test.tags = []
md_test.tags = set()
md_test.pages = [
{"Image": 0, "ImageHeight": "1280", "ImageSize": "195977", "ImageWidth": "800", "Type": PageType.FrontCover},
{"Image": 1, "ImageHeight": "2039", "ImageSize": "611993", "ImageWidth": "1327"},

View File

@ -32,7 +32,7 @@ class CBLTransformer:
# helper funcs
def append_to_tags_if_unique(item: str) -> None:
if item.casefold() not in (tag.casefold() for tag in self.metadata.tags):
self.metadata.tags.append(item)
self.metadata.tags.add(item)
def add_string_list_to_tags(str_list: str | None) -> None:
if str_list:

View File

@ -49,7 +49,7 @@ class ImageHasher:
def average_hash(self) -> int:
try:
image = self.image.resize((self.width, self.height), Image.ANTIALIAS).convert("L")
image = self.image.resize((self.width, self.height), Image.Resampling.LANCZOS).convert("L")
except Exception:
logger.exception("average_hash error")
return 0

View File

@ -26,7 +26,7 @@ import pprint
import re
import sys
import webbrowser
from typing import Any, Callable, cast
from typing import Any, Callable, Iterable, cast
from urllib.parse import urlparse
import natsort
@ -944,8 +944,8 @@ Have fun!
tmp = self.teTags.toPlainText()
if tmp is not None:
def strip_list(i: list[str]) -> list[str]:
return [x.strip() for x in i]
def strip_list(i: Iterable[str]) -> set[str]:
return {x.strip() for x in i}
md.tags = strip_list(tmp.split(","))

View File

@ -1,7 +1,5 @@
from __future__ import annotations
import dataclasses
import comicapi.genericmetadata
import comictaggerlib.resulttypes
from comicapi import utils
@ -55,15 +53,48 @@ select_details = [
metadata = [
(
comicapi.genericmetadata.GenericMetadata(series="test", issue="2", title="never"),
dataclasses.replace(comicapi.genericmetadata.md_test, series="test", issue="2", title="never"),
comicapi.genericmetadata.md_test.replace(series="test", issue="2", title="never"),
),
(
comicapi.genericmetadata.GenericMetadata(series="", issue="2", title="never"),
dataclasses.replace(comicapi.genericmetadata.md_test, series=None, issue="2", title="never"),
comicapi.genericmetadata.md_test.replace(series=None, issue="2", title="never"),
),
(
comicapi.genericmetadata.GenericMetadata(),
dataclasses.replace(comicapi.genericmetadata.md_test),
comicapi.genericmetadata.md_test.copy(),
),
]
metadata_keys = [
(
comicapi.genericmetadata.GenericMetadata(),
{
"issue_count": 6,
"issue_number": "1",
"month": 10,
"series": "Cory Doctorow's Futuristic Tales of the Here and Now",
"year": 2007,
},
),
(
comicapi.genericmetadata.GenericMetadata(series="test"),
{
"issue_count": 6,
"issue_number": "1",
"month": 10,
"series": "test",
"year": 2007,
},
),
(
comicapi.genericmetadata.GenericMetadata(series="test", issue="3"),
{
"issue_count": 6,
"issue_number": "3",
"month": 10,
"series": "test",
"year": 2007,
},
),
]

View File

@ -22,16 +22,16 @@ cv_issue_result: dict[str, Any] = {
"status_code": 1,
"results": {
"aliases": None,
"api_detail_url": "https://comicvine.gamespot.com/api/issue/4000-311811/",
"api_detail_url": "https://comicvine.gamespot.com/api/issue/4000-140529/",
"associated_images": [],
"character_credits": [],
"character_died_in": [],
"concept_credits": [],
"cover_date": "2007-12-01",
"date_added": "2012-01-18 06:48:56",
"date_last_updated": "2012-01-18 17:27:48",
"cover_date": "2007-10-01",
"date_added": "2008-10-16 05:25:47",
"date_last_updated": "2010-06-09 18:05:49",
"deck": None,
"description": '<p><i>IDW Publishing continues to bring the stories of acclaimed science-fiction author Cory Doctorow to comics, this time offering up "Craphound." Despite the exoskeleton and mouth full of poisonous suckers, Jerry got along with the alien better than with most humans. In fact, Jerry had nicknamed him "Craphound", after their shared love of hunting for unique treasures at garage sales and thrift stores. They were buddies. That is, until Craphound found the old cowboy trunk. Adapted by Dara Naraghi (whose Lifelike debuts this month, too. See previous page for info), with a cover by Eisner-winning artist Paul Pope!</i></p>',
"description": "<i>For 12-year-old Anda, getting paid real money to kill the characters of players who were cheating in her favorite online computer game was a win-win situation. Until she found out who was paying her, and what those characters meant to the livelihood of children around the world.</i>",
"first_appearance_characters": None,
"first_appearance_concepts": None,
"first_appearance_locations": None,
@ -39,22 +39,22 @@ cv_issue_result: dict[str, Any] = {
"first_appearance_storyarcs": None,
"first_appearance_teams": None,
"has_staff_review": False,
"id": 311811,
"id": 140529,
"image": {
"icon_url": "https://comicvine.gamespot.com/a/uploads/square_avatar/11/115179/2165551-cd3.jpg",
"medium_url": "https://comicvine.gamespot.com/a/uploads/scale_medium/11/115179/2165551-cd3.jpg",
"screen_url": "https://comicvine.gamespot.com/a/uploads/screen_medium/11/115179/2165551-cd3.jpg",
"screen_large_url": "https://comicvine.gamespot.com/a/uploads/screen_kubrick/11/115179/2165551-cd3.jpg",
"small_url": "https://comicvine.gamespot.com/a/uploads/scale_small/11/115179/2165551-cd3.jpg",
"super_url": "https://comicvine.gamespot.com/a/uploads/scale_large/11/115179/2165551-cd3.jpg",
"thumb_url": "https://comicvine.gamespot.com/a/uploads/scale_avatar/11/115179/2165551-cd3.jpg",
"tiny_url": "https://comicvine.gamespot.com/a/uploads/square_mini/11/115179/2165551-cd3.jpg",
"original_url": "https://comicvine.gamespot.com/a/uploads/original/11/115179/2165551-cd3.jpg",
"icon_url": "https://comicvine.gamespot.com/a/uploads/square_avatar/0/574/585444-109004_20080707014047_large.jpg",
"medium_url": "https://comicvine.gamespot.com/a/uploads/scale_medium/0/574/585444-109004_20080707014047_large.jpg",
"screen_url": "https://comicvine.gamespot.com/a/uploads/screen_medium/0/574/585444-109004_20080707014047_large.jpg",
"screen_large_url": "https://comicvine.gamespot.com/a/uploads/screen_kubrick/0/574/585444-109004_20080707014047_large.jpg",
"small_url": "https://comicvine.gamespot.com/a/uploads/scale_small/0/574/585444-109004_20080707014047_large.jpg",
"super_url": "https://comicvine.gamespot.com/a/uploads/scale_large/0/574/585444-109004_20080707014047_large.jpg",
"thumb_url": "https://comicvine.gamespot.com/a/uploads/scale_avatar/0/574/585444-109004_20080707014047_large.jpg",
"tiny_url": "https://comicvine.gamespot.com/a/uploads/square_mini/0/574/585444-109004_20080707014047_large.jpg",
"original_url": "https://comicvine.gamespot.com/a/uploads/original/0/574/585444-109004_20080707014047_large.jpg",
"image_tags": "All Images",
},
"issue_number": "3",
"issue_number": "1",
"location_credits": [],
"name": "Craphound",
"name": "Anda's Game",
"object_credits": [],
"person_credits": [
{
@ -65,14 +65,35 @@ cv_issue_result: dict[str, Any] = {
"role": "writer",
},
{
"api_detail_url": "https://comicvine.gamespot.com/api/person/4040-4306/",
"id": 4306,
"name": "Paul Pope",
"site_detail_url": "https://comicvine.gamespot.com/paul-pope/4040-4306/",
"api_detail_url": "https://comicvine.gamespot.com/api/person/4040-57222/",
"id": 57222,
"name": "Esteve Polls",
"site_detail_url": "https://comicvine.gamespot.com/esteve-polls/4040-57222/",
"role": "artist",
},
{
"api_detail_url": "https://comicvine.gamespot.com/api/person/4040-48472/",
"id": 48472,
"name": "Neil Uyetake",
"site_detail_url": "https://comicvine.gamespot.com/neil-uyetake/4040-48472/",
"role": "letterer",
},
{
"api_detail_url": "https://comicvine.gamespot.com/api/person/4040-5329/",
"id": 5329,
"name": "Sam Kieth",
"site_detail_url": "https://comicvine.gamespot.com/sam-kieth/4040-5329/",
"role": "cover",
},
{
"api_detail_url": "https://comicvine.gamespot.com/api/person/4040-58534/",
"id": 58534,
"name": "Ted Adams",
"site_detail_url": "https://comicvine.gamespot.com/ted-adams/4040-58534/",
"role": "editor",
},
],
"site_detail_url": "https://comicvine.gamespot.com/cory-doctorows-futuristic-tales-of-the-here-and-no/4000-311811/",
"site_detail_url": "https://comicvine.gamespot.com/cory-doctorows-futuristic-tales-of-the-here-and-no/4000-140529/",
"store_date": None,
"story_arc_credits": [],
"team_credits": [],
@ -95,15 +116,33 @@ cv_volume_result: dict[str, Any] = {
"number_of_total_results": 1,
"status_code": 1,
"results": {
"count_of_issues": 6,
"id": 23437,
"name": "Cory Doctorow's Futuristic Tales of the Here and Now",
"aliases": None,
"api_detail_url": "https://comicvine.gamespot.com/api/volume/4050-23437/",
"count_of_issues": 6,
"date_added": "2008-10-16 05:25:47",
"date_last_updated": "2012-01-18 17:21:57",
"deck": None,
"description": "<p>Writer and <em>BoingBoing.net</em> co-editor <strong>Cory Doctorow</strong> has won acclaim for his science-fiction writing as well as his Creative Commons presentation of his material. Now, IDW Publishing is proud to present six standalone stories adapted from Doctorow's work, each featuring cover art by some of comics' top talents.</p>",
"id": 23437,
"image": {
"icon_url": "https://comicvine.gamespot.com/a/uploads/square_avatar/0/574/585444-109004_20080707014047_large.jpg",
"medium_url": "https://comicvine.gamespot.com/a/uploads/scale_medium/0/574/585444-109004_20080707014047_large.jpg",
"screen_url": "https://comicvine.gamespot.com/a/uploads/screen_medium/0/574/585444-109004_20080707014047_large.jpg",
"screen_large_url": "https://comicvine.gamespot.com/a/uploads/screen_kubrick/0/574/585444-109004_20080707014047_large.jpg",
"small_url": "https://comicvine.gamespot.com/a/uploads/scale_small/0/574/585444-109004_20080707014047_large.jpg",
"super_url": "https://comicvine.gamespot.com/a/uploads/scale_large/0/574/585444-109004_20080707014047_large.jpg",
"thumb_url": "https://comicvine.gamespot.com/a/uploads/scale_avatar/0/574/585444-109004_20080707014047_large.jpg",
"tiny_url": "https://comicvine.gamespot.com/a/uploads/square_mini/0/574/585444-109004_20080707014047_large.jpg",
"original_url": "https://comicvine.gamespot.com/a/uploads/original/0/574/585444-109004_20080707014047_large.jpg",
"image_tags": "All Images",
},
"name": "Cory Doctorow's Futuristic Tales of the Here and Now",
"publisher": {
"api_detail_url": "https://comicvine.gamespot.com/api/publisher/4010-1190/",
"id": 1190,
"name": "IDW Publishing",
},
"site_detail_url": "https://comicvine.gamespot.com/cory-doctorows-futuristic-tales-of-the-here-and-no/4050-23437/",
"start_year": "2007",
},
"version": "1.0",
@ -143,7 +182,7 @@ cv_md = comicapi.genericmetadata.GenericMetadata(
alternate_number=None,
alternate_count=None,
imprint=None,
notes="Tagged with ComicTagger 1.4.4a9.dev20 using info from Comic Vine on 2022-07-11 17:42:41. [Issue ID 311811]",
notes="Tagged with ComicTagger 1.4.4a9.dev20 using info from Comic Vine on 2022-07-11 17:42:41. [Issue ID 140529]",
web_link=cv_issue_result["results"]["site_detail_url"],
format=None,
manga=None,
@ -157,18 +196,10 @@ cv_md = comicapi.genericmetadata.GenericMetadata(
teams="",
locations="",
credits=[
{
"person": cv_issue_result["results"]["person_credits"][0]["name"],
"role": cv_issue_result["results"]["person_credits"][0]["role"].title(),
"primary": False,
},
{
"person": cv_issue_result["results"]["person_credits"][1]["name"],
"role": cv_issue_result["results"]["person_credits"][1]["role"].title(),
"primary": False,
},
comicapi.genericmetadata.CreditMetadata(person=x["name"], role=x["role"].title(), primary=False)
for x in cv_issue_result["results"]["person_credits"]
],
tags=[],
tags=set(),
pages=[],
price=None,
is_version_of=None,
@ -182,10 +213,10 @@ cv_md = comicapi.genericmetadata.GenericMetadata(
class MockResponse:
"""Mocks the response object from requests"""
def __init__(self, result: dict[str, Any]) -> None:
def __init__(self, result: dict[str, Any], content=None) -> None:
self.status_code = 200
self.result = result
self.content = content
# mock json() method always returns a specific testing dictionary
def json(self) -> dict[str, list]:
return self.result

View File

@ -6,7 +6,7 @@ import pytest
import comicapi.comicarchive
import comicapi.genericmetadata
from testing.filenames import cbz_path, datadir
from testing.filenames import datadir
@pytest.mark.xfail(not comicapi.comicarchive.rar_support, reason="rar support")
@ -35,43 +35,31 @@ def test_metadata_read(cbz):
assert md == comicapi.genericmetadata.md_test
def test_save_cix(tmp_path):
comic_path = tmp_path / cbz_path.name
shutil.copy(cbz_path, comic_path)
def test_save_cix(tmp_comic):
md = tmp_comic.read_cix()
md.set_default_page_list(tmp_comic.get_number_of_pages())
c = comicapi.comicarchive.ComicArchive(comic_path)
md = c.read_cix()
md.set_default_page_list(c.get_number_of_pages())
assert tmp_comic.write_cix(md)
assert c.write_cix(md)
md = c.read_cix()
md = tmp_comic.read_cix()
def test_page_type_save(tmp_path):
comic_path = tmp_path / cbz_path.name
shutil.copy(cbz_path, comic_path)
c = comicapi.comicarchive.ComicArchive(comic_path)
md = c.read_cix()
def test_page_type_save(tmp_comic):
md = tmp_comic.read_cix()
t = md.pages[0]
t["Type"] = ""
assert c.write_cix(md)
assert tmp_comic.write_cix(md)
md = c.read_cix()
md = tmp_comic.read_cix()
def test_invalid_zip(tmp_path):
comic_path = tmp_path / cbz_path.name
def test_invalid_zip(tmp_comic):
with open(tmp_comic.path, mode="b+r") as f:
f.write(b"PK\000\000")
with open(cbz_path, mode="b+r") as f:
comic_path.write_bytes(b"PK\003\004" + f.read()[4:].replace(b"PK\003\004", b"PK\000\000"))
c = comicapi.comicarchive.ComicArchive(comic_path)
assert not c.write_cix(comicapi.genericmetadata.md_test)
result = tmp_comic.write_cix(comicapi.genericmetadata.md_test)
assert not result
archivers = [
@ -86,7 +74,7 @@ archivers = [
@pytest.mark.parametrize("archiver", archivers)
def test_copy_to_archive(archiver, tmp_path, cbz):
def test_copy_from_archive(archiver, tmp_path, cbz):
comic_path = tmp_path / cbz.path.with_suffix("").name
archive = archiver(comic_path)
@ -100,12 +88,3 @@ def test_copy_to_archive(archiver, tmp_path, cbz):
md = comic_archive.read_cix()
assert md == comicapi.genericmetadata.md_test
md = comicapi.genericmetadata.GenericMetadata()
md.overlay(comicapi.genericmetadata.md_test)
md.series = "test"
assert comic_archive.write_cix(md)
test_md = comic_archive.read_cix()
assert md == test_md

View File

@ -8,71 +8,86 @@ import testing.comicvine
from testing.comicdata import select_details
def test_fetch_volume_data(comicvine_api, settings, mock_now, comic_cache):
def test_search_for_series(comicvine_api, comic_cache):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
volume = ct.fetch_volume_data(23437)
volume["start_year"] = int(volume["start_year"])
del volume["publisher"]["id"]
del volume["publisher"]["api_detail_url"]
assert volume == comic_cache.get_volume_info(23437, ct.source_name)
results = ct.search_for_series("cory doctorows futuristic tales of the here and now")
for r in results:
r["image"] = {"super_url": r["image"]["super_url"]}
r["start_year"] = int(r["start_year"])
del r["publisher"]["id"]
del r["publisher"]["api_detail_url"]
cache_issues = comic_cache.get_search_results(ct.source_name, "cory doctorows futuristic tales of the here and now")
assert results == cache_issues
def test_fetch_issues_by_volume(comicvine_api, settings, comic_cache):
def test_fetch_volume_data(comicvine_api, comic_cache):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
issues = ct.fetch_issues_by_volume(23437)
result = ct.fetch_volume_data(23437)
result["start_year"] = int(result["start_year"])
del result["publisher"]["id"]
del result["publisher"]["api_detail_url"]
assert result == comic_cache.get_volume_info(23437, ct.source_name)
def test_fetch_issues_by_volume(comicvine_api, comic_cache):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
results = ct.fetch_issues_by_volume(23437)
cache_issues = comic_cache.get_volume_issues_info(23437, ct.source_name)
issues[0]["image"] = {"super_url": issues[0]["image"]["super_url"], "thumb_url": issues[0]["image"]["thumb_url"]}
del issues[0]["volume"]
assert issues == cache_issues
for r in results:
r["image"] = {"super_url": r["image"]["super_url"], "thumb_url": r["image"]["thumb_url"]}
del r["volume"]
assert results == cache_issues
def test_fetch_issue_data_by_issue_id(comicvine_api, settings, mock_now, mock_version):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
md = ct.fetch_issue_data_by_issue_id(311811, settings)
assert md == testing.comicvine.cv_md
result = ct.fetch_issue_data_by_issue_id(140529, settings)
assert result == testing.comicvine.cv_md
def test_fetch_issues_by_volume_issue_num_and_year(comicvine_api):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
cv = ct.fetch_issues_by_volume_issue_num_and_year([23437], "3", None)
results = ct.fetch_issues_by_volume_issue_num_and_year([23437], "1", None)
cv_expected = testing.comicvine.cv_issue_result["results"].copy()
testing.comicvine.filter_field_list(
cv_expected,
{"params": {"field_list": "id,volume,issue_number,name,image,cover_date,site_detail_url,description,aliases"}},
)
assert cv[0] == cv_expected
for r, e in zip(results, [cv_expected]):
assert r == e
cv_issue = [
(23437, "3", testing.comicvine.cv_md),
(23437, "", comicapi.genericmetadata.GenericMetadata()),
(23437, "", testing.comicvine.cv_md),
(23437, "1", testing.comicvine.cv_md),
(23437, "0", comicapi.genericmetadata.GenericMetadata()),
]
@pytest.mark.parametrize("volume_id, issue_number, result_md", cv_issue)
def test_fetch_issue_data(comicvine_api, settings, mock_now, mock_version, volume_id, issue_number, result_md):
@pytest.mark.parametrize("volume_id, issue_number, expected", cv_issue)
def test_fetch_issue_data(comicvine_api, settings, mock_now, mock_version, volume_id, issue_number, expected):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
md = ct.fetch_issue_data(volume_id, issue_number, settings)
assert md == result_md
results = ct.fetch_issue_data(volume_id, issue_number, settings)
assert results == expected
# @pytest.mark.parametrize("volume_id, issue_number, result_md", cv_issue)
def test_fetch_issue_select_details(comicvine_api, settings, mock_now, mock_version):
def test_fetch_issue_select_details(comicvine_api, mock_now, mock_version):
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
md = ct.fetch_issue_select_details(311811)
res = {
result = ct.fetch_issue_select_details(140529)
expected = {
"cover_date": testing.comicvine.cv_issue_result["results"]["cover_date"],
"site_detail_url": testing.comicvine.cv_issue_result["results"]["site_detail_url"],
"image_url": testing.comicvine.cv_issue_result["results"]["image"]["super_url"],
"thumb_image_url": testing.comicvine.cv_issue_result["results"]["image"]["thumb_url"],
}
assert md == res
assert result == expected
@pytest.mark.parametrize("details", select_details)
def test_issue_select_details(comic_cache, details):
expected = details.copy()
del expected["issue_id"]
ct = comictaggerlib.comicvinetalker.ComicVineTalker()
ct.cache_issue_select_details(
issue_id=details["issue_id"],
@ -81,6 +96,6 @@ def test_issue_select_details(comic_cache, details):
cover_date=details["cover_date"],
page_url=details["site_detail_url"],
)
det = details.copy()
del det["issue_id"]
assert det == comic_cache.get_issue_select_details(details["issue_id"], ct.source_name)
result = comic_cache.get_issue_select_details(details["issue_id"], ct.source_name)
assert result == expected

View File

@ -1,12 +1,15 @@
from __future__ import annotations
import dataclasses
import copy
import datetime
import io
import shutil
import unittest.mock
from typing import Any, Generator
import pytest
import requests
from PIL import Image
import comicapi.comicarchive
import comicapi.genericmetadata
@ -23,6 +26,27 @@ def cbz():
yield comicapi.comicarchive.ComicArchive(filenames.cbz_path)
@pytest.fixture
def tmp_comic(tmp_path):
shutil.copy(filenames.cbz_path, tmp_path)
yield comicapi.comicarchive.ComicArchive(tmp_path / filenames.cbz_path.name)
@pytest.fixture
def cbz_double_cover(tmp_path, tmp_comic):
cover = Image.open(io.BytesIO(tmp_comic.get_page(0)))
other_page = Image.open(io.BytesIO(tmp_comic.get_page(tmp_comic.get_number_of_pages() - 1)))
double_cover = Image.new("RGB", (cover.width * 2, cover.height))
double_cover.paste(other_page, (0, 0))
double_cover.paste(cover, (cover.width, 0))
tmp_comic.archiver.write_file("double_cover.jpg", double_cover.tobytes("jpeg", "RGB"))
yield tmp_comic
@pytest.fixture(autouse=True)
def no_requests(monkeypatch) -> None:
"""Remove requests.sessions.Session.request for all tests."""
@ -30,16 +54,24 @@ def no_requests(monkeypatch) -> None:
@pytest.fixture
def comicvine_api(monkeypatch) -> unittest.mock.Mock:
def comicvine_api(monkeypatch, cbz, comic_cache) -> unittest.mock.Mock:
# Any arguments may be passed and mock_get() will always return our
# mocked object, which only has the .json() method or None for invalid urls.
def make_list(cv_result):
cv_list = copy.deepcopy(cv_result)
if isinstance(cv_list["results"], dict):
cv_list["results"] = [cv_list["results"]]
return cv_list
def mock_get(*args, **kwargs):
if args:
if args[0].startswith("https://comicvine.gamespot.com/api/volume/4050-23437"):
return comicvine.MockResponse(comicvine.cv_volume_result)
if args[0].startswith("https://comicvine.gamespot.com/api/issue/4000-311811"):
cv_result = copy.deepcopy(comicvine.cv_volume_result)
comicvine.filter_field_list(cv_result["results"], kwargs)
return comicvine.MockResponse(cv_result)
if args[0].startswith("https://comicvine.gamespot.com/api/issue/4000-140529"):
return comicvine.MockResponse(comicvine.cv_issue_result)
if (
args[0].startswith("https://comicvine.gamespot.com/api/issues/")
@ -47,11 +79,32 @@ def comicvine_api(monkeypatch) -> unittest.mock.Mock:
and "filter" in kwargs["params"]
and "23437" in kwargs["params"]["filter"]
):
cv_list = comicvine.cv_issue_result.copy()
cv_list["results"] = cv_list["results"].copy()
comicvine.filter_field_list(cv_list["results"], kwargs)
cv_list["results"] = [cv_list["results"]]
cv_list = make_list(comicvine.cv_issue_result)
for cv in cv_list["results"]:
comicvine.filter_field_list(cv, kwargs)
return comicvine.MockResponse(cv_list)
if (
args[0].startswith("https://comicvine.gamespot.com/api/search")
and "params" in kwargs
and "resources" in kwargs["params"]
and "volume" == kwargs["params"]["resources"]
):
cv_list = make_list(comicvine.cv_volume_result)
for cv in cv_list["results"]:
comicvine.filter_field_list(cv, kwargs)
return comicvine.MockResponse(cv_list)
if (
args[0]
== "https://comicvine.gamespot.com/a/uploads/scale_large/0/574/585444-109004_20080707014047_large.jpg"
):
return comicvine.MockResponse({}, cbz.get_page(0))
if (
args[0]
== "https://comicvine.gamespot.com/a/uploads/scale_avatar/0/574/585444-109004_20080707014047_large.jpg"
):
thumb = Image.open(io.BytesIO(cbz.get_page(0)))
thumb.resize((105, 160), Image.Resampling.LANCZOS)
return comicvine.MockResponse({}, thumb.tobytes("jpeg", "RGB"))
return comicvine.MockResponse(comicvine.cv_not_found)
m_get = unittest.mock.Mock(side_effect=mock_get)
@ -86,7 +139,7 @@ def mock_version(monkeypatch):
@pytest.fixture
def md():
yield dataclasses.replace(comicapi.genericmetadata.md_test)
yield comicapi.genericmetadata.md_test.copy()
# manually seeds publishers

View File

@ -26,7 +26,7 @@ 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}]
assert md.credits == [comicapi.genericmetadata.CreditMetadata(person="test", role="writer", primary=False)]
def test_add_credit_primary():
@ -34,7 +34,7 @@ def test_add_credit_primary():
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}]
assert md.credits == [comicapi.genericmetadata.CreditMetadata(person="test", role="writer", primary=True)]
@pytest.mark.parametrize("role, expected", credits)

View File

@ -0,0 +1,75 @@
from __future__ import annotations
import pytest
import comicapi.comicarchive
import comicapi.issuestring
import comictaggerlib.comicvinetalker
import comictaggerlib.issueidentifier
import testing.comicdata
import testing.comicvine
def test_crop(cbz_double_cover, settings, tmp_path):
ii = comictaggerlib.issueidentifier.IssueIdentifier(cbz_double_cover, settings)
cropped = ii.crop_cover(cbz_double_cover.archiver.read_file("double_cover.jpg"))
original_cover = cbz_double_cover.get_page(0)
original_hash = ii.calculate_hash(original_cover)
cropped_hash = ii.calculate_hash(cropped)
assert original_hash == cropped_hash
@pytest.mark.parametrize("additional_md, expected", testing.comicdata.metadata_keys)
def test_get_search_keys(cbz, settings, additional_md, expected):
ii = comictaggerlib.issueidentifier.IssueIdentifier(cbz, settings)
ii.set_additional_metadata(additional_md)
assert expected == ii.get_search_keys()
def test_get_issue_cover_match_score(cbz, settings, comicvine_api):
ii = comictaggerlib.issueidentifier.IssueIdentifier(cbz, settings)
score = ii.get_issue_cover_match_score(
comictaggerlib.comicvinetalker.ComicVineTalker(),
int(
comicapi.issuestring.IssueString(
cbz.read_metadata(comicapi.comicarchive.MetaDataStyle.CIX).issue
).as_float()
),
"https://comicvine.gamespot.com/a/uploads/scale_large/0/574/585444-109004_20080707014047_large.jpg",
"https://comicvine.gamespot.com/a/uploads/scale_avatar/0/574/585444-109004_20080707014047_large.jpg",
"https://comicvine.gamespot.com/cory-doctorows-futuristic-tales-of-the-here-and-no/4000-140529/",
[ii.calculate_hash(cbz.get_page(0))],
)
expected = {
"hash": 1747255366011518976,
"score": 0,
"url": "https://comicvine.gamespot.com/a/uploads/scale_large/0/574/585444-109004_20080707014047_large.jpg",
}
assert expected == score
def test_search(cbz, settings, comicvine_api):
ii = comictaggerlib.issueidentifier.IssueIdentifier(cbz, settings)
results = ii.search()
cv_expected = {
"series": f"{testing.comicvine.cv_volume_result['results']['name']} ({testing.comicvine.cv_volume_result['results']['start_year']})",
"distance": 0,
"issue_number": testing.comicvine.cv_issue_result["results"]["issue_number"],
"cv_issue_count": testing.comicvine.cv_volume_result["results"]["count_of_issues"],
"issue_title": testing.comicvine.cv_issue_result["results"]["name"],
"issue_id": testing.comicvine.cv_issue_result["results"]["id"],
"volume_id": testing.comicvine.cv_volume_result["results"]["id"],
"month": testing.comicvine.date[1],
"year": testing.comicvine.date[2],
"publisher": testing.comicvine.cv_volume_result["results"]["publisher"]["name"],
"image_url": testing.comicvine.cv_issue_result["results"]["image"]["super_url"],
"thumb_url": testing.comicvine.cv_issue_result["results"]["image"]["thumb_url"],
"page_url": testing.comicvine.cv_issue_result["results"]["site_detail_url"],
"description": testing.comicvine.cv_issue_result["results"]["description"],
}
for r, e in zip(results, [cv_expected]):
del r["url_image_hash"]
assert r == e