Skip to content

Replace percent, string concat, format calls with f-strings #5890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
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
15 changes: 6 additions & 9 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,33 +238,30 @@ There are a few coding conventions we use in beets:
.. code-block:: python

with g.lib.transaction() as tx:
rows = tx.query(
"SELECT DISTINCT '{0}' FROM '{1}' ORDER BY '{2}'".format(
field, model._table, sort_field
)
)
rows = tx.query("SELECT DISTINCT {field} FROM {model._table} ORDER BY {sort_field}")

To fetch Item objects from the database, use lib.items(…) and supply a query
as an argument. Resist the urge to write raw SQL for your query. If you must
use lower-level queries into the database, do this:
use lower-level queries into the database, do this, for example:

.. code-block:: python

with lib.transaction() as tx:
rows = tx.query("SELECT …")
rows = tx.query("SELECT path FROM items WHERE album_id = ?", (album_id,))

Transaction objects help control concurrent access to the database and assist
in debugging conflicting accesses.

- ``str.format()`` should be used instead of the ``%`` operator
- f-strings should be used instead of the ``%`` operator and ``str.format()``
calls.
- Never ``print`` informational messages; use the `logging
<http://docs.python.org/library/logging.html>`__ module instead. In
particular, we have our own logging shim, so you’ll see ``from beets import
logging`` in most files.

- The loggers use `str.format
<http://docs.python.org/library/stdtypes.html#str.format>`__-style logging
instead of ``%``-style, so you can type ``log.debug("{0}", obj)`` to do your
instead of ``%``-style, so you can type ``log.debug("{}", obj)`` to do your
formatting.

- Exception handlers must use ``except A as B:`` instead of ``except A, B:``.
Expand Down
2 changes: 1 addition & 1 deletion beets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def read(self, user=True, defaults=True):
except confuse.NotFoundError:
pass
except confuse.ConfigReadError as err:
stderr.write("configuration `import` failed: {}".format(err.reason))
stderr.write(f"configuration `import` failed: {err.reason}")


config = IncludeLazyConfig("beets", __name__)
33 changes: 14 additions & 19 deletions beets/art.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +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 {0}: {1}",
displayable_path(item.path),
exc,
)
log.warning("Could not extract art from {.filepath}: {}", item, exc)
return

return mf.art
Expand Down Expand Up @@ -83,16 +79,16 @@ def embed_item(

# Get the `Image` object from the file.
try:
log.debug("embedding {0}", displayable_path(imagepath))
log.debug("embedding {}", displayable_path(imagepath))
image = mediafile_image(imagepath, maxwidth)
except OSError as exc:
log.warning("could not read image file: {0}", exc)
log.warning("could not read image file: {}", exc)
return

# 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)
Expand All @@ -110,19 +106,19 @@ def embed_album(
"""Embed album art into all of the album's items."""
imagepath = album.artpath
if not imagepath:
log.info("No album art present for {0}", album)
log.info("No album art present for {}", album)
return
if not os.path.isfile(syspath(imagepath)):
log.info(
"Album art not found at {0} for {1}",
"Album art not found at {} for {}",
displayable_path(imagepath),
album,
)
return
if maxwidth:
imagepath = resize_image(log, imagepath, maxwidth, quality)

log.info("Embedding album art into {0}", album)
log.info("Embedding album art into {}", album)

for item in album.items():
embed_item(
Expand All @@ -143,8 +139,7 @@ def resize_image(log, imagepath, maxwidth, quality):
specified quality level.
"""
log.debug(
"Resizing album art to {0} pixels wide and encoding at quality \
level {1}",
"Resizing album art to {} pixels wide and encoding at quality level {}",
maxwidth,
quality,
)
Expand Down Expand Up @@ -184,18 +179,18 @@ def extract(log, outpath, item):
art = get_art(log, item)
outpath = bytestring_path(outpath)
if not art:
log.info("No album art present in {0}, skipping.", item)
log.info("No album art present in {}, skipping.", item)
return

# Add an extension to the filename.
ext = mediafile.image_extension(art)
if not ext:
log.warning("Unknown image type in {0}.", displayable_path(item.path))
log.warning("Unknown image type in {.filepath}.", item)
return
outpath += bytestring_path("." + ext)
outpath += bytestring_path(f".{ext}")

log.info(
"Extracting album art from: {0} to: {1}",
"Extracting album art from: {} to: {}",
item,
displayable_path(outpath),
)
Expand All @@ -213,7 +208,7 @@ def extract_first(log, outpath, items):

def clear(log, lib, query):
items = lib.items(query)
log.info("Clearing album art from {0} items", len(items))
log.info("Clearing album art from {} items", len(items))
for item in items:
log.debug("Clearing art for {0}", item)
log.debug("Clearing art for {}", item)
item.try_write(tags={"images": None})
12 changes: 6 additions & 6 deletions beets/autotag/distance.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ def string_dist(str1: str | None, str2: str | None) -> float:
# example, "the something" should be considered equal to
# "something, the".
for word in SD_END_WORDS:
if str1.endswith(", %s" % word):
str1 = "{} {}".format(word, str1[: -len(word) - 2])
if str2.endswith(", %s" % word):
str2 = "{} {}".format(word, str2[: -len(word) - 2])
if str1.endswith(f", {word}"):
str1 = f"{word} {str1[: -len(word) - 2]}"
if str2.endswith(f", {word}"):
str2 = f"{word} {str2[: -len(word) - 2]}"

# Perform a couple of basic normalizing substitutions.
for pat, repl in SD_REPLACE:
Expand Down Expand Up @@ -230,7 +230,7 @@ def update(self, dist: Distance):
"""Adds all the distance penalties from `dist`."""
if not isinstance(dist, Distance):
raise ValueError(
"`dist` must be a Distance object, not {}".format(type(dist))
f"`dist` must be a Distance object, not {type(dist)}"
)
for key, penalties in dist._penalties.items():
self._penalties.setdefault(key, []).extend(penalties)
Expand Down Expand Up @@ -444,7 +444,7 @@ def distance(
# Preferred media options.
media_patterns: Sequence[str] = preferred_config["media"].as_str_seq()
options = [
re.compile(r"(\d+x)?(%s)" % pat, re.I) for pat in media_patterns
re.compile(rf"(\d+x)?({pat})", re.I) for pat in media_patterns
]
if options:
dist.add_priority("media", album_info.media, options)
Expand Down
30 changes: 14 additions & 16 deletions beets/autotag/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def match_by_id(items: Iterable[Item]) -> AlbumInfo | None:
log.debug("No album ID consensus.")
return None
# If all album IDs are equal, look up the album.
log.debug("Searching for discovered album ID: {0}", first)
log.debug("Searching for discovered album ID: {}", first)
return metadata_plugins.album_for_id(first)


Expand Down Expand Up @@ -197,9 +197,7 @@ def _add_candidate(
checking the track count, ordering the items, checking for
duplicates, and calculating the distance.
"""
log.debug(
"Candidate: {0} - {1} ({2})", 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:
Expand All @@ -215,7 +213,7 @@ def _add_candidate(
required_tags: Sequence[str] = config["match"]["required"].as_str_seq()
for req_tag in required_tags:
if getattr(info, req_tag) is None:
log.debug("Ignored. Missing required tag: {0}", req_tag)
log.debug("Ignored. Missing required tag: {}", req_tag)
return

# Find mapping between the items and the track info.
Expand All @@ -229,10 +227,10 @@ def _add_candidate(
ignored_tags: Sequence[str] = config["match"]["ignored"].as_str_seq()
for penalty in ignored_tags:
if penalty in penalties:
log.debug("Ignored. Penalty: {0}", penalty)
log.debug("Ignored. Penalty: {}", penalty)
return

log.debug("Success. Distance: {0}", dist)
log.debug("Success. Distance: {}", dist)
results[info.album_id] = hooks.AlbumMatch(
dist, info, mapping, extra_items, extra_tracks
)
Expand Down Expand Up @@ -265,15 +263,15 @@ def tag_album(
likelies, consensus = get_most_common_tags(items)
cur_artist: str = likelies["artist"]
cur_album: str = likelies["album"]
log.debug("Tagging {0} - {1}", cur_artist, cur_album)
log.debug("Tagging {} - {}", cur_artist, cur_album)

# The output result, keys are the MB album ID.
candidates: dict[Any, AlbumMatch] = {}

# Search by explicit ID.
if search_ids:
for search_id in search_ids:
log.debug("Searching for album ID: {0}", search_id)
log.debug("Searching for album ID: {}", search_id)
if info := metadata_plugins.album_for_id(search_id):
_add_candidate(items, candidates, info)

Expand All @@ -283,7 +281,7 @@ def tag_album(
if info := match_by_id(items):
_add_candidate(items, candidates, info)
rec = _recommendation(list(candidates.values()))
log.debug("Album ID match recommendation is {0}", rec)
log.debug("Album ID match recommendation is {}", rec)
if candidates and not config["import"]["timid"]:
# If we have a very good MBID match, return immediately.
# Otherwise, this match will compete against metadata-based
Expand All @@ -300,23 +298,23 @@ def tag_album(
if not (search_artist and search_album):
# No explicit search terms -- use current metadata.
search_artist, search_album = cur_artist, cur_album
log.debug("Search terms: {0} - {1}", search_artist, search_album)
log.debug("Search terms: {} - {}", search_artist, search_album)

# Is this album likely to be a "various artist" release?
va_likely = (
(not consensus["artist"])
or (search_artist.lower() in VA_ARTISTS)
or any(item.comp for item in items)
)
log.debug("Album might be VA: {0}", va_likely)
log.debug("Album might be VA: {}", va_likely)

# Get the results from the data sources.
for matched_candidate in metadata_plugins.candidates(
items, search_artist, search_album, va_likely
):
_add_candidate(items, candidates, matched_candidate)

log.debug("Evaluating {0} candidates.", len(candidates))
log.debug("Evaluating {} candidates.", len(candidates))
# Sort and get the recommendation.
candidates_sorted = _sort_candidates(candidates.values())
rec = _recommendation(candidates_sorted)
Expand Down Expand Up @@ -345,7 +343,7 @@ def tag_item(
trackids = search_ids or [t for t in [item.mb_trackid] if t]
if trackids:
for trackid in trackids:
log.debug("Searching for track ID: {0}", trackid)
log.debug("Searching for track ID: {}", trackid)
if info := metadata_plugins.track_for_id(trackid):
dist = track_distance(item, info, incl_artist=True)
candidates[info.track_id] = hooks.TrackMatch(dist, info)
Expand All @@ -369,7 +367,7 @@ def tag_item(
# Search terms.
search_artist = search_artist or item.artist
search_title = search_title or item.title
log.debug("Item search terms: {0} - {1}", search_artist, search_title)
log.debug("Item search terms: {} - {}", search_artist, search_title)

# Get and evaluate candidate metadata.
for track_info in metadata_plugins.item_candidates(
Expand All @@ -379,7 +377,7 @@ def tag_item(
candidates[track_info.track_id] = hooks.TrackMatch(dist, track_info)

# Sort by distance and return with recommendation.
log.debug("Found {0} candidates.", len(candidates))
log.debug("Found {} candidates.", len(candidates))
candidates_sorted = _sort_candidates(candidates.values())
rec = _recommendation(candidates_sorted)
return Proposal(candidates_sorted, rec)
Loading
Loading