mirror of
https://github.com/beetbox/beets.git
synced 2026-01-20 15:14:13 +01:00
Address RUF012
This commit is contained in:
parent
c52656fb0a
commit
1c20e4bd4e
28 changed files with 118 additions and 78 deletions
|
|
@ -29,7 +29,7 @@ from collections import defaultdict
|
|||
from collections.abc import Mapping
|
||||
from functools import cached_property
|
||||
from sqlite3 import sqlite_version_info
|
||||
from typing import TYPE_CHECKING, Any, AnyStr, Generic
|
||||
from typing import TYPE_CHECKING, Any, AnyStr, ClassVar, Generic
|
||||
|
||||
from typing_extensions import (
|
||||
Self,
|
||||
|
|
@ -299,7 +299,7 @@ class Model(ABC, Generic[D]):
|
|||
"""The flex field SQLite table name.
|
||||
"""
|
||||
|
||||
_fields: dict[str, types.Type] = {}
|
||||
_fields: ClassVar[dict[str, types.Type]] = {}
|
||||
"""A mapping indicating available "fixed" fields on this type. The
|
||||
keys are field names and the values are `Type` objects.
|
||||
"""
|
||||
|
|
@ -314,7 +314,7 @@ class Model(ABC, Generic[D]):
|
|||
"""Optional types for non-fixed (flexible and computed) fields."""
|
||||
return {}
|
||||
|
||||
_sorts: dict[str, type[FieldSort]] = {}
|
||||
_sorts: ClassVar[dict[str, type[FieldSort]]] = {}
|
||||
"""Optional named sort criteria. The keys are strings and the values
|
||||
are subclasses of `Sort`.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from datetime import datetime, timedelta
|
|||
from functools import cached_property, reduce
|
||||
from operator import mul, or_
|
||||
from re import Pattern
|
||||
from typing import TYPE_CHECKING, Any, Generic, TypeVar
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar
|
||||
|
||||
from beets import util
|
||||
from beets.util.units import raw_seconds_short
|
||||
|
|
@ -691,7 +691,12 @@ class Period:
|
|||
("%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"), # minute
|
||||
("%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"), # second
|
||||
)
|
||||
relative_units = {"y": 365, "m": 30, "w": 7, "d": 1}
|
||||
relative_units: ClassVar[dict[str, int]] = {
|
||||
"y": 365,
|
||||
"m": 30,
|
||||
"w": 7,
|
||||
"d": 1,
|
||||
}
|
||||
relative_re = "(?P<sign>[+|-]?)(?P<quantity>[0-9]+)(?P<timespan>[y|m|w|d])"
|
||||
|
||||
def __init__(self, date: datetime, precision: str):
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import re
|
|||
import time
|
||||
import typing
|
||||
from abc import ABC
|
||||
from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar, cast
|
||||
|
||||
import beets
|
||||
from beets import util
|
||||
|
|
@ -406,7 +406,7 @@ class MusicalKey(String):
|
|||
The standard format is C, Cm, C#, C#m, etc.
|
||||
"""
|
||||
|
||||
ENHARMONIC = {
|
||||
ENHARMONIC: ClassVar[dict[str, str]] = {
|
||||
r"db": "c#",
|
||||
r"eb": "d#",
|
||||
r"gb": "f#",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import time
|
|||
import unicodedata
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
from mediafile import MediaFile, UnreadableFileError
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ class Album(LibModel):
|
|||
_table = "albums"
|
||||
_flex_table = "album_attributes"
|
||||
_always_dirty = True
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, types.Type]] = {
|
||||
"id": types.PRIMARY_ID,
|
||||
"artpath": types.NullPathType(),
|
||||
"added": types.DATE,
|
||||
|
|
@ -281,13 +281,13 @@ class Album(LibModel):
|
|||
def _types(cls) -> dict[str, types.Type]:
|
||||
return {**super()._types, "path": types.PathType()}
|
||||
|
||||
_sorts = {
|
||||
_sorts: ClassVar[dict[str, type[dbcore.query.FieldSort]]] = {
|
||||
"albumartist": dbcore.query.SmartArtistSort,
|
||||
"artist": dbcore.query.SmartArtistSort,
|
||||
}
|
||||
|
||||
# List of keys that are set on an album's items.
|
||||
item_keys = [
|
||||
item_keys: ClassVar[list[str]] = [
|
||||
"added",
|
||||
"albumartist",
|
||||
"albumartists",
|
||||
|
|
@ -624,7 +624,7 @@ class Item(LibModel):
|
|||
|
||||
_table = "items"
|
||||
_flex_table = "item_attributes"
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, types.Type]] = {
|
||||
"id": types.PRIMARY_ID,
|
||||
"path": types.PathType(),
|
||||
"album_id": types.FOREIGN_ID,
|
||||
|
|
@ -744,7 +744,9 @@ class Item(LibModel):
|
|||
|
||||
_formatter = FormattedItemMapping
|
||||
|
||||
_sorts = {"artist": dbcore.query.SmartArtistSort}
|
||||
_sorts: ClassVar[dict[str, type[dbcore.query.FieldSort]]] = {
|
||||
"artist": dbcore.query.SmartArtistSort
|
||||
}
|
||||
|
||||
@cached_classproperty
|
||||
def _queries(cls) -> dict[str, FieldQueryType]:
|
||||
|
|
|
|||
|
|
@ -141,7 +141,13 @@ class PluginLogFilter(logging.Filter):
|
|||
# Managing the plugins themselves.
|
||||
|
||||
|
||||
class BeetsPlugin(metaclass=abc.ABCMeta):
|
||||
class BeetsPluginMeta(abc.ABCMeta):
|
||||
template_funcs: ClassVar[TFuncMap[str]] = {}
|
||||
template_fields: ClassVar[TFuncMap[Item]] = {}
|
||||
album_template_fields: ClassVar[TFuncMap[Album]] = {}
|
||||
|
||||
|
||||
class BeetsPlugin(metaclass=BeetsPluginMeta):
|
||||
"""The base class for all beets plugins. Plugins provide
|
||||
functionality by defining a subclass of BeetsPlugin and overriding
|
||||
the abstract methods defined here.
|
||||
|
|
@ -151,9 +157,10 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
|
|||
list
|
||||
)
|
||||
listeners: ClassVar[dict[EventType, list[Listener]]] = defaultdict(list)
|
||||
template_funcs: ClassVar[TFuncMap[str]] | TFuncMap[str] = {} # type: ignore[valid-type]
|
||||
template_fields: ClassVar[TFuncMap[Item]] | TFuncMap[Item] = {} # type: ignore[valid-type]
|
||||
album_template_fields: ClassVar[TFuncMap[Album]] | TFuncMap[Album] = {} # type: ignore[valid-type]
|
||||
|
||||
template_funcs: TFuncMap[str]
|
||||
template_fields: TFuncMap[Item]
|
||||
album_template_fields: TFuncMap[Album]
|
||||
|
||||
name: str
|
||||
config: ConfigView
|
||||
|
|
@ -220,14 +227,10 @@ class BeetsPlugin(metaclass=abc.ABCMeta):
|
|||
self.name = name or self.__module__.split(".")[-1]
|
||||
self.config = beets.config[self.name]
|
||||
|
||||
# If the class attributes are not set, initialize as instance attributes.
|
||||
# TODO: Revise with v3.0.0, see also type: ignore[valid-type] above
|
||||
if not self.template_funcs:
|
||||
self.template_funcs = {}
|
||||
if not self.template_fields:
|
||||
self.template_fields = {}
|
||||
if not self.album_template_fields:
|
||||
self.album_template_fields = {}
|
||||
# create per-instance storage for template fields and functions
|
||||
self.template_funcs = {}
|
||||
self.template_fields = {}
|
||||
self.album_template_fields = {}
|
||||
|
||||
self.early_import_stages = []
|
||||
self.import_stages = []
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ class ImportHelper(TestHelper):
|
|||
autotagging library and several assertions for the library.
|
||||
"""
|
||||
|
||||
default_import_config = {
|
||||
default_import_config: ClassVar[dict[str, bool]] = {
|
||||
"autotag": True,
|
||||
"copy": True,
|
||||
"hardlink": False,
|
||||
|
|
@ -880,7 +880,7 @@ class FetchImageHelper:
|
|||
def run(self, *args, **kwargs):
|
||||
super().run(*args, **kwargs)
|
||||
|
||||
IMAGEHEADER: dict[str, bytes] = {
|
||||
IMAGEHEADER: ClassVar[dict[str, bytes]] = {
|
||||
"image/jpeg": b"\xff\xd8\xff\x00\x00\x00JFIF",
|
||||
"image/png": b"\211PNG\r\n\032\n",
|
||||
"image/gif": b"GIF89a",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"""Fetch various AcousticBrainz metadata using MBID."""
|
||||
|
||||
from collections import defaultdict
|
||||
from typing import ClassVar
|
||||
|
||||
import requests
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ ABSCHEME = {
|
|||
|
||||
|
||||
class AcousticPlugin(plugins.BeetsPlugin):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"average_loudness": types.Float(6),
|
||||
"chords_changes_rate": types.Float(6),
|
||||
"chords_key": types.STRING,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import sys
|
|||
import time
|
||||
import traceback
|
||||
from string import Template
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
import beets
|
||||
import beets.ui
|
||||
|
|
@ -1344,7 +1344,7 @@ class Server(BaseServer):
|
|||
|
||||
# Searching.
|
||||
|
||||
tagtype_map = {
|
||||
tagtype_map: ClassVar[dict[str, str]] = {
|
||||
"Artist": "artist",
|
||||
"ArtistSort": "artist_sort",
|
||||
"Album": "album",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from __future__ import annotations
|
|||
|
||||
import collections
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
from typing import TYPE_CHECKING, ClassVar, Literal
|
||||
|
||||
import requests
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
class DeezerPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"deezer_track_rank": types.INTEGER,
|
||||
"deezer_track_id": types.INTEGER,
|
||||
"deezer_updated": types.DATE,
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ class ArtSource(RequestMixin, ABC):
|
|||
# Specify whether this source fetches local or remote images
|
||||
LOC: ClassVar[SourceLocation]
|
||||
# A list of methods to match metadata, sorted by descending accuracy
|
||||
VALID_MATCHING_CRITERIA: list[str] = ["default"]
|
||||
VALID_MATCHING_CRITERIA: ClassVar[list[str]] = ["default"]
|
||||
# A human-readable name for the art source
|
||||
NAME: ClassVar[str]
|
||||
# The key to select the art source in the config. This value will also be
|
||||
|
|
@ -518,8 +518,8 @@ class RemoteArtSource(ArtSource):
|
|||
class CoverArtArchive(RemoteArtSource):
|
||||
NAME = "Cover Art Archive"
|
||||
ID = "coverart"
|
||||
VALID_MATCHING_CRITERIA = ["release", "releasegroup"]
|
||||
VALID_THUMBNAIL_SIZES = [250, 500, 1200]
|
||||
VALID_MATCHING_CRITERIA: ClassVar[list[str]] = ["release", "releasegroup"]
|
||||
VALID_THUMBNAIL_SIZES: ClassVar[list[int]] = [250, 500, 1200]
|
||||
|
||||
URL = "https://coverartarchive.org/release/{mbid}"
|
||||
GROUP_URL = "https://coverartarchive.org/release-group/{mbid}"
|
||||
|
|
@ -1128,7 +1128,7 @@ class LastFM(RemoteArtSource):
|
|||
ID = "lastfm"
|
||||
|
||||
# Sizes in priority order.
|
||||
SIZES = OrderedDict(
|
||||
SIZES: ClassVar[dict[str, tuple[int, int]]] = OrderedDict(
|
||||
[
|
||||
("mega", (300, 300)),
|
||||
("extralarge", (300, 300)),
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ from functools import cached_property, partial, total_ordering
|
|||
from html import unescape
|
||||
from itertools import groupby
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, NamedTuple
|
||||
from typing import TYPE_CHECKING, ClassVar, NamedTuple
|
||||
from urllib.parse import quote, quote_plus, urlencode, urlparse
|
||||
|
||||
import langdetect
|
||||
|
|
@ -367,7 +367,7 @@ class LRCLib(Backend):
|
|||
class MusiXmatch(Backend):
|
||||
URL_TEMPLATE = "https://www.musixmatch.com/lyrics/{}/{}"
|
||||
|
||||
REPLACEMENTS = {
|
||||
REPLACEMENTS: ClassVar[dict[str, str]] = {
|
||||
r"\s+": "-",
|
||||
"<": "Less_Than",
|
||||
">": "Greater_Than",
|
||||
|
|
@ -600,7 +600,7 @@ class Google(SearchBackend):
|
|||
SEARCH_URL = "https://www.googleapis.com/customsearch/v1"
|
||||
|
||||
#: Exclude some letras.mus.br pages which do not contain lyrics.
|
||||
EXCLUDE_PAGES = [
|
||||
EXCLUDE_PAGES: ClassVar[list[str]] = [
|
||||
"significado.html",
|
||||
"traduccion.html",
|
||||
"traducao.html",
|
||||
|
|
@ -630,9 +630,12 @@ class Google(SearchBackend):
|
|||
#: Split cleaned up URL title into artist and title parts.
|
||||
URL_TITLE_PARTS_RE = re.compile(r" +(?:[ :|-]+|par|by) +|, ")
|
||||
|
||||
SOURCE_DIST_FACTOR = {"www.azlyrics.com": 0.5, "www.songlyrics.com": 0.6}
|
||||
SOURCE_DIST_FACTOR: ClassVar[dict[str, float]] = {
|
||||
"www.azlyrics.com": 0.5,
|
||||
"www.songlyrics.com": 0.6,
|
||||
}
|
||||
|
||||
ignored_domains: set[str] = set()
|
||||
ignored_domains: ClassVar[set[str]] = set()
|
||||
|
||||
@classmethod
|
||||
def pre_process_html(cls, html: str) -> str:
|
||||
|
|
@ -937,7 +940,7 @@ class RestFiles:
|
|||
|
||||
|
||||
class LyricsPlugin(LyricsRequestHandler, plugins.BeetsPlugin):
|
||||
BACKEND_BY_NAME = {
|
||||
BACKEND_BY_NAME: ClassVar[dict[str, type[Backend]]] = {
|
||||
b.name: b for b in [LRCLib, Google, Genius, Tekstowo, MusiXmatch]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,20 @@
|
|||
|
||||
"""Synchronize information from music player libraries"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from importlib import import_module
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
from confuse import ConfigValueError
|
||||
|
||||
from beets import ui
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from beets.dbcore import types
|
||||
|
||||
METASYNC_MODULE = "beetsplug.metasync"
|
||||
|
||||
# Dictionary to map the MODULE and the CLASS NAME of meta sources
|
||||
|
|
@ -32,8 +38,9 @@ SOURCES = {
|
|||
|
||||
|
||||
class MetaSource(metaclass=ABCMeta):
|
||||
item_types: ClassVar[dict[str, types.Type]]
|
||||
|
||||
def __init__(self, config, log):
|
||||
self.item_types = {}
|
||||
self.config = config
|
||||
self._log = log
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
from datetime import datetime
|
||||
from os.path import basename
|
||||
from time import mktime
|
||||
from typing import ClassVar
|
||||
from xml.sax.saxutils import quoteattr
|
||||
|
||||
from beets.dbcore import types
|
||||
|
|
@ -35,7 +36,7 @@ dbus = import_dbus()
|
|||
|
||||
|
||||
class Amarok(MetaSource):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"amarok_rating": types.INTEGER,
|
||||
"amarok_score": types.FLOAT,
|
||||
"amarok_uid": types.STRING,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import shutil
|
|||
import tempfile
|
||||
from contextlib import contextmanager
|
||||
from time import mktime
|
||||
from typing import ClassVar
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
from confuse import ConfigValueError
|
||||
|
|
@ -58,7 +59,7 @@ def _norm_itunes_path(path):
|
|||
|
||||
|
||||
class Itunes(MetaSource):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"itunes_rating": types.INTEGER, # 0..100 scale
|
||||
"itunes_playcount": types.INTEGER,
|
||||
"itunes_skipcount": types.INTEGER,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
import requests
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ def _item(track_info, album_info, album_id):
|
|||
class MissingPlugin(MusicBrainzAPIMixin, BeetsPlugin):
|
||||
"""List missing tracks"""
|
||||
|
||||
album_types = {
|
||||
album_types: ClassVar[dict[str, types.Type]] = {
|
||||
"missing": types.INTEGER,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
import os
|
||||
import time
|
||||
from typing import ClassVar
|
||||
|
||||
import mpd
|
||||
|
||||
|
|
@ -318,7 +319,7 @@ class MPDStats:
|
|||
|
||||
|
||||
class MPDStatsPlugin(plugins.BeetsPlugin):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"play_count": types.INTEGER,
|
||||
"skip_count": types.INTEGER,
|
||||
"last_played": types.DATE,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from __future__ import annotations
|
|||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
import beets
|
||||
from beets.dbcore.query import BLOB_TYPE, InQuery
|
||||
|
|
@ -24,6 +24,8 @@ from beets.util import path_as_posix
|
|||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
|
||||
from beets.dbcore.query import FieldQueryType
|
||||
|
||||
|
||||
def is_m3u_file(path: str) -> bool:
|
||||
return Path(path).suffix.lower() in {".m3u", ".m3u8"}
|
||||
|
|
@ -85,7 +87,9 @@ class PlaylistQuery(InQuery[bytes]):
|
|||
|
||||
|
||||
class PlaylistPlugin(beets.plugins.BeetsPlugin):
|
||||
item_queries = {"playlist": PlaylistQuery}
|
||||
item_queries: ClassVar[dict[str, FieldQueryType]] = {
|
||||
"playlist": PlaylistQuery
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import re
|
|||
import threading
|
||||
import time
|
||||
import webbrowser
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Literal
|
||||
|
||||
import confuse
|
||||
import requests
|
||||
|
|
@ -88,7 +88,7 @@ class AudioFeaturesUnavailableError(Exception):
|
|||
class SpotifyPlugin(
|
||||
SearchApiMetadataSourcePlugin[SearchResponseAlbums | SearchResponseTracks]
|
||||
):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"spotify_track_popularity": types.INTEGER,
|
||||
"spotify_acousticness": types.FLOAT,
|
||||
"spotify_danceability": types.FLOAT,
|
||||
|
|
@ -114,7 +114,7 @@ class SpotifyPlugin(
|
|||
track_url = "https://api.spotify.com/v1/tracks/"
|
||||
audio_features_url = "https://api.spotify.com/v1/audio-features/"
|
||||
|
||||
spotify_audio_features = {
|
||||
spotify_audio_features: ClassVar[dict[str, str]] = {
|
||||
"acousticness": "spotify_acousticness",
|
||||
"danceability": "spotify_danceability",
|
||||
"energy": "spotify_energy",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"""Moves patterns in path formats (suitable for moving articles)."""
|
||||
|
||||
import re
|
||||
from typing import ClassVar
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ FORMAT = "{}, {}"
|
|||
|
||||
|
||||
class ThePlugin(BeetsPlugin):
|
||||
patterns: list[str] = []
|
||||
patterns: ClassVar[list[str]] = []
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
|
|
|||
|
|
@ -72,10 +72,10 @@ class ConfDomain(Domain):
|
|||
|
||||
name = "conf"
|
||||
label = "Simple Configuration"
|
||||
object_types = {"conf": ObjType("conf", "conf")}
|
||||
directives = {"conf": Conf}
|
||||
roles = {"conf": XRefRole()}
|
||||
initial_data: dict[str, Any] = {"objects": {}}
|
||||
object_types = {"conf": ObjType("conf", "conf")} # noqa: RUF012
|
||||
directives = {"conf": Conf} # noqa: RUF012
|
||||
roles = {"conf": XRefRole()} # noqa: RUF012
|
||||
initial_data: dict[str, Any] = {"objects": {}} # noqa: RUF012
|
||||
|
||||
def get_objects(self) -> Iterable[tuple[str, str, str, str, str, int]]:
|
||||
"""Return an iterable of object tuples for the inventory."""
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class LyricsPage(NamedTuple):
|
|||
artist: str = "The Beatles"
|
||||
track_title: str = "Lady Madonna"
|
||||
url_title: str | None = None # only relevant to the Google backend
|
||||
marks: list[str] = [] # markers for pytest.param
|
||||
marks: list[str] = [] # markers for pytest.param # noqa: RUF012
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return name of this test case."""
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import threading
|
|||
import time
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
from typing import ClassVar
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import confuse
|
||||
|
|
@ -837,7 +838,7 @@ class BPDQueueTest(BPDTestHelper):
|
|||
fail=True,
|
||||
)
|
||||
|
||||
METADATA = {"Pos", "Time", "Id", "file", "duration"}
|
||||
METADATA: ClassVar[set[str]] = {"Pos", "Time", "Id", "file", "duration"}
|
||||
|
||||
def test_cmd_add(self):
|
||||
with self.run_bpd() as client:
|
||||
|
|
@ -1032,7 +1033,7 @@ class BPDConnectionTest(BPDTestHelper):
|
|||
}
|
||||
)
|
||||
|
||||
ALL_MPD_TAGTYPES = {
|
||||
ALL_MPD_TAGTYPES: ClassVar[set[str]] = {
|
||||
"Artist",
|
||||
"ArtistSort",
|
||||
"Album",
|
||||
|
|
@ -1057,7 +1058,7 @@ class BPDConnectionTest(BPDTestHelper):
|
|||
"MUSICBRAINZ_RELEASETRACKID",
|
||||
"MUSICBRAINZ_WORKID",
|
||||
}
|
||||
UNSUPPORTED_TAGTYPES = {
|
||||
UNSUPPORTED_TAGTYPES: ClassVar[set[str]] = {
|
||||
"MUSICBRAINZ_WORKID", # not tracked by beets
|
||||
"Performer", # not tracked by beets
|
||||
"AlbumSort", # not tracked by beets
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
import codecs
|
||||
from typing import ClassVar
|
||||
from unittest.mock import patch
|
||||
|
||||
from beets.dbcore.query import TrueQuery
|
||||
|
|
@ -319,7 +320,7 @@ class EditDuringImporterTestCase(
|
|||
|
||||
matching = AutotagStub.GOOD
|
||||
|
||||
IGNORED = ["added", "album_id", "id", "mtime", "path"]
|
||||
IGNORED: ClassVar[list[str]] = ["added", "album_id", "id", "mtime", "path"]
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import os
|
|||
import sys
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
from beets import plugins
|
||||
from beets.test.helper import PluginTestCase, capture_log
|
||||
|
|
@ -70,7 +70,7 @@ class HookLogsTest(HookTestCase):
|
|||
|
||||
|
||||
class HookCommandTest(HookTestCase):
|
||||
EVENTS: list[plugins.EventType] = ["write", "after_write"]
|
||||
EVENTS: ClassVar[list[plugins.EventType]] = ["write", "after_write"]
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
from typing import Any, ClassVar
|
||||
from unittest.mock import ANY, Mock, call, patch
|
||||
|
||||
from beets import util
|
||||
|
|
@ -46,9 +47,8 @@ class MPDStatsTest(PluginTestCase):
|
|||
assert mpdstats.get_item("/some/non-existing/path") is None
|
||||
assert "item not found:" in log.info.call_args[0][0]
|
||||
|
||||
FAKE_UNKNOWN_STATE = "some-unknown-one"
|
||||
STATUSES = [
|
||||
{"state": FAKE_UNKNOWN_STATE},
|
||||
STATUSES: ClassVar[list[dict[str, Any]]] = [
|
||||
{"state": "some-unknown-one"},
|
||||
{"state": "pause"},
|
||||
{"state": "play", "songid": 1, "time": "0:1"},
|
||||
{"state": "stop"},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"""Tests for MusicBrainz API wrapper."""
|
||||
|
||||
import unittest
|
||||
from typing import ClassVar
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
|
@ -1017,7 +1018,11 @@ class TestMusicBrainzPlugin(PluginMixin):
|
|||
plugin = "musicbrainz"
|
||||
|
||||
mbid = "d2a6f856-b553-40a0-ac54-a321e8e2da99"
|
||||
RECORDING = {"title": "foo", "id": "bar", "length": 42}
|
||||
RECORDING: ClassVar[dict[str, int | str]] = {
|
||||
"title": "foo",
|
||||
"id": "bar",
|
||||
"length": 42,
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def plugin_config(self):
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import shutil
|
|||
import sqlite3
|
||||
import unittest
|
||||
from tempfile import mkstemp
|
||||
from typing import ClassVar
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -57,13 +58,13 @@ class QueryFixture(dbcore.query.FieldQuery):
|
|||
class ModelFixture1(LibModel):
|
||||
_table = "test"
|
||||
_flex_table = "testflex"
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, dbcore.types.Type]] = {
|
||||
"id": dbcore.types.PRIMARY_ID,
|
||||
"field_one": dbcore.types.INTEGER,
|
||||
"field_two": dbcore.types.STRING,
|
||||
}
|
||||
|
||||
_sorts = {
|
||||
_sorts: ClassVar[dict[str, type[dbcore.query.FieldSort]]] = {
|
||||
"some_sort": SortFixture,
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +93,7 @@ class DatabaseFixture1(dbcore.Database):
|
|||
|
||||
|
||||
class ModelFixture2(ModelFixture1):
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, dbcore.types.Type]] = {
|
||||
"id": dbcore.types.PRIMARY_ID,
|
||||
"field_one": dbcore.types.INTEGER,
|
||||
"field_two": dbcore.types.INTEGER,
|
||||
|
|
@ -104,7 +105,7 @@ class DatabaseFixture2(dbcore.Database):
|
|||
|
||||
|
||||
class ModelFixture3(ModelFixture1):
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, dbcore.types.Type]] = {
|
||||
"id": dbcore.types.PRIMARY_ID,
|
||||
"field_one": dbcore.types.INTEGER,
|
||||
"field_two": dbcore.types.INTEGER,
|
||||
|
|
@ -117,7 +118,7 @@ class DatabaseFixture3(dbcore.Database):
|
|||
|
||||
|
||||
class ModelFixture4(ModelFixture1):
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, dbcore.types.Type]] = {
|
||||
"id": dbcore.types.PRIMARY_ID,
|
||||
"field_one": dbcore.types.INTEGER,
|
||||
"field_two": dbcore.types.INTEGER,
|
||||
|
|
@ -133,14 +134,14 @@ class DatabaseFixture4(dbcore.Database):
|
|||
class AnotherModelFixture(ModelFixture1):
|
||||
_table = "another"
|
||||
_flex_table = "anotherflex"
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, dbcore.types.Type]] = {
|
||||
"id": dbcore.types.PRIMARY_ID,
|
||||
"foo": dbcore.types.INTEGER,
|
||||
}
|
||||
|
||||
|
||||
class ModelFixture5(ModelFixture1):
|
||||
_fields = {
|
||||
_fields: ClassVar[dict[str, dbcore.types.Type]] = {
|
||||
"some_string_field": dbcore.types.STRING,
|
||||
"some_float_field": dbcore.types.FLOAT,
|
||||
"some_boolean_field": dbcore.types.BOOLEAN,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import logging
|
|||
import os
|
||||
import pkgutil
|
||||
import sys
|
||||
from typing import ClassVar
|
||||
from unittest.mock import ANY, Mock, patch
|
||||
|
||||
import pytest
|
||||
|
|
@ -46,7 +47,7 @@ from beets.util import PromptChoice, displayable_path, syspath
|
|||
|
||||
class TestPluginRegistration(PluginTestCase):
|
||||
class RatingPlugin(plugins.BeetsPlugin):
|
||||
item_types = {
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"rating": types.Float(),
|
||||
"multi_value": types.MULTI_VALUE_DSV,
|
||||
}
|
||||
|
|
@ -70,7 +71,9 @@ class TestPluginRegistration(PluginTestCase):
|
|||
|
||||
def test_duplicate_type(self):
|
||||
class DuplicateTypePlugin(plugins.BeetsPlugin):
|
||||
item_types = {"rating": types.INTEGER}
|
||||
item_types: ClassVar[dict[str, types.Type]] = {
|
||||
"rating": types.INTEGER
|
||||
}
|
||||
|
||||
self.register_plugin(DuplicateTypePlugin)
|
||||
with pytest.raises(
|
||||
|
|
|
|||
Loading…
Reference in a new issue