mirror of
https://github.com/beetbox/beets.git
synced 2026-01-30 03:54:21 +01:00
Fix and simplify path truncation
This commit is contained in:
parent
b3fd84b356
commit
40fbc8ee7e
2 changed files with 30 additions and 29 deletions
|
|
@ -696,22 +696,26 @@ def sanitize_path(path: str, replacements: Replacements | None = None) -> str:
|
|||
return os.path.join(*comps)
|
||||
|
||||
|
||||
def truncate_path(path: AnyStr) -> AnyStr:
|
||||
"""Given a bytestring path or a Unicode path fragment, truncate the
|
||||
components to a legal length. In the last component, the extension
|
||||
is preserved.
|
||||
def truncate_str(s: str, length: int) -> str:
|
||||
"""Truncate the string to the given byte length.
|
||||
|
||||
If we end up truncating a unicode character in the middle (rendering it invalid),
|
||||
it is removed:
|
||||
|
||||
>>> s = "🎹🎶" # 8 bytes
|
||||
>>> truncate_str(s, 6)
|
||||
'🎹'
|
||||
"""
|
||||
return os.fsencode(s)[:length].decode(sys.getfilesystemencoding(), "ignore")
|
||||
|
||||
|
||||
def truncate_path(str_path: str) -> str:
|
||||
"""Truncate each path part to a legal length preserving the extension."""
|
||||
max_length = get_max_filename_length()
|
||||
comps = components(path)
|
||||
|
||||
out = [c[:length] for c in comps]
|
||||
base, ext = os.path.splitext(comps[-1])
|
||||
if ext:
|
||||
# Last component has an extension.
|
||||
base = base[: max_length - len(ext)]
|
||||
out[-1] = base + ext
|
||||
|
||||
return os.path.join(*out)
|
||||
path = Path(str_path)
|
||||
parent_parts = [truncate_str(p, max_length) for p in path.parts[:-1]]
|
||||
stem = truncate_str(path.stem, max_length - len(path.suffix))
|
||||
return str(Path(*parent_parts, stem).with_suffix(path.suffix))
|
||||
|
||||
|
||||
def _legalize_stage(
|
||||
|
|
|
|||
|
|
@ -175,18 +175,15 @@ class PathConversionTest(BeetsTestCase):
|
|||
assert outpath == "C:\\caf\xe9".encode()
|
||||
|
||||
|
||||
class PathTruncationTest(BeetsTestCase):
|
||||
def test_truncate_bytestring(self):
|
||||
with _common.platform_posix():
|
||||
p = util.truncate_path(b"abcde/fgh", 4)
|
||||
assert p == b"abcd/fgh"
|
||||
|
||||
def test_truncate_unicode(self):
|
||||
with _common.platform_posix():
|
||||
p = util.truncate_path("abcde/fgh", 4)
|
||||
assert p == "abcd/fgh"
|
||||
|
||||
def test_truncate_preserves_extension(self):
|
||||
with _common.platform_posix():
|
||||
p = util.truncate_path("abcde/fgh.ext", 5)
|
||||
assert p == "abcde/f.ext"
|
||||
@patch("beets.util.get_max_filename_length", lambda: 5)
|
||||
@pytest.mark.parametrize(
|
||||
"path, expected",
|
||||
[
|
||||
("abcdeX/fgh", "abcde/fgh"),
|
||||
("abcde/fXX.ext", "abcde/f.ext"),
|
||||
("a🎹/a.ext", "a🎹/a.ext"),
|
||||
("ab🎹/a.ext", "ab/a.ext"),
|
||||
],
|
||||
)
|
||||
def test_truncate_path(path, expected):
|
||||
assert util.truncate_path(path) == expected
|
||||
|
|
|
|||
Loading…
Reference in a new issue