Skip to content

Commit 2c1aa27

Browse files
authored
lastgenre: Add --pretend option for previewing genre changes (#6008)
Introduce a `--pretend` option to the lastgenre plugin, allowing users to preview genre changes without making any modifications to their library. This feature enhances user control by showing potential changes before they are applied.
2 parents dc4e4e5 + 2e307b5 commit 2c1aa27

File tree

4 files changed

+84
-15
lines changed

4 files changed

+84
-15
lines changed

beetsplug/lastgenre/__init__.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,12 @@ def _try_resolve_stage(stage_label: str, keep_genres, new_genres):
461461

462462
def commands(self):
463463
lastgenre_cmd = ui.Subcommand("lastgenre", help="fetch genres")
464+
lastgenre_cmd.parser.add_option(
465+
"-p",
466+
"--pretend",
467+
action="store_true",
468+
help="show actions but do nothing",
469+
)
464470
lastgenre_cmd.parser.add_option(
465471
"-f",
466472
"--force",
@@ -521,45 +527,64 @@ def commands(self):
521527

522528
def lastgenre_func(lib, opts, args):
523529
write = ui.should_write()
530+
pretend = getattr(opts, "pretend", False)
524531
self.config.set_args(opts)
525532

526533
if opts.album:
527534
# Fetch genres for whole albums
528535
for album in lib.albums(args):
529-
album.genre, src = self._get_genre(album)
536+
album_genre, src = self._get_genre(album)
537+
prefix = "Pretend: " if pretend else ""
530538
self._log.info(
531-
'genre for album "{0.album}" ({1}): {0.genre}',
539+
'{}genre for album "{.album}" ({}): {}',
540+
prefix,
532541
album,
533542
src,
543+
album_genre,
534544
)
535-
if "track" in self.sources:
536-
album.store(inherit=False)
537-
else:
538-
album.store()
545+
if not pretend:
546+
album.genre = album_genre
547+
if "track" in self.sources:
548+
album.store(inherit=False)
549+
else:
550+
album.store()
539551

540552
for item in album.items():
541553
# If we're using track-level sources, also look up each
542554
# track on the album.
543555
if "track" in self.sources:
544-
item.genre, src = self._get_genre(item)
545-
item.store()
556+
item_genre, src = self._get_genre(item)
546557
self._log.info(
547-
'genre for track "{0.title}" ({1}): {0.genre}',
558+
'{}genre for track "{.title}" ({}): {}',
559+
prefix,
548560
item,
549561
src,
562+
item_genre,
550563
)
564+
if not pretend:
565+
item.genre = item_genre
566+
item.store()
551567

552-
if write:
568+
if write and not pretend:
553569
item.try_write()
554570
else:
555571
# Just query singletons, i.e. items that are not part of
556572
# an album
557573
for item in lib.items(args):
558-
item.genre, src = self._get_genre(item)
559-
item.store()
574+
item_genre, src = self._get_genre(item)
575+
prefix = "Pretend: " if pretend else ""
560576
self._log.info(
561-
"genre for track {0.title} ({1}): {0.genre}", item, src
577+
'{}genre for track "{0.title}" ({1}): {}',
578+
prefix,
579+
item,
580+
src,
581+
item_genre,
562582
)
583+
if not pretend:
584+
item.genre = item_genre
585+
item.store()
586+
if write and not pretend:
587+
item.try_write()
563588

564589
lastgenre_cmd.func = lastgenre_func
565590
return [lastgenre_cmd]

docs/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Unreleased
99

1010
New features:
1111

12+
- :doc:`plugins/lastgenre`: Add a ``--pretend`` option to preview genre changes
13+
without storing or writing them.
14+
1215
Bug fixes:
1316

1417
- :doc:`plugins/spotify` Fixed an issue where track matching and lookups could

docs/plugins/lastgenre.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ tags** and will only **fetch new genres for empty tags**. When ``force`` is
124124
``yes`` the setting of the ``whitelist`` option (as documented in Usage_)
125125
applies to any existing or newly fetched genres.
126126

127-
The follwing configurations are possible:
127+
The following configurations are possible:
128128

129129
**Setup 1** (default)
130130

@@ -213,5 +213,9 @@ fetch genres for albums or items matching a certain query.
213213
By default, ``beet lastgenre`` matches albums. To match individual tracks or
214214
singletons, use the ``-A`` switch: ``beet lastgenre -A [QUERY]``.
215215

216+
To preview the changes that would be made without applying them, use the ``-p``
217+
or ``--pretend`` flag. This shows which genres would be set but does not write
218+
or store any changes.
219+
216220
To disable automatic genre fetching on import, set the ``auto`` config option to
217221
false.

test/plugins/test_lastgenre.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Tests for the 'lastgenre' plugin."""
1616

17-
from unittest.mock import Mock
17+
from unittest.mock import Mock, patch
1818

1919
import pytest
2020

@@ -131,6 +131,43 @@ def test_prefer_specific_without_canonical(self):
131131
"math rock",
132132
]
133133

134+
def test_pretend_option_skips_library_updates(self):
135+
item = self.create_item(
136+
album="Pretend Album",
137+
albumartist="Pretend Artist",
138+
artist="Pretend Artist",
139+
title="Pretend Track",
140+
genre="Original Genre",
141+
)
142+
album = self.lib.add_album([item])
143+
144+
command = self.plugin.commands()[0]
145+
opts, args = command.parser.parse_args(["--pretend"])
146+
147+
with patch.object(lastgenre.ui, "should_write", return_value=True):
148+
with patch.object(
149+
self.plugin,
150+
"_get_genre",
151+
return_value=("Mock Genre", "mock stage"),
152+
) as mock_get_genre:
153+
with patch.object(self.plugin._log, "info") as log_info:
154+
# Mock try_write to verify it's never called in pretend mode
155+
with patch.object(item, "try_write") as mock_try_write:
156+
command.func(self.lib, opts, args)
157+
158+
mock_get_genre.assert_called_once()
159+
160+
assert any(
161+
call.args[1] == "Pretend: " for call in log_info.call_args_list
162+
)
163+
164+
# Verify that try_write was never called (file operations skipped)
165+
mock_try_write.assert_not_called()
166+
167+
stored_album = self.lib.get_album(album.id)
168+
assert stored_album.genre == "Original Genre"
169+
assert stored_album.items()[0].genre == "Original Genre"
170+
134171
def test_no_duplicate(self):
135172
"""Remove duplicated genres."""
136173
self._setup_config(count=99)

0 commit comments

Comments
 (0)