Skip to content

Commit f6ee49a

Browse files
committed
Address code review feedback for multi-value genres
- Add duplicate removal in Beatport plugin using dict.fromkeys() - Add test for conflicting genre/genres values when disabled - Add test for handling genres=None when feature is disabled - Add library tests for genres field with template functions - Fix lastgenre test case to include count parameter - Make lastgenre plugin use global genre_separator for consistency All changes ensure plugins use consistent separators and handle edge cases properly while maintaining backward compatibility.
1 parent 11f38e8 commit f6ee49a

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

beetsplug/beatport.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ def __init__(self, data: JSONDict):
235235
self.artists = [(x["id"], str(x["name"])) for x in data["artists"]]
236236
if "genres" in data:
237237
genre_list = [str(x["name"]) for x in data["genres"]]
238+
# Remove duplicates while preserving order
239+
genre_list = list(dict.fromkeys(genre_list))
238240
if beets.config["multi_value_genres"]:
239241
self.genres = genre_list
240242
else:
@@ -319,6 +321,9 @@ def __init__(self, data: JSONDict):
319321
else:
320322
genre_list = []
321323

324+
# Remove duplicates while preserving order
325+
genre_list = list(dict.fromkeys(genre_list))
326+
322327
if beets.config["multi_value_genres"]:
323328
# New behavior: populate both genres list and joined string
324329
separator = beets.config["genre_separator"].get(str)

test/plugins/test_lastgenre.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ def test_sort_by_depth(self):
409409
"separator": "\u0000",
410410
"canonical": False,
411411
"prefer_specific": False,
412+
"count": 10,
412413
},
413414
"Blues",
414415
{
@@ -567,6 +568,14 @@ def mock_fetch_artist_genre(self, obj):
567568
# Configure
568569
plugin.config.set(config_values)
569570
plugin.setup() # Loads default whitelist and canonicalization tree
571+
572+
# If test specifies a separator, set it as the global genre_separator
573+
# (when multi_value_genres is enabled, plugins use the global separator)
574+
if "separator" in config_values:
575+
from beets import config
576+
577+
config["genre_separator"] = config_values["separator"]
578+
570579
item = _common.item()
571580
item.genre = item_genre
572581

test/test_autotag.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,17 @@ def test_sync_genres_priority_list_over_string(self):
562562
assert item.genres == ["Rock", "Alternative"]
563563
assert item.genre == "Rock, Alternative"
564564

565+
def test_sync_genres_disabled_conflicting_values(self):
566+
"""When multi_value_genres is disabled with conflicting values."""
567+
config["multi_value_genres"] = False
568+
569+
item = Item(genre="Jazz", genres=["Rock", "Alternative"])
570+
correct_list_fields(item)
571+
572+
# genre string should take priority and be added to front of list
573+
assert item.genre == "Jazz"
574+
assert item.genres == ["Jazz", "Rock", "Alternative"]
575+
565576
def test_sync_genres_none_values(self):
566577
"""Handle None values in genre/genres fields without errors."""
567578
config["multi_value_genres"] = True
@@ -588,3 +599,14 @@ def test_sync_genres_disabled_empty_genres(self):
588599
# Should handle empty list without errors
589600
assert item.genres == []
590601
assert item.genre == ""
602+
603+
def test_sync_genres_disabled_none_genres(self):
604+
"""Handle disabled config with genres=None."""
605+
config["multi_value_genres"] = False
606+
607+
item = Item(genres=None)
608+
correct_list_fields(item)
609+
610+
# Should handle None without errors
611+
assert item.genres == []
612+
assert item.genre == ""

test/test_library.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,35 @@ def test_first_different_sep(self):
701701
self._setf("%first{Alice / Bob / Eve,2,0, / , & }")
702702
self._assert_dest(b"/base/Alice & Bob")
703703

704+
def test_first_genres_list(self):
705+
# Test that setting genres as a list syncs to genre field properly
706+
# and works with %first template function
707+
from beets import config
708+
709+
config["genre_separator"] = "; "
710+
from beets.autotag import correct_list_fields
711+
712+
self.i.genres = ["Pop", "Rock", "Classical Crossover"]
713+
correct_list_fields(self.i)
714+
# genre field should now be synced
715+
assert self.i.genre == "Pop; Rock; Classical Crossover"
716+
# %first should work on the synced genre field
717+
self._setf("%first{$genre}")
718+
self._assert_dest(b"/base/Pop")
719+
720+
def test_first_genres_list_skip(self):
721+
# Test that genres list works with %first skip parameter
722+
from beets import config
723+
724+
config["genre_separator"] = "; "
725+
from beets.autotag import correct_list_fields
726+
727+
self.i.genres = ["Pop", "Rock", "Classical Crossover"]
728+
correct_list_fields(self.i)
729+
# %first with skip should work on the synced genre field
730+
self._setf("%first{$genre,1,2}")
731+
self._assert_dest(b"/base/Classical Crossover")
732+
704733

705734
class DisambiguationTest(BeetsTestCase, PathFormattingMixin):
706735
def setUp(self):

0 commit comments

Comments
 (0)