Skip to content

Commit fab4f8d

Browse files
semohrpeterjdolan
authored andcommitted
Allow to pickle db models by removing the current connection. (#5641)
## Description This might be a quick one, depending on how you feel about it... It allows you to pickle DB model objects. I don't think this is used directly in Beets, but it might be useful in general. For instance, we encountered an issue where we wanted to quickly pickle an Item or Album. This sometimes worked and other times failed, which seemed quite inconsistent. Some DB model methods and properties have the side effect of attaching an SQLite connection to self (._db), which prevents serialization. The fix is quite straightforward, so I thought we might want to integrate this into beets directly. ## To Do - [x] Changelog - [x] Tests
1 parent ad80cc0 commit fab4f8d

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

beets/dbcore/db.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,15 @@ def set_parse(self, key, string: str):
716716
"""Set the object's key to a value represented by a string."""
717717
self[key] = self._parse(key, string)
718718

719+
def __getstate__(self):
720+
"""Return the state of the object for pickling.
721+
Remove the database connection as sqlite connections are not
722+
picklable.
723+
"""
724+
state = self.__dict__.copy()
725+
state["_db"] = None
726+
return state
727+
719728

720729
# Database controller and supporting interfaces.
721730

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Other changes:
106106
EXTM3U playlists instead of JSON-encoding them.
107107
* :doc:`plugins/ftintitle`: Optimize the plugin by avoiding unnecessary writes
108108
to the database.
109+
* Database models are now serializable with pickle.
109110

110111
2.2.0 (December 02, 2024)
111112
-------------------------

test/test_dbcore.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,20 @@ def test_parse_nonstring(self):
421421
with pytest.raises(TypeError, match="must be a string"):
422422
dbcore.Model._parse(None, 42)
423423

424+
def test_pickle_dump(self):
425+
"""Tries to pickle an item. This tests the __getstate__ method
426+
of the Model ABC"""
427+
import pickle
428+
429+
model = ModelFixture1(self.db)
430+
model.add(self.db)
431+
model.field_one = 123
432+
433+
model.store()
434+
assert model._db is not None
435+
436+
pickle.dumps(model)
437+
424438

425439
class FormatTest(unittest.TestCase):
426440
def test_format_fixed_field_integer(self):

0 commit comments

Comments
 (0)