Skip to content

Commit 704418e

Browse files
committed
Add missing fields to distance
1 parent eb6c04d commit 704418e

File tree

3 files changed

+31
-17
lines changed

3 files changed

+31
-17
lines changed

.mypy.ini

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ allow_any_generics = false
33
# FIXME: Would be better to actually type the libraries (if under our control),
44
# or write our own stubs. For now, silence errors
55
ignore_missing_imports = true
6+
strict = true

beets/autotag/hooks.py

+29-17
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import re
2020
from copy import deepcopy
2121
from dataclasses import dataclass
22-
from functools import total_ordering
22+
from functools import cached_property, total_ordering
2323
from typing import (
2424
TYPE_CHECKING,
2525
Any,
@@ -37,6 +37,7 @@
3737
)
3838

3939
from jellyfish import levenshtein_distance
40+
from rich_tables.utils import make_console
4041
from typing_extensions import Self
4142
from unidecode import unidecode
4243

@@ -52,6 +53,8 @@
5253

5354
log = logging.getLogger(__name__)
5455

56+
console = make_console()
57+
5558

5659
# Classes used to represent candidate options.
5760
class AttrDict(dict):
@@ -420,21 +423,21 @@ def string_dist(str1: Optional[str], str2: Optional[str]) -> float:
420423
return base_dist + penalty
421424

422425

423-
class LazyClassProperty:
426+
class cached_classproperty:
424427
"""A decorator implementing a read-only property that is *lazy* in
425428
the sense that the getter is only invoked once. Subsequent accesses
426429
through *any* instance use the cached result.
427430
"""
428431

429432
def __init__(self, getter):
430433
self.getter = getter
431-
self.computed = False
434+
self.cache = {}
435+
436+
def __get__(self, instance, owner):
437+
if owner not in self.cache:
438+
self.cache[owner] = self.getter(owner)
432439

433-
def __get__(self, obj, owner):
434-
if not self.computed:
435-
self.value = self.getter(owner)
436-
self.computed = True
437-
return self.value
440+
return self.cache[owner]
438441

439442

440443
@total_ordering
@@ -448,7 +451,7 @@ def __init__(self):
448451
self._penalties = {}
449452
self.tracks: Dict[TrackInfo, Distance] = {}
450453

451-
@LazyClassProperty
454+
@cached_classproperty
452455
def _weights(cls) -> Dict[str, float]: # noqa: N805
453456
"""A dictionary from keys to floating-point weights."""
454457
weights_view = config["match"]["distance_weights"]
@@ -492,6 +495,7 @@ def raw_distance(self) -> float:
492495
dist_raw += sum(penalty) * self._weights[key]
493496
return dist_raw
494497

498+
@property
495499
def items(self) -> List[Tuple[str, float]]:
496500
"""Return a list of (key, dist) pairs, with `dist` being the
497501
weighted distance, sorted from highest to lowest. Does not
@@ -543,13 +547,13 @@ def __getitem__(self, key) -> float:
543547
return 0.0
544548

545549
def __iter__(self) -> Iterator[Tuple[str, float]]:
546-
return iter(self.items())
550+
return iter(self.items)
547551

548552
def __len__(self) -> int:
549-
return len(self.items())
553+
return len(self.items)
550554

551555
def keys(self) -> List[str]:
552-
return [key for key, _ in self.items()]
556+
return [key for key, _ in self.items]
553557

554558
def update(self, dist: "Distance"):
555559
"""Adds all the distance penalties from `dist`."""
@@ -679,6 +683,13 @@ class Match:
679683
distance: Distance
680684
info: AttrDict
681685

686+
@cached_classproperty
687+
def disambig_fields(cls) -> Iterable[str]:
688+
fields: List[str] = config["match"][
689+
cls.disambig_fields_key
690+
].as_str_seq()
691+
return fields
692+
682693
@property
683694
def dist(self) -> str:
684695
if self.distance <= config["match"]["strong_rec_thresh"].as_number():
@@ -693,22 +704,23 @@ def dist(self) -> str:
693704
def name(self) -> str:
694705
return self.info.name
695706

696-
@property
707+
@cached_property
697708
def penalty(self, limit: int = 0) -> Optional[str]:
698709
"""Returns a colorized string that indicates all the penalties
699710
applied to a distance object.
700711
"""
712+
field_count = len(self.disambig_fields)
713+
missing_field_count = sum(
714+
1 for f in self.disambig_fields if not self.info.get(f)
715+
)
716+
self.distance.add("missing_fields", missing_field_count / field_count)
701717
penalties = self.distance.penalties
702718
if penalties:
703719
if limit and len(penalties) > limit:
704720
penalties = penalties[:limit] + ["..."]
705721
return colorize("text_warning", f"({', '.join(penalties)})")
706722
return None
707723

708-
@property
709-
def disambig_fields(self) -> Iterable[str]:
710-
return config["match"][self.disambig_fields_key].as_str_seq()
711-
712724
@property
713725
def dist_data(self) -> JSONDict:
714726
return {

beets/autotag/mb.py

+1
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ def album_info(release: Dict) -> beets.autotag.hooks.AlbumInfo:
622622
if any(
623623
config["musicbrainz"]["external_ids"].get().values()
624624
) and release.get("url-relation-list"):
625+
log.error("{}", release.get("url-relation-list"))
625626
discogs_url, bandcamp_url, spotify_url = None, None, None
626627
deezer_url, beatport_url, tidal_url = None, None, None
627628
fetch_discogs, fetch_bandcamp, fetch_spotify = False, False, False

0 commit comments

Comments
 (0)