Centralise warnings for maintainers into deprecate_for_maintainers

This commit is contained in:
Šarūnas Nejus 2025-10-25 11:48:09 +01:00
parent c79cad4ed1
commit 39288637b9
No known key found for this signature in database
8 changed files with 62 additions and 55 deletions

View file

@ -26,13 +26,9 @@ __author__ = "Adrian Sampson <adrian@radbox.org>"
def __getattr__(name: str): def __getattr__(name: str):
"""Handle deprecated imports.""" """Handle deprecated imports."""
return deprecate_imports( return deprecate_imports(
old_module=__name__, __name__,
new_module_by_name={ {"art": "beetsplug._utils", "vfs": "beetsplug._utils"},
"art": "beetsplug._utils", name,
"vfs": "beetsplug._utils",
},
name=name,
version="3.0.0",
) )

View file

@ -16,7 +16,6 @@
from __future__ import annotations from __future__ import annotations
import warnings
from importlib import import_module from importlib import import_module
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -24,7 +23,7 @@ from beets import config, logging
# Parts of external interface. # Parts of external interface.
from beets.util import unique_list from beets.util import unique_list
from beets.util.deprecation import deprecate_imports from beets.util.deprecation import deprecate_for_maintainers, deprecate_imports
from .hooks import AlbumInfo, AlbumMatch, TrackInfo, TrackMatch from .hooks import AlbumInfo, AlbumMatch, TrackInfo, TrackMatch
from .match import Proposal, Recommendation, tag_album, tag_item from .match import Proposal, Recommendation, tag_album, tag_item
@ -37,18 +36,13 @@ if TYPE_CHECKING:
def __getattr__(name: str): def __getattr__(name: str):
if name == "current_metadata": if name == "current_metadata":
warnings.warn( deprecate_for_maintainers(
( f"'beets.autotag.{name}'", "'beets.util.get_most_common_tags'"
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,
) )
return import_module("beets.util").get_most_common_tags return import_module("beets.util").get_most_common_tags
return deprecate_imports( return deprecate_imports(
__name__, {"Distance": "beets.autotag.distance"}, name, "3.0.0" __name__, {"Distance": "beets.autotag.distance"}, name
) )

View file

@ -13,7 +13,7 @@ NEW_MODULE_BY_NAME = dict.fromkeys(
def __getattr__(name: str): 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__ = [ __all__ = [

View file

@ -13,17 +13,11 @@
# included in all copies or substantial portions of the Software. # included in all copies or substantial portions of the Software.
import warnings
import mediafile import mediafile
warnings.warn( from .util.deprecation import deprecate_for_maintainers
"beets.mediafile is deprecated; use mediafile instead",
# Show the location of the `import mediafile` statement as the warning's deprecate_for_maintainers("'beets.mediafile'", "'mediafile'", stacklevel=2)
# source, rather than this file, such that the offending module can be
# identified easily.
stacklevel=2,
)
# Import everything from the mediafile module into this module. # Import everything from the mediafile module into this module.
for key, value in mediafile.__dict__.items(): for key, value in mediafile.__dict__.items():
@ -31,4 +25,4 @@ for key, value in mediafile.__dict__.items():
globals()[key] = value globals()[key] = value
# Cleanup namespace. # Cleanup namespace.
del key, value, warnings, mediafile del key, value, mediafile

View file

@ -20,7 +20,6 @@ import abc
import inspect import inspect
import re import re
import sys import sys
import warnings
from collections import defaultdict from collections import defaultdict
from functools import cached_property, wraps from functools import cached_property, wraps
from importlib import import_module from importlib import import_module
@ -33,6 +32,7 @@ from typing_extensions import ParamSpec
import beets import beets
from beets import logging from beets import logging
from beets.util import unique_list from beets.util import unique_list
from beets.util.deprecation import deprecate_for_maintainers
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Callable, Iterable, Sequence from collections.abc import Callable, Iterable, Sequence
@ -184,11 +184,12 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
): ):
return return
warnings.warn( deprecate_for_maintainers(
f"{cls.__name__} is used as a legacy metadata source. " (
"It should extend MetadataSourcePlugin instead of BeetsPlugin. " f"'{cls.__name__}' is used as a legacy metadata source since it"
"Support for this will be removed in the v3.0.0 release!", " inherits 'beets.plugins.BeetsPlugin'. Support for this"
DeprecationWarning, ),
"'beets.metadata_plugins.MetadataSourcePlugin'",
stacklevel=3, stacklevel=3,
) )
@ -265,7 +266,10 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
if source.filename: # user config if source.filename: # user config
self._log.warning(message) self._log.warning(message)
else: # 3rd-party plugin config 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]: def commands(self) -> Sequence[Subcommand]:
"""Should return a list of beets.ui.Subcommand objects for """Should return a list of beets.ui.Subcommand objects for

View file

@ -28,7 +28,6 @@ import sqlite3
import sys import sys
import textwrap import textwrap
import traceback import traceback
import warnings
from difflib import SequenceMatcher from difflib import SequenceMatcher
from functools import cache from functools import cache
from itertools import chain 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 db
from beets.dbcore import query as db_query from beets.dbcore import query as db_query
from beets.util import as_string from beets.util import as_string
from beets.util.deprecation import deprecate_for_maintainers
from beets.util.functemplate import template from beets.util.functemplate import template
if TYPE_CHECKING: if TYPE_CHECKING:
@ -114,11 +114,7 @@ def decargs(arglist):
.. deprecated:: 2.4.0 .. deprecated:: 2.4.0
This function will be removed in 3.0.0. This function will be removed in 3.0.0.
""" """
warnings.warn( deprecate_for_maintainers("'beets.ui.decargs'")
"decargs() is deprecated and will be removed in version 3.0.0.",
DeprecationWarning,
stacklevel=2,
)
return arglist return arglist

View file

@ -16,7 +16,7 @@
interface. interface.
""" """
from beets.util import deprecate_imports from beets.util.deprecation import deprecate_imports
from .completion import completion_cmd from .completion import completion_cmd
from .config import config_cmd from .config import config_cmd
@ -36,14 +36,12 @@ from .write import write_cmd
def __getattr__(name: str): def __getattr__(name: str):
"""Handle deprecated imports.""" """Handle deprecated imports."""
return deprecate_imports( return deprecate_imports(
old_module=__name__, __name__,
new_module_by_name={ {
"TerminalImportSession": "beets.ui.commands.import_.session", "TerminalImportSession": "beets.ui.commands.import_.session",
"PromptChoice": "beets.ui.commands.import_.session", "PromptChoice": "beets.ui.commands.import_.session",
# TODO: We might want to add more deprecated imports here
}, },
name=name, name,
version="3.0.0",
) )

View file

@ -1,10 +1,39 @@
from __future__ import annotations
import warnings import warnings
from importlib import import_module from importlib import import_module
from typing import Any from typing import Any
from packaging.version import Version
import beets
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_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( def deprecate_imports(
old_module: str, new_module_by_name: dict[str, str], name: str, version: str old_module: str, new_module_by_name: dict[str, str], name: str
) -> Any: ) -> Any:
"""Handle deprecated module imports by redirecting to new locations. """Handle deprecated module imports by redirecting to new locations.
@ -14,13 +43,9 @@ def deprecate_imports(
existing code to continue working during transition periods. existing code to continue working during transition periods.
""" """
if new_module := new_module_by_name.get(name): if new_module := new_module_by_name.get(name):
warnings.warn( deprecate_for_maintainers(
( f"'{old_module}.{name}'", f"'{new_module}.{name}'", stacklevel=2
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) return getattr(import_module(new_module), name)
raise AttributeError(f"module '{old_module}' has no attribute '{name}'") raise AttributeError(f"module '{old_module}' has no attribute '{name}'")