Skip to content

Commit 1c9aebd

Browse files
committed
match.current_metadata -> util.get_most_common_tags
1 parent 509cbdc commit 1c9aebd

File tree

6 files changed

+127
-130
lines changed

6 files changed

+127
-130
lines changed

beets/autotag/__init__.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@
2424
from beets.util import unique_list
2525

2626
from .hooks import AlbumInfo, AlbumMatch, Distance, TrackInfo, TrackMatch
27-
from .match import (
28-
Proposal,
29-
Recommendation,
30-
current_metadata,
31-
tag_album,
32-
tag_item,
33-
)
27+
from .match import Proposal, Recommendation, tag_album, tag_item
3428

3529
__all__ = [
3630
"AlbumInfo",
@@ -43,7 +37,6 @@
4337
"apply_album_metadata",
4438
"apply_item_metadata",
4539
"apply_metadata",
46-
"current_metadata",
4740
"tag_album",
4841
"tag_item",
4942
]

beets/autotag/match.py

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
TrackMatch,
3737
hooks,
3838
)
39-
from beets.util import plurality
39+
from beets.util import get_most_common_tags
4040

4141
if TYPE_CHECKING:
4242
from collections.abc import Iterable, Sequence
@@ -80,44 +80,6 @@ class Proposal(NamedTuple):
8080
# Primary matching functionality.
8181

8282

83-
def current_metadata(
84-
items: Iterable[Item],
85-
) -> tuple[dict[str, Any], dict[str, Any]]:
86-
"""Extract the likely current metadata for an album given a list of its
87-
items. Return two dictionaries:
88-
- The most common value for each field.
89-
- Whether each field's value was unanimous (values are booleans).
90-
"""
91-
assert items # Must be nonempty.
92-
93-
likelies = {}
94-
consensus = {}
95-
fields = [
96-
"artist",
97-
"album",
98-
"albumartist",
99-
"year",
100-
"disctotal",
101-
"mb_albumid",
102-
"label",
103-
"barcode",
104-
"catalognum",
105-
"country",
106-
"media",
107-
"albumdisambig",
108-
]
109-
for field in fields:
110-
values = [item[field] for item in items if item]
111-
likelies[field], freq = plurality(values)
112-
consensus[field] = freq == len(values)
113-
114-
# If there's an album artist consensus, use this for the artist.
115-
if consensus["albumartist"] and likelies["albumartist"]:
116-
likelies["artist"] = likelies["albumartist"]
117-
118-
return likelies, consensus
119-
120-
12183
def assign_items(
12284
items: Sequence[Item],
12385
tracks: Sequence[TrackInfo],
@@ -231,7 +193,7 @@ def distance(
231193
keys are a subset of `items` and the values are a subset of
232194
`album_info.tracks`.
233195
"""
234-
likelies, _ = current_metadata(items)
196+
likelies, _ = get_most_common_tags(items)
235197

236198
dist = hooks.Distance()
237199

@@ -499,7 +461,7 @@ def tag_album(
499461
candidates.
500462
"""
501463
# Get current metadata.
502-
likelies, consensus = current_metadata(items)
464+
likelies, consensus = get_most_common_tags(items)
503465
cur_artist: str = likelies["artist"]
504466
cur_album: str = likelies["album"]
505467
log.debug("Tagging {0} - {1}", cur_artist, cur_album)

beets/importer/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def chosen_info(self):
228228
or APPLY (in which case the data comes from the choice).
229229
"""
230230
if self.choice_flag in (Action.ASIS, Action.RETAG):
231-
likelies, consensus = autotag.current_metadata(self.items)
231+
likelies, consensus = util.get_most_common_tags(self.items)
232232
return likelies
233233
elif self.choice_flag is Action.APPLY and self.match:
234234
return self.match.info.copy()

beets/util/__init__.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
from collections.abc import Iterator, Sequence
5757
from logging import Logger
5858

59+
from beets.library import Item
60+
5961
if sys.version_info >= (3, 10):
6062
from typing import TypeAlias
6163
else:
@@ -814,6 +816,44 @@ def plurality(objs: Iterable[T]) -> tuple[T, int]:
814816
return c.most_common(1)[0]
815817

816818

819+
def get_most_common_tags(
820+
items: Sequence[Item],
821+
) -> tuple[dict[str, Any], dict[str, Any]]:
822+
"""Extract the likely current metadata for an album given a list of its
823+
items. Return two dictionaries:
824+
- The most common value for each field.
825+
- Whether each field's value was unanimous (values are booleans).
826+
"""
827+
assert items # Must be nonempty.
828+
829+
likelies = {}
830+
consensus = {}
831+
fields = [
832+
"artist",
833+
"album",
834+
"albumartist",
835+
"year",
836+
"disctotal",
837+
"mb_albumid",
838+
"label",
839+
"barcode",
840+
"catalognum",
841+
"country",
842+
"media",
843+
"albumdisambig",
844+
]
845+
for field in fields:
846+
values = [item[field] for item in items if item]
847+
likelies[field], freq = plurality(values)
848+
consensus[field] = freq == len(values)
849+
850+
# If there's an album artist consensus, use this for the artist.
851+
if consensus["albumartist"] and likelies["albumartist"]:
852+
likelies["artist"] = likelies["albumartist"]
853+
854+
return likelies, consensus
855+
856+
817857
# stdout and stderr as bytes
818858
class CommandOutput(NamedTuple):
819859
stdout: bytes

test/test_autotag.py

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -24,86 +24,6 @@
2424
from beets.autotag.hooks import Distance, string_dist
2525
from beets.library import Item
2626
from beets.test.helper import BeetsTestCase, ConfigMixin
27-
from beets.util import plurality
28-
29-
30-
class PluralityTest(BeetsTestCase):
31-
def test_plurality_consensus(self):
32-
objs = [1, 1, 1, 1]
33-
obj, freq = plurality(objs)
34-
assert obj == 1
35-
assert freq == 4
36-
37-
def test_plurality_near_consensus(self):
38-
objs = [1, 1, 2, 1]
39-
obj, freq = plurality(objs)
40-
assert obj == 1
41-
assert freq == 3
42-
43-
def test_plurality_conflict(self):
44-
objs = [1, 1, 2, 2, 3]
45-
obj, freq = plurality(objs)
46-
assert obj in (1, 2)
47-
assert freq == 2
48-
49-
def test_plurality_empty_sequence_raises_error(self):
50-
with pytest.raises(ValueError, match="must be non-empty"):
51-
plurality([])
52-
53-
def test_current_metadata_finds_pluralities(self):
54-
items = [
55-
Item(artist="The Beetles", album="The White Album"),
56-
Item(artist="The Beatles", album="The White Album"),
57-
Item(artist="The Beatles", album="Teh White Album"),
58-
]
59-
likelies, consensus = match.current_metadata(items)
60-
assert likelies["artist"] == "The Beatles"
61-
assert likelies["album"] == "The White Album"
62-
assert not consensus["artist"]
63-
64-
def test_current_metadata_artist_consensus(self):
65-
items = [
66-
Item(artist="The Beatles", album="The White Album"),
67-
Item(artist="The Beatles", album="The White Album"),
68-
Item(artist="The Beatles", album="Teh White Album"),
69-
]
70-
likelies, consensus = match.current_metadata(items)
71-
assert likelies["artist"] == "The Beatles"
72-
assert likelies["album"] == "The White Album"
73-
assert consensus["artist"]
74-
75-
def test_albumartist_consensus(self):
76-
items = [
77-
Item(artist="tartist1", album="album", albumartist="aartist"),
78-
Item(artist="tartist2", album="album", albumartist="aartist"),
79-
Item(artist="tartist3", album="album", albumartist="aartist"),
80-
]
81-
likelies, consensus = match.current_metadata(items)
82-
assert likelies["artist"] == "aartist"
83-
assert not consensus["artist"]
84-
85-
def test_current_metadata_likelies(self):
86-
fields = [
87-
"artist",
88-
"album",
89-
"albumartist",
90-
"year",
91-
"disctotal",
92-
"mb_albumid",
93-
"label",
94-
"barcode",
95-
"catalognum",
96-
"country",
97-
"media",
98-
"albumdisambig",
99-
]
100-
items = [Item(**{f: f"{f}_{i or 1}" for f in fields}) for i in range(5)]
101-
likelies, _ = match.current_metadata(items)
102-
for f in fields:
103-
if isinstance(likelies[f], int):
104-
assert likelies[f] == 0
105-
else:
106-
assert likelies[f] == f"{f}_1"
10727

10828

10929
def _make_item(title, track, artist="some artist"):

test/test_util.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
import pytest
2525

2626
from beets import util
27+
from beets.library import Item
2728
from beets.test import _common
29+
from beets.test.helper import BeetsTestCase
30+
from beets.util import plurality
2831

2932

3033
class UtilTest(unittest.TestCase):
@@ -217,3 +220,82 @@ def test_replacements(
217220
expected_path,
218221
expected_truncated,
219222
)
223+
224+
225+
class PluralityTest(BeetsTestCase):
226+
def test_plurality_consensus(self):
227+
objs = [1, 1, 1, 1]
228+
obj, freq = plurality(objs)
229+
assert obj == 1
230+
assert freq == 4
231+
232+
def test_plurality_near_consensus(self):
233+
objs = [1, 1, 2, 1]
234+
obj, freq = plurality(objs)
235+
assert obj == 1
236+
assert freq == 3
237+
238+
def test_plurality_conflict(self):
239+
objs = [1, 1, 2, 2, 3]
240+
obj, freq = plurality(objs)
241+
assert obj in (1, 2)
242+
assert freq == 2
243+
244+
def test_plurality_empty_sequence_raises_error(self):
245+
with pytest.raises(ValueError, match="must be non-empty"):
246+
plurality([])
247+
248+
def test_current_metadata_finds_pluralities(self):
249+
items = [
250+
Item(artist="The Beetles", album="The White Album"),
251+
Item(artist="The Beatles", album="The White Album"),
252+
Item(artist="The Beatles", album="Teh White Album"),
253+
]
254+
likelies, consensus = util.get_most_common_tags(items)
255+
assert likelies["artist"] == "The Beatles"
256+
assert likelies["album"] == "The White Album"
257+
assert not consensus["artist"]
258+
259+
def test_current_metadata_artist_consensus(self):
260+
items = [
261+
Item(artist="The Beatles", album="The White Album"),
262+
Item(artist="The Beatles", album="The White Album"),
263+
Item(artist="The Beatles", album="Teh White Album"),
264+
]
265+
likelies, consensus = util.get_most_common_tags(items)
266+
assert likelies["artist"] == "The Beatles"
267+
assert likelies["album"] == "The White Album"
268+
assert consensus["artist"]
269+
270+
def test_albumartist_consensus(self):
271+
items = [
272+
Item(artist="tartist1", album="album", albumartist="aartist"),
273+
Item(artist="tartist2", album="album", albumartist="aartist"),
274+
Item(artist="tartist3", album="album", albumartist="aartist"),
275+
]
276+
likelies, consensus = util.get_most_common_tags(items)
277+
assert likelies["artist"] == "aartist"
278+
assert not consensus["artist"]
279+
280+
def test_current_metadata_likelies(self):
281+
fields = [
282+
"artist",
283+
"album",
284+
"albumartist",
285+
"year",
286+
"disctotal",
287+
"mb_albumid",
288+
"label",
289+
"barcode",
290+
"catalognum",
291+
"country",
292+
"media",
293+
"albumdisambig",
294+
]
295+
items = [Item(**{f: f"{f}_{i or 1}" for f in fields}) for i in range(5)]
296+
likelies, _ = util.get_most_common_tags(items)
297+
for f in fields:
298+
if isinstance(likelies[f], int):
299+
assert likelies[f] == 0
300+
else:
301+
assert likelies[f] == f"{f}_1"

0 commit comments

Comments
 (0)