Skip to content

typing: add types to command handlers - #6932

Open
snejus wants to merge 7 commits into
masterfrom
typing-type-command-handlers
Open

typing: add types to command handlers#6932
snejus wants to merge 7 commits into
masterfrom
typing-type-command-handlers

Conversation

@snejus

@snejus snejus commented Aug 17, 2026

Copy link
Copy Markdown
Member

First part of #6924.

Summary

  • Give command handlers across core commands and many plugins a consistent Library, options, and list[str] interface.
  • Describe command-specific options with small Protocol types where handlers depend on particular flags, while retaining optparse.Values for handlers that do not need a narrower shape. This makes the CLI boundary easier for type checkers to follow without coupling handlers to a concrete options container.
  • Broaden beets.dbcore.sort from list to Sequence and tighten several item/album collection annotations to match the data actually passed between APIs.
  • Fix small runtime mismatches exposed while making these types concrete:
    • beetsplug.ipfs invokes PlayPlugin._play_command with the expected options shape and closes remote libraries after use.
    • beetsplug.bpd reads control_port through the config API that matches its actual value type.
    • beets.ui.commands.update handles excluded fields, missing prior items, optional flags, and byte paths safely.
    • Command option defaults and config handoffs are normalized where their runtime values can be optional.

Tests

  • Add regression coverage for IPFS playback through the Play plugin and context-managed remote libraries.
  • Refresh lyrics integration fixtures for the current LRCLIB and LRCGET responses.

Most changes are annotations and interface clarification. The behavioral changes are limited to the mismatches listed above.

Copilot AI lite review requested due to automatic review settings August 17, 2026 10:33
@snejus
snejus requested review from a team and henry-oberholtzer as code owners August 17, 2026 10:33
@github-actions

Copy link
Copy Markdown

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

grug see PR try make CLI command handler shape same everywhere: (Library, optparse.Values, list[str]). grug also see small runtime fixes found by typing, like ipfs -> play wiring, plus small API tighten in db sort.

Changes:

  • add shared typed command-handler signature across core commands + many plugins
  • widen beets.dbcore.sort.Sort.sort input from list to Iterable to match real call flow
  • adjust a few plugins/core helpers where typing show runtime mismatch (ipfs/play, update exclude fields, etc.)

Reviewed changes

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

Show a summary per file
File Description
test/plugins/test_ipfs.py add regression test for ipfs playback wiring
beetsplug/zero.py type command handler params
beetsplug/web/init.py type command handler params; add ignore for wsgi_app assign
beetsplug/unimported.py type command handler params
beetsplug/titlecase.py type command handler params
beetsplug/thumbnails.py type command handler params + lib type import
beetsplug/subsonicplaylist.py type command handler params
beetsplug/spotify.py type command handler params; tighten _match_library_tracks keywords type
beetsplug/scrub.py type command handler params
beetsplug/play.py type _play_command params; add selection annotation
beetsplug/parentwork.py type command handler params
beetsplug/mpdstats.py type command handler params
beetsplug/missing.py type command handler params
beetsplug/metasync/init.py type command handler params
beetsplug/mbsync.py type command handler params
beetsplug/mbsubmit.py type command handler params
beetsplug/mbcollection.py type update_collection handler params
beetsplug/lyrics.py type command handler params
beetsplug/listenbrainz.py type command handler params
beetsplug/limit.py type command handler params; annotate iterable selection
beetsplug/lastimport.py type command handler params
beetsplug/keyfinder.py type command handler params
beetsplug/ipfs.py type handlers; change ipfs_play to call play plugin command
beetsplug/info.py type command handler params; clarify summary annotation
beetsplug/ftintitle.py type command handler params
beetsplug/freedesktop.py type command handler params
beetsplug/fish.py type command handler params
beetsplug/fetchart.py type command handler params
beetsplug/export.py type command handler params
beetsplug/edit.py type command handler params
beetsplug/duplicates.py type command handler params; annotate items selection
beetsplug/deezer.py type command handler params
beetsplug/chroma.py type command handler params; rename loop var to avoid confusion
beetsplug/bpsync.py type command handler params
beetsplug/bpm.py type command handler params
beetsplug/bpd/init.py type command handler params; adjust control_port config get
beetsplug/bareasc.py type command handler params
beetsplug/badfiles.py type command handler params
beetsplug/autobpm.py type command handler params
beetsplug/aura.py type command handler params
beetsplug/acousticbrainz.py type command handler params
beetsplug/absubmit.py type command handler params
beets/ui/commands/write.py type command handler params
beets/ui/commands/update.py type command handler params; safer exclude fields + old item lookup + bytes path print
beets/ui/commands/stats.py type command handler params
beets/ui/commands/remove.py type command handler params
beets/ui/commands/move.py type command handler params
beets/ui/commands/modify.py type command handler params
beets/ui/commands/list.py type command handler params
beets/ui/commands/help.py type command handler params
beets/ui/commands/fields.py type command handler params
beets/ui/commands/config.py type command handler params
beets/dbcore/sort.py accept Iterable for sort inputs; update sort method type shapes

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread beetsplug/ipfs.py Outdated
Comment thread test/plugins/test_ipfs.py Outdated
Comment thread beetsplug/info.py Outdated
Comment thread beets/dbcore/sort.py Outdated
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.78082% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.29%. Comparing base (293ae11) to head (40538b7).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
beetsplug/bench.py 52.94% 8 Missing ⚠️
beetsplug/ipfs.py 87.50% 3 Missing ⚠️
beetsplug/bareasc.py 71.42% 2 Missing ⚠️
beetsplug/spotify.py 77.77% 2 Missing ⚠️
beetsplug/web/__init__.py 66.66% 2 Missing ⚠️
beets/ui/commands/import_/__init__.py 85.71% 1 Missing ⚠️
beets/ui/commands/move.py 90.00% 1 Missing ⚠️
beets/ui/commands/update.py 92.85% 1 Missing ⚠️
beetsplug/acousticbrainz.py 75.00% 1 Missing ⚠️
beetsplug/aura.py 75.00% 1 Missing ⚠️
... and 8 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6932      +/-   ##
==========================================
+ Coverage   75.84%   76.29%   +0.44%     
==========================================
  Files         164      164              
  Lines       21295    21529     +234     
  Branches     3333     3332       -1     
==========================================
+ Hits        16151    16425     +274     
+ Misses       4360     4315      -45     
- Partials      784      789       +5     
Files with missing lines Coverage Δ
beets/dbcore/sort.py 92.52% <100.00%> (ø)
beets/ui/__init__.py 82.71% <100.00%> (ø)
beets/ui/commands/completion.py 96.29% <100.00%> (+0.14%) ⬆️
beets/ui/commands/config.py 78.43% <100.00%> (+4.01%) ⬆️
beets/ui/commands/fields.py 90.90% <100.00%> (+0.90%) ⬆️
beets/ui/commands/help.py 100.00% <100.00%> (ø)
beets/ui/commands/list.py 100.00% <100.00%> (ø)
beets/ui/commands/modify.py 95.74% <100.00%> (+0.29%) ⬆️
beets/ui/commands/remove.py 100.00% <100.00%> (ø)
beets/ui/commands/stats.py 79.48% <100.00%> (+2.34%) ⬆️
... and 54 more
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@snejus
snejus force-pushed the typing-type-command-handlers branch 3 times, most recently from 9a2d57d to 5ed97bd Compare August 17, 2026 20:16
@snejus
snejus force-pushed the type-embedart-art-utils-import-command branch from 37266f8 to 6a9182c Compare August 18, 2026 09:47
@snejus
snejus requested review from asardaes and semohr as code owners August 18, 2026 09:47
@snejus
snejus force-pushed the typing-type-command-handlers branch from 5ed97bd to 74d1233 Compare August 18, 2026 09:56
@snejus
snejus force-pushed the type-embedart-art-utils-import-command branch from 6a9182c to c495306 Compare August 18, 2026 22:22
Base automatically changed from type-embedart-art-utils-import-command to master August 18, 2026 22:28
@snejus
snejus force-pushed the typing-type-command-handlers branch from 74d1233 to 7f8f933 Compare August 18, 2026 22:29
@snejus
snejus requested a lite review from Copilot August 18, 2026 22:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 55 out of 55 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

beets/dbcore/sort.py:26

  • grug read PR text say beets.dbcore.sort accept Iterable now. but code change use Sequence, still reject many iterables (like iterators / generator / Results) for typing. if goal is accept any iterable, need swap Sequence -> Iterable (and update overrides in this file same way so signatures match).
    def sort(self, items: Sequence[AnyModel]) -> Sequence[AnyModel]:
        """Sort the given sequence of model objects."""
        return sorted(items)

test/plugins/test_ipfs.py:99

  • grug see test call ipfs_play(self.lib, None, []) but new typing say opts: optparse.Values. if mypy check tests, this fail. pass real optparse.Values (can grab from beetsplug.ipfs module) so test match command interface.

Comment thread beetsplug/ipfs.py
@snejus
snejus force-pushed the typing-type-command-handlers branch from 7f8f933 to ba078ad Compare August 19, 2026 01:40
@snejus
snejus requested a review from JOJ0 as a code owner August 19, 2026 01:40
@snejus
snejus force-pushed the typing-type-command-handlers branch 2 times, most recently from 8afa61f to ed37e83 Compare August 19, 2026 01:58
@snejus
snejus requested a lite review from Copilot August 19, 2026 01:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 65 out of 65 changed files in this pull request and generated no new comments.

Suppressed comments (1)

beets/ui/init.py:475

  • grug see add_album_option now set default=False. this break config mirror trick. many plugin do self.config.set_args(opts) and have album in config (ex duplicates plugin). if user set duplicates: album: yes and run beet duplicates with no -a, opts.album False will override config back to False, so config no work (docs say config options mirror CLI). better keep album default None so set_args can skip when user not pass flag, and call sites can use bool(opts.album) when they need strict bool.
        album = optparse.Option(
            *flags,
            action="store_true",
            default=False,
            help="match albums instead of tracks",
        )

@snejus
snejus force-pushed the typing-type-command-handlers branch 3 times, most recently from 11bee48 to 2191fd8 Compare August 19, 2026 06:44
@snejus
snejus force-pushed the typing-type-command-handlers branch from 2191fd8 to 0ebd95c Compare August 19, 2026 09:49
Comment thread beets/ui/commands/fields.py
Comment thread beets/ui/__init__.py
"""

func: Callable[[library.Library, optparse.Values, list[str]], Any]
func: Callable[[library.Library, Any, list[str]], Any]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

optparse.Values was more concise. I guess this is needed now since we use protocols for typing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Indeed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why was Protocol chosen instead of using optparse.Values as a base class?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

optparse always constructs a plain Values, not instances of our command-specific subclasses. A Protocol lets each handler declare the fields it consumes without incorrectly claiming that the runtime object is an instance of a custom Values subclass.

We also don't need to import optparse this way :)

Comment thread beetsplug/bpd/__init__.py Outdated
@snejus
snejus force-pushed the typing-type-command-handlers branch from 0ebd95c to e7b3692 Compare August 19, 2026 10:43
@snejus
snejus force-pushed the typing-type-command-handlers branch from e7b3692 to 40538b7 Compare August 19, 2026 22:57
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.

3 participants