Skip to content

Commit 8637db7

Browse files
committed
Add ability to set temporary music dir context for ipfs
1 parent 7445c7f commit 8637db7

4 files changed

Lines changed: 62 additions & 33 deletions

File tree

beets/context.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from contextlib import contextmanager
12
from contextvars import ContextVar
23

34
# Holds the music dir context
@@ -12,3 +13,13 @@ def get_music_dir() -> bytes:
1213
def set_music_dir(value: bytes) -> None:
1314
"""Set the current music directory context."""
1415
_music_dir_var.set(value)
16+
17+
18+
@contextmanager
19+
def music_dir(value: bytes):
20+
"""Temporarily bind the active music directory for query parsing."""
21+
token = _music_dir_var.set(value)
22+
try:
23+
yield
24+
finally:
25+
_music_dir_var.reset(token)

beets/library/library.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
from contextlib import contextmanager
34
from typing import TYPE_CHECKING
45

56
import platformdirs
@@ -32,10 +33,12 @@ def __init__(
3233
directory: str | None = None,
3334
path_formats=((PF_KEY_DEFAULT, "$artist/$album/$track $title"),),
3435
replacements=None,
36+
set_music_dir: bool = True,
3537
):
3638
timeout = beets.config["timeout"].as_number()
3739
self.directory = normpath(directory or platformdirs.user_music_path())
38-
context.set_music_dir(self.directory)
40+
if set_music_dir:
41+
context.set_music_dir(self.directory)
3942

4043
super().__init__(path, timeout=timeout)
4144

@@ -45,6 +48,12 @@ def __init__(
4548
# Used for template substitution performance.
4649
self._memotable: dict[tuple[str, ...], str] = {}
4750

51+
@contextmanager
52+
def music_dir_context(self):
53+
"""Temporarily bind this library's directory to path conversion."""
54+
with context.music_dir(self.directory):
55+
yield self
56+
4857
# Adding objects to the database.
4958

5059
def add(self, obj):
@@ -95,10 +104,13 @@ def _fetch(self, model_cls, query, sort=None):
95104
# Parse the query, if necessary.
96105
try:
97106
parsed_sort = None
98-
if isinstance(query, str):
99-
query, parsed_sort = parse_query_string(query, model_cls)
100-
elif isinstance(query, (list, tuple)):
101-
query, parsed_sort = parse_query_parts(query, model_cls)
107+
# Query parsing needs the library root, but keeping it scoped here
108+
# avoids leaking one Library's directory into another's work.
109+
with context.music_dir(self.directory):
110+
if isinstance(query, str):
111+
query, parsed_sort = parse_query_string(query, model_cls)
112+
elif isinstance(query, (list, tuple)):
113+
query, parsed_sort = parse_query_parts(query, model_cls)
102114
except dbcore.query.InvalidQueryArgumentValueError as exc:
103115
raise dbcore.InvalidQueryError(query, exc)
104116

beetsplug/ipfs.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,16 @@ def get_remote_lib(self, lib):
281281

282282
def ipfs_added_albums(self, rlib, tmpname):
283283
"""Returns a new library with only albums/items added to ipfs"""
284-
tmplib = library.Library(tmpname, directory="/ipfs/")
285-
for album in rlib.albums():
286-
try:
287-
if album.ipfs:
288-
self.create_new_album(album, tmplib)
289-
except AttributeError:
290-
pass
284+
tmplib = library.Library(
285+
tmpname, directory="/ipfs/", set_music_dir=False
286+
)
287+
with tmplib.music_dir_context():
288+
for album in rlib.albums():
289+
try:
290+
if album.ipfs:
291+
self.create_new_album(album, tmplib)
292+
except AttributeError:
293+
pass
291294
return tmplib
292295

293296
def create_new_album(self, album, tmplib):

test/plugins/test_ipfs.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,30 @@ def test_stored_hashes(self):
2929
test_album = self.mk_test_album()
3030
ipfs = IPFSPlugin()
3131
added_albums = ipfs.ipfs_added_albums(self.lib, self.lib.path)
32-
added_album = added_albums.get_album(1)
33-
assert added_album.ipfs == test_album.ipfs
34-
found = False
35-
want_item = test_album.items()[2]
36-
for check_item in added_album.items():
37-
try:
38-
if check_item.get("ipfs", with_album=False):
39-
ipfs_item = os.fsdecode(os.path.basename(want_item.path))
40-
want_path = util.normpath(
41-
os.path.join("/ipfs", test_album.ipfs, ipfs_item)
42-
)
43-
assert check_item.path == want_path
44-
assert (
45-
check_item.get("ipfs", with_album=False)
46-
== want_item.ipfs
47-
)
48-
assert check_item.title == want_item.title
49-
found = True
50-
except AttributeError:
51-
pass
52-
assert found
32+
with added_albums.music_dir_context():
33+
added_album = added_albums.get_album(1)
34+
assert added_album.ipfs == test_album.ipfs
35+
found = False
36+
want_item = test_album.items()[2]
37+
for check_item in added_album.items():
38+
try:
39+
if check_item.get("ipfs", with_album=False):
40+
ipfs_item = os.fsdecode(
41+
os.path.basename(want_item.path)
42+
)
43+
want_path = util.normpath(
44+
os.path.join("/ipfs", test_album.ipfs, ipfs_item)
45+
)
46+
assert check_item.path == want_path
47+
assert (
48+
check_item.get("ipfs", with_album=False)
49+
== want_item.ipfs
50+
)
51+
assert check_item.title == want_item.title
52+
found = True
53+
except AttributeError:
54+
pass
55+
assert found
5356

5457
def mk_test_album(self):
5558
items = [_common.item() for _ in range(3)]

0 commit comments

Comments
 (0)