11from __future__ import annotations
22
3+ from contextlib import contextmanager
34from typing import TYPE_CHECKING
45
56import 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
0 commit comments