Since this code was introduced in f8559fdd7, it was returning None implicitly if no "release-events" were found in node.
This behavior differs from other methods of the same kind like release_dates_and_countries_from_node()
This change shouldn't have any negative impact, since callers always test for emptyness
- use generators for candidates
- introduce picard.util.find_best_match() and sort_by_similarity() with tests
- partially revert change that removed sorted(), it was actually faster and cleaner
- use namedtuples to get rid of numeric indexes
- when no match, output max similarity, threshold and number of candidates to debug log
- make code easier to understand, using long names and namedtuple attributes, and simpler workflow
- use repr(best_match) for debug, as it provides all the needed info
- set values explicitly using namedtuple kw parameters
- use same prefix for namedtuples names, it eases searching through code
Typical debug output looks like:
```
D: 13:16:41,806 cluster._lookup_finished:223: BestMatch(similarity=0.79, result=SimMatchRelease(similarity=0.79, release={'id': '36b8f767-c4c0-4ba1-becd-f40a452303d5', 'score': 79, 'count': 1, 'title': 'Purple', 'status': 'Official', 'packaging': 'Jewel Case', 'text-representation': {'language': 'eng', 'script': 'Latn'}, 'artist-credit': [{'artist': {'id': '8c32bb01-58a3-453b-8050-8c0620edb0e5', 'name': 'Stone Temple Pilots', 'sort-name': 'Stone Temple Pilots'}}], 'release-group': {'id': '01d45519-54a6-3427-b0dc-222203fa5d57', 'type-id': 'f529b476-6e62-324f-b0aa-1f3e33d313fc', 'title': 'Purple', 'primary-type': 'Album'}, 'date': '1995-08-25', 'country': 'US', 'release-events': [{'date': '1995-08-25', 'area': {'id': '489ce91b-6658-3307-9877-795b68554c98', 'name': 'United States', 'sort-name': 'United States', 'iso-3166-1-codes': ['US']}}], 'track-count': 11, 'media': [{'format': 'CD', 'disc-count': 10, 'track-count': 11}]}), num_results=25) < threshold=0.800000
```
- image.types_as_string() was called from get_image_type() without translate=False
- dependency wasn't satisfied, so impossible to test as is
- make tests depending on languages isn't a good idea anyway
- use new CoverArtImage.normalized_types() instead
- simplify code
- add tests for ImageList.append() and ImageList.__eq__()
This is needed because types can be in any order (and even contains duplicate)
So output of types_as_string() was differing, depending on how types were set
- basically it returns config.setting[key] when key isn't in the internal dict
- it protects config.setting from any write, since __setitem__ only write to self._dict
- del settings['xxx'] will remove 'xxx' from internal dict, but still allow access to config.setting
- it can be used for tests
- minimal implementation based on MutableMapping
- add tests for it
m['tag'] = 0 wasn't doing the same thing as m.add('tag', 0), because the test in __setitem__()
was different: if value vs if value or value == 0
So modify it to make behavior much more consistent.
m['tag'] = 0 or m.add('tag', 0) actually set tag to ['0']
m.add('tag', '') does nothing
m['tag'] = '' explicitly delete the tag (removing it from store, adding it to deleted tags)
m = Metadata(tag='') doesn't create an entry 'tag' (at all)
m = Metadata(tag=0) creates a tag, with internal value ['0']
This way, one can rewrite:
self.metadata = Metadata()
self.metadata['album'] = name
self.metadata['albumartist'] = artist
self.metadata['totaltracks'] = 0
to:
self.metadata = Metadata(album=name, albumartist=artist, totaltracks=0)
Without this patch, totaltracks wasn't set at all.
```python
m = Metadata(tag1='a', tag2='b')
del m['tag1']
```
```
m store: {'tag2': ['b']}
m deleted: {'tag1'}
```
```python
m2 = Metadata(tag1='c', tag2='d')
del m2['tag2']
```
```
m2 store: {'tag2': ['b']}
m2 deleted: {'tag1'}
```
```python
m.update(m2)
```
```
m store: {'tag1': ['c']}
m deleted: {'tag1', 'tag2'} <---- this was incorrect, and untested case
```
This patch fixes it, and results to:
```
m store: {'tag1': ['c']}
m deleted: {'tag2'}
```
- access times are likely to differ, a race condition is possible
- stat() has be done after the change to be able to compare
- comments added
- force sync after modifying test file
- make code easier to understand
See https://github.com/metabrainz/picard/pull/1132#issuecomment-474113665