typing: type metadata source plugins: discogs, deezer, beatport, spotify chroma, listenbrainz, mbsubmit, spotify - #6938
Conversation
|
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. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## type-api-export-plugins #6938 +/- ##
===========================================================
- Coverage 76.01% 75.99% -0.02%
===========================================================
Files 164 164
Lines 21577 21585 +8
Branches 3341 3342 +1
===========================================================
+ Hits 16401 16404 +3
- Misses 4381 4387 +6
+ Partials 795 794 -1
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
grug see PR try make typing tighter for many metadata plugins and shared request/MusicBrainz helpers, so plugin code match real API shapes and type checker help more.
Changes:
- Add/adjust return + param types across multiple metadata source plugins.
- Reshape MusicBrainz typing: split
Releasefields intoBaseRelease, addRecordingWithReleases, addget_recording_with_releases(). - Small mbsubmit cleanup: print via
format()with cached format string, drop cross-plugin helper call.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| beetsplug/spotify.py | Add richer type hints for plugin lifecycle + matching helpers. |
| beetsplug/mbsubmit.py | Replace print_data with format() output; add cached format property and typing. |
| beetsplug/listenbrainz.py | Type API helpers and switch recording lookup to new “with releases” shape. |
| beetsplug/discogs/init.py | Add typing for importer session hook param. |
| beetsplug/deezer.py | Type commands/update flow; make rank fetch more defensive. |
| beetsplug/chroma.py | Add typing around Acoustid path + release sorting + helpers. |
| beetsplug/beatport.py | Tighten typing on client/plugin helpers. |
| beetsplug/acousticbrainz.py | Tighten typing for request/mapping pipeline and CLI option parsing. |
| beetsplug/_utils/requests.py | Add return annotations for HTTP session helpers/overrides. |
| beetsplug/_utils/musicbrainz.py | Introduce new typed shapes and new recording lookup helper. |
Suppressed comments (2)
beetsplug/chroma.py:143
- grug think
.as_str()here make original_year always truthy ("no" still true). this break configmatch.preferred.original_year: no. should read bool value.
original_year = config["match"]["preferred"]["original_year"].as_str()
beetsplug/listenbrainz.py:392
- grug see
.get("track")can return None, then loop crash. alsoidentifiercan be missing/None, then.split()crash. make safe default list and skip bad entries.
for track in playlist.get("playlist", {}).get("track"):
identifier = track.get("identifier")
if isinstance(identifier, list):
identifier = identifier[0]
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
5324a42 to
ea70c51
Compare
8311344 to
ca026db
Compare
ea70c51 to
f8349ad
Compare
ca026db to
c764422
Compare
f8349ad to
2a9a56d
Compare
c764422 to
48d67c4
Compare
0e0f5c2 to
1481471
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (3)
beetsplug/deezer.py:276
- grug see walrus precedence bug:
(rank := track.get("rank") is not None)setrankto bool, so log/int(rank)become 0/1, not Deezer rank value. need bind get() result, then checkis not None.
if track and (rank := track.get("rank") is not None):
self._log.debug(
"Deezer track: {} has {} rank", deezer_track_id, rank
)
item.deezer_track_rank = int(rank)
beetsplug/listenbrainz.py:395
- grug see
.get("track")can return None, thenforloop crash. alsoidentifiercan be None (or empty list) and.split()crash. better default empty list and skip entries with bad identifier.
tracks = []
for track in playlist.get("playlist", {}).get("track"):
identifier = track.get("identifier")
if isinstance(identifier, list):
identifier = identifier[0]
beetsplug/spotify.py:611
- grug see
_match_library_tracks()always calls_search_api("track", ...)and appends track objects, so return type should belist[SearchResponseTracks] | None(not album union). tighter type make later code safer.
def _match_library_tracks(
self, library: Library, keywords: list[str]
) -> list[SearchResponseAlbums | SearchResponseTracks] | None:
48d67c4 to
b9de1ce
Compare
1481471 to
211f4c3
Compare
b9de1ce to
485ae8d
Compare
211f4c3 to
8aa82f1
Compare
485ae8d to
01233c7
Compare
8aa82f1 to
20145a4
Compare
01233c7 to
7494176
Compare
20145a4 to
dab3a68
Compare
7494176 to
87da1ca
Compare
dab3a68 to
38f9195
Compare
Part of #6924.
This change tightens typing across metadata source plugins and shared request/MusicBrainz utilities, so plugin code lines up better with the data it actually consumes.
Biggest architecture change is in
beetsplug/_utils/musicbrainz.py: common release fields move intoBaseRelease, and newRecordingWithReleasesplusget_recording_with_releases()make'recording with releases'an explicit shape instead of loose dict guessing.Plugin code in
listenbrainz,chroma,acousticbrainz,beatport,deezer,spotify,discogs, andmbsubmitis then updated to use clearer return types, typed collections, and safer access patterns for optional API data.High-level impact: less ambiguity at plugin boundaries, better editor/type-checker help, and fewer runtime mistakes from assuming fields exist when remote APIs may omit them.
There is also a small cleanup in
mbsubmit: output formatting now goes throughformat()with a cached config value, which removes a cross-plugin helper dependency and keeps the command simpler.