Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pathvalidate/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,8 @@ def truncate_str(text: str, encoding: str, max_bytes: int) -> str:
str_bytes = text.encode(encoding)
str_bytes = str_bytes[:max_bytes]
# last char might be malformed, ignore it
return str_bytes.decode(encoding, "ignore")
truncated = str_bytes.decode(encoding, "ignore")
# Stateful encodings can add closing escape sequences when re-encoded.
while truncated and len(truncated.encode(encoding)) > max_bytes:
truncated = truncated[:-1]
return truncated
22 changes: 22 additions & 0 deletions test/test_filename.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,3 +808,25 @@ def test_max_len_fs_encoding(self, value, platform, fs_encoding, max_len, expect
"fs_encoding": fs_encoding,
}
assert sanitize_filename(value, **kwargs) == expected

@pytest.mark.parametrize(
["value", "fs_encoding", "max_len", "expected"],
[
["日本語", "iso2022_jp", 8, "日"],
["日本語", "iso2022_jp", 9, "日"],
["日本語", "iso2022_jp", 10, "日本"],
["日本語", "iso2022_jp", 12, "日本語"],
["汉字测试", "hz", 8, "汉字"],
["日本語", "utf-7", 7, "日"],
["日本語", "utf-7", 8, "日本"],
["日本語", "utf-8", 8, "日本"],
["日本語", "utf-16", 7, "日本"],
],
)
def test_sanitized_name_fits_reencoded_byte_limit(self, value, fs_encoding, max_len, expected):
kwargs = {"platform": "linux", "fs_encoding": fs_encoding, "max_len": max_len}
sanitized = sanitize_filename(value, **kwargs)
assert sanitized == expected
assert len(sanitized.encode(fs_encoding)) <= max_len
validate_filename(sanitized, **kwargs)
assert sanitize_filename(value, validate_after_sanitize=True, **kwargs) == expected