Skip to content

Add type annotations to edition.py and enable mypy strict checking#2978

Merged
jonathangreen merged 3 commits intomainfrom
chore/add-type-annotations-edition
Jan 11, 2026
Merged

Add type annotations to edition.py and enable mypy strict checking#2978
jonathangreen merged 3 commits intomainfrom
chore/add-type-annotations-edition

Conversation

@jonathangreen
Copy link
Member

@jonathangreen jonathangreen commented Jan 10, 2026

Description

Add comprehensive type annotations to the Edition model in edition.py and enable mypy strict checking for this module.

Motivation and Context

This change improves code quality and type safety by:

  • Adding type annotations to all methods in the Edition class
  • Removing edition.py from the mypy exclusion list in pyproject.toml
  • Using Sequence types for more flexible parameter acceptance in add_contributor()
  • Fixing type annotation for identifier_id_column parameter in Identifier class

How Has This Been Tested?

  • All existing tests pass
  • mypy passes with no errors on the modified files
  • Fixed a test that was passing an unused _sort_name kwarg (exposed by removing **kwargs)

Checklist

  • I have updated the documentation accordingly.
  • All new and existing tests passed.

@codecov
Copy link

codecov bot commented Jan 10, 2026

Codecov Report

❌ Patch coverage is 87.83784% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.81%. Comparing base (7ca295e) to head (ea0b026).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/palace/manager/sqlalchemy/model/edition.py 89.85% 6 Missing and 1 partial ⚠️
src/palace/manager/data_layer/bibliographic.py 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2978      +/-   ##
==========================================
- Coverage   92.82%   92.81%   -0.02%     
==========================================
  Files         454      454              
  Lines       42942    42953      +11     
  Branches     5998     6000       +2     
==========================================
+ Hits        39860    39865       +5     
- Misses       2014     2018       +4     
- Partials     1068     1070       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jonathangreen jonathangreen force-pushed the chore/add-type-annotations-edition branch from d2afb10 to 2369419 Compare January 10, 2026 01:01
Comment on lines +193 to +194
if not self.title:
return None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added null check for self.title to satisfy mypy. calculate_permanent_work_id_for_title_and_author requires a non-None title parameter. This check is consistent with the existing primary_author null check above.

if (
contributor_data.aliases
and contributor_data.aliases != contributor.aliases
and list(contributor_data.aliases) != contributor.aliases
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to list(contributor_data.aliases) for proper comparison. contributor_data.aliases is a Sequence (could be tuple), while contributor.aliases is a list. Direct comparison between tuple and list would always be False.

Comment on lines +489 to +490
if representation is None:
return
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added early return when resource.representation is None. This provides type narrowing so mypy knows representation is not None in subsequent code. The original code would have raised an AttributeError in this case anyway.

self.cover_thumbnail_url,
)

def add_contributor(self, name, roles, aliases=None, lc=None, viaf=None, **kwargs):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed **kwargs which was accepting but silently ignoring extra keyword arguments.

Comment on lines +534 to +539
self,
name: Contributor | str | None,
roles: Sequence[str] | str,
aliases: Sequence[str] | None = None,
lc: str | None = None,
viaf: str | None = None,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed roles to Sequence[str] for flexibility (accepts tuples from Pydantic models). Added None to name type since Contributor.lookup accepts it.

"""Assign a contributor to this Edition."""
_db = Session.object_session(self)
if isinstance(roles, (bytes, str)):
if isinstance(roles, str):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed bytes from the isinstance check. Roles should never be bytes - this was likely legacy Python 2 compatibility code.

title = self.title
if self.subtitle:
title += ": " + self.subtitle
title = (title or "") + ": " + self.subtitle
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle edge case where title is None but subtitle exists. Uses (title or "") to avoid TypeError when concatenating.

Comment on lines -873 to +925
if rep:
self.cover_thumbnail_url = rep.public_url
break
else:
# No thumbnail was found. If the Edition references a thumbnail,
# it needs to be removed.
if self.cover_thumbnail_url:
self.cover_thumbnail_url = None
self.cover_thumbnail_url = rep.public_url
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed if rep: check - safe because we're in the else block of if not best_thumbnail.representation, so representation is guaranteed to exist. Also removed the for...else block that cleared cover_thumbnail_url - redundant because we only enter this loop when cover_thumbnail_url is already falsy, and the fallback code at line 934 handles the no-thumbnail case.

def recursively_equivalent_identifier_ids_query(
cls,
identifier_id_column: str,
identifier_id_column: ColumnElement[Any] | int,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed incorrect type annotation. The parameter was typed as str but actually accepts either an integer ID or a SQLAlchemy column expression (e.g., Edition.primary_identifier_id) for use in subqueries.

[c_orig] = list(edition.contributors)

c1 = edition.add_contributor("c1", Contributor.Role.AUTHOR, _sort_name="c1")
c1 = edition.add_contributor("c1", Contributor.Role.AUTHOR)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed _sort_name="c1" argument. This was being silently swallowed by **kwargs but never actually used - the contributor's sort_name is set through Contributor.lookup, not via this kwarg.

@jonathangreen jonathangreen requested a review from a team January 10, 2026 01:25
- Add comprehensive type annotations to Edition model methods
- Remove edition module from mypy exclusion list in pyproject.toml
- Use Sequence types for more flexible parameter acceptance
- Fix type annotation for identifier_id_column in Identifier class
- Add null check for title in BibliographicData.calculate_permanent_work_id
- Remove unused _sort_name kwarg from test (was silently ignored by **kwargs)
@jonathangreen jonathangreen force-pushed the chore/add-type-annotations-edition branch from 3856ca3 to bede7d5 Compare January 11, 2026 14:42
@jonathangreen
Copy link
Member Author

Codecov is complaining about patch coverage, but the coverage gaps were pre-existing, so I think we can ignore it on this PR.

Copy link
Contributor

@tdilauro tdilauro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☑️

Co-authored-by: Tim DiLauro <tdilauro@users.noreply.github.com>
@jonathangreen jonathangreen merged commit 7fb181e into main Jan 11, 2026
18 of 19 checks passed
@jonathangreen jonathangreen deleted the chore/add-type-annotations-edition branch January 11, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants