From 4417fea0abfe074b869c018933633c997f9e9bdd Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 27 Jun 2026 10:52:09 +0200 Subject: [PATCH] Fix storing flex media fields during update --- beets/dbcore/db.py | 2 +- docs/changelog.rst | 2 ++ test/test_dbcore.py | 9 +++++++++ test/ui/commands/test_update.py | 25 +++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/beets/dbcore/db.py b/beets/dbcore/db.py index ca42eb2b10..517368abf5 100755 --- a/beets/dbcore/db.py +++ b/beets/dbcore/db.py @@ -599,7 +599,7 @@ def store(self, fields: Iterable[str] | None = None): assignments = [] subvars: list[SQLiteType] = [] for key in fields: - if key != "id" and key in self._dirty: + if key != "id" and key in self._fields and key in self._dirty: self._dirty.remove(key) assignments.append(f"{key}=?") value = self._type(key).to_sql(self[key]) diff --git a/docs/changelog.rst b/docs/changelog.rst index 2609ce8fa9..caabfb249e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -34,6 +34,8 @@ Bug fixes example a multi-disc album whose cover lives in the album root rather than a per-disc directory); the missing art is skipped instead. :bug:`4692` - :doc:`plugins/tidal`: Normalize Tidal album types to lowercase. +- ``beet update`` no longer crashes when a plugin-added media field is stored as + a flexible attribute. :bug:`5580` .. For plugin developers diff --git a/test/test_dbcore.py b/test/test_dbcore.py index 283a3c6c2a..e8833b0e5f 100644 --- a/test/test_dbcore.py +++ b/test/test_dbcore.py @@ -325,6 +325,15 @@ def test_store_and_retrieve_flexattr(self): other_model = self.db._get(ModelFixture1, model.id) assert other_model.foo == "bar" + def test_store_flexattr_in_fields(self): + model = ModelFixture1() + model.add(self.db) + model.foo = "bar" + model.store(fields=["foo"]) + + other_model = self.db._get(ModelFixture1, model.id) + assert other_model.foo == "bar" + def test_delete_flexattr(self): model = ModelFixture1() model["foo"] = "bar" diff --git a/test/ui/commands/test_update.py b/test/ui/commands/test_update.py index 937ded10cb..003ef71b9e 100644 --- a/test/ui/commands/test_update.py +++ b/test/ui/commands/test_update.py @@ -1,8 +1,10 @@ import os +import mediafile from mediafile import MediaFile from beets import library +from beets.plugins import BeetsPlugin from beets.test import _common from beets.test.helper import BeetsTestCase, IOMixin from beets.ui.commands.update import update_items @@ -84,6 +86,29 @@ def test_modified_metadata_detected(self): item = self.lib.items().get() assert item.title == "differentTitle" + def test_modified_plugin_media_field_detected(self): + plugin = BeetsPlugin() + plugin.add_media_field( + "customtag", + mediafile.MediaField( + mediafile.MP3DescStorageStyle("customtag"), + mediafile.StorageStyle("customtag"), + ), + ) + + try: + mf = MediaFile(syspath(self.i.path)) + mf.customtag = "F#" + mf.save() + + self._update() + + item = self.lib.get_item(self.i.id) + assert item["customtag"] == "F#" + finally: + delattr(mediafile.MediaFile, "customtag") + library.Item._media_fields.remove("customtag") + def test_modified_metadata_moved(self): mf = MediaFile(syspath(self.i.path)) mf.title = "differentTitle"