mirror of https://github.com/streamlink/streamlink
cli.utils.path: add truncate_path()
This commit is contained in:
parent
4abb9ae9cf
commit
54803f5a80
|
@ -35,6 +35,28 @@ def replace_chars(path: str, charmap: Optional[str] = None, replacement: str = R
|
|||
return pattern.sub(replacement, path)
|
||||
|
||||
|
||||
# This method does not take care of unicode modifier characters when truncating
|
||||
def truncate_path(path: str, length: int = 255, keep_extension: bool = True) -> str:
|
||||
if len(path) <= length:
|
||||
return path
|
||||
|
||||
parts = path.rsplit(".", 1)
|
||||
|
||||
# no file name extension (no dot separator in path or file name extension too long):
|
||||
# truncate the whole thing
|
||||
if not keep_extension or len(parts) == 1 or len(parts[1]) > 10:
|
||||
encoded = path.encode("utf-8")
|
||||
truncated = encoded[:length]
|
||||
decoded = truncated.decode("utf-8", errors="ignore")
|
||||
return decoded
|
||||
|
||||
# truncate file name, but keep file name extension
|
||||
encoded = parts[0].encode("utf-8")
|
||||
truncated = encoded[:length - len(parts[1]) - 1]
|
||||
decoded = truncated.decode("utf-8", errors="ignore")
|
||||
return f"{decoded}.{parts[1]}"
|
||||
|
||||
|
||||
def replace_path(pathlike: Union[str, Path], mapper: Callable[[str], str]) -> Path:
|
||||
def get_part(part):
|
||||
newpart = mapper(part)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from pathlib import Path
|
||||
from string import ascii_lowercase as alphabet
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from streamlink_cli.utils.path import replace_chars, replace_path
|
||||
from streamlink_cli.utils.path import replace_chars, replace_path, truncate_path
|
||||
|
||||
|
||||
@pytest.mark.parametrize("char", list(range(32)))
|
||||
|
@ -77,3 +79,117 @@ def test_replace_path_expanduser_posix(os_environ):
|
|||
def test_replace_path_expanduser_windows(os_environ):
|
||||
assert replace_path("~\\bar", lambda s: s) == Path("C:\\Users\\foo\\bar")
|
||||
assert replace_path("foo\\bar", lambda s: dict(foo="~").get(s, s)) == Path("~\\bar")
|
||||
|
||||
|
||||
text = alphabet * 10
|
||||
bear = "🐻" # Unicode character: "Bear Face" (U+1F43B)
|
||||
bears = bear * 512
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("args", "expected"), [
|
||||
pytest.param(
|
||||
(alphabet, 255, True),
|
||||
alphabet,
|
||||
id="text - no truncation",
|
||||
),
|
||||
pytest.param(
|
||||
(text, 255, True),
|
||||
text[:255],
|
||||
id="text - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(text, 50, True),
|
||||
text[:50],
|
||||
id="text - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{alphabet}.ext", 255, True),
|
||||
f"{alphabet}.ext",
|
||||
id="text+ext1 - no truncation",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{text}.ext", 255, True),
|
||||
f"{text[:251]}.ext",
|
||||
id="text+ext1 - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{text}.ext", 50, True),
|
||||
f"{text[:46]}.ext",
|
||||
id="text+ext1 - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{text}.ext", 255, False),
|
||||
text[:255],
|
||||
id="text+ext1+nokeep - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{text}.ext", 50, False),
|
||||
text[:50],
|
||||
id="text+ext1+nokeep - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{text}.notafilenameextension", 255, True),
|
||||
text[:255],
|
||||
id="text+ext2 - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{text}.notafilenameextension", 50, True),
|
||||
text[:50],
|
||||
id="text+ext2 - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(bear, 255, True),
|
||||
bear,
|
||||
id="bear - no truncation",
|
||||
),
|
||||
pytest.param(
|
||||
(bears, 255, True),
|
||||
bear * 63,
|
||||
id="bear - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(bears, 50, True),
|
||||
bear * 12,
|
||||
id="bear - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bear}.ext", 255, True),
|
||||
f"{bear}.ext",
|
||||
id="bear+ext1 - no truncation",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bears}.ext", 255, True),
|
||||
f"{bear * 62}.ext",
|
||||
id="bear+ext1 - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bears}.ext", 50, True),
|
||||
f"{bear * 11}.ext",
|
||||
id="bear+ext1 - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bears}.ext", 255, False),
|
||||
bear * 63,
|
||||
id="bear+ext1+nokeep - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bears}.ext", 50, False),
|
||||
bear * 12,
|
||||
id="bear+ext1+nokeep - truncate at 50",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bears}.notafilenameextension", 255, True),
|
||||
bear * 63,
|
||||
id="bear+ext2 - truncate",
|
||||
),
|
||||
pytest.param(
|
||||
(f"{bears}.notafilenameextension", 50, True),
|
||||
bear * 12,
|
||||
id="bear+ext2 - truncate at 50",
|
||||
),
|
||||
])
|
||||
def test_truncate_path(args: Tuple[str, int, bool], expected: str):
|
||||
path, length, keep_extension = args
|
||||
result = truncate_path(path, length, keep_extension)
|
||||
assert len(result.encode("utf-8")) <= length
|
||||
assert result == expected
|
||||
|
|
Loading…
Reference in New Issue