Skip to content

Commit 0f76312

Browse files
valrusJOJ0
andauthored
Fix duplicate database change event send on Library.add (#5561)
## Description Fixes #5560. Also a couple other incidental changes / improvements: * Add `EventType` that holds the actual string literals used for event sending. With type checking, this can prevent subtle bugs resulting from misspelled event names. * Fix `HiddenFileTest` by using `bytestring_path()` ## To Do - [x] ~Documentation.~ - [x] Changelog. - [x] Tests. --------- Co-authored-by: J0J0 Todos <[email protected]> Co-authored-by: J0J0 Todos <[email protected]>
1 parent dd2f203 commit 0f76312

File tree

6 files changed

+66
-5
lines changed

6 files changed

+66
-5
lines changed

beets/event_types.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import Literal
2+
3+
EventType = Literal[
4+
"pluginload",
5+
"import",
6+
"album_imported",
7+
"album_removed",
8+
"item_copied",
9+
"item_imported",
10+
"before_item_moved",
11+
"item_moved",
12+
"item_linked",
13+
"item_hardlinked",
14+
"item_reflinked",
15+
"item_removed",
16+
"write",
17+
"after_write",
18+
"import_task_created",
19+
"import_task_start",
20+
"import_task_apply",
21+
"import_task_before_choice",
22+
"import_task_choice",
23+
"import_task_files",
24+
"library_opened",
25+
"database_change",
26+
"cli_exit",
27+
"import_begin",
28+
"trackinfo_received",
29+
"albuminfo_received",
30+
"before_choose_candidate",
31+
"mb_track_extract",
32+
"mb_album_extract",
33+
]

beets/library.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,9 @@ def remove(self):
369369
plugins.send("database_change", lib=self._db, model=self)
370370

371371
def add(self, lib=None):
372+
# super().add() calls self.store(), which sends `database_change`,
373+
# so don't do it here
372374
super().add(lib)
373-
plugins.send("database_change", lib=self._db, model=self)
374375

375376
def __format__(self, spec):
376377
if not spec:

beets/plugins.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
from beets import logging
4040
from beets.util.id_extractors import extract_release_id
4141

42+
if TYPE_CHECKING:
43+
from beets.event_types import EventType
44+
4245
if sys.version_info >= (3, 10):
4346
from typing import ParamSpec
4447
else:
@@ -292,7 +295,7 @@ def add_media_field(
292295
_raw_listeners: dict[str, list[Listener]] | None = None
293296
listeners: dict[str, list[Listener]] | None = None
294297

295-
def register_listener(self, event: str, func: Listener) -> None:
298+
def register_listener(self, event: "EventType", func: Listener):
296299
"""Add a function as a listener for the specified event."""
297300
wrapped_func = self._set_log_level_and_params(logging.WARNING, func)
298301

docs/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Bug fixes:
3131
:bug:`5788`
3232
* tests: Fix library tests failing on Windows when run from outside ``D:/``.
3333
:bug:`5802`
34+
* Fix an issue where calling `Library.add` would cause the `database_change`
35+
event to be sent twice, not once.
36+
:bug:`5560`
37+
* Fix ``HiddenFileTest`` by using ``bytestring_path()``.
3438

3539
For packagers:
3640

test/test_hidden.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import unittest
2323

2424
from beets import util
25-
from beets.util import hidden
25+
from beets.util import bytestring_path, hidden
2626

2727

2828
class HiddenFileTest(unittest.TestCase):
@@ -44,7 +44,7 @@ def test_osx_hidden(self):
4444
else:
4545
raise e
4646

47-
assert hidden.is_hidden(f.name)
47+
assert hidden.is_hidden(bytestring_path(f.name))
4848

4949
def test_windows_hidden(self):
5050
if not sys.platform == "win32":

test/test_library.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@
2929

3030
import beets.dbcore.query
3131
import beets.library
32+
import beets.logging as blog
3233
from beets import config, plugins, util
3334
from beets.library import Album
3435
from beets.test import _common
3536
from beets.test._common import item
36-
from beets.test.helper import BeetsTestCase, ItemInDBTestCase
37+
from beets.test.helper import BeetsTestCase, ItemInDBTestCase, capture_log
3738
from beets.util import as_string, bytestring_path, normpath, syspath
3839

3940
# Shortcut to path normalization.
@@ -126,6 +127,25 @@ def test_library_add_path_inserts_row(self):
126127
)
127128
assert new_grouping == self.i.grouping
128129

130+
def test_library_add_one_database_change_event(self):
131+
"""Test library.add emits only one database_change event."""
132+
self.item = _common.item()
133+
self.item.path = beets.util.normpath(
134+
os.path.join(
135+
self.temp_dir,
136+
b"a",
137+
b"b.mp3",
138+
)
139+
)
140+
self.item.album = "a"
141+
self.item.title = "b"
142+
143+
blog.getLogger("beets").set_global_level(blog.DEBUG)
144+
with capture_log() as logs:
145+
self.lib.add(self.item)
146+
147+
assert logs.count("Sending event: database_change") == 1
148+
129149

130150
class RemoveTest(ItemInDBTestCase):
131151
def test_remove_deletes_from_db(self):

0 commit comments

Comments
 (0)