Skip to content

Commit

Permalink
Update how contributor roles are normalized via OPDS2 importer (PP-1530
Browse files Browse the repository at this point in the history
…) (#1978)

* Update Contributor.role to be an enum

* Update opds2 importer contributor handling
  • Loading branch information
jonathangreen authored Aug 8, 2024
1 parent 6ce240f commit 57a88c2
Show file tree
Hide file tree
Showing 32 changed files with 394 additions and 292 deletions.
54 changes: 27 additions & 27 deletions src/palace/manager/api/admin/controller/work_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,31 +89,31 @@ def roles(self):
CODES = Contributor.MARC_ROLE_CODES
marc_to_role = dict()
for role in [
Contributor.ACTOR_ROLE,
Contributor.ADAPTER_ROLE,
Contributor.AFTERWORD_ROLE,
Contributor.ARTIST_ROLE,
Contributor.ASSOCIATED_ROLE,
Contributor.AUTHOR_ROLE,
Contributor.COMPILER_ROLE,
Contributor.COMPOSER_ROLE,
Contributor.CONTRIBUTOR_ROLE,
Contributor.COPYRIGHT_HOLDER_ROLE,
Contributor.DESIGNER_ROLE,
Contributor.DIRECTOR_ROLE,
Contributor.EDITOR_ROLE,
Contributor.ENGINEER_ROLE,
Contributor.FOREWORD_ROLE,
Contributor.ILLUSTRATOR_ROLE,
Contributor.INTRODUCTION_ROLE,
Contributor.LYRICIST_ROLE,
Contributor.MUSICIAN_ROLE,
Contributor.NARRATOR_ROLE,
Contributor.PERFORMER_ROLE,
Contributor.PHOTOGRAPHER_ROLE,
Contributor.PRODUCER_ROLE,
Contributor.TRANSCRIBER_ROLE,
Contributor.TRANSLATOR_ROLE,
Contributor.Role.ACTOR,
Contributor.Role.ADAPTER,
Contributor.Role.AFTERWORD,
Contributor.Role.ARTIST,
Contributor.Role.ASSOCIATED,
Contributor.Role.AUTHOR,
Contributor.Role.COMPILER,
Contributor.Role.COMPOSER,
Contributor.Role.CONTRIBUTOR,
Contributor.Role.COPYRIGHT_HOLDER,
Contributor.Role.DESIGNER,
Contributor.Role.DIRECTOR,
Contributor.Role.EDITOR,
Contributor.Role.ENGINEER,
Contributor.Role.FOREWORD,
Contributor.Role.ILLUSTRATOR,
Contributor.Role.INTRODUCTION,
Contributor.Role.LYRICIST,
Contributor.Role.MUSICIAN,
Contributor.Role.NARRATOR,
Contributor.Role.PERFORMER,
Contributor.Role.PHOTOGRAPHER,
Contributor.Role.PRODUCER,
Contributor.Role.TRANSCRIBER,
Contributor.Role.TRANSLATOR,
]:
marc_to_role[CODES[role]] = role
return marc_to_role
Expand Down Expand Up @@ -185,8 +185,8 @@ def edit(self, identifier_type, identifier):
# The first author in the form is considered the primary author, even
# though there's no separate MARC code for that.
for i, role in enumerate(new_contributor_roles):
if role == Contributor.AUTHOR_ROLE:
new_contributor_roles[i] = Contributor.PRIMARY_AUTHOR_ROLE
if role == Contributor.Role.AUTHOR:
new_contributor_roles[i] = Contributor.Role.PRIMARY_AUTHOR
break
roles_and_names = list(zip(new_contributor_roles, new_contributor_names))

Expand Down
26 changes: 13 additions & 13 deletions src/palace/manager/api/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,12 +1051,12 @@ def extract_availability(
role_abbreviation = re.compile(r"\(([A-Z][A-Z][A-Z])\)$")
generic_author = object()
role_abbreviation_to_role = dict(
INT=Contributor.INTRODUCTION_ROLE,
EDT=Contributor.EDITOR_ROLE,
PHT=Contributor.PHOTOGRAPHER_ROLE,
ILT=Contributor.ILLUSTRATOR_ROLE,
TRN=Contributor.TRANSLATOR_ROLE,
FRW=Contributor.FOREWORD_ROLE,
INT=Contributor.Role.INTRODUCTION,
EDT=Contributor.Role.EDITOR,
PHT=Contributor.Role.PHOTOGRAPHER,
ILT=Contributor.Role.ILLUSTRATOR,
TRN=Contributor.Role.TRANSLATOR,
FRW=Contributor.Role.FOREWORD,
ADP=generic_author, # Author of adaptation
COR=generic_author, # Corporate author
)
Expand All @@ -1066,7 +1066,7 @@ def parse_contributor(
cls,
author: str,
primary_author_found: bool = False,
force_role: str | None = None,
force_role: Contributor.Role | None = None,
) -> ContributorData:
"""Parse an Axis 360 contributor string.
Expand All @@ -1088,20 +1088,20 @@ def parse_contributor(
over the value implied by primary_author_found.
"""
if primary_author_found:
default_author_role = Contributor.AUTHOR_ROLE
default_author_role = Contributor.Role.AUTHOR
else:
default_author_role = Contributor.PRIMARY_AUTHOR_ROLE
default_author_role = Contributor.Role.PRIMARY_AUTHOR
role = default_author_role
match = cls.role_abbreviation.search(author)
if match:
role_type = match.groups()[0]
mapped_role = cls.role_abbreviation_to_role.get(
role_type, Contributor.UNKNOWN_ROLE
role_type, Contributor.Role.UNKNOWN
)
role = (
default_author_role
if mapped_role is cls.generic_author
else cast(str, mapped_role)
else cast(Contributor.Role, mapped_role)
)
author = author[:-5].strip()
if force_role:
Expand Down Expand Up @@ -1131,15 +1131,15 @@ def extract_bibliographic(
if contributor:
for c in self.parse_list(contributor):
contributor_data = self.parse_contributor(c, found_primary_author)
if Contributor.PRIMARY_AUTHOR_ROLE in contributor_data.roles:
if Contributor.Role.PRIMARY_AUTHOR in contributor_data.roles:
found_primary_author = True
contributors.append(contributor_data)

narrator = self.text_of_optional_subtag(element, "axis:narrator", ns)
if narrator:
for n in self.parse_list(narrator):
contributor_data = self.parse_contributor(
n, force_role=Contributor.NARRATOR_ROLE
n, force_role=Contributor.Role.NARRATOR
)
contributors.append(contributor_data)

Expand Down
4 changes: 2 additions & 2 deletions src/palace/manager/api/bibliotheca.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ def xpath_expression(self) -> str:

@classmethod
def contributors_from_string(
cls, string: str | None, role: str = Contributor.AUTHOR_ROLE
cls, string: str | None, role: str = Contributor.Role.AUTHOR
) -> list[ContributorData]:
contributors: list[ContributorData] = []
if not string:
Expand Down Expand Up @@ -752,7 +752,7 @@ def value(bibliotheca_key):

authors = list(self.contributors_from_string(value("Authors")))
narrators = list(
self.contributors_from_string(value("Narrator"), Contributor.NARRATOR_ROLE)
self.contributors_from_string(value("Narrator"), Contributor.Role.NARRATOR)
)

published_date = None
Expand Down
10 changes: 5 additions & 5 deletions src/palace/manager/api/metadata/novelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ def get_items_from_query(self, library: Library) -> list[dict[str, str]]:
i1 = aliased(Identifier)
i2 = aliased(Identifier)
roles = list(Contributor.AUTHOR_ROLES)
roles.append(Contributor.NARRATOR_ROLE)
roles.append(Contributor.Role.NARRATOR)

isbnQuery = (
select(
Expand Down Expand Up @@ -670,7 +670,7 @@ def create_item_object(
return (None, None, None, False)

roles = list(Contributor.AUTHOR_ROLES)
roles.append(Contributor.NARRATOR_ROLE)
roles.append(Contributor.Role.NARRATOR)

role = object[6]
author_or_narrator = object[7] if role in roles else ""
Expand All @@ -684,9 +684,9 @@ def create_item_object(
if isbn == currentIdentifier and existingItem:
if not existingItem.get("author") and role in Contributor.AUTHOR_ROLES:
existingItem["author"] = author_or_narrator
if not existingItem.get("narrator") and role == Contributor.NARRATOR_ROLE:
if not existingItem.get("narrator") and role == Contributor.Role.NARRATOR:
existingItem["narrator"] = author_or_narrator
if role == Contributor.PRIMARY_AUTHOR_ROLE:
if role == Contributor.Role.PRIMARY_AUTHOR:
existingItem["author"] = author_or_narrator
existingItem["role"] = role

Expand Down Expand Up @@ -718,7 +718,7 @@ def create_item_object(
addItem = True if existingItem else False
if role in Contributor.AUTHOR_ROLES:
newItem["author"] = author_or_narrator
if role == Contributor.NARRATOR_ROLE:
if role == Contributor.Role.NARRATOR:
newItem["narrator"] = author_or_narrator

return (isbn, existingItem, newItem, addItem)
Expand Down
66 changes: 33 additions & 33 deletions src/palace/manager/api/overdrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -2331,38 +2331,38 @@ def internal_formats(cls, overdrive_format):
ignorable_overdrive_formats: set[str] = set()

overdrive_role_to_simplified_role = {
"actor": Contributor.ACTOR_ROLE,
"artist": Contributor.ARTIST_ROLE,
"book producer": Contributor.PRODUCER_ROLE,
"associated name": Contributor.ASSOCIATED_ROLE,
"author": Contributor.AUTHOR_ROLE,
"author of introduction": Contributor.INTRODUCTION_ROLE,
"author of foreword": Contributor.FOREWORD_ROLE,
"author of afterword": Contributor.AFTERWORD_ROLE,
"contributor": Contributor.CONTRIBUTOR_ROLE,
"colophon": Contributor.COLOPHON_ROLE,
"adapter": Contributor.ADAPTER_ROLE,
"etc.": Contributor.UNKNOWN_ROLE,
"cast member": Contributor.ACTOR_ROLE,
"collaborator": Contributor.COLLABORATOR_ROLE,
"compiler": Contributor.COMPILER_ROLE,
"composer": Contributor.COMPOSER_ROLE,
"copyright holder": Contributor.COPYRIGHT_HOLDER_ROLE,
"director": Contributor.DIRECTOR_ROLE,
"editor": Contributor.EDITOR_ROLE,
"engineer": Contributor.ENGINEER_ROLE,
"executive producer": Contributor.EXECUTIVE_PRODUCER_ROLE,
"illustrator": Contributor.ILLUSTRATOR_ROLE,
"musician": Contributor.MUSICIAN_ROLE,
"narrator": Contributor.NARRATOR_ROLE,
"other": Contributor.UNKNOWN_ROLE,
"performer": Contributor.PERFORMER_ROLE,
"producer": Contributor.PRODUCER_ROLE,
"translator": Contributor.TRANSLATOR_ROLE,
"photographer": Contributor.PHOTOGRAPHER_ROLE,
"lyricist": Contributor.LYRICIST_ROLE,
"transcriber": Contributor.TRANSCRIBER_ROLE,
"designer": Contributor.DESIGNER_ROLE,
"actor": Contributor.Role.ACTOR,
"artist": Contributor.Role.ARTIST,
"book producer": Contributor.Role.PRODUCER,
"associated name": Contributor.Role.ASSOCIATED,
"author": Contributor.Role.AUTHOR,
"author of introduction": Contributor.Role.INTRODUCTION,
"author of foreword": Contributor.Role.FOREWORD,
"author of afterword": Contributor.Role.AFTERWORD,
"contributor": Contributor.Role.CONTRIBUTOR,
"colophon": Contributor.Role.COLOPHON,
"adapter": Contributor.Role.ADAPTER,
"etc.": Contributor.Role.UNKNOWN,
"cast member": Contributor.Role.ACTOR,
"collaborator": Contributor.Role.COLLABORATOR,
"compiler": Contributor.Role.COMPILER,
"composer": Contributor.Role.COMPOSER,
"copyright holder": Contributor.Role.COPYRIGHT_HOLDER,
"director": Contributor.Role.DIRECTOR,
"editor": Contributor.Role.EDITOR,
"engineer": Contributor.Role.ENGINEER,
"executive producer": Contributor.Role.EXECUTIVE_PRODUCER,
"illustrator": Contributor.Role.ILLUSTRATOR,
"musician": Contributor.Role.MUSICIAN,
"narrator": Contributor.Role.NARRATOR,
"other": Contributor.Role.UNKNOWN,
"performer": Contributor.Role.PERFORMER,
"producer": Contributor.Role.PRODUCER,
"translator": Contributor.Role.TRANSLATOR,
"photographer": Contributor.Role.PHOTOGRAPHER,
"lyricist": Contributor.Role.LYRICIST,
"transcriber": Contributor.Role.TRANSCRIBER,
"designer": Contributor.Role.DESIGNER,
}

overdrive_medium_to_simplified_medium = {
Expand Down Expand Up @@ -2555,7 +2555,7 @@ def book_info_to_metadata(
display_name = creator["name"]
role = creator["role"]
roles = cls.parse_roles(overdrive_id, role) or [
Contributor.UNKNOWN_ROLE
Contributor.Role.UNKNOWN
]
contributor = ContributorData(
sort_name=sort_name,
Expand Down
8 changes: 4 additions & 4 deletions src/palace/manager/core/metadata_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def __init__(
self.family_name = family_name
self.wikipedia_name = wikipedia_name
if roles is None:
roles = Contributor.AUTHOR_ROLE
roles = Contributor.Role.AUTHOR
if not isinstance(roles, list):
roles = [roles]
self.roles = roles
Expand Down Expand Up @@ -1212,7 +1212,7 @@ def from_edition(cls, edition):
ContributorData(
sort_name=edition.sort_author,
display_name=edition.author,
roles=[Contributor.PRIMARY_AUTHOR_ROLE],
roles=[Contributor.Role.PRIMARY_AUTHOR],
)
)

Expand Down Expand Up @@ -1367,7 +1367,7 @@ def guess_license_pools(self, _db):
for contributor in self.contributors:
if not any(
x in contributor.roles
for x in (Contributor.AUTHOR_ROLE, Contributor.PRIMARY_AUTHOR_ROLE)
for x in (Contributor.Role.AUTHOR, Contributor.Role.PRIMARY_AUTHOR)
):
continue
contributor.find_sort_name(_db)
Expand Down Expand Up @@ -2018,7 +2018,7 @@ def row_to_metadata(self, row):
ContributorData(
sort_name=sort_author,
display_name=display_author,
roles=[Contributor.AUTHOR_ROLE],
roles=[Contributor.Role.AUTHOR],
)
)

Expand Down
Loading

0 comments on commit 57a88c2

Please sign in to comment.