mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Add deprecation warning for musicbrainz.enabled but use it to load the plugin, centralise deprecations handling (#6127)
Fixes: #6121 This PR introduces a centralized deprecation system and adjusts `musicbrainz` plugin loading to properly handle the deprecated `musicbrainz.enabled` configuration option. #### MusicBrainz - Added deprecation warnings for the `musicbrainz.enabled` configuration option: - When set to `true`, warns users to explicitly add `musicbrainz` to their `plugins` configuration and adds it if not already present - When set to `false`, warns users and adds the plugin to `disabled_plugins` (list received by the `--disable-plugins` flag) #### Deprecations - Created new `beets/util/deprecation.py` module with standardized deprecation helpers: - `deprecate_for_user()` - logs warnings visible to end users - `deprecate_for_maintainers()` - emits `DeprecationWarning` for developers - `deprecate_imports()` - handles deprecated module imports with automatic version calculation - `_format_message()` - generates consistent deprecation messages that auto-calculate next major version - Migrated all deprecation handling to use the new centralized functions: - Replaced inline `warnings.warn()` calls throughout codebase - Updated `deprecate_imports()` signature to remove explicit `version` parameter - Converted user-facing deprecation warnings in plugins to use logger-based `deprecate_for_user()`
This commit is contained in:
commit
6abb901b6b
16 changed files with 174 additions and 115 deletions
|
|
@ -17,7 +17,7 @@ from sys import stderr
|
|||
|
||||
import confuse
|
||||
|
||||
from .util import deprecate_imports
|
||||
from .util.deprecation import deprecate_imports
|
||||
|
||||
__version__ = "2.5.1"
|
||||
__author__ = "Adrian Sampson <adrian@radbox.org>"
|
||||
|
|
@ -26,13 +26,9 @@ __author__ = "Adrian Sampson <adrian@radbox.org>"
|
|||
def __getattr__(name: str):
|
||||
"""Handle deprecated imports."""
|
||||
return deprecate_imports(
|
||||
old_module=__name__,
|
||||
new_module_by_name={
|
||||
"art": "beetsplug._utils",
|
||||
"vfs": "beetsplug._utils",
|
||||
},
|
||||
name=name,
|
||||
version="3.0.0",
|
||||
__name__,
|
||||
{"art": "beetsplug._utils", "vfs": "beetsplug._utils"},
|
||||
name,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
|
@ -24,8 +23,8 @@ from beets import config, logging
|
|||
|
||||
# Parts of external interface.
|
||||
from beets.util import unique_list
|
||||
from beets.util.deprecation import deprecate_for_maintainers, deprecate_imports
|
||||
|
||||
from ..util import deprecate_imports
|
||||
from .hooks import AlbumInfo, AlbumMatch, TrackInfo, TrackMatch
|
||||
from .match import Proposal, Recommendation, tag_album, tag_item
|
||||
|
||||
|
|
@ -37,18 +36,13 @@ if TYPE_CHECKING:
|
|||
|
||||
def __getattr__(name: str):
|
||||
if name == "current_metadata":
|
||||
warnings.warn(
|
||||
(
|
||||
f"'beets.autotag.{name}' is deprecated and will be removed in"
|
||||
" 3.0.0. Use 'beets.util.get_most_common_tags' instead."
|
||||
),
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
deprecate_for_maintainers(
|
||||
f"'beets.autotag.{name}'", "'beets.util.get_most_common_tags'"
|
||||
)
|
||||
return import_module("beets.util").get_most_common_tags
|
||||
|
||||
return deprecate_imports(
|
||||
__name__, {"Distance": "beets.autotag.distance"}, name, "3.0.0"
|
||||
__name__, {"Distance": "beets.autotag.distance"}, name
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from beets.util import deprecate_imports
|
||||
from beets.util.deprecation import deprecate_imports
|
||||
|
||||
from .exceptions import FileOperationError, ReadError, WriteError
|
||||
from .library import Library
|
||||
|
|
@ -13,7 +13,7 @@ NEW_MODULE_BY_NAME = dict.fromkeys(
|
|||
|
||||
|
||||
def __getattr__(name: str):
|
||||
return deprecate_imports(__name__, NEW_MODULE_BY_NAME, name, "3.0.0")
|
||||
return deprecate_imports(__name__, NEW_MODULE_BY_NAME, name)
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
|
|||
|
|
@ -13,17 +13,11 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
import warnings
|
||||
|
||||
import mediafile
|
||||
|
||||
warnings.warn(
|
||||
"beets.mediafile is deprecated; use mediafile instead",
|
||||
# Show the location of the `import mediafile` statement as the warning's
|
||||
# source, rather than this file, such that the offending module can be
|
||||
# identified easily.
|
||||
stacklevel=2,
|
||||
)
|
||||
from .util.deprecation import deprecate_for_maintainers
|
||||
|
||||
deprecate_for_maintainers("'beets.mediafile'", "'mediafile'", stacklevel=2)
|
||||
|
||||
# Import everything from the mediafile module into this module.
|
||||
for key, value in mediafile.__dict__.items():
|
||||
|
|
@ -31,4 +25,4 @@ for key, value in mediafile.__dict__.items():
|
|||
globals()[key] = value
|
||||
|
||||
# Cleanup namespace.
|
||||
del key, value, warnings, mediafile
|
||||
del key, value, mediafile
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import abc
|
|||
import inspect
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from functools import cached_property, wraps
|
||||
from importlib import import_module
|
||||
|
|
@ -33,6 +32,7 @@ from typing_extensions import ParamSpec
|
|||
import beets
|
||||
from beets import logging
|
||||
from beets.util import unique_list
|
||||
from beets.util.deprecation import deprecate_for_maintainers, deprecate_for_user
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable, Iterable, Sequence
|
||||
|
|
@ -184,11 +184,12 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
|
|||
):
|
||||
return
|
||||
|
||||
warnings.warn(
|
||||
f"{cls.__name__} is used as a legacy metadata source. "
|
||||
"It should extend MetadataSourcePlugin instead of BeetsPlugin. "
|
||||
"Support for this will be removed in the v3.0.0 release!",
|
||||
DeprecationWarning,
|
||||
deprecate_for_maintainers(
|
||||
(
|
||||
f"'{cls.__name__}' is used as a legacy metadata source since it"
|
||||
" inherits 'beets.plugins.BeetsPlugin'. Support for this"
|
||||
),
|
||||
"'beets.metadata_plugins.MetadataSourcePlugin'",
|
||||
stacklevel=3,
|
||||
)
|
||||
|
||||
|
|
@ -256,16 +257,19 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
|
|||
):
|
||||
return
|
||||
|
||||
message = (
|
||||
"'source_weight' configuration option is deprecated and will be"
|
||||
" removed in v3.0.0. Use 'data_source_mismatch_penalty' instead"
|
||||
)
|
||||
for source in self.config.root().sources:
|
||||
if "source_weight" in (source.get(self.name) or {}):
|
||||
if source.filename: # user config
|
||||
self._log.warning(message)
|
||||
deprecate_for_user(
|
||||
self._log,
|
||||
f"'{self.name}.source_weight' configuration option",
|
||||
f"'{self.name}.data_source_mismatch_penalty'",
|
||||
)
|
||||
else: # 3rd-party plugin config
|
||||
warnings.warn(message, DeprecationWarning, stacklevel=0)
|
||||
deprecate_for_maintainers(
|
||||
"'source_weight' configuration option",
|
||||
"'data_source_mismatch_penalty'",
|
||||
)
|
||||
|
||||
def commands(self) -> Sequence[Subcommand]:
|
||||
"""Should return a list of beets.ui.Subcommand objects for
|
||||
|
|
@ -410,16 +414,22 @@ def get_plugin_names() -> list[str]:
|
|||
# *contain* a `beetsplug` package.
|
||||
sys.path += paths
|
||||
plugins = unique_list(beets.config["plugins"].as_str_seq())
|
||||
# TODO: Remove in v3.0.0
|
||||
if (
|
||||
"musicbrainz" not in plugins
|
||||
and "musicbrainz" in beets.config
|
||||
and beets.config["musicbrainz"].get().get("enabled")
|
||||
):
|
||||
plugins.append("musicbrainz")
|
||||
|
||||
beets.config.add({"disabled_plugins": []})
|
||||
disabled_plugins = set(beets.config["disabled_plugins"].as_str_seq())
|
||||
# TODO: Remove in v3.0.0
|
||||
mb_enabled = beets.config["musicbrainz"].flatten().get("enabled")
|
||||
if mb_enabled:
|
||||
deprecate_for_user(
|
||||
log,
|
||||
"'musicbrainz.enabled' configuration option",
|
||||
"'plugins' configuration to explicitly add 'musicbrainz'",
|
||||
)
|
||||
if "musicbrainz" not in plugins:
|
||||
plugins.append("musicbrainz")
|
||||
elif mb_enabled is False:
|
||||
deprecate_for_user(log, "'musicbrainz.enabled' configuration option")
|
||||
disabled_plugins.add("musicbrainz")
|
||||
|
||||
return [p for p in plugins if p not in disabled_plugins]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import sqlite3
|
|||
import sys
|
||||
import textwrap
|
||||
import traceback
|
||||
import warnings
|
||||
from difflib import SequenceMatcher
|
||||
from functools import cache
|
||||
from itertools import chain
|
||||
|
|
@ -40,6 +39,7 @@ from beets import config, library, logging, plugins, util
|
|||
from beets.dbcore import db
|
||||
from beets.dbcore import query as db_query
|
||||
from beets.util import as_string
|
||||
from beets.util.deprecation import deprecate_for_maintainers
|
||||
from beets.util.functemplate import template
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -114,11 +114,7 @@ def decargs(arglist):
|
|||
.. deprecated:: 2.4.0
|
||||
This function will be removed in 3.0.0.
|
||||
"""
|
||||
warnings.warn(
|
||||
"decargs() is deprecated and will be removed in version 3.0.0.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
deprecate_for_maintainers("'beets.ui.decargs'")
|
||||
return arglist
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
interface.
|
||||
"""
|
||||
|
||||
from beets.util import deprecate_imports
|
||||
from beets.util.deprecation import deprecate_imports
|
||||
|
||||
from .completion import completion_cmd
|
||||
from .config import config_cmd
|
||||
|
|
@ -36,14 +36,12 @@ from .write import write_cmd
|
|||
def __getattr__(name: str):
|
||||
"""Handle deprecated imports."""
|
||||
return deprecate_imports(
|
||||
old_module=__name__,
|
||||
new_module_by_name={
|
||||
__name__,
|
||||
{
|
||||
"TerminalImportSession": "beets.ui.commands.import_.session",
|
||||
"PromptChoice": "beets.ui.commands.import_.session",
|
||||
# TODO: We might want to add more deprecated imports here
|
||||
"PromptChoice": "beets.util",
|
||||
},
|
||||
name=name,
|
||||
version="3.0.0",
|
||||
name,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
from collections import Counter
|
||||
from itertools import chain
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
from beets import autotag, config, importer, logging, plugins, ui
|
||||
from beets.autotag import Recommendation
|
||||
from beets.util import displayable_path
|
||||
from beets.util import PromptChoice, displayable_path
|
||||
from beets.util.units import human_bytes, human_seconds_short
|
||||
|
||||
from .display import (
|
||||
|
|
@ -368,12 +367,6 @@ def _summary_judgment(rec):
|
|||
return action
|
||||
|
||||
|
||||
class PromptChoice(NamedTuple):
|
||||
short: str
|
||||
long: str
|
||||
callback: Any
|
||||
|
||||
|
||||
def choose_candidate(
|
||||
candidates,
|
||||
singleton,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import subprocess
|
|||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
import warnings
|
||||
from collections import Counter
|
||||
from collections.abc import Callable, Sequence
|
||||
from contextlib import suppress
|
||||
|
|
@ -168,6 +167,12 @@ class MoveOperation(Enum):
|
|||
REFLINK_AUTO = 5
|
||||
|
||||
|
||||
class PromptChoice(NamedTuple):
|
||||
short: str
|
||||
long: str
|
||||
callback: Any
|
||||
|
||||
|
||||
def normpath(path: PathLike) -> bytes:
|
||||
"""Provide the canonical form of the path suitable for storing in
|
||||
the database.
|
||||
|
|
@ -1195,26 +1200,3 @@ def get_temp_filename(
|
|||
def unique_list(elements: Iterable[T]) -> list[T]:
|
||||
"""Return a list with unique elements in the original order."""
|
||||
return list(dict.fromkeys(elements))
|
||||
|
||||
|
||||
def deprecate_imports(
|
||||
old_module: str, new_module_by_name: dict[str, str], name: str, version: str
|
||||
) -> Any:
|
||||
"""Handle deprecated module imports by redirecting to new locations.
|
||||
|
||||
Facilitates gradual migration of module structure by intercepting import
|
||||
attempts for relocated functionality. Issues deprecation warnings while
|
||||
transparently providing access to the moved implementation, allowing
|
||||
existing code to continue working during transition periods.
|
||||
"""
|
||||
if new_module := new_module_by_name.get(name):
|
||||
warnings.warn(
|
||||
(
|
||||
f"'{old_module}.{name}' is deprecated and will be removed"
|
||||
f" in {version}. Use '{new_module}.{name}' instead."
|
||||
),
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return getattr(import_module(new_module), name)
|
||||
raise AttributeError(f"module '{old_module}' has no attribute '{name}'")
|
||||
|
|
|
|||
60
beets/util/deprecation.py
Normal file
60
beets/util/deprecation.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from packaging.version import Version
|
||||
|
||||
import beets
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from logging import Logger
|
||||
|
||||
|
||||
def _format_message(old: str, new: str | None = None) -> str:
|
||||
next_major = f"{Version(beets.__version__).major + 1}.0.0"
|
||||
msg = f"{old} is deprecated and will be removed in version {next_major}."
|
||||
if new:
|
||||
msg += f" Use {new} instead."
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def deprecate_for_user(
|
||||
logger: Logger, old: str, new: str | None = None
|
||||
) -> None:
|
||||
logger.warning(_format_message(old, new))
|
||||
|
||||
|
||||
def deprecate_for_maintainers(
|
||||
old: str, new: str | None = None, stacklevel: int = 1
|
||||
) -> None:
|
||||
"""Issue a deprecation warning visible to maintainers during development.
|
||||
|
||||
Emits a DeprecationWarning that alerts developers about deprecated code
|
||||
patterns. Unlike user-facing warnings, these are primarily for internal
|
||||
code maintenance and appear during test runs or with warnings enabled.
|
||||
"""
|
||||
warnings.warn(
|
||||
_format_message(old, new), DeprecationWarning, stacklevel=stacklevel + 1
|
||||
)
|
||||
|
||||
|
||||
def deprecate_imports(
|
||||
old_module: str, new_module_by_name: dict[str, str], name: str
|
||||
) -> Any:
|
||||
"""Handle deprecated module imports by redirecting to new locations.
|
||||
|
||||
Facilitates gradual migration of module structure by intercepting import
|
||||
attempts for relocated functionality. Issues deprecation warnings while
|
||||
transparently providing access to the moved implementation, allowing
|
||||
existing code to continue working during transition periods.
|
||||
"""
|
||||
if new_module := new_module_by_name.get(name):
|
||||
deprecate_for_maintainers(
|
||||
f"'{old_module}.{name}'", f"'{new_module}.{name}'", stacklevel=2
|
||||
)
|
||||
|
||||
return getattr(import_module(new_module), name)
|
||||
raise AttributeError(f"module '{old_module}' has no attribute '{name}'")
|
||||
|
|
@ -25,8 +25,8 @@ import yaml
|
|||
from beets import plugins, ui, util
|
||||
from beets.dbcore import types
|
||||
from beets.importer import Action
|
||||
from beets.ui.commands.import_.session import PromptChoice
|
||||
from beets.ui.commands.utils import do_query
|
||||
from beets.util import PromptChoice
|
||||
|
||||
# These "safe" types can avoid the format/parse cycle that most fields go
|
||||
# through: they are safe to edit with native YAML types.
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ import subprocess
|
|||
from beets import ui
|
||||
from beets.autotag import Recommendation
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui.commands import PromptChoice
|
||||
from beets.util import displayable_path
|
||||
from beets.util import PromptChoice, displayable_path
|
||||
from beetsplug.info import print_data
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import beets
|
|||
import beets.autotag.hooks
|
||||
from beets import config, plugins, util
|
||||
from beets.metadata_plugins import MetadataSourcePlugin
|
||||
from beets.util.deprecation import deprecate_for_user
|
||||
from beets.util.id_extractors import extract_release_id
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -403,9 +404,10 @@ class MusicBrainzPlugin(MetadataSourcePlugin):
|
|||
self.config["search_limit"] = self.config["match"][
|
||||
"searchlimit"
|
||||
].get()
|
||||
self._log.warning(
|
||||
"'musicbrainz.searchlimit' option is deprecated and will be "
|
||||
"removed in 3.0.0. Use 'musicbrainz.search_limit' instead."
|
||||
deprecate_for_user(
|
||||
self._log,
|
||||
"'musicbrainz.searchlimit' configuration option",
|
||||
"'musicbrainz.search_limit'",
|
||||
)
|
||||
hostname = self.config["host"].as_str()
|
||||
https = self.config["https"].get(bool)
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ from os.path import relpath
|
|||
from beets import config, ui, util
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand
|
||||
from beets.ui.commands import PromptChoice
|
||||
from beets.util import get_temp_filename
|
||||
from beets.util import PromptChoice, get_temp_filename
|
||||
|
||||
# Indicate where arguments should be inserted into the command string.
|
||||
# If this is missing, they're placed at the end.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ shall expose to the user:
|
|||
.. code-block:: python
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui.commands import PromptChoice
|
||||
from beets.util import PromptChoice
|
||||
|
||||
|
||||
class ExamplePlugin(BeetsPlugin):
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ from beets.test.helper import (
|
|||
PluginTestCase,
|
||||
TerminalImportMixin,
|
||||
)
|
||||
from beets.util import displayable_path, syspath
|
||||
from beets.util import PromptChoice, displayable_path, syspath
|
||||
|
||||
|
||||
class TestPluginRegistration(PluginTestCase):
|
||||
|
|
@ -292,8 +292,8 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
|||
|
||||
def return_choices(self, session, task):
|
||||
return [
|
||||
ui.commands.PromptChoice("f", "Foo", None),
|
||||
ui.commands.PromptChoice("r", "baR", None),
|
||||
PromptChoice("f", "Foo", None),
|
||||
PromptChoice("r", "baR", None),
|
||||
]
|
||||
|
||||
self.register_plugin(DummyPlugin)
|
||||
|
|
@ -328,8 +328,8 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
|||
|
||||
def return_choices(self, session, task):
|
||||
return [
|
||||
ui.commands.PromptChoice("f", "Foo", None),
|
||||
ui.commands.PromptChoice("r", "baR", None),
|
||||
PromptChoice("f", "Foo", None),
|
||||
PromptChoice("r", "baR", None),
|
||||
]
|
||||
|
||||
self.register_plugin(DummyPlugin)
|
||||
|
|
@ -363,10 +363,10 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
|||
|
||||
def return_choices(self, session, task):
|
||||
return [
|
||||
ui.commands.PromptChoice("a", "A foo", None), # dupe
|
||||
ui.commands.PromptChoice("z", "baZ", None), # ok
|
||||
ui.commands.PromptChoice("z", "Zupe", None), # dupe
|
||||
ui.commands.PromptChoice("z", "Zoo", None),
|
||||
PromptChoice("a", "A foo", None), # dupe
|
||||
PromptChoice("z", "baZ", None), # ok
|
||||
PromptChoice("z", "Zupe", None), # dupe
|
||||
PromptChoice("z", "Zoo", None),
|
||||
] # dupe
|
||||
|
||||
self.register_plugin(DummyPlugin)
|
||||
|
|
@ -399,7 +399,7 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
|||
)
|
||||
|
||||
def return_choices(self, session, task):
|
||||
return [ui.commands.PromptChoice("f", "Foo", self.foo)]
|
||||
return [PromptChoice("f", "Foo", self.foo)]
|
||||
|
||||
def foo(self, session, task):
|
||||
pass
|
||||
|
|
@ -441,7 +441,7 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
|||
)
|
||||
|
||||
def return_choices(self, session, task):
|
||||
return [ui.commands.PromptChoice("f", "Foo", self.foo)]
|
||||
return [PromptChoice("f", "Foo", self.foo)]
|
||||
|
||||
def foo(self, session, task):
|
||||
return Action.SKIP
|
||||
|
|
@ -543,3 +543,39 @@ class TestDeprecationCopy:
|
|||
assert hasattr(LegacyMetadataPlugin, "data_source_mismatch_penalty")
|
||||
assert hasattr(LegacyMetadataPlugin, "_extract_id")
|
||||
assert hasattr(LegacyMetadataPlugin, "get_artist")
|
||||
|
||||
|
||||
class TestMusicBrainzPluginLoading:
|
||||
@pytest.fixture(autouse=True)
|
||||
def config(self):
|
||||
_config = config
|
||||
_config.sources = []
|
||||
_config.read(user=False, defaults=True)
|
||||
return _config
|
||||
|
||||
def test_default(self):
|
||||
assert "musicbrainz" in plugins.get_plugin_names()
|
||||
|
||||
def test_other_plugin_enabled(self, config):
|
||||
config["plugins"] = ["anything"]
|
||||
|
||||
assert "musicbrainz" not in plugins.get_plugin_names()
|
||||
|
||||
def test_deprecated_enabled(self, config, caplog):
|
||||
config["plugins"] = ["anything"]
|
||||
config["musicbrainz"]["enabled"] = True
|
||||
|
||||
assert "musicbrainz" in plugins.get_plugin_names()
|
||||
assert (
|
||||
"musicbrainz.enabled' configuration option is deprecated"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
def test_deprecated_disabled(self, config, caplog):
|
||||
config["musicbrainz"]["enabled"] = False
|
||||
|
||||
assert "musicbrainz" not in plugins.get_plugin_names()
|
||||
assert (
|
||||
"musicbrainz.enabled' configuration option is deprecated"
|
||||
in caplog.text
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue