Skip to content

Commit c1b11aa

Browse files
committed
Fix paths for Windows
1 parent 27cf3bd commit c1b11aa

5 files changed

Lines changed: 21 additions & 20 deletions

File tree

beets/dbcore/pathutils.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
from beets import context, util
66

77

8+
def _is_same_path_or_child(path: bytes, music_dir: bytes) -> bool:
9+
path_cmp = os.path.normcase(os.fsdecode(path))
10+
music_dir_cmp = os.path.normcase(os.fsdecode(music_dir))
11+
return path_cmp == music_dir_cmp or path_cmp.startswith(
12+
os.path.join(music_dir_cmp, "")
13+
)
14+
15+
816
def normalize_path_for_db(path: bytes) -> bytes:
917
"""Convert an absolute library path to its database representation."""
1018
if not path or not os.path.isabs(path):
@@ -14,10 +22,7 @@ def normalize_path_for_db(path: bytes) -> bytes:
1422
if not music_dir:
1523
return path
1624

17-
if path == music_dir:
18-
return os.path.relpath(path, music_dir)
19-
20-
if path.startswith(os.path.join(music_dir, b"")):
25+
if _is_same_path_or_child(path, music_dir):
2126
return os.path.relpath(path, music_dir)
2227

2328
return path

beets/library/models.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
from mediafile import MediaFile, UnreadableFileError
1313

1414
import beets
15-
from beets import context, dbcore, logging, plugins, util
15+
from beets import dbcore, logging, plugins, util
1616
from beets.dbcore import types
17+
from beets.dbcore.pathutils import normalize_path_for_db
1718
from beets.util import (
1819
MoveOperation,
1920
bytestring_path,
@@ -104,19 +105,15 @@ def field_query(
104105
if (
105106
cls._type(field).query is dbcore.query.PathQuery
106107
and query_cls is not dbcore.query.PathQuery
107-
and (music_dir := context.get_music_dir())
108108
):
109109
# Regex, exact, and string queries operate on the raw DB value, so
110110
# strip the library prefix to match the stored relative path.
111111
if isinstance(pattern, bytes):
112-
prefix = os.path.join(music_dir, b"")
113-
if pattern.startswith(prefix):
114-
pattern = os.path.relpath(pattern, music_dir)
112+
pattern = normalize_path_for_db(pattern)
115113
else:
116-
music_dir_str = os.fsdecode(music_dir)
117-
prefix = music_dir_str + os.sep
118-
if pattern.startswith(prefix):
119-
pattern = pattern.removeprefix(prefix)
114+
pattern = os.fsdecode(
115+
normalize_path_for_db(util.bytestring_path(pattern))
116+
)
120117
if field in cls.shared_db_fields:
121118
# This field exists in both tables, so SQLite will encounter
122119
# an OperationalError if we try to use it in a query.

test/library/test_migrations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def helper(self, monkeypatch):
161161
helper.teardown_beets()
162162

163163
def test_migrate(self, helper: TestHelper):
164-
relative_path = "foo/bar/baz.mp3"
164+
relative_path = os.path.join("foo", "bar", "baz.mp3")
165165
absolute_path = os.fsencode(helper.lib_path / relative_path)
166166

167167
# need to insert the path directly into the database to bypass the path setter

test/plugins/test_ipfs.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import os
1616
from unittest.mock import Mock, patch
1717

18+
from beets import util
1819
from beets.test import _common
1920
from beets.test.helper import PluginTestCase
20-
from beets.util import bytestring_path
2121
from beetsplug.ipfs import IPFSPlugin
2222

2323

@@ -37,10 +37,9 @@ def test_stored_hashes(self):
3737
try:
3838
if check_item.get("ipfs", with_album=False):
3939
ipfs_item = os.fsdecode(os.path.basename(want_item.path))
40-
want_path = os.path.normpath(
41-
f"/ipfs/{test_album.ipfs}/{ipfs_item}"
40+
want_path = util.normpath(
41+
os.path.join("/ipfs", test_album.ipfs, ipfs_item)
4242
)
43-
want_path = bytestring_path(want_path)
4443
assert check_item.path == want_path
4544
assert (
4645
check_item.get("ipfs", with_album=False)

test/test_library.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ def test_art_destination_returns_bytestring(self):
10941094
assert isinstance(dest, bytes)
10951095

10961096
def test_artpath_stores_special_chars(self):
1097-
path = b"b\xe1r"
1097+
path = bytestring_path("b\xe1r")
10981098
alb = self.lib.add_album([self.i])
10991099
alb.artpath = path
11001100
alb.store()
@@ -1131,7 +1131,7 @@ def test_unicode_artpath_in_database_decoded(self):
11311131
assert isinstance(alb.artpath, bytes)
11321132

11331133
def test_relative_path_is_stored(self):
1134-
relative_path = b"abc/foo.mp3"
1134+
relative_path = os.path.join(b"abc", b"foo.mp3")
11351135
absolute_path = os.path.join(self.libdir, relative_path)
11361136
self.i.path = absolute_path
11371137
self.i.store()

0 commit comments

Comments
 (0)