Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions beets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ class IncludeLazyConfig(confuse.LazyConfig):
YAML files specified in an `include` setting.
"""

def read(self, user=True, defaults=True):
def read(self, user: bool = True, defaults: bool = True) -> None:
super().read(user, defaults)

try:
for view in self["include"]:
for view in self["include"].sequence():
self.set_file(view.as_filename())
except confuse.NotFoundError:
pass
Expand Down
4 changes: 2 additions & 2 deletions beets/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
if TYPE_CHECKING:
from collections.abc import Callable, Iterable, Iterator, Sequence

from confuse import ConfigView
from confuse import Subview

from beets.dbcore import Query
from beets.dbcore.db import FieldQueryType
Expand Down Expand Up @@ -162,7 +162,7 @@ class BeetsPlugin(metaclass=BeetsPluginMeta):
album_template_fields: TFuncMap[Album]

name: str
config: ConfigView
config: Subview
early_import_stages: list[ImportStageFunc]
import_stages: list[ImportStageFunc]

Expand Down
23 changes: 12 additions & 11 deletions beets/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import traceback
from difflib import SequenceMatcher
from functools import cache
from itertools import chain
from typing import TYPE_CHECKING, Any, Literal

import confuse
Expand Down Expand Up @@ -551,19 +550,21 @@ def get_color_config() -> dict[ColorName, str]:
legacy single-color format. Validates all color names against known codes
and raises an error for any invalid entries.
"""
colors_by_color_name: dict[ColorName, list[str]] = {
template_dict: dict[ColorName, confuse.OneOf[str | list[str]]] = {
n: confuse.OneOf(
[
confuse.Choice(sorted(LEGACY_COLORS)),
confuse.Sequence(confuse.Choice(sorted(CODE_BY_COLOR))),
]
)
for n in ColorName.__args__ # type: ignore[attr-defined]
}
template = confuse.MappingTemplate(template_dict)
colors_by_color_name = {
k: (v if isinstance(v, list) else LEGACY_COLORS.get(v, [v]))
for k, v in config["ui"]["colors"].flatten().items()
for k, v in config["ui"]["colors"].get(template).items()
}

if invalid_colors := (
set(chain.from_iterable(colors_by_color_name.values()))
- CODE_BY_COLOR.keys()
):
raise UserError(
f"Invalid color(s) in configuration: {', '.join(invalid_colors)}"
)

return {
n: ";".join(str(CODE_BY_COLOR[c]) for c in colors)
for n, colors in colors_by_color_name.items()
Expand Down
3 changes: 2 additions & 1 deletion beets/ui/commands/import_/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,14 +327,15 @@ def summarize_items(items, singleton):
return ", ".join(summary_parts)


def _summary_judgment(rec):
def _summary_judgment(rec: Recommendation) -> importer.Action | None:
"""Determines whether a decision should be made without even asking
the user. This occurs in quiet mode and when an action is chosen for
NONE recommendations. Return None if the user should be queried.
Otherwise, returns an action. May also print to the console if a
summary judgment is made.
"""

action: importer.Action | None
if config["import"]["quiet"]:
if rec == Recommendation.strong:
return importer.Action.APPLY
Expand Down
7 changes: 3 additions & 4 deletions beetsplug/discogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,9 @@ def get_album_info(self, result: Release) -> AlbumInfo | None:
style = self.format(result.data.get("styles"))
base_genre = self.format(result.data.get("genres"))

if self.config["append_style_genre"] and style:
genre = self.config["separator"].as_str().join([base_genre, style])
else:
genre = base_genre
genre = base_genre
if self.config["append_style_genre"] and genre is not None and style:
genre += f"{self.config['separator'].as_str()}{style}"

discogs_albumid = self._extract_id(result.data.get("uri"))

Expand Down
5 changes: 3 additions & 2 deletions beetsplug/fetchart.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ def _resize(
elif check == ImageAction.REFORMAT:
self.path = ArtResizer.shared.reformat(
self.path,
plugin.cover_format,
# TODO: fix this gnarly logic to remove the need for type ignore
plugin.cover_format, # type: ignore[arg-type]
deinterlaced=plugin.deinterlace,
)

Expand Down Expand Up @@ -1367,7 +1368,7 @@ def __init__(self) -> None:

# allow both pixel and percentage-based margin specifications
self.enforce_ratio = self.config["enforce_ratio"].get(
confuse.OneOf(
confuse.OneOf[bool | str](
[
bool,
confuse.String(pattern=self.PAT_PX),
Expand Down
22 changes: 10 additions & 12 deletions beetsplug/lastgenre/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import optparse
from collections.abc import Callable

from beets.importer import ImportSession, ImportTask
from beets.library import LibModel

LASTFM = pylast.LastFMNetwork(api_key=plugins.LASTFM_KEY)
Expand Down Expand Up @@ -178,14 +179,13 @@ def sources(self) -> tuple[str, ...]:
"""A tuple of allowed genre sources. May contain 'track',
'album', or 'artist.'
"""
source = self.config["source"].as_choice(("track", "album", "artist"))
if source == "track":
return "track", "album", "artist"
if source == "album":
return "album", "artist"
if source == "artist":
return ("artist",)
return tuple()
return self.config["source"].as_choice(
{
"track": ("track", "album", "artist"),
"album": ("album", "artist"),
"artist": ("artist",),
Comment thread
JOJ0 marked this conversation as resolved.
}
)

# More canonicalization and general helpers.

Expand Down Expand Up @@ -603,10 +603,8 @@ def lastgenre_func(
lastgenre_cmd.func = lastgenre_func
return [lastgenre_cmd]

def imported(
self, session: library.Session, task: library.ImportTask
) -> None:
self._process(task.album if task.is_album else task.item, write=False)
def imported(self, _: ImportSession, task: ImportTask) -> None:
self._process(task.album if task.is_album else task.item, write=False) # type: ignore[attr-defined]

def _tags_for(
self,
Expand Down
2 changes: 1 addition & 1 deletion beetsplug/lyrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ def fetch(
for group in self.fetch_candidates(artist, title, album, length):
candidates = [evaluate_item(item) for item in group]
if item := self.pick_best_match(candidates):
lyrics = item.get_text(self.config["synced"])
lyrics = item.get_text(self.config["synced"].get(bool))
return lyrics, f"{self.GET_URL}/{item.id}"

return None
Expand Down
4 changes: 2 additions & 2 deletions beetsplug/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def __init__(self, _, pattern: str, __):
relative_to = os.path.dirname(playlist_path)
else:
relative_to = config["relative_to"].as_filename()
relative_to = beets.util.bytestring_path(relative_to)
relative_to_bytes = beets.util.bytestring_path(relative_to)

for line in f:
if line[0] == "#":
Expand All @@ -78,7 +78,7 @@ def __init__(self, _, pattern: str, __):

paths.append(
beets.util.normpath(
os.path.join(relative_to, line.rstrip())
os.path.join(relative_to_bytes, line.rstrip())
)
)
f.close()
Expand Down
5 changes: 3 additions & 2 deletions beetsplug/smartplaylist.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,9 @@ def update_playlists(self, lib: Library, pretend: bool = False) -> None:
"Updating {} smart playlists...", len(self._matched_playlists)
)

playlist_dir = self.config["playlist_dir"].as_filename()
playlist_dir = bytestring_path(playlist_dir)
playlist_dir = bytestring_path(
self.config["playlist_dir"].as_filename()
)
tpl = self.config["uri_format"].get()
prefix = bytestring_path(self.config["prefix"].as_str())
relative_to = self.config["relative_to"].get()
Expand Down
2 changes: 1 addition & 1 deletion beetsplug/titlecase.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def force_lowercase(self) -> bool:

@cached_property
def replace(self) -> list[tuple[str, str]]:
return self.config["replace"].as_pairs()
return self.config["replace"].as_pairs(default_value="")

@cached_property
def the_artist(self) -> bool:
Expand Down
13 changes: 8 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Changelog = "https://github.com/beetbox/beets/blob/master/docs/changelog.rst"
python = ">=3.10,<4"

colorama = { version = "*", markers = "sys_platform == 'win32'" }
confuse = ">=2.1.0"
confuse = ">=2.2.0"
jellyfish = "*"
lap = ">=0.5.12"
mediafile = ">=0.12.0"
Expand Down
Loading