From 4cd29f9a85b2d9402fb864a0c05ecc728619f42f Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 9 Jan 2026 18:08:56 -0800 Subject: [PATCH] Fixes and refinements, 100% coverage. --- beetsplug/fromfilename.py | 28 +++++++++++++--------------- docs/plugins/fromfilename.rst | 2 +- test/plugins/test_fromfilename.py | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/beetsplug/fromfilename.py b/beetsplug/fromfilename.py index 35b35bec9..a95d63b19 100644 --- a/beetsplug/fromfilename.py +++ b/beetsplug/fromfilename.py @@ -112,11 +112,12 @@ RE_BRACKETS = re.compile(r"[\(\[\{].*?[\)\]\}]") class FilenameMatch(MutableMapping[str, str | None]): - def __init__(self, matches: dict[str, str] = {}) -> None: + def __init__(self, matches: dict[str, str] | None = None) -> None: self._matches: dict[str, str] = {} - for key, value in matches.items(): - if value is not None: - self._matches[key.lower()] = str(value).strip() + if matches: + for key, value in matches.items(): + if value is not None: + self._matches[key.lower()] = str(value).strip() def __getitem__(self, key: str) -> str | None: return self._matches.get(key, None) @@ -159,13 +160,13 @@ class FromFilenamePlugin(BeetsPlugin): } ) self.fields = set(self.config["fields"].as_str_seq()) - # Evaluate the user patterns to expand the fields self.file_patterns = self._user_pattern_to_regex( self.config["patterns"]["file"].as_str_seq() ) self.folder_patterns = self._user_pattern_to_regex( self.config["patterns"]["folder"].as_str_seq() ) + self.session_fields: set[str] = set() self.register_listener("import_task_start", self.filename_task) @cached_property @@ -209,16 +210,13 @@ class FromFilenamePlugin(BeetsPlugin): If no fields are detect that need to be processed, return false to shortcut the plugin. """ - remove = set() + self.session_fields = set({}) for field in self.fields: # If any field is a bad field if any([True for item in items if self._bad_field(item[field])]): - continue - else: - remove.add(field) - self.fields = self.fields - remove + self.session_fields.add(field) # If all fields have been removed, there is nothing to do - if not len(self.fields): + if not len(self.session_fields): return False return True @@ -335,13 +333,13 @@ class FromFilenamePlugin(BeetsPlugin): track_matches: dict[Item, FilenameMatch], ) -> None: """Apply all valid matched fields to all items in the match dictionary.""" - match = album_match + match = dict(album_match._matches) for item in track_matches: - match.update(track_matches[item]) + match.update(track_matches[item]._matches) found_data: dict[str, int | str] = {} self._log.debug(f"Attempting keys: {match.keys()}") for key in match.keys(): - if key in self.fields: + if key in self.session_fields: old_value = item.get(key) new_value = match[key] if self._bad_field(old_value) and new_value: @@ -445,7 +443,7 @@ class FromFilenamePlugin(BeetsPlugin): for f in fields: pattern = re.sub(rf"\\\${f}", f"(?P<{f}>.+)", pattern) self.fields.add(f) - return rf"{pattern}" + return pattern @staticmethod def _mutate_string(text: str, span: tuple[int, int]) -> str: diff --git a/docs/plugins/fromfilename.rst b/docs/plugins/fromfilename.rst index fae2cf12d..98ea92f94 100644 --- a/docs/plugins/fromfilename.rst +++ b/docs/plugins/fromfilename.rst @@ -63,7 +63,7 @@ Default of the file. If ``fromfilename`` can't match the entire string to the given pattern, it will - falls back to the default pattern. + fall back to the default pattern. The following custom patterns will match this path and retrieve the specified fields. diff --git a/test/plugins/test_fromfilename.py b/test/plugins/test_fromfilename.py index 8800ee04d..4f09deee1 100644 --- a/test/plugins/test_fromfilename.py +++ b/test/plugins/test_fromfilename.py @@ -746,7 +746,7 @@ class TestFromFilename(PluginMixin): ) as mock: f = FromFilenamePlugin() f.filename_task(task, Session()) - assert len(f.fields) == 1 + assert len(f.session_fields) == 1 assert "title" in f.fields mock.assert_called()