Skip to content

Commit a135d1d

Browse files
committed
Normalise Windows paths
1 parent f032c91 commit a135d1d

4 files changed

Lines changed: 29 additions & 11 deletions

File tree

beets/dbcore/pathutils.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
from typing import TypeVar
55

66
from beets import context, util
7+
from beets.util import path_as_posix
78

89
MaybeBytes = TypeVar("MaybeBytes", bytes, None)
10+
DB_PATH_SEP = b"/"
911

1012

1113
def _is_same_path_or_child(path: bytes, music_dir: bytes) -> bool:
@@ -17,6 +19,16 @@ def _is_same_path_or_child(path: bytes, music_dir: bytes) -> bool:
1719
)
1820

1921

22+
def _to_db_path(path: bytes) -> bytes:
23+
"""Store relative paths with a platform-neutral separator."""
24+
return path_as_posix(path)
25+
26+
27+
def _from_db_path(path: bytes) -> bytes:
28+
"""Convert a stored relative path to the current platform syntax."""
29+
return path.replace(DB_PATH_SEP, os.fsencode(os.sep))
30+
31+
2032
def normalize_path_for_db(path: MaybeBytes) -> MaybeBytes:
2133
"""Convert an absolute library path to its database representation."""
2234
if not path or not os.path.isabs(path):
@@ -27,7 +39,7 @@ def normalize_path_for_db(path: MaybeBytes) -> MaybeBytes:
2739
return path
2840

2941
if _is_same_path_or_child(path, music_dir):
30-
return os.path.relpath(path, music_dir)
42+
return _to_db_path(os.path.relpath(path, music_dir))
3143

3244
return path
3345

@@ -36,6 +48,6 @@ def expand_path_from_db(path: bytes) -> bytes:
3648
"""Convert a stored database path to an absolute library path."""
3749
music_dir = context.get_music_dir()
3850
if path and not os.path.isabs(path) and music_dir:
39-
return util.normpath(os.path.join(music_dir, path))
51+
return util.normpath(os.path.join(music_dir, _from_db_path(path)))
4052

4153
return path

beets/library/models.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,11 @@ def field_query(
112112
):
113113
# Regex, exact, and string queries operate on the raw DB value, so
114114
# strip the library prefix to match the stored relative path.
115-
if isinstance(pattern, bytes):
116-
pattern = normalize_path_for_db(pattern)
117-
else:
118-
pattern = os.fsdecode(
119-
normalize_path_for_db(util.bytestring_path(pattern))
120-
)
115+
bytes_pattern = normalize_path_for_db(util.bytestring_path(pattern))
116+
if query_cls is not dbcore.query.RegexpQuery:
117+
bytes_pattern = util.path_as_posix(bytes_pattern)
118+
pattern = os.fsdecode(bytes_pattern)
119+
121120
if field in cls.shared_db_fields:
122121
# This field exists in both tables, so SQLite will encounter
123122
# an OperationalError if we try to use it in a query.

test/library/test_migrations.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from beets.library import migrations
99
from beets.library.models import Album, Item
1010
from beets.test.helper import TestHelper
11+
from beets.util import path_as_posix
1112

1213

1314
class TestMultiGenreFieldMigration:
@@ -270,6 +271,6 @@ def test_migrate(self, helper: TestHelper):
270271
.execute("select path from items where id=?", (item.id,))
271272
.fetchone()[0]
272273
)
273-
assert stored_path == os.fsencode(relative_path)
274+
assert stored_path == path_as_posix(os.fsencode(relative_path))
274275
# and the item.path property still returns an absolute path
275276
assert item.path == absolute_path

test/test_library.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@
3434
from beets.test import _common
3535
from beets.test._common import item
3636
from beets.test.helper import BeetsTestCase, ItemInDBTestCase, capture_log
37-
from beets.util import as_string, bytestring_path, normpath, syspath
37+
from beets.util import (
38+
as_string,
39+
bytestring_path,
40+
normpath,
41+
path_as_posix,
42+
syspath,
43+
)
3844

3945
# Shortcut to path normalization.
4046
np = util.normpath
@@ -1143,7 +1149,7 @@ def test_relative_path_is_stored(self):
11431149
album = self.lib.add_album([self.i])
11441150

11451151
assert self.i.path == absolute_path
1146-
assert stored_path == relative_path
1152+
assert stored_path == path_as_posix(relative_path)
11471153
assert album.path == os.path.dirname(absolute_path)
11481154

11491155

0 commit comments

Comments
 (0)