diff --git a/beets/metadata_plugins.py b/beets/metadata_plugins.py index 429a6e716..381881b51 100644 --- a/beets/metadata_plugins.py +++ b/beets/metadata_plugins.py @@ -8,7 +8,6 @@ implemented as plugins. from __future__ import annotations import abc -import inspect import re import warnings from typing import TYPE_CHECKING, Generic, Literal, Sequence, TypedDict, TypeVar @@ -421,13 +420,3 @@ class SearchApiMetadataSourcePlugin( query = unidecode.unidecode(query) return query - - -# Dynamically copy methods to BeetsPlugin for legacy support -# TODO: Remove this in the future major release, v3.0.0 - -for name, method in inspect.getmembers( - MetadataSourcePlugin, predicate=inspect.isfunction -): - if not hasattr(BeetsPlugin, name): - setattr(BeetsPlugin, name, method) diff --git a/beets/plugins.py b/beets/plugins.py index d9df4323c..d8d465183 100644 --- a/beets/plugins.py +++ b/beets/plugins.py @@ -158,6 +158,21 @@ class BeetsPlugin(metaclass=abc.ABCMeta): early_import_stages: list[ImportStageFunc] import_stages: list[ImportStageFunc] + def __init_subclass__(cls) -> None: + # Dynamically copy methods to BeetsPlugin for legacy support + # TODO: Remove this in the future major release, v3.0.0 + if inspect.isabstract(cls): + return + + from beets.metadata_plugins import MetadataSourcePlugin + + abstractmethods = MetadataSourcePlugin.__abstractmethods__ + for name, method in inspect.getmembers( + MetadataSourcePlugin, predicate=inspect.isfunction + ): + if name not in abstractmethods and not hasattr(cls, name): + setattr(cls, name, method) + def __init__(self, name: str | None = None): """Perform one-time plugin setup."""