Skip to content

Type musicbrainz#6329

Open
snejus wants to merge 4 commits intomasterfrom
type-musicbrainz
Open

Type musicbrainz#6329
snejus wants to merge 4 commits intomasterfrom
type-musicbrainz

Conversation

@snejus
Copy link
Copy Markdown
Member

@snejus snejus commented Feb 1, 2026

Add full type coverage to the MusicBrainz plugin

This PR introduces complete static typing for beetsplug/musicbrainz.py, beetsplug/mbpseudo.py, and beetsplug/_utils/musicbrainz.py, and enforces it via mypy strict mode.

Key changes

New TypedDict schema in beetsplug/_utils/musicbrainz.py

A comprehensive set of TypedDict classes now models the full MusicBrainz API response surface — Release, Recording, Track, ReleaseGroup, Artist, ArtistCredit, Work, and all relation types. Public API methods (get_release, get_recording, etc.) now return these typed shapes instead of the opaque JSONDict.

Key normalization: dash-to-underscore

The internal _normalize_data method (previously _group_relations) now also converts all hyphenated keys (e.g. artist-credit, release-group, sort-name) to underscored equivalents (e.g. artist_credit, release_group, sort_name) at parse time. This makes the data structure Python-idiomatic and is what allows the TypedDict definitions to use clean attribute names. All downstream field accesses, test fixtures, and JSON test resources are updated accordingly.

mypy strict mode enabled for the three affected modules via setup.cfg.

Impact

  • No behaviour change for end users — this is purely an internal refactor.
  • Code reading the MusicBrainz response now has IDE completion and type-checking support.
  • The normalization boundary is clearly established at _normalize_data, so callers never see raw hyphenated keys.
  • Test fixtures and resource JSON files are updated to match the new normalized shape.

@snejus snejus requested a review from asardaes as a code owner February 1, 2026 16:15
@snejus snejus requested review from JOJ0 and Copilot February 1, 2026 16:15
@snejus snejus requested a review from a team as a code owner February 1, 2026 16:15
@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 1, 2026

Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces comprehensive typing for MusicBrainz API payloads through TypedDict models, refactors parsing logic into smaller helpers, normalizes API responses at the boundary (converting dashes to underscores and grouping relations), and replaces hand-written test dictionaries with factory-based data generation.

Changes:

  • Introduced typed domain models (Release, Recording, Medium, etc.) in beetsplug/_utils/musicbrainz.py
  • Normalized MusicBrainz API responses by converting dashed keys to underscores and grouping relations
  • Refactored parsing into focused helper methods (_parse_artist_credits, _parse_release_group, etc.)

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/rsrc/mbpseudo/pseudo_release.json Updated test fixture to use underscored keys matching normalized payload format
test/rsrc/mbpseudo/official_release.json Updated test fixture to use underscored keys matching normalized payload format
test/plugins/utils/test_musicbrainz.py Renamed test from test_group_relations to test_normalize_data reflecting the renamed internal method
test/plugins/test_musicbrainz.py Replaced manual test data construction with factory-based approach and updated assertions to match factory defaults
test/plugins/test_mbpseudo.py Updated references from dashed keys to underscored keys
test/plugins/factories/musicbrainz.py Added factory classes for generating typed MusicBrainz test data
setup.cfg Enabled strict mypy checking for musicbrainz-related modules
pyproject.toml Added pytest-factoryboy test dependency
beetsplug/musicbrainz.py Refactored parsing logic into typed helper methods and updated to consume normalized payloads
beetsplug/mbpseudo.py Updated to use typed Release structures and underscored keys
beetsplug/_utils/musicbrainz.py Added comprehensive TypedDict models and renamed/enhanced _group_relations to _normalize_data
Comments suppressed due to low confidence (2)

beetsplug/_utils/musicbrainz.py:1

  • The length checks are redundant. If map(int, date_str.split('-')) produces fewer than three parts, accessing parts[1] or parts[2] will raise an IndexError rather than returning None. The current implementation doesn't actually prevent the error. Consider using parts[i] if i < len(parts) else None or a more concise approach like padding the list.
"""Helpers for communicating with the MusicBrainz webservice.

beetsplug/musicbrainz.py:1

  • Corrected spelling of 'attribute_credits' to 'attribute_values' to match the actual field name in ArtistRelation TypedDict.
# This file is part of beets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 1, 2026

Codecov Report

❌ Patch coverage is 99.56897% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 70.51%. Comparing base (7b0e4e2) to head (a4420a2).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
beetsplug/mbpseudo.py 83.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6329      +/-   ##
==========================================
+ Coverage   70.19%   70.51%   +0.32%     
==========================================
  Files         147      147              
  Lines       18698    18904     +206     
  Branches     3046     3046              
==========================================
+ Hits        13125    13331     +206     
  Misses       4930     4930              
  Partials      643      643              
Files with missing lines Coverage Δ
beetsplug/_utils/musicbrainz.py 97.29% <100.00%> (+4.38%) ⬆️
beetsplug/listenbrainz.py 34.88% <100.00%> (ø)
beetsplug/mbcollection.py 92.85% <100.00%> (ø)
beetsplug/parentwork.py 70.65% <100.00%> (ø)
beetsplug/mbpseudo.py 79.87% <83.33%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@amogus07
Copy link
Copy Markdown
Contributor

amogus07 commented Feb 2, 2026

I also did a similar sort of refactoring recently, and this is what I ended up with: https://github.com/prTopi/beets-vocadb/tree/eeb047027a54d331cfe1d54bc1126046c5382a9b/src/beetsplug/_utils/vocadb/vocadb_api_client

Feel free to take inpiration!

Here are some suggestions:

  1. TypedDicts are only referenced in type annotations, so they can all be put under if TYPE_CHECKING:
  2. Using StrEnums instead of Literals (or a custom Enum type like this that overrides auto()).
  3. Perhaps it's worth putting the models into their own module or even package.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 6 comments.

@snejus snejus marked this pull request as draft February 23, 2026 05:22
@snejus snejus added the musicbrainz musicbrainz plugin label Apr 5, 2026
@snejus snejus force-pushed the type-musicbrainz branch 4 times, most recently from a6a3aa5 to ec1ce1d Compare April 6, 2026 08:22
@snejus snejus marked this pull request as ready for review April 6, 2026 08:23
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.

@snejus snejus force-pushed the type-musicbrainz branch 4 times, most recently from 7d0a0e5 to fa3e5ac Compare April 6, 2026 09:59
@snejus snejus requested a review from Copilot April 6, 2026 10:01
@snejus
Copy link
Copy Markdown
Member Author

snejus commented Apr 6, 2026

1. `TypedDict`s are only referenced in type annotations, so they can all be put under `if TYPE_CHECKING:`

I don't see any benefit for doing so (this may actually increase verbosity because of shorter line lengths and reformatting). Sometimes they should be defined outside the TYPE_CHECKING block, e.g. see beets.util.color.get_color_config.

2. Using `StrEnum`s instead of Literals (or a custom `Enum` type [like this](https://github.com/prTopi/beets-vocadb/blob/65d21d3c752691f8da34e200232e3fa6919a3ddc/beetsplug/vocadb/vocadb_api_client/models/__init__.py#L22) that overrides auto()).

Again, I don't see any benefit for this - these are just static definitions without any functionality attached to them.

3. Perhaps it's worth putting the models into their own module or even package.

These definitions belong to the MusicBrainzAPI and I think they should be tightly coupled. I don't want to force users of this API to import the definitions form another module.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

@snejus snejus force-pushed the type-musicbrainz branch from fa3e5ac to 5bc9462 Compare April 6, 2026 11:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

@snejus snejus force-pushed the type-musicbrainz branch from 5bc9462 to a4420a2 Compare April 7, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

musicbrainz musicbrainz plugin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants