Skip to content

Conversation

@snejus
Copy link
Member

@snejus snejus commented Dec 28, 2025

Summary

This PR updates typing and linting across the codebase and enables stricter ruff checks for Python 3.10:

  1. Enable tool.ruff.lint.future-annotations
    Very handy feature released in 0.13.0: if required, it automatically adds from __future__ import annotations and moves relevant imports under if TYPE_CHECKING:

    # before (runtime import)
    from beets.library import Library
    
    # after
    from __future__ import annotations
    
    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
        from beets.library import Library
  2. Set tool.ruff.target-version = "py310"

    This enforced PEP 604 unions in the codebase:

    # before
    SQLiteType = Union[str, bytes, float, int, memoryview, None]
    
    # after
    SQLiteType = str | bytes | float | int | memoryview | None
  3. Enable RUF* family of checks

    • Remove unused # noqas

    • Ignore unused unpacked variables

      # before
      likelies, consensus = util.get_most_common_tags(self.items)
      
      # after
      likelies, _ = util.get_most_common_tags(self.items)
    • Avoid list materialization

      # before
      for part in parts + [","]:
      
      # after
      for part in [*parts, ","]:
    • And, most importantly, RUF012: use ClassVar for mutable class attributes

      • This underlined our messy BeetsPlugin.template_* attributes design, where I have now defined BeetsPluginMeta to make a clear distinction between class and instance attributes. @semohr and @asardaes I saw you had a discussion regarding these earlier - we will need to revisit this at some point to sort it out for good.
      • It also revealed a legitimate issue in metasync.MetaSource where item_types were initialised as an instance attribute (but luckily never used).

@snejus snejus requested a review from semohr December 28, 2025 03:52
@snejus snejus requested a review from a team as a code owner December 28, 2025 03:52
@snejus snejus requested a review from JOJ0 December 28, 2025 03:52
@github-actions
Copy link

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
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 security issue, 2 other issues, and left some high level feedback:

Security issues:

  • Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. (link)

General comments:

  • The change to BeetsPlugin/BeetsPluginMeta switches template_funcs/template_fields/album_template_fields from shared class-level dicts to per-instance dicts; double-check whether any existing plugins rely on cross-instance sharing of these registries and, if so, consider keeping a central class-level store in addition to per-instance overrides.
  • In several places the new [*seq, elem] pattern is used where the original code relied on list concatenation semantics (seq + [elem]); it may be worth standardizing on a single style (e.g., [*seq, elem] everywhere) for consistency and to make the refactor’s intent clearer.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The change to `BeetsPlugin`/`BeetsPluginMeta` switches `template_funcs`/`template_fields`/`album_template_fields` from shared class-level dicts to per-instance dicts; double-check whether any existing plugins rely on cross-instance sharing of these registries and, if so, consider keeping a central class-level store in addition to per-instance overrides.
- In several places the new `[*seq, elem]` pattern is used where the original code relied on list concatenation semantics (`seq + [elem]`); it may be worth standardizing on a single style (e.g., `[*seq, elem]` everywhere) for consistency and to make the refactor’s intent clearer.

## Individual Comments

### Comment 1
<location> `pyproject.toml:314-316` </location>
<code_context>
     "N", # pep8-naming
     "PT", # flake8-pytest-style
-    # "RUF", # ruff
+    "RUF", # ruff
     "UP", # pyupgrade
-    "TCH", # flake8-type-checking
+    "TC", # flake8-type-checking
     "W", # pycodestyle
 ]
</code_context>

<issue_to_address>
**issue (bug_risk):** The `TC` code in Ruff `select` likely doesn’t correspond to flake8-type-checking

Ruff uses the `TCH` prefix for flake8-type-checking rules (e.g., `TCH001`), not `TC`, so this entry won’t enable the plugin as intended. Update the code to use `"TCH"` instead of `"TC"` here.
</issue_to_address>

### Comment 2
<location> `beets/util/pipeline.py:195` </location>
<code_context>
         task: R | T | None = None
         while True:
             task = yield task
-            task = func(*(args + (task,)))
+            task = func(*((*args, task)))

     return coro
</code_context>

<issue_to_address>
**suggestion:** The new argument expansion in `coro` is more complex than necessary and slightly obscures intent

`func(*((*args, task)))` is equivalent to `func(*args, task)` but less readable and creates an unnecessary tuple. Please simplify to `func(*args, task)` here and in the similar `coro` call below.
</issue_to_address>

### Comment 3
<location> `beetsplug/mbsubmit.py:72` </location>
<code_context>
            subprocess.Popen([picard_path, *paths])
</code_context>

<issue_to_address>
**security (python.lang.security.audit.dangerous-subprocess-use-audit):** Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link

codecov bot commented Dec 28, 2025

Codecov Report

❌ Patch coverage is 90.15152% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.91%. Comparing base (bd319c2) to head (c9625f8).
⚠️ Report is 6 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
beetsplug/replaygain.py 0.00% 4 Missing ⚠️
beets/util/artresizer.py 66.66% 3 Missing ⚠️
beetsplug/bpd/gstplayer.py 33.33% 2 Missing ⚠️
beets/ui/commands/import_/display.py 66.66% 1 Missing ⚠️
beetsplug/bpd/__init__.py 66.66% 1 Missing ⚠️
beetsplug/bpsync.py 0.00% 1 Missing ⚠️
beetsplug/mbsubmit.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6245      +/-   ##
==========================================
+ Coverage   68.68%   68.91%   +0.23%     
==========================================
  Files         138      138              
  Lines       18540    18553      +13     
  Branches     3064     3061       -3     
==========================================
+ Hits        12734    12786      +52     
+ Misses       5152     5116      -36     
+ Partials      654      651       -3     
Files with missing lines Coverage Δ
beets/autotag/match.py 76.92% <100.00%> (ø)
beets/dbcore/db.py 94.04% <100.00%> (ø)
beets/dbcore/query.py 91.34% <100.00%> (ø)
beets/dbcore/queryparse.py 97.46% <100.00%> (ø)
beets/dbcore/types.py 95.98% <100.00%> (ø)
beets/importer/__init__.py 100.00% <ø> (ø)
beets/importer/session.py 94.36% <100.00%> (ø)
beets/importer/stages.py 88.05% <100.00%> (ø)
beets/importer/tasks.py 90.89% <100.00%> (ø)
beets/library/__init__.py 100.00% <ø> (ø)
... and 41 more
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jackwilsdon jackwilsdon requested a review from asardaes as a code owner January 1, 2026 15:46
Copilot AI review requested due to automatic review settings January 7, 2026 12:34
@snejus snejus force-pushed the update-lint-rules branch from 97fe1f1 to 2d0b8f8 Compare January 7, 2026 12:34
Copy link
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 updates typing and linting across the codebase to enable stricter ruff checks for Python 3.10+. It automatically adds from __future__ import annotations where needed, enforces PEP 604 union syntax, and addresses various linting issues including proper use of ClassVar for mutable class attributes.

Key changes:

  • Enabled ruff's future-annotations feature (auto-adds from __future__ import annotations and moves imports under TYPE_CHECKING)
  • Set target-version = "py310" to enforce PEP 604 union syntax (str | None instead of Union[str, None])
  • Enabled RUF* rules and addressed all identified issues (unused # noqa, unused unpacked variables, list materialization, ClassVar annotations)

Reviewed changes

Copilot reviewed 79 out of 80 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pyproject.toml Updated ruff version requirement and configuration to enable future-annotations, set py310 target, and enable RUF rules
.git-blame-ignore-revs Added commit hashes for the linting/typing changes to git blame ignore list
Multiple test files Replaced unused variables with _ placeholder and removed unnecessary # noqa comments
Multiple plugin files Added ClassVar type hints to mutable class attributes and moved imports under TYPE_CHECKING
beets/plugins.py Introduced BeetsPluginMeta metaclass to properly distinguish class vs instance attributes for template fields
beets/dbcore/*.py Added ClassVar annotations to class-level field/sort dictionaries and moved type imports
beets/library/models.py Added ClassVar annotations to _fields, _sorts, and item_keys dictionaries
Multiple source files Replaced list concatenation with unpacking syntax ([*list, item]) and converted to PEP 604 union types

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

@JOJ0 JOJ0 added the core Pull requests that modify the beets core `beets` label Jan 10, 2026
@JOJ0 JOJ0 added this to the 2.6.0 milestone Jan 13, 2026
@JOJ0 JOJ0 added the typehints label Jan 13, 2026
Copy link
Member

@JOJ0 JOJ0 left a comment

Choose a reason for hiding this comment

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

I've looked through points 1. and 2. which essentially are commits f75cbfe and f70eb4c

That is done if someone cares to continue with point 3.

@snejus
Copy link
Member Author

snejus commented Jan 13, 2026

image

I just had to address these:

image

joj0-biz

This comment was marked as resolved.

@JOJ0
Copy link
Member

JOJ0 commented Jan 13, 2026

damnit I used the wrong github account for the review. It's me as you've probably guessed ;-)

Copy link
Member

@henry-oberholtzer henry-oberholtzer left a comment

Choose a reason for hiding this comment

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

Looks good to me - doesn't look like it'll conflict terribly with any existing PR's either, if at all.

@snejus snejus force-pushed the update-lint-rules branch from 2d0b8f8 to 78d8bc8 Compare January 13, 2026 20:09
@snejus snejus force-pushed the update-lint-rules branch from 78d8bc8 to 177cde2 Compare January 13, 2026 20:54
@snejus snejus force-pushed the update-lint-rules branch from 177cde2 to c9625f8 Compare January 13, 2026 20:55
@snejus snejus merged commit b3c42a3 into master Jan 13, 2026
18 of 19 checks passed
@snejus snejus deleted the update-lint-rules branch January 13, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Pull requests that modify the beets core `beets` typehints

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants