diff --git a/picard/cluster.py b/picard/cluster.py index 1cfac31c5..0399baaf7 100644 --- a/picard/cluster.py +++ b/picard/cluster.py @@ -46,6 +46,7 @@ from PyQt5 import QtCore from picard.config import get_config from picard.const import QUERY_LIMIT +from picard.file import File from picard.metadata import ( Metadata, SimMatchRelease, @@ -317,7 +318,7 @@ class Cluster(FileList): if token: cluster_list[token].add(album, artist or various_artists, file) - yield from (cluster for cluster in cluster_list.values() if len(cluster.files) > 1) + yield from cluster_list.values() class UnclusteredFiles(Cluster): @@ -388,18 +389,22 @@ class ClusterList(list, Item): class FileCluster: def __init__(self): - self.files = [] + self._files = [] self._artist_counts = Counter() self._artists = defaultdict(Counter) self._titles = Counter() def add(self, album, artist, file): - self.files.append(file) + self._files.append(file) token = tokenize(artist) self._artist_counts[token] += 1 self._artists[token][artist] += 1 self._titles[album] += 1 + @property + def files(self): + yield from (file for file in self._files if file.state != File.REMOVED) + @property def artist(self): tokenized_artist = self._artist_counts.most_common(1)[0][0] diff --git a/picard/tagger.py b/picard/tagger.py index 6f3b7d226..3ad2a7edf 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -927,8 +927,10 @@ class Tagger(QtWidgets.QApplication): with self.window.ignore_selection_changes: self.window.set_sorting(False) for file_cluster in process_events_iter(result): - cluster = self.load_cluster(file_cluster.title, file_cluster.artist) - cluster.add_files(file_cluster.files) + files = set(file_cluster.files) + if len(files) > 1: + cluster = self.load_cluster(file_cluster.title, file_cluster.artist) + cluster.add_files(files) self.window.set_sorting(True) if callback: diff --git a/test/test_clustering.py b/test/test_clustering.py index cd86edd8d..ea3169ca3 100644 --- a/test/test_clustering.py +++ b/test/test_clustering.py @@ -73,8 +73,7 @@ class ClusterTest(PicardTestCase): self._create_file('album foo', 'artist foo'), ] clusters = list(Cluster.cluster(files)) - # No cluster is being created for single files - self.assertEqual(0, len(clusters)) + self.assertEqual(1, len(clusters)) def test_cluster_single_cluster(self): files = [ @@ -92,12 +91,13 @@ class ClusterTest(PicardTestCase): self._create_file('album cluster2', 'artist foo'), self._create_file('album cluster1', 'artist foo'), self._create_file('albumcluster2', 'artist bar'), - self._create_file('album nocluster', 'artist bar'), + self._create_file('album single', 'artist bar'), ] clusters = list(Cluster.cluster(files)) - self.assertEqual(2, len(clusters)) + self.assertEqual(3, len(clusters)) self.assertClusterEqual('album cluster1', 'artist bar', {files[0], files[2]}, clusters[0]) self.assertClusterEqual('album cluster2', 'artist foo', {files[1], files[3]}, clusters[1]) + self.assertClusterEqual('album single', 'artist bar', {files[4]}, clusters[2]) def test_cluster_by_path(self): files = [ @@ -105,13 +105,14 @@ class ClusterTest(PicardTestCase): self._create_file(None, None, 'album2/foo1.ogg'), self._create_file(None, None, 'artist1/album1/foo2.ogg'), self._create_file(None, None, 'album2/foo2.ogg'), - self._create_file(None, None, 'nocluster/foo.ogg'), + self._create_file(None, None, 'single/foo.ogg'), self._create_file(None, None, 'album1/foo3.ogg'), ] clusters = list(Cluster.cluster(files)) - self.assertEqual(2, len(clusters)) + self.assertEqual(3, len(clusters)) self.assertClusterEqual('album1', 'artist1', {files[0], files[2], files[5]}, clusters[0]) self.assertClusterEqual('album2', 'Diverse Interpreten', {files[1], files[3]}, clusters[1]) + self.assertClusterEqual('single', 'Diverse Interpreten', {files[4]}, clusters[2]) def test_cluster_no_metadata(self): files = [ @@ -143,7 +144,7 @@ class FileClusterTest(PicardTestCase): fc.add('album 1', 'artist 1', file) self.assertEqual('album 1', fc.title) self.assertEqual('artist 1', fc.artist) - self.assertEqual([file], fc.files) + self.assertEqual([file], list(fc.files)) def test_multi(self): files = [ @@ -161,4 +162,4 @@ class FileClusterTest(PicardTestCase): fc.add('album 2', 'Artist 1', files[4]) self.assertEqual('Album 1', fc.title) self.assertEqual('Artist 1', fc.artist) - self.assertEqual(files, fc.files) + self.assertEqual(files, list(fc.files))