Delegate attribute access to logging

This commit is contained in:
Šarūnas Nejus 2025-08-30 18:33:25 +01:00
parent e334e81d40
commit b3d434f58f
No known key found for this signature in database
GPG key ID: DD28F6704DBE3435
35 changed files with 179 additions and 201 deletions

View file

@ -38,7 +38,7 @@ def get_art(log, item):
try:
mf = mediafile.MediaFile(syspath(item.path))
except mediafile.UnreadableFileError as exc:
log.warning("Could not extract art from {}: {}", item.filepath, exc)
log.warning("Could not extract art from {.filepath}: {}", item, exc)
return
return mf.art
@ -88,7 +88,7 @@ def embed_item(
# Make sure the image kind is safe (some formats only support PNG
# and JPEG).
if image.mime_type not in ("image/jpeg", "image/png"):
log.info("not embedding image of unsupported type: {}", image.mime_type)
log.info("not embedding image of unsupported type: {.mime_type}", image)
return
item.try_write(path=itempath, tags={"images": [image]}, id3v23=id3v23)
@ -185,7 +185,7 @@ def extract(log, outpath, item):
# Add an extension to the filename.
ext = mediafile.image_extension(art)
if not ext:
log.warning("Unknown image type in {}.", item.filepath)
log.warning("Unknown image type in {.filepath}.", item)
return
outpath += bytestring_path(f".{ext}")

View file

@ -197,7 +197,7 @@ def _add_candidate(
checking the track count, ordering the items, checking for
duplicates, and calculating the distance.
"""
log.debug("Candidate: {} - {} ({})", info.artist, info.album, info.album_id)
log.debug("Candidate: {0.artist} - {0.album} ({0.album_id})", info)
# Discard albums with zero tracks.
if not info.tracks:

View file

@ -82,10 +82,7 @@ def query_tasks(session: ImportSession):
# Search for albums.
for album in session.lib.albums(session.query):
log.debug(
"yielding album {}: {} - {}",
album.id,
album.albumartist,
album.album,
"yielding album {0.id}: {0.albumartist} - {0.album}", album
)
items = list(album.items())
_freshen_items(items)

View file

@ -271,7 +271,7 @@ class ImportTask(BaseImportTask):
for item in duplicate_items:
item.remove()
if lib.directory in util.ancestry(item.path):
log.debug("deleting duplicate {}", item.filepath)
log.debug("deleting duplicate {.filepath}", item)
util.remove(item.path)
util.prune_dirs(os.path.dirname(item.path), lib.directory)
@ -552,12 +552,11 @@ class ImportTask(BaseImportTask):
]
if overwritten_fields:
log.debug(
"Reimported {} {}. Not preserving flexible attributes {}. "
"Path: {}",
"Reimported {0} {1.id}. Not preserving flexible attributes {2}. "
"Path: {1.filepath}",
noun,
new_obj.id,
new_obj,
overwritten_fields,
new_obj.filepath,
)
for key in overwritten_fields:
del existing_fields[key]
@ -576,17 +575,15 @@ class ImportTask(BaseImportTask):
self.album.artpath = replaced_album.artpath
self.album.store()
log.debug(
"Reimported album {}. Preserving attribute ['added']. "
"Path: {}",
self.album.id,
self.album.filepath,
"Reimported album {0.album.id}. Preserving attribute ['added']. "
"Path: {0.album.filepath}",
self,
)
log.debug(
"Reimported album {}. Preserving flexible attributes {}. "
"Path: {}",
self.album.id,
"Reimported album {0.album.id}. Preserving flexible"
" attributes {1}. Path: {0.album.filepath}",
self,
list(album_fields.keys()),
self.album.filepath,
)
for item in self.imported_items():
@ -595,21 +592,19 @@ class ImportTask(BaseImportTask):
if dup_item.added and dup_item.added != item.added:
item.added = dup_item.added
log.debug(
"Reimported item {}. Preserving attribute ['added']. "
"Path: {}",
item.id,
item.filepath,
"Reimported item {0.id}. Preserving attribute ['added']. "
"Path: {0.filepath}",
item,
)
item_fields = _reduce_and_log(
item, dup_item._values_flex, REIMPORT_FRESH_FIELDS_ITEM
)
item.update(item_fields)
log.debug(
"Reimported item {}. Preserving flexible attributes {}. "
"Path: {}",
item.id,
"Reimported item {0.id}. Preserving flexible attributes {1}. "
"Path: {0.filepath}",
item,
list(item_fields.keys()),
item.filepath,
)
item.store()
@ -619,7 +614,7 @@ class ImportTask(BaseImportTask):
"""
for item in self.imported_items():
for dup_item in self.replaced_items[item]:
log.debug("Replacing item {}: {}", dup_item.id, item.filepath)
log.debug("Replacing item {.id}: {.filepath}", dup_item, item)
dup_item.remove()
log.debug(
"{} of {} items replaced",
@ -1067,7 +1062,7 @@ class ImportTaskFactory:
# Now read albums from the extracted directory.
self.toppath = archive_task.toppath
log.debug("Archive extracted to: {}", self.toppath)
log.debug("Archive extracted to: {.toppath}", self)
return archive_task
def read_item(self, path: util.PathBytes):

View file

@ -1012,7 +1012,7 @@ class Item(LibModel):
if move:
# Check whether this file is inside the library directory.
if self._db and self._db.directory in util.ancestry(self.path):
log.debug("moving {} to synchronize path", self.filepath)
log.debug("moving {.filepath} to synchronize path", self)
self.move(with_album=with_album)
self.store()

View file

@ -1280,11 +1280,10 @@ class TerminalImportSession(importer.ImportSession):
dup_choices = [c for c in all_choices if c.short == short]
for c in dup_choices[1:]:
log.warning(
"Prompt choice '{}' removed due to conflict "
"with '{}' (short letter: '{}')",
c.long,
dup_choices[0].long,
c.short,
"Prompt choice '{0.long}' removed due to conflict "
"with '{1[0].long}' (short letter: '{0.short}')",
c,
dup_choices,
)
extra_choices.remove(c)
@ -1639,9 +1638,8 @@ def update_items(lib, query, album, move, pretend, fields, exclude_fields=None):
# Did the item change since last checked?
if item.current_mtime() <= item.mtime:
log.debug(
"skipping {} because mtime is up to date ({})",
item.filepath,
item.mtime,
"skipping {0.filepath} because mtime is up to date ({0.mtime})",
item,
)
continue
@ -1649,7 +1647,7 @@ def update_items(lib, query, album, move, pretend, fields, exclude_fields=None):
try:
item.read()
except library.ReadError as exc:
log.error("error reading {}: {}", item.filepath, exc)
log.error("error reading {.filepath}: {}", item, exc)
continue
# Special-case album artist when it matches track artist. (Hacky
@ -1882,7 +1880,7 @@ def show_stats(lib, query, exact):
try:
total_size += os.path.getsize(syspath(item.path))
except OSError as exc:
log.info("could not get size of {}: {}", item.path, exc)
log.info("could not get size of {.path}: {}", item, exc)
else:
total_size += int(item.length * item.bitrate / 8)
total_time += item.length
@ -2173,7 +2171,7 @@ def move_items(
)
for obj in objs:
log.debug("moving: {}", obj.filepath)
log.debug("moving: {.filepath}", obj)
if export:
# Copy without affecting the database.
@ -2256,14 +2254,14 @@ def write_items(lib, query, pretend, force):
for item in items:
# Item deleted?
if not os.path.exists(syspath(item.path)):
log.info("missing file: {}", item.filepath)
log.info("missing file: {.filepath}", item)
continue
# Get an Item object reflecting the "clean" (on-disk) state.
try:
clean_item = library.Item.from_path(item.path)
except library.ReadError as exc:
log.error("error reading {}: {}", item.filepath, exc)
log.error("error reading {.filepath}: {}", item, exc)
continue
# Check for and display changes.

View file

@ -126,7 +126,7 @@ class HumanReadableError(Exception):
"""
if self.tb:
logger.debug(self.tb)
logger.error("{}: {}", self.error_kind, self.args[0])
logger.error("{0.error_kind}: {0.args[0]}", self)
class FilesystemError(HumanReadableError):

View file

@ -306,9 +306,9 @@ class IMBackend(LocalBackend):
except subprocess.CalledProcessError as exc:
log.warning("ImageMagick size query failed")
log.debug(
"`convert` exited with (status {}) when "
"`convert` exited with (status {.returncode}) when "
"getting size with command {}:\n{}",
exc.returncode,
exc,
cmd,
exc.output.strip(),
)
@ -441,8 +441,8 @@ class IMBackend(LocalBackend):
convert_proc.wait()
if convert_proc.returncode:
log.debug(
"ImageMagick convert failed with status {}: {!r}",
convert_proc.returncode,
"ImageMagick convert failed with status {.returncode}: {!r}",
convert_proc,
convert_stderr,
)
return None

View file

@ -153,7 +153,7 @@ class AcousticPlugin(plugins.BeetsPlugin):
try:
data.update(res.json())
except ValueError:
self._log.debug("Invalid Response: {}", res.text)
self._log.debug("Invalid Response: {.text}", res)
return {}
return data

View file

@ -127,12 +127,11 @@ class BadFiles(BeetsPlugin):
except CheckerCommandError as e:
if e.errno == errno.ENOENT:
self._log.error(
"command not found: {} when validating file: {}",
e.checker,
e.path,
"command not found: {0.checker} when validating file: {0.path}",
e,
)
else:
self._log.error("error invoking {}: {}", e.checker, e.msg)
self._log.error("error invoking {0.checker}: {0.msg}", e)
return []
error_lines = []

View file

@ -763,7 +763,7 @@ class Connection:
def debug(self, message, kind=" "):
"""Log a debug message about this connection."""
self.server._log.debug("{}[{}]: {}", kind, self.address, message)
self.server._log.debug("{}[{.address}]: {}", kind, self, message)
def run(self):
pass
@ -911,7 +911,7 @@ class ControlConnection(Connection):
super().__init__(server, sock)
def debug(self, message, kind=" "):
self.server._log.debug("CTRL {}[{}]: {}", kind, self.address, message)
self.server._log.debug("CTRL {}[{.address}]: {}", kind, self, message)
def run(self):
"""Listen for control commands and delegate to `ctrl_*` methods."""

View file

@ -82,8 +82,8 @@ class BPSyncPlugin(BeetsPlugin):
if not self.is_beatport_track(item):
self._log.info(
"Skipping non-{} singleton: {}",
self.beatport_plugin.data_source,
"Skipping non-{.beatport_plugin.data_source} singleton: {}",
self,
item,
)
continue
@ -107,8 +107,8 @@ class BPSyncPlugin(BeetsPlugin):
return False
if not album.mb_albumid.isnumeric():
self._log.info(
"Skipping album with invalid {} ID: {}",
self.beatport_plugin.data_source,
"Skipping album with invalid {.beatport_plugin.data_source} ID: {}",
self,
album,
)
return False
@ -117,8 +117,8 @@ class BPSyncPlugin(BeetsPlugin):
return items
if not all(self.is_beatport_track(item) for item in items):
self._log.info(
"Skipping non-{} release: {}",
self.beatport_plugin.data_source,
"Skipping non-{.beatport_plugin.data_source} release: {}",
self,
album,
)
return False
@ -139,9 +139,7 @@ class BPSyncPlugin(BeetsPlugin):
albuminfo = self.beatport_plugin.album_for_id(album.mb_albumid)
if not albuminfo:
self._log.info(
"Release ID {} not found for album {}",
album.mb_albumid,
album,
"Release ID {0.mb_albumid} not found for album {0}", album
)
continue

View file

@ -343,20 +343,20 @@ def fingerprint_item(log, item, write=False):
"""
# Get a fingerprint and length for this track.
if not item.length:
log.info("{}: no duration available", item.filepath)
log.info("{.filepath}: no duration available", item)
elif item.acoustid_fingerprint:
if write:
log.info("{}: fingerprint exists, skipping", item.filepath)
log.info("{.filepath}: fingerprint exists, skipping", item)
else:
log.info("{}: using existing fingerprint", item.filepath)
log.info("{.filepath}: using existing fingerprint", item)
return item.acoustid_fingerprint
else:
log.info("{}: fingerprinting", item.filepath)
log.info("{.filepath}: fingerprinting", item)
try:
_, fp = acoustid.fingerprint_file(util.syspath(item.path))
item.acoustid_fingerprint = fp.decode()
if write:
log.info("{}: writing fingerprint", item.filepath)
log.info("{.filepath}: writing fingerprint", item)
item.try_write()
if item._db:
item.store()

View file

@ -319,10 +319,9 @@ class ConvertPlugin(BeetsPlugin):
util.displayable_path(source),
)
self._log.debug(
"Command {} exited with status {}: {}",
"Command {0} exited with status {1.returncode}: {1.output}",
args,
exc.returncode,
exc.output,
exc,
)
util.remove(dest)
util.prune_dirs(os.path.dirname(dest))
@ -388,15 +387,15 @@ class ConvertPlugin(BeetsPlugin):
if os.path.exists(util.syspath(dest)):
self._log.info(
"Skipping {} (target file exists)", item.filepath
"Skipping {.filepath} (target file exists)", item
)
continue
if keep_new:
if pretend:
self._log.info(
"mv {} {}",
item.filepath,
"mv {.filepath} {}",
item,
util.displayable_path(original),
)
else:
@ -430,7 +429,7 @@ class ConvertPlugin(BeetsPlugin):
else ("Linking" if link else "Copying")
)
self._log.info("{} {}", msg, item.filepath)
self._log.info("{} {.filepath}", msg, item)
if hardlink:
util.hardlink(original, converted)
@ -461,7 +460,7 @@ class ConvertPlugin(BeetsPlugin):
if album and album.artpath:
maxwidth = self._get_art_resize(album.artpath)
self._log.debug(
"embedding album art from {}", album.art_filepath
"embedding album art from {.art_filepath}", album
)
art.embed_item(
self._log,
@ -519,7 +518,7 @@ class ConvertPlugin(BeetsPlugin):
if os.path.exists(util.syspath(dest)):
self._log.info(
"Skipping {} (target file exists)", album.art_filepath
"Skipping {.art_filepath} (target file exists)", album
)
return
@ -529,8 +528,8 @@ class ConvertPlugin(BeetsPlugin):
# Either copy or resize (while copying) the image.
if maxwidth is not None:
self._log.info(
"Resizing cover art from {} to {}",
album.art_filepath,
"Resizing cover art from {.art_filepath} to {}",
album,
util.displayable_path(dest),
)
if not pretend:
@ -540,9 +539,9 @@ class ConvertPlugin(BeetsPlugin):
msg = "ln" if hardlink else ("ln -s" if link else "cp")
self._log.info(
"{} {} {}",
"{} {.art_filepath} {}",
msg,
album.art_filepath,
album,
util.displayable_path(dest),
)
else:
@ -553,9 +552,9 @@ class ConvertPlugin(BeetsPlugin):
)
self._log.info(
"{} cover art from {} to {}",
"{} cover art from {.art_filepath} to {}",
msg,
album.art_filepath,
album,
util.displayable_path(dest),
)
if hardlink:

View file

@ -251,16 +251,16 @@ class DeezerPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
response.raise_for_status()
except requests.exceptions.RequestException as e:
self._log.error(
"Error fetching data from {} API\n Error: {}",
self.data_source,
"Error fetching data from {.data_source} API\n Error: {}",
self,
e,
)
return ()
response_data: Sequence[IDResponse] = response.json().get("data", [])
self._log.debug(
"Found {} result(s) from {} for '{}'",
"Found {} result(s) from {.data_source} for '{}'",
len(response_data),
self.data_source,
self,
query,
)
return response_data

View file

@ -254,24 +254,24 @@ class DuplicatesPlugin(BeetsPlugin):
checksum = getattr(item, key, False)
if not checksum:
self._log.debug(
"key {} on item {} not cached:computing checksum",
"key {} on item {.filepath} not cached:computing checksum",
key,
item.filepath,
item,
)
try:
checksum = command_output(args).stdout
setattr(item, key, checksum)
item.store()
self._log.debug(
"computed checksum for {} using {}", item.title, key
"computed checksum for {.title} using {}", item, key
)
except subprocess.CalledProcessError as e:
self._log.debug("failed to checksum {}: {}", item.filepath, e)
self._log.debug("failed to checksum {.filepath}: {}", item, e)
else:
self._log.debug(
"key {} on item {} cached:not computing checksum",
"key {} on item {.filepath} cached:not computing checksum",
key,
item.filepath,
item,
)
return key, checksum
@ -289,15 +289,15 @@ class DuplicatesPlugin(BeetsPlugin):
values = [v for v in values if v not in (None, "")]
if strict and len(values) < len(keys):
self._log.debug(
"some keys {} on item {} are null or empty: skipping",
"some keys {} on item {.filepath} are null or empty: skipping",
keys,
obj.filepath,
obj,
)
elif not strict and not len(values):
self._log.debug(
"all keys {} on item {} are null or empty: skipping",
"all keys {} on item {.filepath} are null or empty: skipping",
keys,
obj.filepath,
obj,
)
else:
key = tuple(values)
@ -356,10 +356,10 @@ class DuplicatesPlugin(BeetsPlugin):
if value:
self._log.debug(
"key {} on item {} is null "
"or empty: setting from item {}",
"or empty: setting from item {.filepath}",
f,
displayable_path(objs[0].path),
o.filepath,
o,
)
setattr(objs[0], f, value)
objs[0].store()
@ -380,10 +380,10 @@ class DuplicatesPlugin(BeetsPlugin):
missing.add(i._db)
self._log.debug(
"item {} missing from album {}:"
" merging from {} into {}",
" merging from {.filepath} into {}",
missing,
objs[0],
o.filepath,
o,
displayable_path(missing.destination()),
)
missing.move(operation=MoveOperation.COPY)

View file

@ -133,7 +133,7 @@ class Candidate:
# get_size returns None if no local imaging backend is available
if not self.size:
self.size = ArtResizer.shared.get_size(self.path)
self._log.debug("image size: {}", self.size)
self._log.debug("image size: {.size}", self)
if not self.size:
self._log.warning(
@ -151,7 +151,7 @@ class Candidate:
# Check minimum dimension.
if plugin.minwidth and self.size[0] < plugin.minwidth:
self._log.debug(
"image too small ({} < {})", self.size[0], plugin.minwidth
"image too small ({} < {.minwidth})", self.size[0], plugin
)
return ImageAction.BAD
@ -162,10 +162,10 @@ class Candidate:
if edge_diff > plugin.margin_px:
self._log.debug(
"image is not close enough to being "
"square, ({} - {} > {})",
"square, ({} - {} > {.margin_px})",
long_edge,
short_edge,
plugin.margin_px,
plugin,
)
return ImageAction.BAD
elif plugin.margin_percent:
@ -190,7 +190,7 @@ class Candidate:
downscale = False
if plugin.maxwidth and self.size[0] > plugin.maxwidth:
self._log.debug(
"image needs rescaling ({} > {})", self.size[0], plugin.maxwidth
"image needs rescaling ({} > {.maxwidth})", self.size[0], plugin
)
downscale = True
@ -200,9 +200,9 @@ class Candidate:
filesize = os.stat(syspath(self.path)).st_size
if filesize > plugin.max_filesize:
self._log.debug(
"image needs resizing ({}B > {}B)",
"image needs resizing ({}B > {.max_filesize}B)",
filesize,
plugin.max_filesize,
plugin,
)
downsize = True
@ -213,9 +213,9 @@ class Candidate:
reformat = fmt != plugin.cover_format
if reformat:
self._log.debug(
"image needs reformatting: {} -> {}",
"image needs reformatting: {} -> {.cover_format}",
fmt,
plugin.cover_format,
plugin,
)
skip_check_for = skip_check_for or []
@ -329,7 +329,7 @@ def _logged_get(log: Logger, *args, **kwargs) -> requests.Response:
prepped.url, {}, None, None, None
)
send_kwargs.update(settings)
log.debug("{}: {}", message, prepped.url)
log.debug("{}: {.url}", message, prepped)
return s.send(prepped, **send_kwargs)
@ -542,14 +542,14 @@ class CoverArtArchive(RemoteArtSource):
try:
response = self.request(url)
except requests.RequestException:
self._log.debug("{}: error receiving response", self.NAME)
self._log.debug("{.NAME}: error receiving response", self)
return
try:
data = response.json()
except ValueError:
self._log.debug(
"{}: error loading response: {}", self.NAME, response.text
"{.NAME}: error loading response: {.text}", self, response
)
return
@ -629,7 +629,7 @@ class AlbumArtOrg(RemoteArtSource):
# Get the page from albumart.org.
try:
resp = self.request(self.URL, params={"asin": album.asin})
self._log.debug("scraped art URL: {}", resp.url)
self._log.debug("scraped art URL: {.url}", resp)
except requests.RequestException:
self._log.debug("error scraping art page")
return
@ -702,7 +702,7 @@ class GoogleImages(RemoteArtSource):
try:
data = response.json()
except ValueError:
self._log.debug("google: error loading response: {}", response.text)
self._log.debug("google: error loading response: {.text}", response)
return
if "error" in data:
@ -764,7 +764,7 @@ class FanartTV(RemoteArtSource):
data = response.json()
except ValueError:
self._log.debug(
"fanart.tv: error loading response: {}", response.text
"fanart.tv: error loading response: {.text}", response
)
return
@ -953,8 +953,8 @@ class Wikipedia(RemoteArtSource):
self._log.debug("wikipedia: album not found on dbpedia")
except (ValueError, KeyError, IndexError):
self._log.debug(
"wikipedia: error scraping dbpedia response: {}",
dbpedia_response.text,
"wikipedia: error scraping dbpedia response: {.text}",
dbpedia_response,
)
# Ensure we have a filename before attempting to query wikipedia
@ -1179,7 +1179,7 @@ class LastFM(RemoteArtSource):
if "error" in data:
if data["error"] == 6:
self._log.debug(
"lastfm: no results for {}", album.mb_albumid
"lastfm: no results for {.mb_albumid}", album
)
else:
self._log.error(
@ -1200,7 +1200,7 @@ class LastFM(RemoteArtSource):
url=images[size], size=self.SIZES[size]
)
except ValueError:
self._log.debug("lastfm: error loading response: {}", response.text)
self._log.debug("lastfm: error loading response: {.text}", response)
return
@ -1244,7 +1244,7 @@ class Spotify(RemoteArtSource):
soup = BeautifulSoup(html, "html.parser")
except ValueError:
self._log.debug(
"Spotify: error loading response: {}", response.text
"Spotify: error loading response: {.text}", response
)
return
@ -1541,7 +1541,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
out = candidate
assert out.path is not None # help mypy
self._log.debug(
"using {.LOC} image {}", source, out.path
"using {.LOC} image {.path}", source, out
)
break
# Remove temporary files for invalid candidates.

View file

@ -150,10 +150,10 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
# In case the artist is kept, do not update the artist fields.
if keep_in_artist_field:
self._log.info(
"artist: {} (Not changing due to keep_in_artist)", item.artist
"artist: {.artist} (Not changing due to keep_in_artist)", item
)
else:
self._log.info("artist: {} -> {}", item.artist, item.albumartist)
self._log.info("artist: {0.artist} -> {0.albumartist}", item)
item.artist = item.albumartist
if item.artist_sort:
@ -166,7 +166,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
feat_format = self.config["format"].as_str()
new_format = feat_format.format(feat_part)
new_title = f"{item.title} {new_format}"
self._log.info("title: {} -> {}", item.title, new_title)
self._log.info("title: {.title} -> {}", item, new_title)
item.title = new_title
def ft_in_title(
@ -194,7 +194,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
if not featured:
return False
self._log.info("{}", item.filepath)
self._log.info("{.filepath}", item)
# Attempt to find the featured artist.
feat_part = find_feat_part(artist, albumartist)

View file

@ -83,7 +83,7 @@ class HookPlugin(BeetsPlugin):
subprocess.check_call(command_pieces)
except subprocess.CalledProcessError as exc:
self._log.error(
"hook for {} exited with status {}", event, exc.returncode
"hook for {} exited with status {.returncode}", event, exc
)
except OSError as exc:
self._log.error("hook for {} failed: {}", event, exc)

View file

@ -103,9 +103,9 @@ class ImportAddedPlugin(BeetsPlugin):
def update_album_times(self, lib, album):
if self.reimported_album(album):
self._log.debug(
"Album '{}' is reimported, skipping import of "
"Album '{.filepath}' is reimported, skipping import of "
"added dates for the album and its items.",
album.filepath,
album,
)
return
@ -119,18 +119,17 @@ class ImportAddedPlugin(BeetsPlugin):
item.store()
album.added = min(album_mtimes)
self._log.debug(
"Import of album '{}', selected album.added={} "
"Import of album '{0.album}', selected album.added={0.added} "
"from item file mtimes.",
album.album,
album.added,
album,
)
album.store()
def update_item_times(self, lib, item):
if self.reimported_item(item):
self._log.debug(
"Item '{}' is reimported, skipping import of added date.",
item.filepath,
"Item '{.filepath}' is reimported, skipping import of added date.",
item,
)
return
mtime = self.item_mtime.pop(item.path, None)
@ -139,9 +138,8 @@ class ImportAddedPlugin(BeetsPlugin):
if self.config["preserve_mtimes"].get(bool):
self.write_item_mtime(item, mtime)
self._log.debug(
"Import of item '{}', selected item.added={}",
item.filepath,
item.added,
"Import of item '{0.filepath}', selected item.added={0.added}",
item,
)
item.store()
@ -153,7 +151,6 @@ class ImportAddedPlugin(BeetsPlugin):
if self.config["preserve_write_mtimes"].get(bool):
self.write_item_mtime(item, item.added)
self._log.debug(
"Write of item '{}', selected item.added={}",
item.filepath,
item.added,
"Write of item '{0.filepath}', selected item.added={0.added}",
item,
)

View file

@ -180,7 +180,7 @@ class IPFSPlugin(BeetsPlugin):
util.command_output(cmd)
except (OSError, subprocess.CalledProcessError) as err:
self._log.error(
"Failed to get {} from ipfs.\n{}", _hash, err.output
"Failed to get {} from ipfs.\n{.output}", _hash, err
)
return False

View file

@ -73,7 +73,7 @@ class KeyFinderPlugin(BeetsPlugin):
except IndexError:
# Sometimes keyfinder-cli returns 0 but with no key, usually
# when the file is silent or corrupt, so we log and skip.
self._log.error("no key returned for path: {}", item.path)
self._log.error("no key returned for path: {.path}", item)
continue
try:
@ -84,7 +84,7 @@ class KeyFinderPlugin(BeetsPlugin):
item["initial_key"] = key
self._log.info(
"added computed initial key {} for {}", key, item.filepath
"added computed initial key {} for {.filepath}", key, item
)
if write:

View file

@ -268,10 +268,9 @@ def process_tracks(lib, tracks, log):
count = int(song.get("play_count", 0))
new_count = int(tracks[num].get("playcount", 1))
log.debug(
"match: {} - {} ({}) updating: play_count {} => {}",
song.artist,
song.title,
song.album,
"match: {0.artist} - {0.title} ({0.album}) updating:"
" play_count {1} => {2}",
song,
count,
new_count,
)

View file

@ -508,9 +508,9 @@ class SearchBackend(SoupMixin, Backend):
# log out the candidate that did not make it but was close.
# This may show a matching candidate with some noise in the name
self.debug(
"({}, {}) does not match ({}, {}) but dist was close: {:.2f}",
result.artist,
result.title,
"({0.artist}, {0.title}) does not match ({1}, {2}) but dist"
" was close: {3:.2f}",
result,
target_artist,
target_title,
max_dist,
@ -838,15 +838,16 @@ class Translator(RequestHandler):
lyrics_language = langdetect.detect(new_lyrics).upper()
if lyrics_language == self.to_language:
self.info(
"🔵 Lyrics are already in the target language {}",
self.to_language,
"🔵 Lyrics are already in the target language {.to_language}",
self,
)
return new_lyrics
if self.from_languages and lyrics_language not in self.from_languages:
self.info(
"🔵 Configuration {} does not permit translating from {}",
self.from_languages,
"🔵 Configuration {.from_languages} does not permit translating"
" from {}",
self,
lyrics_language,
)
return new_lyrics
@ -854,7 +855,7 @@ class Translator(RequestHandler):
lyrics, *url = new_lyrics.split("\n\nSource: ")
with self.handle_request():
translated_lines = self.append_translations(lyrics.splitlines())
self.info("🟢 Translated lyrics to {}", self.to_language)
self.info("🟢 Translated lyrics to {.to_language}", self)
return "\n\nSource: ".join(["\n".join(translated_lines), *url])

View file

@ -226,8 +226,8 @@ class MissingPlugin(BeetsPlugin):
for track_info in album_info.tracks:
if track_info.track_id not in item_mbids:
self._log.debug(
"track {} in album {}",
track_info.track_id,
album_info.album_id,
"track {.track_id} in album {.album_id}",
track_info,
album_info,
)
yield _item(track_info, album_info, album.id)

View file

@ -51,8 +51,8 @@ class MPDClientWrapper:
if not self.strip_path.endswith("/"):
self.strip_path += "/"
self._log.debug("music_directory: {}", self.music_directory)
self._log.debug("strip_path: {}", self.strip_path)
self._log.debug("music_directory: {.music_directory}", self)
self._log.debug("strip_path: {.strip_path}", self)
self.client = mpd.MPDClient()
@ -188,10 +188,10 @@ class MPDStats:
item.store()
self._log.debug(
"updated: {} = {} [{}]",
"updated: {} = {} [{.filepath}]",
attribute,
item[attribute],
item.filepath,
item,
)
def update_rating(self, item, skipped):

View file

@ -101,8 +101,8 @@ class MPDUpdatePlugin(BeetsPlugin):
try:
s = BufferedSocket(host, port)
except OSError as e:
self._log.warning("MPD connection failed: {}", str(e.strerror))
except OSError:
self._log.warning("MPD connection failed", exc_info=True)
return
resp = s.readline()

View file

@ -179,9 +179,8 @@ class ParentWorkPlugin(BeetsPlugin):
if not item.mb_workid:
self._log.info(
"No work for {}, add one at https://musicbrainz.org/recording/{}",
"No work for {0}, add one at https://musicbrainz.org/recording/{0.mb_trackid}",
item,
item.mb_trackid,
)
return

View file

@ -142,7 +142,7 @@ class PlaylistPlugin(beets.plugins.BeetsPlugin):
dir_contents = os.listdir(playlist_dir)
except OSError:
self._log.warning(
"Unable to open playlist directory {}", self.playlist_dir
"Unable to open playlist directory {.playlist_dir}", self
)
return

View file

@ -141,9 +141,8 @@ class RgTask:
item.rg_track_peak = track_gain.peak
item.store()
self._log.debug(
"applied track gain {} LU, peak {} of FS",
item.rg_track_gain,
item.rg_track_peak,
"applied track gain {0.rg_track_gain} LU, peak {0.rg_track_peak} of FS",
item,
)
def _store_album_gain(self, item: Item, album_gain: Gain):
@ -155,9 +154,8 @@ class RgTask:
item.rg_album_peak = album_gain.peak
item.store()
self._log.debug(
"applied album gain {} LU, peak {} of FS",
item.rg_album_gain,
item.rg_album_peak,
"applied album gain {0.rg_album_gain} LU, peak {0.rg_album_peak} of FS",
item,
)
def _store_track(self, write: bool):
@ -230,7 +228,7 @@ class R128Task(RgTask):
def _store_track_gain(self, item: Item, track_gain: Gain):
item.r128_track_gain = track_gain.gain
item.store()
self._log.debug("applied r128 track gain {} LU", item.r128_track_gain)
self._log.debug("applied r128 track gain {.r128_track_gain} LU", item)
def _store_album_gain(self, item: Item, album_gain: Gain):
"""
@ -239,7 +237,7 @@ class R128Task(RgTask):
"""
item.r128_album_gain = album_gain.gain
item.store()
self._log.debug("applied r128 album gain {} LU", item.r128_album_gain)
self._log.debug("applied r128 album gain {.r128_album_gain} LU", item)
AnyRgTask = TypeVar("AnyRgTask", bound=RgTask)
@ -380,7 +378,7 @@ class FfmpegBackend(Backend):
album_gain = target_level_lufs - album_gain
self._log.debug(
"{}: gain {} LU, peak {}", task.album, album_gain, album_peak
"{.album}: gain {} LU, peak {}", task, album_gain, album_peak
)
task.album_gain = Gain(album_gain, album_peak)
@ -1093,9 +1091,8 @@ class AudioToolsBackend(Backend):
)
self._log.debug(
"ReplayGain for track {} - {}: {2:.2f}, {3:.2f}",
item.artist,
item.title,
"ReplayGain for track {0.artist} - {0.title}: {1:.2f}, {2:.2f}",
item,
rg_track_gain,
rg_track_peak,
)
@ -1133,8 +1130,8 @@ class AudioToolsBackend(Backend):
rg_album_gain, task.target_level
)
self._log.debug(
"ReplayGain for album {}: {.2f}, {.2f}",
task.items[0].album,
"ReplayGain for album {.items[0].album}: {.2f}, {.2f}",
task,
rg_album_gain,
rg_album_peak,
)

View file

@ -59,7 +59,7 @@ class ScrubPlugin(BeetsPlugin):
def scrub_func(lib, opts, args):
# Walk through matching files and remove tags.
for item in lib.items(args):
self._log.info("scrubbing: {}", item.filepath)
self._log.info("scrubbing: {.filepath}", item)
self._scrub_item(item, opts.write)
scrub_cmd = ui.Subcommand("scrub", help="clean audio tags")
@ -147,5 +147,5 @@ class ScrubPlugin(BeetsPlugin):
def import_task_files(self, session, task):
"""Automatically scrub imported files."""
for item in task.imported_items():
self._log.debug("auto-scrubbing {}", item.filepath)
self._log.debug("auto-scrubbing {.filepath}", item)
self._scrub_item(item, ui.should_write())

View file

@ -188,9 +188,7 @@ class SpotifyPlugin(
self.access_token = response.json()["access_token"]
# Save the token for later use.
self._log.debug(
"{} access token: {}", self.data_source, self.access_token
)
self._log.debug("{0.data_source} access token: {0.access_token}", self)
with open(self._tokenfile(), "w") as f:
json.dump({"access_token": self.access_token}, f)
@ -451,9 +449,9 @@ class SpotifyPlugin(
return ()
response_data = response.get(f"{query_type}s", {}).get("items", [])
self._log.debug(
"Found {} result(s) from {} for '{}'",
"Found {} result(s) from {.data_source} for '{}'",
len(response_data),
self.data_source,
self,
query,
)
return response_data
@ -539,8 +537,8 @@ class SpotifyPlugin(
if not items:
self._log.debug(
"Your beets query returned no items, skipping {}.",
self.data_source,
"Your beets query returned no items, skipping {.data_source}.",
self,
)
return
@ -595,8 +593,8 @@ class SpotifyPlugin(
or self.config["tiebreak"].get() == "first"
):
self._log.debug(
"{} track(s) found, count: {}",
self.data_source,
"{.data_source} track(s) found, count: {}",
self,
len(response_data_tracks),
)
chosen_result = response_data_tracks[0]
@ -619,19 +617,19 @@ class SpotifyPlugin(
if failure_count > 0:
if self.config["show_failures"].get():
self._log.info(
"{} track(s) did not match a {} ID:",
"{} track(s) did not match a {.data_source} ID:",
failure_count,
self.data_source,
self,
)
for track in failures:
self._log.info("track: {}", track)
self._log.info("")
else:
self._log.warning(
"{} track(s) did not match a {} ID:\n"
"{} track(s) did not match a {.data_source} ID:\n"
"use --show-failures to display",
failure_count,
self.data_source,
self,
)
return results

View file

@ -108,7 +108,7 @@ class SubsonicUpdate(BeetsPlugin):
auth = self.config["auth"].as_str()
url = self.__format_url("startScan")
self._log.debug("URL is {}", url)
self._log.debug("auth type is {}", self.config["auth"])
self._log.debug("auth type is {.config[auth]}", self)
if auth == "token":
salt, token = self.__create_token()

View file

@ -127,7 +127,7 @@ class ThumbnailsPlugin(BeetsPlugin):
size = ArtResizer.shared.get_size(album.artpath)
if not size:
self._log.warning(
"problem getting the picture size for {}", album.artpath
"problem getting the picture size for {.artpath}", album
)
return

View file

@ -275,6 +275,7 @@ select = [
"E", # pycodestyle
"F", # pyflakes
# "B", # flake8-bugbear
"G", # flake8-logging-format
"I", # isort
"ISC", # flake8-implicit-str-concat
"N", # pep8-naming