Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Mapping for Series Format #135

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions darkseid/metroninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class MetronInfo:
}
)

# Ratings Mapping
unknown_synonyms = frozenset({"rating pending", "unknown"})
everyone_synonyms = frozenset(
{"everyone", "everyone 10+", "g", "kids to adults", "early childhood"}
Expand All @@ -143,6 +144,19 @@ class MetronInfo:
mature_synonyms = frozenset({"adults only 18+", "mature 17+", "r18+", "m"})
explicit_synonyms = frozenset({"x18+"})

# Series Format Mapping
annual_synonyms = frozenset({"annual"})
digital_chapter_synonyms = frozenset({"digital chapter", "digital"})
graphic_novel_synonyms = frozenset({"graphic novel"})
hardcover_synonyms = frozenset({"hardcover", "hard-cover"})
limited_series_synonyms = frozenset({"limited series"})
omnibus_synonyms = frozenset({"omnibus"})
one_shot_synonyms = frozenset({"1 shot", "1-shot", "fcbd", "one shot", "one-shot", "preview"})
single_issue_synonyms = frozenset(
{"single issue", "magazine", "series", "giant", "giant size", "giant-size"}
)
trade_paperback_synonyms = frozenset({"trade paperback", "tpb", "trade paper back"})

def metadata_from_string(self, string: str) -> Metadata:
"""Convert an XML string to a Metadata object.

Expand Down Expand Up @@ -208,6 +222,28 @@ def _valid_age_rating(cls, val: AgeRatings | None = None) -> str | None:
return rating
return None

@classmethod
def _valid_series_format(cls, val: str | None) -> str | None:
if not val or val is None:
return None

format_mapping = {
"Annual": cls.annual_synonyms,
"Digital Chapter": cls.digital_chapter_synonyms,
"Graphic Novel": cls.graphic_novel_synonyms,
"Hardcover": cls.hardcover_synonyms,
"Limited Series": cls.limited_series_synonyms,
"Omnibus": cls.omnibus_synonyms,
"One-Shot": cls.one_shot_synonyms,
"Single Issue": cls.single_issue_synonyms,
"Trade Paperback": cls.trade_paperback_synonyms,
}
lower_val = val.lower()
return next(
(fmt for fmt, synonyms in format_mapping.items() if lower_val in synonyms),
None,
)

@staticmethod
def _get_or_create_element(parent: ET.Element, tag: str) -> ET.Element:
element = parent.find(tag)
Expand Down Expand Up @@ -293,8 +329,8 @@ def _assign_publisher(root: ET.Element, publisher: Publisher) -> None:
)
imprint_node.text = publisher.imprint.name

@staticmethod
def _assign_series(root: ET.Element, series: Series) -> None:
@classmethod
def _assign_series(cls, root: ET.Element, series: Series) -> None: # NOQA: C901
if series is None:
return
series_node = MetronInfo._get_or_create_element(root, "Series")
Expand All @@ -315,9 +351,9 @@ def _assign_series(root: ET.Element, series: Series) -> None:
create_sub_element(series_node, "SortName").text = series.sort_name
if series.volume is not None:
create_sub_element(series_node, "Volume").text = str(series.volume)
create_sub_element(series_node, "Format").text = (
series.format if series.format in MetronInfo.mix_series_format else "Single Issue"
)
series_fmt = cls._valid_series_format(series.format)
if series_fmt is not None:
create_sub_element(series_node, "Format").text = series_fmt
if series.start_year:
create_sub_element(series_node, "StartYear").text = str(series.start_year)
if series.issue_count:
Expand Down
43 changes: 43 additions & 0 deletions tests/test_metroninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,49 @@ def test_valid_info_source(metron_info, val, expected_result):
assert result == expected_result


@pytest.mark.parametrize(
("val", "expected"),
[
("Annual", "Annual"), # happy path
("Digital Chapter", "Digital Chapter"), # happy path
("Graphic Novel", "Graphic Novel"), # happy path
("Hardcover", "Hardcover"), # happy path
("Limited Series", "Limited Series"), # happy path
("Omnibus", "Omnibus"), # happy path
("One-Shot", "One-Shot"), # happy path
("Single Issue", "Single Issue"), # happy path
("Trade Paperback", "Trade Paperback"), # happy path
("", None), # edge case: empty string
(None, None), # edge case: None value
("Unknown Format", None), # edge case: unknown format
("annual", "Annual"), # edge case: case insensitivity
("ANNUAL", "Annual"), # edge case: uppercase
],
ids=[
"valid_annual",
"valid_digital_chapter",
"valid_graphic_novel",
"valid_hardcover",
"valid_limited_series",
"valid_omnibus",
"valid_one_shot",
"valid_single_issue",
"valid_trade_paperback",
"empty_string",
"none_value",
"unknown_format",
"case_insensitivity_lower",
"case_insensitivity_upper",
],
)
def test_valid_series_format(metron_info, val, expected):
# Act
result = metron_info._valid_series_format(val) # NOQA: SLF001

# Assert
assert result == expected


@pytest.mark.parametrize(
("val", "expected_result"),
[
Expand Down
Loading